Skip to content

Commit b1e91ae

Browse files
Fix C++20 modules BMI configuration and stabilize external build tests
- Resolved Linux configuration mismatches (GNU extensions) by propagating CMAKE_CXX_EXTENSIONS and HPX_CXX_STANDARD to external tests. - Fixed Windows installation crashes by removing CXX_MODULES_DIRECTORY from install(EXPORT) and adding MSVC guards for Clang linker flags. - Improved module metadata propagation by explicitly linking HPXInternal module targets in external examples. - Added CXX_STANDARD support to hpx_setup_target and applied it to hello_world_component. - Skipped pkg-config tests when modules are enabled due to lack of BMI discovery support. - Fixed CMake quoting and logic bugs in standard header collection. - Applied project-wide cmake-format and resolved CI linting failures.
1 parent ac34da2 commit b1e91ae

9 files changed

Lines changed: 137 additions & 125 deletions

File tree

.cmake-format.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@
586586
'INCLUDE_DIRS': '+',
587587
'FOUND_HEADERS': 1},
588588
'pargs': { 'flags': [], 'nargs': '1+'}},
589-
'hpx_configure_module_producer': { 'kwargs': { 'MODULE_OUT_DIR': 1},
589+
'hpx_configure_module_producer': { 'kwargs': {},
590590
'pargs': { 'flags': [], 'nargs': '1+'}}
591591
}
592592

cmake/HPX_CXXModules.cmake

Lines changed: 29 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# Distributed under the Boost Software License, Version 1.0. (See accompanying
55
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
66

7-
include(HPX_AddCompileFlag)
87
include(HPX_Message)
98

109
macro(hpx_check_cxx_modules_support)
@@ -65,79 +64,39 @@ if(NOT HPX_WITH_CXX_MODULES)
6564
return()
6665
endif()
6766

68-
# hpx_configure_module_producer(<producer> [MODULE_OUT_DIR <dir>])
67+
# hpx_configure_module_producer(<producer>)
6968
#
70-
# * Ensures a stable module output dir for producer target
71-
# * Adds compiler flags to write module cache there (Clang/GCC)
72-
# * Creates an interface target '<producer>_if' for consumers to link to
69+
# * Creates an interface target '<producer>_if' for consumers to link to.
70+
# * Sets INTERFACE_CXX_SCAN_FOR_MODULES ON so that CMake's native module
71+
# dependency tracking propagates to all consumers.
72+
#
73+
# CMake 3.29+ with FILE_SET CXX_MODULES handles BMI generation and
74+
# -fmodule-output/-fprebuilt-module-path flags automatically. No manual compiler
75+
# flags are needed here.
7376
function(hpx_configure_module_producer producer)
7477
if(NOT TARGET ${producer})
7578
hpx_error("hpx_configure_module_producer: target '${producer}' not found")
7679
endif()
7780

78-
# parse optional args
79-
set(options)
80-
set(one_value_args MODULE_OUT_DIR)
81-
set(multi_value_args)
82-
cmake_parse_arguments(
83-
_args "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}
84-
)
85-
86-
if(_args_MODULE_OUT_DIR)
87-
set(_moddir "${_args_MODULE_OUT_DIR}")
88-
else()
89-
set(_moddir "$<TARGET_FILE_DIR:${producer}>")
90-
endif()
91-
9281
set(_iface "${producer}_if")
9382
if(NOT TARGET ${_iface})
9483
add_library(${_iface} INTERFACE)
9584
target_link_libraries(${_iface} INTERFACE ${producer})
9685
endif()
9786

98-
# Set a property so consumers can query the BMI directory via
99-
# get_target_property.
100-
set_target_properties(
101-
${_iface} PROPERTIES INTERFACE_EXPORT_MODULE_DIR "${_moddir}"
102-
)
103-
104-
# Make sure consumers scan for the BMI
105-
set_target_properties(${_iface} PROPERTIES INTERFACE_CXX_SCAN_FOR_MODULES On)
106-
107-
if(MSVC)
108-
# MSVC: CMake/MSVC handle IFCs automatically; create a target for
109-
# convenience, consumers can link to this to get ordering and include info
110-
return()
111-
endif()
112-
113-
# Compiler-specific flags to instruct where to write module cache
114-
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES
115-
"AppleClang"
116-
)
117-
# Clang common flags
118-
target_compile_options(${producer} PRIVATE "-fmodule-output=${_moddir}")
119-
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
120-
# GCC: modern flags
121-
hpx_add_target_compile_option_if_available(
122-
${producer} PRIVATE "-fmodule-output=${_moddir}" RESULT ok
123-
)
124-
if(NOT ok)
125-
hpx_error(
126-
"hpx_configure_module_producer: the used version of gcc does not support '-fmodule-output'"
127-
)
128-
endif()
129-
else()
130-
hpx_warn(
131-
"hpx_configure_module_producer: unknown compiler '${CMAKE_CXX_COMPILER_ID}'; "
132-
"exposing EXPORT_MODULE_DIR='${_moddir}' for manual handling"
133-
)
134-
endif()
87+
# Propagate scanning requirement to consumers via the interface target. CMake
88+
# uses this to enable its native module dependency scanning for any target
89+
# that links to this interface.
90+
set_target_properties(${_iface} PROPERTIES INTERFACE_CXX_SCAN_FOR_MODULES ON)
13591
endfunction()
13692

137-
# hpx_configure_module_consumer(<consumer> <producer>])
93+
# hpx_configure_module_consumer(<consumer> <producer>)
94+
#
95+
# * Links the consumer to the producer interface target.
96+
# * Enables CMake's native module scanning on the consumer.
13897
#
139-
# * propagates module-related properties from producer interface target
140-
# * sets necessary consumer compiler flags for clang and gcc
98+
# CMake 3.29+ automatically resolves the BMI location from the FILE_SET
99+
# CXX_MODULES declared on the producer. No -fprebuilt-module-path needed.
141100
function(hpx_configure_module_consumer consumer producer)
142101
if(NOT TARGET ${consumer})
143102
hpx_error("hpx_configure_module_consumer: target '${consumer}' not found")
@@ -146,41 +105,20 @@ function(hpx_configure_module_consumer consumer producer)
146105
hpx_error("hpx_configure_module_consumer: target '${producer}' not found")
147106
endif()
148107

108+
# Imported module metadata is only picked up from direct link dependencies.
109+
# Link the underlying module target directly when the producer follows the
110+
# '<module>_if' wrapper pattern.
111+
if(producer MATCHES "_if$")
112+
string(REGEX REPLACE "_if$" "" _producer_target "${producer}")
113+
if(TARGET ${_producer_target})
114+
target_link_libraries(${consumer} PRIVATE ${_producer_target})
115+
endif()
116+
endif()
117+
149118
target_link_libraries(${consumer} PRIVATE ${producer})
119+
150120
get_target_property(_scan ${producer} INTERFACE_CXX_SCAN_FOR_MODULES)
151121
if(_scan)
152122
set_target_properties(${consumer} PROPERTIES CXX_SCAN_FOR_MODULES ${_scan})
153123
endif()
154-
155-
get_target_property(_module_dir ${producer} INTERFACE_EXPORT_MODULE_DIR)
156-
if(_module_dir)
157-
if(MSVC)
158-
return()
159-
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID
160-
MATCHES "AppleClang"
161-
)
162-
target_compile_options(
163-
${consumer} PRIVATE "-fprebuilt-module-path=${_module_dir}"
164-
)
165-
get_target_property(_type ${consumer} TYPE)
166-
if((_type STREQUAL "SHARED_LIBRARY") OR (_type STREQUAL "EXECUTABLE"))
167-
target_link_options(${consumer} PRIVATE "-fuse-ld=lld")
168-
target_link_options(${consumer} PRIVATE "-Wl,--error-limit=0")
169-
endif()
170-
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
171-
hpx_add_target_compile_option_if_available(
172-
${consumer} PRIVATE "-fprebuilt-module-path=${_module_dir}" RESULT ok
173-
)
174-
if(NOT ok)
175-
hpx_error(
176-
"hpx_configure_module_consumer: the used version of gcc does not "
177-
"support '-fprebuilt-module-path='"
178-
)
179-
endif()
180-
else()
181-
hpx_warn(
182-
"hpx_configure_module_consumer: unknown compiler '${CMAKE_CXX_COMPILER_ID}'"
183-
)
184-
endif()
185-
endif()
186124
endfunction()

cmake/HPX_CollectStdHeaders.cmake

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,10 @@ function(hpx_extract_includes_from_file module)
134134
foreach(include ${includes})
135135
string(REGEX REPLACE "#include (<[^>]+>)" "\\1" filename ${include})
136136

137-
if(NOT filename MATCHES "\\.|/")
138-
# Check if the include is a standard library header
139-
if(${filename} IN_LIST STANDARD_LIBRARY_HEADERS)
140-
list(APPEND found_includes ${filename})
141-
endif()
137+
if("${filename}" IN_LIST STANDARD_LIBRARY_HEADERS)
138+
# Capture standard library headers (with or without extensions, e.g.
139+
# <vector>, <link.h>, <dlfcn.h>).
140+
list(APPEND found_includes "${filename}")
142141
endif()
143142
endforeach()
144143

cmake/HPX_GeneratePackage.cmake

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ write_basic_package_version_file(
1919
COMPATIBILITY AnyNewerVersion
2020
)
2121

22-
# Export HPXInternalTargets in the build directory
22+
# CXX_MODULES_DIRECTORY was added in CMake 3.28
23+
set(_cxx_modules_directory_arg)
24+
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
25+
set(_cxx_modules_directory_arg CXX_MODULES_DIRECTORY cxx-modules)
26+
endif()
27+
28+
# Export HPXInternalTargets in the build directory. Use the EXPORT signature so
29+
# CMake also generates the per-target C++ module metadata files.
2330
export(
2431
TARGETS ${HPX_EXPORT_INTERNAL_TARGETS}
2532
NAMESPACE HPXInternal::
2633
FILE "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${HPX_PACKAGE_NAME}/HPXInternalTargets.cmake"
34+
${_cxx_modules_directory_arg}
2735
)
2836

2937
# Export HPXInternalTargets in the install directory
@@ -35,11 +43,13 @@ install(
3543
COMPONENT cmake
3644
)
3745

38-
# Export HPXTargets in the build directory
46+
# Export HPXTargets in the build directory. Use the EXPORT signature so CMake
47+
# also generates the per-target C++ module metadata files.
3948
export(
4049
TARGETS ${HPX_EXPORT_TARGETS}
4150
NAMESPACE HPX::
4251
FILE "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${HPX_PACKAGE_NAME}/HPXTargets.cmake"
52+
${_cxx_modules_directory_arg}
4353
)
4454

4555
# Add aliases with the namespace for use within HPX

cmake/HPX_SetupTarget.cmake

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function(hpx_setup_target target)
3838
HPX_PREFIX
3939
HEADER_ROOT
4040
SCAN_FOR_MODULES
41+
CXX_STANDARD
4142
)
4243
set(multi_value_args DEPENDENCIES COMPONENT_DEPENDENCIES COMPILE_FLAGS
4344
LINK_FLAGS INSTALL_FLAGS INSTALL_PDB
@@ -87,6 +88,13 @@ function(hpx_setup_target target)
8788
hpx_debug("setup_target.${target}" "LINK_FLAGS: ${target_LINK_FLAGS}")
8889
endif()
8990

91+
if(target_CXX_STANDARD)
92+
set_target_properties(
93+
${target} PROPERTIES CXX_STANDARD ${target_CXX_STANDARD}
94+
)
95+
hpx_debug("setup_target.${target}" "CXX_STANDARD: ${target_CXX_STANDARD}")
96+
endif()
97+
9098
if(target_NAME)
9199
set(name "${target_NAME}")
92100
else()
@@ -232,9 +240,21 @@ function(hpx_setup_target target)
232240
if(HPX_WITH_CXX_MODULES AND target_SCAN_FOR_MODULES)
233241
hpx_debug("setup_target.${target} SCAN_FOR_MODULES: ON")
234242

235-
hpx_configure_module_consumer(${target} hpx_core_module_if)
243+
if(TARGET hpx_core_module_if)
244+
hpx_configure_module_consumer(${target} hpx_core_module_if)
245+
elseif(TARGET HPXInternal::hpx_core_module_if)
246+
hpx_configure_module_consumer(${target} HPXInternal::hpx_core_module_if)
247+
else()
248+
hpx_error(
249+
"setup_target.${target}: C++ modules scanning is enabled, but neither "
250+
"hpx_core_module_if nor HPXInternal::hpx_core_module_if exists"
251+
)
252+
endif()
253+
236254
if(TARGET hpx_full_module_if)
237255
hpx_configure_module_consumer(${target} hpx_full_module_if)
256+
elseif(TARGET HPXInternal::hpx_full_module_if)
257+
hpx_configure_module_consumer(${target} HPXInternal::hpx_full_module_if)
238258
endif()
239259
else()
240260
hpx_debug("setup_target.${target} SCAN_FOR_MODULES: OFF")
@@ -247,8 +267,9 @@ function(hpx_setup_target target)
247267

248268
# If modules are enabled, Clang emits DWARF v5, which requires using lld
249269
# instead of ld.
250-
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES
251-
"AppleClang"
270+
if((NOT MSVC)
271+
AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID
272+
MATCHES "AppleClang")
252273
)
253274
get_target_property(_type ${target} TYPE)
254275
if((_type STREQUAL "SHARED_LIBRARY") OR (_type STREQUAL "EXECUTABLE"))

examples/gtest_emulation/CMakeLists.txt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,23 @@ if(EXISTS "${HPX_DIR}")
1414

1515
if(HPX_WITH_CXX_MODULES)
1616
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
17+
# CMake only propagates imported C++ module metadata from targets that are
18+
# linked directly by the consumer. The exported HPXInternal module targets
19+
# are therefore linked explicitly for the external build tests.
20+
set(hpx_cxx_module_targets)
21+
if(TARGET HPXInternal::hpx_core_module)
22+
list(APPEND hpx_cxx_module_targets HPXInternal::hpx_core_module)
23+
endif()
24+
if(TARGET HPXInternal::hpx_full_module)
25+
list(APPEND hpx_cxx_module_targets HPXInternal::hpx_full_module)
26+
endif()
1727
endif()
1828

1929
# Add a static library which contains a main to emulate gtest_main
2030
add_library(static_main_lib STATIC static_main.cpp)
31+
set_target_properties(
32+
static_main_lib PROPERTIES CXX_STANDARD ${HPX_CXX_STANDARD}
33+
)
2134

2235
# /!\ This helper interface is needed to keep the right linking order
2336
add_library(hpx_helper_interface INTERFACE)
@@ -27,7 +40,14 @@ if(EXISTS "${HPX_DIR}")
2740

2841
# Test with the main function in a separate static library
2942
add_executable(hpx_main_ext_main hpx_main_ext_main.cpp)
30-
target_link_libraries(hpx_main_ext_main PRIVATE hpx_helper_interface)
43+
# Keep the helper interface for link order, but link module targets directly
44+
# to the executable so CMake can see the imported BMI metadata.
45+
target_link_libraries(
46+
hpx_main_ext_main PRIVATE hpx_helper_interface ${hpx_cxx_module_targets}
47+
)
48+
set_target_properties(
49+
hpx_main_ext_main PROPERTIES CXX_STANDARD ${HPX_CXX_STANDARD}
50+
)
3151

3252
enable_testing()
3353
add_test(hello_world_test hpx_main_ext_main)

examples/hello_world_component/CMakeLists.txt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,22 @@ project(hello_world_client CXX)
1111
if(EXISTS "${HPX_DIR}")
1212
find_package(HPX REQUIRED)
1313

14-
if(HPX_WITH_DISTRIBUTED_RUNTIME)
15-
add_library(hello_world_component SHARED hello_world_component.cpp)
16-
endif()
17-
1814
if(HPX_WITH_CXX_MODULES)
1915
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
16+
# CMake only propagates imported C++ module metadata from targets that are
17+
# linked directly by the consumer. The exported HPXInternal module targets
18+
# are therefore linked explicitly for the external build tests.
19+
set(hpx_cxx_module_targets)
20+
if(TARGET HPXInternal::hpx_core_module)
21+
list(APPEND hpx_cxx_module_targets HPXInternal::hpx_core_module)
22+
endif()
23+
if(TARGET HPXInternal::hpx_full_module)
24+
list(APPEND hpx_cxx_module_targets HPXInternal::hpx_full_module)
25+
endif()
26+
endif()
27+
28+
if(HPX_WITH_DISTRIBUTED_RUNTIME)
29+
add_library(hello_world_component SHARED hello_world_component.cpp)
2030
endif()
2131

2232
add_executable(hello_world_client hello_world_client.cpp)
@@ -26,11 +36,15 @@ if(EXISTS "${HPX_DIR}")
2636
if(HPX_WITH_DISTRIBUTED_RUNTIME)
2737
target_link_libraries(
2838
hello_world_component PUBLIC HPX::hpx HPX::iostreams_component
39+
${hpx_cxx_module_targets}
2940
)
3041
target_link_libraries(hello_world_component PRIVATE HPX::component)
3142
target_link_libraries(hello_world_client PRIVATE hello_world_component)
3243
endif()
33-
target_link_libraries(hello_world_client PRIVATE HPX::hpx HPX::wrap_main)
44+
target_link_libraries(
45+
hello_world_client PRIVATE HPX::hpx HPX::wrap_main
46+
${hpx_cxx_module_targets}
47+
)
3448

3549
# We still support not linking to HPX::wrap_main when
3650
# HPX_WITH_DYNAMIC_HPX_MAIN=OFF for legacy use. This can only be done using
@@ -44,6 +58,7 @@ if(EXISTS "${HPX_DIR}")
4458

4559
target_link_libraries(
4660
hello_world_client_only_hpx_init PRIVATE hello_world_component
61+
${hpx_cxx_module_targets}
4762
)
4863
endif()
4964
elseif("${SETUP_TYPE}" STREQUAL "MACROS")
@@ -53,10 +68,20 @@ if(EXISTS "${HPX_DIR}")
5368
COMPONENT_DEPENDENCIES iostreams
5469
DEPENDENCIES HPX::wrap_main
5570
TYPE COMPONENT
71+
SCAN_FOR_MODULES ${HPX_WITH_CXX_MODULES} CXX_STANDARD
72+
${HPX_CXX_STANDARD}
73+
)
74+
hpx_setup_target(
75+
hello_world_client
76+
DEPENDENCIES hello_world_component
77+
SCAN_FOR_MODULES ${HPX_WITH_CXX_MODULES} CXX_STANDARD
78+
${HPX_CXX_STANDARD}
5679
)
57-
hpx_setup_target(hello_world_client DEPENDENCIES hello_world_component)
5880
else()
59-
hpx_setup_target(hello_world_client)
81+
hpx_setup_target(
82+
hello_world_client SCAN_FOR_MODULES ${HPX_WITH_CXX_MODULES}
83+
CXX_STANDARD ${HPX_CXX_STANDARD}
84+
)
6085
endif()
6186
else()
6287
message(FATAL_ERROR "Unknown SETUP_TYPE=\"${SETUP_TYPE}\"")

0 commit comments

Comments
 (0)