diff --git a/cmake/HPX_CXXModules.cmake b/cmake/HPX_CXXModules.cmake index f01bf4c3e0a1..e736607a74d7 100644 --- a/cmake/HPX_CXXModules.cmake +++ b/cmake/HPX_CXXModules.cmake @@ -68,7 +68,6 @@ endif() # hpx_configure_module_producer( [MODULE_OUT_DIR ]) # # * Ensures a stable module output dir for producer target -# * Adds compiler flags to write module cache there (Clang/GCC) # * Creates an interface target '_if' for consumers to link to function(hpx_configure_module_producer producer) if(NOT TARGET ${producer}) @@ -103,35 +102,6 @@ function(hpx_configure_module_producer producer) # Make sure consumers scan for the BMI set_target_properties(${_iface} PROPERTIES INTERFACE_CXX_SCAN_FOR_MODULES On) - - if(MSVC) - # MSVC: CMake/MSVC handle IFCs automatically; create a target for - # convenience, consumers can link to this to get ordering and include info - return() - endif() - - # Compiler-specific flags to instruct where to write module cache - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES - "AppleClang" - ) - # Clang common flags - target_compile_options(${producer} PRIVATE "-fmodule-output=${_moddir}") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - # GCC: modern flags - hpx_add_target_compile_option_if_available( - ${producer} PRIVATE "-fmodule-output=${_moddir}" RESULT ok - ) - if(NOT ok) - hpx_error( - "hpx_configure_module_producer: the used version of gcc does not support '-fmodule-output'" - ) - endif() - else() - hpx_warn( - "hpx_configure_module_producer: unknown compiler '${CMAKE_CXX_COMPILER_ID}'; " - "exposing EXPORT_MODULE_DIR='${_moddir}' for manual handling" - ) - endif() endfunction() # hpx_configure_module_consumer( ]) @@ -146,6 +116,16 @@ function(hpx_configure_module_consumer consumer producer) hpx_error("hpx_configure_module_consumer: target '${producer}' not found") endif() + # Imported module metadata is only picked up from direct link dependencies. + # Link the underlying module target directly when the producer follows the + # '_if' wrapper pattern. + if(producer MATCHES "_if$") + string(REGEX REPLACE "_if$" "" _producer_target "${producer}") + if(TARGET ${_producer_target}) + target_link_libraries(${consumer} PRIVATE ${_producer_target}) + endif() + endif() + target_link_libraries(${consumer} PRIVATE ${producer}) get_target_property(_scan ${producer} INTERFACE_CXX_SCAN_FOR_MODULES) if(_scan) @@ -159,28 +139,11 @@ function(hpx_configure_module_consumer consumer producer) elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) - target_compile_options( - ${consumer} PRIVATE "-fprebuilt-module-path=${_module_dir}" - ) get_target_property(_type ${consumer} TYPE) if((_type STREQUAL "SHARED_LIBRARY") OR (_type STREQUAL "EXECUTABLE")) target_link_options(${consumer} PRIVATE "-fuse-ld=lld") target_link_options(${consumer} PRIVATE "-Wl,--error-limit=0") endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - hpx_add_target_compile_option_if_available( - ${consumer} PRIVATE "-fprebuilt-module-path=${_module_dir}" RESULT ok - ) - if(NOT ok) - hpx_error( - "hpx_configure_module_consumer: the used version of gcc does not " - "support '-fprebuilt-module-path='" - ) - endif() - else() - hpx_warn( - "hpx_configure_module_consumer: unknown compiler '${CMAKE_CXX_COMPILER_ID}'" - ) endif() endif() endfunction() diff --git a/cmake/HPX_CollectStdHeaders.cmake b/cmake/HPX_CollectStdHeaders.cmake index 8faaf7bbef37..2ae2aeedc6d6 100644 --- a/cmake/HPX_CollectStdHeaders.cmake +++ b/cmake/HPX_CollectStdHeaders.cmake @@ -105,6 +105,10 @@ set(STANDARD_LIBRARY_HEADERS "" ) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND STANDARD_LIBRARY_HEADERS "" "") +endif() + # Function to extract #includes from a file recursively function(hpx_extract_includes_from_file module) @@ -137,8 +141,11 @@ function(hpx_extract_includes_from_file module) if(NOT filename MATCHES "\\.|/") # Check if the include is a standard library header if(${filename} IN_LIST STANDARD_LIBRARY_HEADERS) - list(APPEND found_includes ${filename}) + list(APPEND found_includes "${filename}") endif() + elseif(${filename} IN_LIST STANDARD_LIBRARY_HEADERS) + # Handle headers with extensions (like link.h) that were added to the list + list(APPEND found_includes "${filename}") endif() endforeach() diff --git a/cmake/HPX_GeneratePackage.cmake b/cmake/HPX_GeneratePackage.cmake index d62821cebad8..1615209c9e76 100644 --- a/cmake/HPX_GeneratePackage.cmake +++ b/cmake/HPX_GeneratePackage.cmake @@ -19,11 +19,19 @@ write_basic_package_version_file( COMPATIBILITY AnyNewerVersion ) -# Export HPXInternalTargets in the build directory +# CXX_MODULES_DIRECTORY was added in CMake 3.28 +set(_cxx_modules_directory_arg) +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28") + set(_cxx_modules_directory_arg CXX_MODULES_DIRECTORY cxx-modules) +endif() + +# Export HPXInternalTargets in the build directory. Use the EXPORT signature so +# CMake also generates the per-target C++ module metadata files. export( - TARGETS ${HPX_EXPORT_INTERNAL_TARGETS} + EXPORT HPXInternalTargets NAMESPACE HPXInternal:: FILE "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${HPX_PACKAGE_NAME}/HPXInternalTargets.cmake" + ${_cxx_modules_directory_arg} ) # Export HPXInternalTargets in the install directory @@ -32,14 +40,17 @@ install( NAMESPACE HPXInternal:: FILE HPXInternalTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${HPX_PACKAGE_NAME} + ${_cxx_modules_directory_arg} COMPONENT cmake ) -# Export HPXTargets in the build directory +# Export HPXTargets in the build directory. Use the EXPORT signature so CMake +# also generates the per-target C++ module metadata files. export( - TARGETS ${HPX_EXPORT_TARGETS} + EXPORT HPXTargets NAMESPACE HPX:: FILE "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${HPX_PACKAGE_NAME}/HPXTargets.cmake" + ${_cxx_modules_directory_arg} ) # Add aliases with the namespace for use within HPX @@ -57,6 +68,7 @@ install( NAMESPACE HPX:: FILE HPXTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${HPX_PACKAGE_NAME} + ${_cxx_modules_directory_arg} COMPONENT cmake ) diff --git a/cmake/templates/hpx.ixx.in b/cmake/templates/hpx.ixx.in index b31141b6b765..8c22fcbb9dbe 100644 --- a/cmake/templates/hpx.ixx.in +++ b/cmake/templates/hpx.ixx.in @@ -23,8 +23,6 @@ export module HPX.@cap_libname@; // Make sure the exported symbols are name-mangled using standard C++ rules. // This is necessary as otherwise the symbols exported from the shared libraries // will be exported from the module using a differently encoded name. -extern "C++" { - #if defined(HPX_MSVC) // disable warning C5244: '#include ' in the purview of module // 'HPX.@cap_libname@' appears erroneous. Consider moving that directive before the @@ -51,5 +49,3 @@ extern "C++" { #if defined(HPX_MSVC) #pragma warning(pop) #endif - -} // extern "C++" diff --git a/examples/gtest_emulation/CMakeLists.txt b/examples/gtest_emulation/CMakeLists.txt index 4b2e39f1d6a7..9930b98dc3a4 100644 --- a/examples/gtest_emulation/CMakeLists.txt +++ b/examples/gtest_emulation/CMakeLists.txt @@ -14,6 +14,17 @@ if(EXISTS "${HPX_DIR}") if(HPX_WITH_CXX_MODULES) set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + # CMake only propagates imported C++ module metadata from targets that are + # linked directly by the consumer. The exported HPXInternal module targets + # are therefore linked explicitly for the external build tests. + set(hpx_cxx_module_targets) + if(TARGET HPXInternal::hpx_core_module) + list(APPEND hpx_cxx_module_targets HPXInternal::hpx_core_module) + endif() + if(TARGET HPXInternal::hpx_full_module) + list(APPEND hpx_cxx_module_targets HPXInternal::hpx_full_module) + endif() endif() # Add a static library which contains a main to emulate gtest_main @@ -27,7 +38,11 @@ if(EXISTS "${HPX_DIR}") # Test with the main function in a separate static library add_executable(hpx_main_ext_main hpx_main_ext_main.cpp) - target_link_libraries(hpx_main_ext_main PRIVATE hpx_helper_interface) + # Keep the helper interface for link order, but link module targets directly + # to the executable so CMake can see the imported BMI metadata. + target_link_libraries( + hpx_main_ext_main PRIVATE hpx_helper_interface ${hpx_cxx_module_targets} + ) enable_testing() add_test(hello_world_test hpx_main_ext_main) diff --git a/examples/hello_world_component/CMakeLists.txt b/examples/hello_world_component/CMakeLists.txt index 48ad4d4cd9b7..1e86f4f24e72 100644 --- a/examples/hello_world_component/CMakeLists.txt +++ b/examples/hello_world_component/CMakeLists.txt @@ -17,6 +17,17 @@ if(EXISTS "${HPX_DIR}") if(HPX_WITH_CXX_MODULES) set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + # CMake only propagates imported C++ module metadata from targets that are + # linked directly by the consumer. The exported HPXInternal module targets + # are therefore linked explicitly for the external build tests. + set(hpx_cxx_module_targets) + if(TARGET HPXInternal::hpx_core_module) + list(APPEND hpx_cxx_module_targets HPXInternal::hpx_core_module) + endif() + if(TARGET HPXInternal::hpx_full_module) + list(APPEND hpx_cxx_module_targets HPXInternal::hpx_full_module) + endif() endif() add_executable(hello_world_client hello_world_client.cpp) @@ -26,11 +37,15 @@ if(EXISTS "${HPX_DIR}") if(HPX_WITH_DISTRIBUTED_RUNTIME) target_link_libraries( hello_world_component PUBLIC HPX::hpx HPX::iostreams_component + ${hpx_cxx_module_targets} ) target_link_libraries(hello_world_component PRIVATE HPX::component) target_link_libraries(hello_world_client PRIVATE hello_world_component) endif() - target_link_libraries(hello_world_client PRIVATE HPX::hpx HPX::wrap_main) + target_link_libraries( + hello_world_client PRIVATE HPX::hpx HPX::wrap_main + ${hpx_cxx_module_targets} + ) # We still support not linking to HPX::wrap_main when # HPX_WITH_DYNAMIC_HPX_MAIN=OFF for legacy use. This can only be done using @@ -44,6 +59,7 @@ if(EXISTS "${HPX_DIR}") target_link_libraries( hello_world_client_only_hpx_init PRIVATE hello_world_component + ${hpx_cxx_module_targets} ) endif() elseif("${SETUP_TYPE}" STREQUAL "MACROS") diff --git a/examples/transpose/transpose_smp_block.cpp b/examples/transpose/transpose_smp_block.cpp index 8c2563076433..0092b977579f 100644 --- a/examples/transpose/transpose_smp_block.cpp +++ b/examples/transpose/transpose_smp_block.cpp @@ -96,7 +96,8 @@ int hpx_main(hpx::program_options::variables_map& vm) std::vector> transpose_futures; transpose_futures.resize(num_blocks); - for_each(par, range, [&](std::uint64_t b) { + for (std::uint64_t b = 0; b < num_blocks; ++b) + { transpose_futures[b] = for_each(par(task), range, [&, b](std::uint64_t phase) { std::uint64_t const block_size = block_order * block_order; @@ -108,7 +109,7 @@ int hpx_main(hpx::program_options::variables_map& vm) transpose(&A[from_block][A_offset], &B[b][B_offset], block_order, tile_size); }).share(); - }); + } hpx::wait_all(transpose_futures); diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 774a18e36ccc..dcff20658cc3 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -338,6 +338,11 @@ foreach(lib ${HPX_LIBS}) # src/CMakeLists.txt. When all of hpx_full has been modularized the target # creation can move here as well. if(HPX_WITH_CXX_MODULES) + if(NOT TARGET hpx_modules) + add_custom_target(hpx_modules ALL) + set_target_properties(hpx_modules PROPERTIES FOLDER "Core") + endif() + add_library(hpx_${lib}_module STATIC) set_target_properties( hpx_${lib}_module PROPERTIES POSITION_INDEPENDENT_CODE ON @@ -353,6 +358,7 @@ foreach(lib ${HPX_LIBS}) PRIVATE hpx_private_flags ) set_target_properties(hpx_${lib}_module PROPERTIES FOLDER "Core") + add_dependencies(hpx_modules hpx_${lib}_module) add_hpx_source_group( NAME hpx_${lib}_module diff --git a/tests/unit/build/CMakeLists.txt b/tests/unit/build/CMakeLists.txt index 7387f4ba7f56..2a200bb3bd49 100644 --- a/tests/unit/build/CMakeLists.txt +++ b/tests/unit/build/CMakeLists.txt @@ -10,12 +10,6 @@ if(NOT HPX_WITH_TESTS_EXTERNAL_BUILD) return() endif() -# If C++ modules are enabled, exit now (we don't know yet how to setup a -# dependent HPX project to use the generated BMIs). -if(HPX_WITH_CXX_MODULES) - return() -endif() - # Try building an external cmake based project ... function( create_cmake_test @@ -79,6 +73,14 @@ function( VERBATIM ) add_dependencies(${name} hpx hpx_init hpx_wrap) + if(HPX_WITH_CXX_MODULES) + if(TARGET hpx_core_module) + add_dependencies(${name} hpx_core_module) + endif() + if(TARGET hpx_full_module) + add_dependencies(${name} hpx_full_module) + endif() + endif() if(HPX_WITH_DISTRIBUTED_RUNTIME) add_dependencies(${name} iostreams_component) endif() @@ -200,7 +202,10 @@ foreach(build_type ${build_types}) endforeach() add_hpx_pseudo_dependencies(tests.unit.build tests.unit.build.cmake) -if(HPX_WITH_PKGCONFIG AND HPX_WITH_DISTRIBUTED_RUNTIME) +if(HPX_WITH_PKGCONFIG + AND HPX_WITH_DISTRIBUTED_RUNTIME + AND NOT HPX_WITH_CXX_MODULES +) find_package(PkgConfig) if(PKGCONFIG_FOUND) create_pkgconfig_test(