1- # Helper for giving every first-party target the same compiler flags.
1+ # Helper for giving every first-party target the same compiler flags and the
2+ # same C++ module configuration.
23#
34# The flags come from the external `project_options` package (added with CPM in
45# the top-level CMakeLists.txt), which exposes them as two INTERFACE targets:
1617# not the usage requirements of libraries linked afterwards. Linking the flags
1718# to `<name>` alone would therefore silently compile nothing with them, so this
1819# always covers the `obj.<name>` twin as well.
20+ #
21+ # The same `obj.<name>` split applies to C++ module settings, and there it is
22+ # easier to miss: `CXX_SCAN_FOR_MODULES` set on `<name>` does not reach the
23+ # object library that actually compiles the sources, so those sources are built
24+ # by CMake's "unscanned" rule with no `-fmodule-mapper`. A TU that imports
25+ # `py.runtime` then fails with either "'import' does not name a type" or, worse,
26+ # a fallback lookup in `gcm.cache/`. Setting the properties on both twins is
27+ # what makes `import py.runtime;` work inside the MLIR layer.
28+ #
29+ # Note: do NOT add `-fmodules` here. CMake supplies `-fmodules-ts` together with
30+ # `-fmodule-mapper=` on its scanned compile rules; adding the flag by hand also
31+ # applies it to unscanned targets, which turns a clear diagnostic into a
32+ # confusing module-not-found error.
1933
2034include_guard (GLOBAL )
2135
@@ -28,8 +42,26 @@ function(python_cpp_link_project_options)
2842 get_target_property (type ${name} TYPE)
2943 if (type STREQUAL "INTERFACE_LIBRARY" )
3044 target_link_libraries (${name} INTERFACE project_options project_warnings )
31- else ()
32- target_link_libraries (${name} PRIVATE project_options project_warnings )
45+ continue ()
46+ endif ()
47+
48+ target_link_libraries (${name} PRIVATE project_options project_warnings )
49+
50+ # Everything first-party either provides or consumes `py.runtime`, so
51+ # scan it all. Scanning costs ~0.16s per TU (a preprocess-only pass) and
52+ # removes a whole class of "this target cannot see the module" failures.
53+ set_target_properties (${name} PROPERTIES CXX_SCAN_FOR_MODULES ON
54+ CXX_MODULE_STD ON )
55+
56+ # Module imports resolve through link dependencies, so every consumer
57+ # needs a path to python-runtime - the sole provider of `py.runtime`.
58+ # It is linked directly rather than via python-cpp because python-cpp and
59+ # python-mlir are mutually dependent: a module provider reached only
60+ # through a link cycle cannot be ordered before its consumers, and they
61+ # compile with an empty module map. python-runtime itself sits below that
62+ # cycle, so linking it here is always acyclic.
63+ if (TARGET python-runtime AND NOT ${target} STREQUAL "python-runtime" )
64+ target_link_libraries (${name} PRIVATE python-runtime )
3365 endif ()
3466 endforeach ()
3567 endforeach ()
0 commit comments