Skip to content

Commit 331c2da

Browse files
committed
build: convert to C++20 named modules
The improvements are currently small, but future refactors that remove dependencies that do not support modules should further improve build times. Also a significant boost would be header units to build TUs that depend on mlir targets (currently longest compilation times). However, cmake does not support this.
1 parent 25411b3 commit 331c2da

514 files changed

Lines changed: 9064 additions & 6587 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1-
cmake_minimum_required(VERSION 3.25)
1+
cmake_minimum_required(VERSION 3.30)
22
include(FetchContent)
33
include(ExternalProject)
44
include(CheckCXXSourceCompiles)
55

6+
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "f35a9ac6-8463-4d38-8eec-5d6008153e7d")
7+
68
project(python++)
79

810
set(CMAKE_CXX_STANDARD 26)
11+
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
12+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
913

1014
include(cmake/CPM.cmake)
1115

12-
CPMAddPackage("gh:gabime/spdlog@1.8.5")
16+
# spdlog 1.11+ can format through std::format instead of its bundled fmt.
17+
# SPDLOG_USE_STD_FORMAT keeps fmt out of the build entirely, which matters for
18+
# modules: spdlog/fmt/fmt.h drags 231 libstdc++ headers, and anything reaching a
19+
# module's global module fragment lands in its BMI and then collides with the
20+
# same headers #included by consumers.
21+
CPMAddPackage(
22+
NAME spdlog
23+
GITHUB_REPOSITORY gabime/spdlog
24+
VERSION 1.15.3
25+
OPTIONS "SPDLOG_USE_STD_FORMAT ON" "SPDLOG_BUILD_PIC ON"
26+
)
1327
CPMAddPackage("gh:google/googletest@1.18.0")
1428
CPMAddPackage("gh:jarro2783/cxxopts@3.3.1")
1529
CPMAddPackage("gh:Tessil/ordered-map@1.2.0")

cmake/PythonCppFlags.cmake

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
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:
@@ -16,6 +17,19 @@
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

2034
include_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()

integration/program.cpp

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
#include "executable/Program.hpp"
2-
#include "executable/bytecode/Bytecode.hpp"
3-
#include "interpreter/Interpreter.hpp"
4-
#include "parser/Parser.hpp"
5-
#include "runtime/PyDict.hpp"
6-
#include "runtime/PyFrame.hpp"
7-
#include "runtime/PyInteger.hpp"
8-
#include "runtime/PyList.hpp"
9-
#include "runtime/PyNumber.hpp"
10-
#include "runtime/PyObject.hpp"
11-
#include "runtime/PyString.hpp"
12-
#include "runtime/PyTuple.hpp"
13-
#include "runtime/types/builtin.hpp"
14-
#include "vm/VM.hpp"
1+
#include "core.hpp"// ASSERT / TODO / overloaded
2+
#include "executable/common.hpp"// compiler::Backend, OptimizationLevel
3+
4+
// gmpxx's operators are declared in py.ast's global module fragment, so they
5+
// are not exported with mpz_class and have to be included here.
6+
#include <cmath>
7+
#include <gmpxx.h>
8+
9+
#include <spdlog/spdlog.h>
1510

1611
#include "gtest/gtest.h"
1712

13+
import py.ast;
14+
import py.types; // py::types::
15+
import py.lexer;
16+
import py.runtime;
17+
import std;
18+
1819
using namespace py;
1920

2021
template<typename T> struct is_vector : std::false_type

0 commit comments

Comments
 (0)