Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ root = true
[*.{h,hpp}]
indent_style = tab
indent_size = 4
# end_of_line = crlf
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
Expand Down
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* text=auto eol=lf

*.bat text eol=crlf
*.cmd text eol=crlf
68 changes: 68 additions & 0 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Test with CMake

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends -y \
libcereal-dev \
libopenmpi-dev \
ninja-build \
openmpi-bin

- name: Configure
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install" \
-DBUILD_TESTING=ON

- name: Check public headers
run: cmake --build build --target libcomm_public_header_check -j $(nproc)

- name: Run tests
run: ctest --test-dir build --output-on-failure

- name: Install
run: cmake --install build

- name: Test installed package
run: |
mkdir -p consumer
cat > consumer/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.23)
project(LibCommConsumer LANGUAGES CXX)

find_package(LibComm CONFIG REQUIRED)

add_executable(libcomm_consumer main.cpp)
target_link_libraries(libcomm_consumer PRIVATE LibComm::LibComm)
EOF

cat > consumer/main.cpp <<'EOF'
#include <Comm/Comm_Assemble/Comm_Assemble.h>

int main()
{
return 0;
}
EOF

cmake -S consumer -B consumer/build -G Ninja \
-DCMAKE_PREFIX_PATH="${{ github.workspace }}/install"
cmake --build consumer/build --parallel 2
126 changes: 126 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
cmake_minimum_required(VERSION 3.23)
if(POLICY CMP0144) # https://cmake.org/cmake/help/git-stage/policy/CMP0144.html
cmake_policy(SET CMP0144 NEW)
endif()

set(LIBCOMM_PACKAGE_VERSION "0.2.0" CACHE STRING
"Package version used for generated LibCommConfigVersion.cmake when the source tree has no explicit release version.")

project(LibComm
VERSION "${LIBCOMM_PACKAGE_VERSION}"
DESCRIPTION "Header-only MPI communication helpers used by LibRI and ABACUS"
LANGUAGES CXX)

include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
include(CTest)

list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

option(LIBCOMM_INSTALL_EXAMPLE_HEADERS
"Install example helper headers under include/Comm/example."
ON)
option(LIBCOMM_ENABLE_HEADER_CHECK
"Add an explicit, non-default target that checks public headers for self-contained compilation."
ON)

find_package(Threads REQUIRED)
find_package(MPI REQUIRED COMPONENTS CXX)
find_package(OpenMP REQUIRED COMPONENTS CXX)
find_package(cereal REQUIRED)

file(GLOB_RECURSE LIBCOMM_PUBLIC_HEADERS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/include/Comm/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/Comm/*.hpp")

if(NOT LIBCOMM_INSTALL_EXAMPLE_HEADERS)
list(FILTER LIBCOMM_PUBLIC_HEADERS EXCLUDE REGEX "/include/Comm/example/")
endif()

add_library(LibComm INTERFACE)
add_library(LibComm::LibComm ALIAS LibComm)

set_target_properties(LibComm PROPERTIES
EXPORT_NAME LibComm)

target_sources(LibComm
INTERFACE
FILE_SET public_headers
TYPE HEADERS
BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
FILES ${LIBCOMM_PUBLIC_HEADERS})

target_compile_features(LibComm INTERFACE cxx_std_17)

target_include_directories(LibComm
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")

target_link_libraries(LibComm
INTERFACE
MPI::MPI_CXX
OpenMP::OpenMP_CXX
Threads::Threads
cereal::cereal)

install(TARGETS LibComm
EXPORT LibCommTargets
FILE_SET public_headers DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")

install(EXPORT LibCommTargets
NAMESPACE LibComm::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/LibComm")

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibCommConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/LibCommConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/LibComm")

write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/LibCommConfigVersion.cmake"
VERSION "${PROJECT_VERSION}"
COMPATIBILITY SameMajorVersion)

install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/LibCommConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/LibCommConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/LibComm")

install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE"
DESTINATION "${CMAKE_INSTALL_DOCDIR}")

if(BUILD_TESTING AND LIBCOMM_ENABLE_HEADER_CHECK)
add_custom_target(libcomm_public_header_check)
set(_libcomm_header_check_index 0)
foreach(_libcomm_header IN LISTS LIBCOMM_PUBLIC_HEADERS)
math(EXPR _libcomm_header_check_index "${_libcomm_header_check_index} + 1")
file(RELATIVE_PATH _libcomm_header_rel
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${_libcomm_header}")
set(_libcomm_header_check_source
"${CMAKE_CURRENT_BINARY_DIR}/header_check_${_libcomm_header_check_index}.cpp")
file(WRITE "${_libcomm_header_check_source}"
"#include <${_libcomm_header_rel}>\nint main() { return 0; }\n")
add_executable(libcomm_header_check_${_libcomm_header_check_index}
EXCLUDE_FROM_ALL
"${_libcomm_header_check_source}")
target_link_libraries(libcomm_header_check_${_libcomm_header_check_index}
PRIVATE LibComm::LibComm)
add_dependencies(libcomm_public_header_check
libcomm_header_check_${_libcomm_header_check_index})
endforeach()

add_test(NAME libcomm_public_header_check
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}"
--target libcomm_public_header_check
--config "$<CONFIG>")
endif()

set(CPACK_PACKAGE_NAME "LibComm")
set(CPACK_PACKAGE_VENDOR "ABACUS")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Header-only MPI communication helpers")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_GENERATOR "TGZ")
include(CPack)
17 changes: 17 additions & 0 deletions cmake/LibCommConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)

list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")

find_dependency(Threads)
find_dependency(MPI COMPONENTS CXX)
find_dependency(OpenMP COMPONENTS CXX)
find_package(cereal CONFIG QUIET)
if(NOT cereal_FOUND)
find_dependency(Cereal)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/LibCommTargets.cmake")

check_required_components(LibComm)
128 changes: 64 additions & 64 deletions include/Comm/Comm_Assemble/Comm_Assemble.h
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
//=======================
// AUTHOR : Peize Lin
// DATE : 2022-07-06
//=======================
#pragma once
#include "../Comm_Keys/Comm_Keys_31-gather.h"
#include "../Comm_Trans/Comm_Trans.h"
#include "../Comm_Tools.h"
#include <mpi.h>
#include <functional>
namespace Comm
{
template<typename Tkey, typename Tvalue, typename Tdatas_provide, typename Tkeys_require, typename Tdatas_require>
class Comm_Assemble
{
public:
Comm_Assemble(const MPI_Comm &mpi_comm_in);
std::function<
void(
const Tdatas_provide &keys_provide_mine,
std::function<void(const Tkey&)> &func)>
&traverse_keys_provide;
std::function<
const Tvalue&(
const Tkey &key,
const Tdatas_provide &datas_provide)>
get_value_provide;
std::function<
void(
Tkey &&key,
Tvalue &&value,
Tdatas_require &datas_require)>
&set_value_require;
Comm_Tools::Lock_Type &flag_lock_set_value;
std::function<
Tdatas_require(
const int rank_recv)>
&init_datas_local;
std::function<
void(
Tdatas_require &&datas_local,
Tdatas_require &datas_recv)>
&add_datas;
void communicate(
const Tdatas_provide &datas_provide,
const Tkeys_require &keys_require,
Tdatas_require &datas_require);
private:
Comm_Keys_31_SenderTraversal<Tkey,Tdatas_provide,Tkeys_require> comm_keys;
Comm_Trans<Tkey,Tvalue,Tdatas_provide,Tdatas_require> comm_trans;
};
}
#include "Comm_Assemble.hpp"
//=======================
// AUTHOR : Peize Lin
// DATE : 2022-07-06
//=======================

#pragma once

#include "../Comm_Keys/Comm_Keys_31-gather.h"
#include "../Comm_Trans/Comm_Trans.h"
#include "../Comm_Tools.h"

#include <mpi.h>
#include <functional>

namespace Comm
{

template<typename Tkey, typename Tvalue, typename Tdatas_provide, typename Tkeys_require, typename Tdatas_require>
class Comm_Assemble
{
public:
Comm_Assemble(const MPI_Comm &mpi_comm_in);

std::function<
void(
const Tdatas_provide &keys_provide_mine,
std::function<void(const Tkey&)> &func)>
&traverse_keys_provide;
std::function<
const Tvalue&(
const Tkey &key,
const Tdatas_provide &datas_provide)>
get_value_provide;
std::function<
void(
Tkey &&key,
Tvalue &&value,
Tdatas_require &datas_require)>
&set_value_require;

Comm_Tools::Lock_Type &flag_lock_set_value;
std::function<
Tdatas_require(
const int rank_recv)>
&init_datas_local;
std::function<
void(
Tdatas_require &&datas_local,
Tdatas_require &datas_recv)>
&add_datas;

void communicate(
const Tdatas_provide &datas_provide,
const Tkeys_require &keys_require,
Tdatas_require &datas_require);

private:
Comm_Keys_31_SenderTraversal<Tkey,Tdatas_provide,Tkeys_require> comm_keys;
Comm_Trans<Tkey,Tvalue,Tdatas_provide,Tdatas_require> comm_trans;
};

}

#include "Comm_Assemble.hpp"
Loading