| # Copyright 2025 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import("//build/config/apple/apple_sdk.gni") |
| import("//build/config/c++/modules.gni") |
| import("//build/config/clang/clang.gni") |
| import("//build/config/compiler/compiler.gni") |
| import("//build/config/sysroot.gni") |
| if (use_xcode_symlinks) { |
| import("//build/config/apple/mobile_config.gni") |
| } |
| if (is_win) { |
| import("//build/toolchain/win/win_toolchain_data.gni") |
| } |
| |
| if (use_clang_modules) { |
| template("clang_module") { |
| source_set(target_name) { |
| forward_variables_from(invoker, "*", [ "modulemap" ]) |
| use_libcxx_modules = false |
| sources = [ invoker.modulemap ] |
| module_name = target_name |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += [ "//buildtools/third_party/libc++:generate_libcxx_modulemap($default_toolchain)" ] |
| |
| if (!defined(public_configs)) { |
| public_configs = [] |
| } |
| |
| public_configs += [ "//build/config/compiler:libcxx_module" ] |
| |
| # Implicit module maps won't work on apple because we're currently |
| # missing some dependencies. |
| if (use_autogenerated_modules) { |
| # Explicitly DO NOT use public configs here. If we have two framework |
| # modules foo and bar, and only foo is transitively depended on by |
| # libcxx: |
| # * When building the module for libcxx, we want both -fmodule-map-file |
| # for both foo and bar, to ensure that if libcxx did depend on bar, we |
| # would throw an error. |
| # * We may choose not to build bar because it's so rarely used that it |
| # won't increase performance to precompile it |
| # * If we provide -fmodule-map-file=bar but choose not to build bar, |
| # then any target that did depend on bar would fail to compile. |
| configs += [ "//buildtools/third_party/libc++:all_modulemap_configs" ] |
| } else { |
| if (use_xcode_symlinks) { |
| # The `copy_sysroot_modulemaps` action depends on SDK paths that |
| # differ between macOS and iOS, so it must be built with the correct |
| # toolchain for the target OS. |
| toolchain = "//build/toolchain/mac:clang_$target_cpu" |
| if (is_ios || target_environment == "catalyst") { |
| toolchain = "//build/toolchain/ios:ios_clang_$target_cpu" |
| } else if (target_os == "ios" && is_mac) { |
| toolchain = "//build/toolchain/mac:clang_$host_cpu" |
| } |
| public_deps += [ "//buildtools/third_party/libc++:copy_sysroot_modulemaps($toolchain)" ] |
| } |
| |
| # By always including all module maps, we can get it to error out if |
| # we attempt to include something not in your dependencies. |
| # Otherwise, it would silently add it to your own AST. |
| public_configs += [ |
| "//buildtools/third_party/libc++:builtin_modulemap", |
| "//buildtools/third_party/libc++:libcxx_modulemap", |
| "//buildtools/third_party/libc++:sysroot_modulemaps", |
| ] |
| } |
| |
| if (is_apple && target_name == "libunwind") { |
| # Apple's libunwind.h #includes ptrauth.h. |
| public_deps += [ ":ptrauth" ] |
| } |
| } |
| } |
| |
| template("builtin_module") { |
| # This is a template to build modules that reside in clang builtin's module |
| # file. |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "${clang_base_path}/lib/clang/${clang_version}/include/module.modulemap" |
| if (use_autogenerated_modules) { |
| public_configs = [ "//buildtools/third_party/libc++:builtin_modulemap" ] |
| } |
| } |
| } |
| |
| template("libcxx_module") { |
| # This is a template to build modules that reside in libc++'s module file. |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "${root_build_dir}/gen/third_party/libc++/src/include/module.modulemap" |
| if (use_autogenerated_modules) { |
| public_configs = [ "//buildtools/third_party/libc++:libcxx_modulemap" ] |
| } |
| } |
| } |
| |
| if (use_autogenerated_modules) { |
| template("sysroot_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "${target_gen_dir}/module.modulemap" |
| public_configs = [ ":sysroot_modulemap" ] |
| } |
| } |
| } else if (is_apple) { |
| template("DarwinBasic_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "$sdk_path/usr/include/DarwinBasic.modulemap" |
| } |
| } |
| |
| template("DarwinFoundation1_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "$sdk_path/usr/include/DarwinFoundation1.modulemap" |
| } |
| } |
| |
| template("DarwinFoundation2_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "$sdk_path/usr/include/DarwinFoundation2.modulemap" |
| } |
| } |
| |
| template("DarwinFoundation3_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = "$sdk_path/usr/include/DarwinFoundation3.modulemap" |
| } |
| } |
| } else { |
| template("sysroot_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*") |
| modulemap = sysroot_modulemap |
| } |
| } |
| } |
| } |
| |
| template("modulemap_config") { |
| config(target_name) { |
| path = rebase_path(invoker.source, root_build_dir) |
| swiftflags = [ "-Xcc=-fmodule-map-file=${path}" ] |
| } |
| } |
| |
| template("sysroot_modulemap") { |
| content = read_file(invoker.source, "string") |
| if (is_win) { |
| # This must be relative to the directory the modulemap is contained within. |
| content = string_replace(content, |
| "\$msvc", |
| rebase_path(current_win_toolchain_data.msvc_dir, |
| target_gen_dir, |
| root_build_dir)) |
| content = |
| string_replace(content, |
| "\$windows_kits", |
| rebase_path(current_win_toolchain_data.windows_kits_dir, |
| target_gen_dir, |
| root_build_dir)) |
| } else { |
| include_dir = "${sysroot}/usr/include" |
| if (is_fuchsia) { |
| include_dir = "${sysroot}/include" |
| } |
| |
| # This must be relative to the directory the modulemap is contained within. |
| content = |
| string_replace(content, |
| "\$sysroot", |
| rebase_path(include_dir, target_gen_dir, root_build_dir)) |
| } |
| write_file(invoker.out, content) |
| |
| modulemap_config(target_name) { |
| source = invoker.out |
| } |
| } |
| |
| template("apple_sysroot_modulemap") { |
| modulemap = "${sysroot_include_dir}/${invoker.sysroot_path}" |
| |
| modulemap_config(target_name) { |
| source = modulemap |
| } |
| |
| # sysroot_modulemaps can be inside the build directory. This no-op action |
| # declares the modulemap files as outputs to satisfy GN's dependency |
| # tracking when other targets use them as inputs. |
| rel = string_split(rebase_path(modulemap, root_build_dir), "/") |
| if (rel[0] == "..") { |
| # It's not in the output directory so we can't declare it as an output file. |
| group(target_name + "_file") { |
| } |
| } else { |
| action(target_name + "_file") { |
| script = "//build/noop.py" |
| outputs = [ modulemap ] |
| } |
| } |
| } |
| |
| template("apple_sysroot_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "modulemap", |
| "modulemap_path", |
| ]) |
| modulemap = "${sysroot_include_dir}/${invoker.modulemap_path}" |
| public_configs = [ invoker.modulemap ] |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| |
| # The no-op action above depends on SDK paths that differ between macOS and |
| # iOS, so it must be built with the correct toolchain |
| # for the target OS. |
| if (use_xcode_symlinks) { |
| toolchain = "//build/toolchain/mac:clang_$target_cpu" |
| if (is_ios || target_environment == "catalyst") { |
| toolchain = "//build/toolchain/ios:ios_clang_$target_cpu" |
| } else if (target_os == "ios" && is_mac) { |
| toolchain = "//build/toolchain/mac:clang_$host_cpu" |
| } |
| public_deps += [ "${invoker.modulemap}_file(${toolchain})" ] |
| } |
| } |
| } |
| |
| template("framework_modulemap") { |
| modulemap_config(target_name) { |
| source = |
| "${frameworks_dir}/${invoker.name}.framework/Modules/module.modulemap" |
| } |
| } |
| |
| template("framework_module") { |
| clang_module(target_name) { |
| forward_variables_from(invoker, "*", [ "framework" ]) |
| |
| # :foo_modulemap -> ${frameworks_dir}/foo.framework/Modules/module.modulemap |
| modulemap = string_replace( |
| string_replace(invoker.modulemap, ":", "${frameworks_dir}/"), |
| "_modulemap", |
| ".framework/Modules/module.modulemap") |
| public_configs = [ invoker.modulemap ] |
| |
| cflags = [ |
| # Some frameworks don't have proper umbrellas. |
| "-Wno-incomplete-umbrella", |
| ] |
| } |
| } |