0

Enable explicit module build by use_libcxx_modules arg

This CL enables explicit clang modules for libc++ and clang's builtin
headers.

There are still many compile errors even if we build `base`, but we'll
fix them one by one.

I also leave implicit modules build with use_implicit_libcxx_modules.

Bug: 40440396
Change-Id: Ie23087ff69e2ab9892625400f2cd182955cc098b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6188686
Reviewed-by: Erik Staab <estaab@chromium.org>
Commit-Queue: Takuto Ikuta <tikuta@chromium.org>
Auto-Submit: Takuto Ikuta <tikuta@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1416006}
This commit is contained in:
Takuto Ikuta
2025-02-04 22:53:22 -08:00
committed by Chromium LUCI CQ
parent b06c27c680
commit 7d1b2b0b0c
6 changed files with 241 additions and 27 deletions
build
buildtools/third_party/libc++
docs

@ -540,11 +540,21 @@ foreach(_target_type,
]) {
template(_target_type) {
target(_target_type, target_name) {
forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
forward_variables_from(invoker,
"*",
TESTONLY_AND_VISIBILITY + [ "no_default_deps" ])
forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
if (!defined(inputs)) {
inputs = []
}
if (!defined(deps)) {
deps = []
}
if (!defined(invoker.no_default_deps) || !invoker.no_default_deps) {
# This is necessary for Clang modules builds.
deps += [ "//buildtools/third_party/libc++:std" ]
}
# Consumed by the unsafe-buffers plugin during compile.
#
@ -622,7 +632,15 @@ foreach(_target_type,
# //build/config:shared_library_deps
# (This explicit list is so that grepping for these configs finds where
# they are used.)
deps += [ "//build/config:${_target_type}_deps" ]
deps += [
"//build/config:${_target_type}_deps",
# These are necessary for Clang modules builds.
"//buildtools/third_party/libc++:_Builtin_limits",
"//buildtools/third_party/libc++:_Builtin_stdarg",
"//buildtools/third_party/libc++:_Builtin_stddef",
"//buildtools/third_party/libc++:std",
]
}
# On Android, write shared library output file to metadata. We will use

@ -42,13 +42,25 @@ declare_args() {
# defaults to off.
enable_iterator_debugging = false
# Use Clang header modules for libc++.
# Use explicit Clang header modules for libc++.
# This is experimental only (see crbug.com/543704).
# For details on the current state of modules in Chromium see
# https://chromium.googlesource.com/chromium/src/+/main/docs/modules.md
use_libcxx_modules = false
# Use implicit Clang header modules for libc++.
# This is experimental only (see crbug.com/543704).
# For details on the current state of modules in Chromium see
# https://chromium.googlesource.com/chromium/src/+/main/docs/modules.md
use_implicit_libcxx_modules = false
}
if (use_implicit_libcxx_modules) {
use_libcxx_modules = true
}
use_explicit_libcxx_modules = use_libcxx_modules && !use_implicit_libcxx_modules
assert(!use_libcxx_modules || !use_remoteexec,
"Implicit Clang header modules don't work with remote execution.")

@ -1707,9 +1707,6 @@ config("libcxx_module") {
"-fmodules",
"-fmodule-map-file=" + modulemap,
"-fno-implicit-module-maps",
"-fbuiltin-module-map",
"-fmodules-cache-path=" +
rebase_path("$libcxx_module_prefix/module_cache", root_build_dir),
"-Xclang",
"-fmodules-local-submodule-visibility", # required for builtins
@ -1724,6 +1721,21 @@ config("libcxx_module") {
# unnecessarily using extern "C".
"-Wno-module-import-in-extern-c",
]
if (use_explicit_libcxx_modules) {
cflags_cc += [
"-fno-implicit-modules",
# This is for exception handling mismatch.
"-Wno-module-file-config-mismatch",
]
} else {
cflags_cc += [
"-fbuiltin-module-map",
"-fmodules-cache-path=" +
rebase_path("$libcxx_module_prefix/module_cache", root_build_dir),
]
}
}
}

@ -353,12 +353,20 @@ template("single_gcc_toolchain") {
tool("cxx") {
depfile = "{{output}}.d"
precompiled_header_type = "gcc"
command = "$cxx $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}"
command = "$cxx $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} {{module_deps_no_self}} -c {{source}} -o {{output}}"
depsformat = "gcc"
description = "CXX {{output}}"
outputs = [ "$object_subdir/{{source_name_part}}.o" ]
}
tool("cxx_module") {
depfile = "{{output}}.d"
command = "$cxx -MD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} {{module_deps_no_self}} -fmodule-name={{label_name}} -c -x c++ -Xclang -emit-module {{source}} -o {{output}}"
depsformat = "gcc"
description = "CXX_MODULE {{output}}"
outputs = [ "$object_subdir/{{source_name_part}}.pcm" ]
}
tool("asm") {
# For GCC we can just use the C compiler to compile assembly.
depfile = "{{output}}.d"

@ -45,11 +45,156 @@ config("winver") {
]
}
template("builtin_modules") {
# This is a template to build clang builtin's module file.
source_set(target_name) {
no_default_deps = true
if (use_explicit_libcxx_modules) {
sources = [ "//third_party/llvm-build/Release+Asserts/lib/clang/20/include/module.modulemap" ]
}
deps = []
if (defined(invoker.deps)) {
deps += invoker.deps
} else {
not_needed(invoker, "*")
}
}
}
builtin_modules("_Builtin_float") {
}
builtin_modules("_Builtin_inttypes") {
deps = [ ":_Builtin_stdint" ]
}
builtin_modules("_Builtin_limits") {
}
builtin_modules("_Builtin_stdalign") {
}
builtin_modules("_Builtin_stdarg") {
}
builtin_modules("_Builtin_stddef") {
}
builtin_modules("_Builtin_stdint") {
}
configs_to_add = [
":config",
"//build/config/compiler:no_chromium_code",
"//build/config/compiler:exceptions",
"//build/config/compiler:rtti",
]
configs_to_remove = [
"//build/config/compiler:chromium_code",
"//build/config/compiler:no_exceptions",
"//build/config/compiler:no_rtti",
"//build/config/coverage:default_coverage",
]
template("libcxx_modules") {
# This is a template to build libc++'s module file.
source_set(target_name) {
no_default_deps = true
if (use_explicit_libcxx_modules) {
sources = [ "//third_party/libc++/src/include/module.modulemap" ]
}
deps = []
configs -= configs_to_remove
configs += configs_to_add
if (defined(invoker.deps)) {
deps += invoker.deps
} else {
not_needed(invoker, "*")
}
}
}
libcxx_modules("std") {
deps = [
":_Builtin_limits",
":_Builtin_stdalign",
":_Builtin_stdarg",
":std_config",
":std_core",
":std_ctype_h",
":std_errno_h",
":std_fenv_h",
":std_float_h",
":std_inttypes_h",
":std_math_h",
":std_private_mbstate_t",
":std_string_h",
":std_uchar_h",
":std_wctype_h",
]
}
libcxx_modules("std_config") {
}
libcxx_modules("std_core") {
deps = [
":_Builtin_stddef",
":_Builtin_stdint",
]
}
libcxx_modules("std_ctype_h") {
}
libcxx_modules("std_errno_h") {
}
libcxx_modules("std_fenv_h") {
}
libcxx_modules("std_float_h") {
deps = [ ":_Builtin_float" ]
}
libcxx_modules("std_inttypes_h") {
deps = [ ":_Builtin_inttypes" ]
}
libcxx_modules("std_math_h") {
deps = [
":_Builtin_limits",
":std_core",
]
}
libcxx_modules("std_private_mbstate_t") {
}
libcxx_modules("std_stddef_h") {
}
libcxx_modules("std_string_h") {
deps = [ ":_Builtin_stddef" ]
}
libcxx_modules("std_uchar_h") {
deps = [ ":_Builtin_stddef" ]
}
libcxx_modules("std_wctype_h") {
}
if (libcxx_is_shared) {
_libcxx_target_type = "shared_library"
} else {
_libcxx_target_type = "source_set"
}
target(_libcxx_target_type, "libc++") {
# Most things that need to depend on libc++ should do so via the implicit
# 'common_deps' dependency below. Some targets that package libc++.so may
@ -108,7 +253,6 @@ target(_libcxx_target_type, "libc++") {
"//third_party/libc++/src/src/hash.cpp",
"//third_party/libc++/src/src/ios.cpp",
"//third_party/libc++/src/src/ios.instantiations.cpp",
"//third_party/libc++/src/src/iostream.cpp",
"//third_party/libc++/src/src/locale.cpp",
"//third_party/libc++/src/src/memory.cpp",
"//third_party/libc++/src/src/mutex.cpp",
@ -135,6 +279,15 @@ target(_libcxx_target_type, "libc++") {
"//third_party/libc++/src/src/verbose_abort.cpp",
]
if (!use_explicit_libcxx_modules) {
sources += [
# TODO(crbug.com/40440396): Have a separate target for this to avoid
# compile errors in explicit modules build due to type mismatch of
# std::{cerr,cin,clog,cout} between declaration and definition.
"//third_party/libc++/src/src/iostream.cpp",
]
}
if (is_apple || (!is_asan && !is_tsan && !is_msan)) {
# In {a,t,m}san configurations, operator new and operator delete will be
# provided by the sanitizer runtime library. Since libc++ defines these
@ -171,12 +324,10 @@ target(_libcxx_target_type, "libc++") {
]
}
}
configs -= [
"//build/config/compiler:chromium_code",
"//build/config/compiler:no_exceptions",
"//build/config/compiler:no_rtti",
"//build/config/coverage:default_coverage",
]
configs -= configs_to_remove
configs += configs_to_add
if (use_libcxx_modules) {
configs -= [ "//build/config/compiler:libcxx_module" ]
}
@ -188,12 +339,6 @@ target(_libcxx_target_type, "libc++") {
configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
}
}
configs += [
":config",
"//build/config/compiler:no_chromium_code",
"//build/config/compiler:exceptions",
"//build/config/compiler:rtti",
]
if (libcxx_is_shared && !is_win) {
configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
@ -201,6 +346,7 @@ target(_libcxx_target_type, "libc++") {
}
defines = []
cflags = []
if (!libcxx_is_shared && !is_win) {
if (is_apple && is_clang) {
@ -209,7 +355,7 @@ target(_libcxx_target_type, "libc++") {
# specified in the C++ spec 3.7.4p2, which makes them always have default
# visibility. This option is needed to force hidden visibility since
# -fvisibility=hidden doesn't have the desired effect.
cflags = [ "-fvisibility-global-new-delete=force-hidden" ]
cflags += [ "-fvisibility-global-new-delete=force-hidden" ]
} else {
# This resets the visibility to default only for the various
# flavors of operator new and operator delete. These symbols
@ -229,6 +375,22 @@ target(_libcxx_target_type, "libc++") {
deps = [ "//third_party/llvm-libc:llvm-libc-shared" ]
if (use_explicit_libcxx_modules) {
modulemap = rebase_path("//third_party/libc++/src/include/module.modulemap",
root_build_dir)
cflags += [
"-fmodules",
"-fmodule-map-file=" + modulemap,
]
deps += [
":std",
":std_config",
":std_core",
":std_stddef_h",
]
}
if (!is_win) {
defines += [ "LIBCXX_BUILDING_LIBCXXABI" ]
if (!export_libcxxabi_from_executables) {

@ -18,17 +18,17 @@ their code bases with large performance wins.
the build system.
We're currently experimenting with modules for libc++ and they can be enabled
with the GN arg `use_libcxx_modules`. Using this arg is not currently
recommended, due to the limitations mentioned below. It is only interesting to
people working on the feature.
with the GN arg `use_libcxx_modules` and `use_implicit_libcxx_modules`. Using
this arg is not currently recommended, due to the limitations mentioned below.
It is only interesting to people working on the feature.
## Current limitations
### Implicit vs explicit modules
We're using implicit modules, which are created on-the-fly when Clang doesn't
see them in the module cache. This doesn't work with remote execution since the
cached modules aren't known to the build system.
`use_implicit_libcxx_modules` is using implicit modules, which are created
on-the-fly when Clang doesn't see them in the module cache. This doesn't work
with remote execution since the cached modules aren't known to the build system.
The module cache is set to `<outdir>/gen/libcxx/module_cache`. Since the modules
aren't known to ninja they aren't cleaned with `ninja -t clean` and need to be
@ -41,6 +41,8 @@ will require support in GN and has been partially implemented
[CL3](https://gn-review.googlesource.com/c/gn/+/9680), and
[crbug.com/gn/373](https://crbug.com/gn/373)).
`use_libcxx_modules` enables explicit modules using existing features.
### Duplicate modules
Multiple pcm files are created per module. For correctness, Clang header modules