Index: build/toolchain/gcc_toolchain.gni |
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7db87a3b10151df5bf9d841ec8e5c6a97aff20de |
--- /dev/null |
+++ b/build/toolchain/gcc_toolchain.gni |
@@ -0,0 +1,534 @@ |
+# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import("//build/config/nacl/config.gni") |
+import("//build/config/sanitizers/sanitizers.gni") |
+import("//build/toolchain/cc_wrapper.gni") |
+import("//build/toolchain/goma.gni") |
+import("//build/toolchain/toolchain.gni") |
+ |
+# "concurrent_links" is a toolchain variable. By computing it here rather than |
+# inside the toolchain, the exec_script will only get run once rather than |
+# each time the toolchain template is invoked. |
+if (allow_posix_link_time_opt || is_cfi) { |
+ concurrent_links_ = |
+ exec_script("get_concurrent_links.py", [ "--lto" ], "value") |
+} else { |
+ concurrent_links_ = exec_script("get_concurrent_links.py", [], "value") |
+} |
+ |
+# This template defines a toolchain for something that works like gcc |
+# (including clang). |
+# |
+# It requires the following variables specifying the executables to run: |
+# - ar |
+# - cc |
+# - cxx |
+# - ld |
+# and the following which is used in the toolchain_args |
+# - toolchain_cpu (What "current_cpu" should be set to when invoking a |
+# build using this toolchain.) |
+# - toolchain_os (What "current_os" should be set to when invoking a |
+# build using this toolchain.) |
+# |
+# Optional parameters that control the tools: |
+# |
+# - extra_cflags |
+# Extra flags to be appended when compiling C files (but not C++ files). |
+# - extra_cppflags |
+# Extra flags to be appended when compiling both C and C++ files. "CPP" |
+# stands for "C PreProcessor" in this context, although it can be |
+# used for non-preprocessor flags as well. Not to be confused with |
+# "CXX" (which follows). |
+# - extra_cxxflags |
+# Extra flags to be appended when compiling C++ files (but not C files). |
+# - extra_ldflags |
+# Extra flags to be appended when linking |
+# |
+# - libs_section_prefix |
+# - libs_section_postfix |
+# The contents of these strings, if specified, will be placed around |
+# the libs section of the linker line. It allows one to inject libraries |
+# at the beginning and end for all targets in a toolchain. |
+# - solink_libs_section_prefix |
+# - solink_libs_section_postfix |
+# Same as libs_section_{pre,post}fix except used for solink instead of link. |
+# - link_outputs |
+# The content of this array, if specified, will be added to the list of |
+# outputs from the link command. This can be useful in conjunction with |
+# the post_link parameter. |
+# - post_link |
+# The content of this string, if specified, will be run as a separate |
+# command following the the link command. |
+# - deps |
+# Just forwarded to the toolchain definition. |
+# - executable_extension |
+# If this string is specified it will be used for the file extension |
+# for an executable, rather than using no extension; targets will |
+# still be able to override the extension using the output_extension |
+# variable. |
+# - rebuild_define |
+# The contents of this string, if specified, will be passed as a #define |
+# to the toolchain. It can be used to force recompiles whenever a |
+# toolchain is updated. |
+# - shlib_extension |
+# If this string is specified it will be used for the file extension |
+# for a shared library, rather than default value specified in |
+# toolchain.gni |
+# - strip |
+# Location of the strip executable. When specified, strip will be run on |
+# all shared libraries and executables as they are built. The pre-stripped |
+# artifacts will be put in lib.unstripped/ and exe.unstripped/. |
+# |
+# Optional build argument contols. |
+# |
+# - clear_sanitizers |
+# When set to true, is_asan, is_msan, etc.will all be set to false. Often |
+# secondary toolchains do not want to run with sanitizers. |
+# - is_clang |
+# Whether to use clang instead of gcc. |
+# - is_component_build |
+# Whether to forcibly enable or disable component builds for this |
+# toolchain; if not specified, the toolchain will inherit the |
+# default setting. |
+# - is_nacl_glibc |
+# Whether NaCl code is built using Glibc instead of Newlib. |
+# - cc_wrapper |
+# Override the global cc_wrapper setting. e.g. "ccache" or "icecc". |
+# useful to opt-out of cc_wrapper in a particular toolchain by setting |
+# cc_wrapper = "" in it. |
+# - use_debug_fission |
+# Override the global use_debug_fission setting, useful if the particular |
+# toolchain should not be generating split-dwarf code. |
+# - use_goma |
+# Override the global use_goma setting, useful to opt-out of goma in a |
+# particular toolchain by setting use_gome = false in it. |
+# - use_gold |
+# Override the global use_gold setting, useful if the particular |
+# toolchain has a custom link step that is not actually using Gold. |
+template("gcc_toolchain") { |
+ toolchain(target_name) { |
+ assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") |
+ assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") |
+ assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") |
+ assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") |
+ assert(defined(invoker.toolchain_cpu), |
+ "gcc_toolchain() must specify a \"toolchain_cpu\"") |
+ assert(defined(invoker.toolchain_os), |
+ "gcc_toolchain() must specify a \"toolchain_os\"") |
+ |
+ concurrent_links = concurrent_links_ |
+ |
+ if (defined(invoker.cc_wrapper)) { |
+ cc_wrapper = invoker.cc_wrapper |
+ } |
+ if (defined(invoker.use_goma)) { |
+ use_goma = invoker.use_goma |
+ } |
+ if (use_goma) { |
+ assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.") |
+ compiler_prefix = "$goma_dir/gomacc " |
+ } else if (cc_wrapper != "") { |
+ compiler_prefix = cc_wrapper + " " |
+ } else { |
+ compiler_prefix = "" |
+ } |
+ |
+ # This define changes when the toolchain changes, forcing a rebuild. |
+ # Nothing should ever use this define. |
+ if (defined(invoker.rebuild_define)) { |
+ rebuild_string = "-D" + invoker.rebuild_define + " " |
+ } else { |
+ rebuild_string = "" |
+ } |
+ |
+ cc = compiler_prefix + invoker.cc |
+ cxx = compiler_prefix + invoker.cxx |
+ ar = invoker.ar |
+ ld = invoker.ld |
+ if (defined(invoker.readelf)) { |
+ readelf = invoker.readelf |
+ } else { |
+ readelf = "readelf" |
+ } |
+ if (defined(invoker.nm)) { |
+ nm = invoker.nm |
+ } else { |
+ nm = "nm" |
+ } |
+ |
+ if (defined(invoker.shlib_extension)) { |
+ default_shlib_extension = invoker.shlib_extension |
+ } else { |
+ default_shlib_extension = shlib_extension |
+ } |
+ |
+ if (defined(invoker.executable_extension)) { |
+ default_executable_extension = invoker.executable_extension |
+ } else { |
+ default_executable_extension = "" |
+ } |
+ |
+ # Bring these into our scope for string interpolation with default values. |
+ if (defined(invoker.libs_section_prefix)) { |
+ libs_section_prefix = invoker.libs_section_prefix |
+ } else { |
+ libs_section_prefix = "" |
+ } |
+ |
+ if (defined(invoker.libs_section_postfix)) { |
+ libs_section_postfix = invoker.libs_section_postfix |
+ } else { |
+ libs_section_postfix = "" |
+ } |
+ |
+ if (defined(invoker.solink_libs_section_prefix)) { |
+ solink_libs_section_prefix = invoker.solink_libs_section_prefix |
+ } else { |
+ solink_libs_section_prefix = "" |
+ } |
+ |
+ if (defined(invoker.solink_libs_section_postfix)) { |
+ solink_libs_section_postfix = invoker.solink_libs_section_postfix |
+ } else { |
+ solink_libs_section_postfix = "" |
+ } |
+ |
+ if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") { |
+ extra_cflags = " " + invoker.extra_cflags |
+ } else { |
+ extra_cflags = "" |
+ } |
+ |
+ if (defined(invoker.extra_cppflags) && invoker.extra_cppflags != "") { |
+ extra_cppflags = " " + invoker.extra_cppflags |
+ } else { |
+ extra_cppflags = "" |
+ } |
+ |
+ if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") { |
+ extra_cxxflags = " " + invoker.extra_cxxflags |
+ } else { |
+ extra_cxxflags = "" |
+ } |
+ |
+ if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") { |
+ extra_ldflags = " " + invoker.extra_ldflags |
+ } else { |
+ extra_ldflags = "" |
+ } |
+ |
+ # These library switches can apply to all tools below. |
+ lib_switch = "-l" |
+ lib_dir_switch = "-L" |
+ |
+ # Object files go in this directory. |
+ object_subdir = "{{target_out_dir}}/{{label_name}}" |
+ |
+ tool("cc") { |
+ depfile = "{{output}}.d" |
+ command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}" |
+ depsformat = "gcc" |
+ description = "CC {{output}}" |
+ outputs = [ |
+ "$object_subdir/{{source_name_part}}.o", |
+ ] |
+ } |
+ |
+ tool("cxx") { |
+ depfile = "{{output}}.d" |
+ command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}" |
+ depsformat = "gcc" |
+ description = "CXX {{output}}" |
+ outputs = [ |
+ "$object_subdir/{{source_name_part}}.o", |
+ ] |
+ } |
+ |
+ tool("asm") { |
+ # For GCC we can just use the C compiler to compile assembly. |
+ depfile = "{{output}}.d" |
+ command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" |
+ depsformat = "gcc" |
+ description = "ASM {{output}}" |
+ outputs = [ |
+ "$object_subdir/{{source_name_part}}.o", |
+ ] |
+ } |
+ |
+ tool("alink") { |
+ rspfile = "{{output}}.rsp" |
+ |
+ # This needs a Python script to avoid using simple sh features in this |
+ # command, in case the host does not use a POSIX shell (e.g. compiling |
+ # POSIX-like toolchains such as NaCl on Windows). |
+ ar_wrapper = |
+ rebase_path("//build/toolchain/gcc_ar_wrapper.py", root_build_dir) |
+ command = "$python_path \"$ar_wrapper\" --output={{output}} --ar=\"$ar\" {{arflags}} rcsD @\"$rspfile\"" |
+ description = "AR {{output}}" |
+ rspfile_content = "{{inputs}}" |
+ outputs = [ |
+ "{{output_dir}}/{{target_output_name}}{{output_extension}}", |
+ ] |
+ |
+ # Shared libraries go in the target out directory by default so we can |
+ # generate different targets with the same name and not have them collide. |
+ default_output_dir = "{{target_out_dir}}" |
+ default_output_extension = ".a" |
+ output_prefix = "lib" |
+ } |
+ |
+ tool("solink") { |
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". |
+ sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir. |
+ rspfile = sofile + ".rsp" |
+ |
+ if (defined(invoker.strip)) { |
+ unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" |
+ } else { |
+ unstripped_sofile = sofile |
+ } |
+ |
+ # These variables are not built into GN but are helpers that |
+ # implement (1) linking to produce a .so, (2) extracting the symbols |
+ # from that file (3) if the extracted list differs from the existing |
+ # .TOC file, overwrite it, otherwise, don't change it. |
+ tocfile = sofile + ".TOC" |
+ |
+ link_command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" |
+ |
+ assert(defined(readelf), "to solink you must have a readelf") |
+ assert(defined(nm), "to solink you must have an nm") |
+ strip_switch = "" |
+ if (defined(invoker.strip)) { |
+ strip_switch = "--strip=${invoker.strip}" |
+ } |
+ |
+ # This needs a Python script to avoid using a complex shell command |
+ # requiring sh control structures, pipelines, and POSIX utilities. |
+ # The host might not have a POSIX shell and utilities (e.g. Windows). |
+ solink_wrapper = rebase_path("//build/toolchain/gcc_solink_wrapper.py") |
+ command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch --sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\" -- $link_command" |
+ |
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" |
+ |
+ description = "SOLINK $sofile" |
+ |
+ # Use this for {{output_extension}} expansions unless a target manually |
+ # overrides it (in which case {{output_extension}} will be what the target |
+ # specifies). |
+ default_output_extension = default_shlib_extension |
+ |
+ default_output_dir = "{{root_out_dir}}" |
+ if (shlib_subdir != ".") { |
+ default_output_dir += "/$shlib_subdir" |
+ } |
+ |
+ output_prefix = "lib" |
+ |
+ # Since the above commands only updates the .TOC file when it changes, ask |
+ # Ninja to check if the timestamp actually changed to know if downstream |
+ # dependencies should be recompiled. |
+ restat = true |
+ |
+ # Tell GN about the output files. It will link to the sofile but use the |
+ # tocfile for dependency management. |
+ outputs = [ |
+ sofile, |
+ tocfile, |
+ ] |
+ if (sofile != unstripped_sofile) { |
+ outputs += [ unstripped_sofile ] |
+ } |
+ link_output = sofile |
+ depend_output = tocfile |
+ } |
+ |
+ tool("solink_module") { |
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". |
+ sofile = "{{output_dir}}/$soname" |
+ rspfile = sofile + ".rsp" |
+ |
+ if (defined(invoker.strip)) { |
+ unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" |
+ } else { |
+ unstripped_sofile = sofile |
+ } |
+ |
+ command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" |
+ |
+ if (defined(invoker.strip)) { |
+ strip_command = "${invoker.strip} --strip-unneeded -o \"$sofile\" \"$unstripped_sofile\"" |
+ command += " && " + strip_command |
+ } |
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" |
+ |
+ description = "SOLINK_MODULE $sofile" |
+ |
+ # Use this for {{output_extension}} expansions unless a target manually |
+ # overrides it (in which case {{output_extension}} will be what the target |
+ # specifies). |
+ if (defined(invoker.loadable_module_extension)) { |
+ default_output_extension = invoker.loadable_module_extension |
+ } else { |
+ default_output_extension = default_shlib_extension |
+ } |
+ |
+ default_output_dir = "{{root_out_dir}}" |
+ if (shlib_subdir != ".") { |
+ default_output_dir += "/$shlib_subdir" |
+ } |
+ |
+ output_prefix = "lib" |
+ |
+ outputs = [ |
+ sofile, |
+ ] |
+ if (sofile != unstripped_sofile) { |
+ outputs += [ unstripped_sofile ] |
+ } |
+ } |
+ |
+ tool("link") { |
+ exename = "{{target_output_name}}{{output_extension}}" |
+ outfile = "{{output_dir}}/$exename" |
+ rspfile = "$outfile.rsp" |
+ unstripped_outfile = outfile |
+ |
+ # Use this for {{output_extension}} expansions unless a target manually |
+ # overrides it (in which case {{output_extension}} will be what the target |
+ # specifies). |
+ default_output_extension = default_executable_extension |
+ |
+ default_output_dir = "{{root_out_dir}}" |
+ |
+ if (defined(invoker.strip)) { |
+ unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" |
+ } |
+ |
+ command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" |
+ if (defined(invoker.strip)) { |
+ link_wrapper = |
+ rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir) |
+ command = "$python_path \"$link_wrapper\" --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\" --output=\"$outfile\" -- $command" |
+ } |
+ description = "LINK $outfile" |
+ rspfile_content = "{{inputs}}" |
+ outputs = [ |
+ outfile, |
+ ] |
+ if (outfile != unstripped_outfile) { |
+ outputs += [ unstripped_outfile ] |
+ } |
+ if (defined(invoker.link_outputs)) { |
+ outputs += invoker.link_outputs |
+ } |
+ } |
+ |
+ # These two are really entirely generic, but have to be repeated in |
+ # each toolchain because GN doesn't allow a template to be used here. |
+ # See //build/toolchain/toolchain.gni for details. |
+ tool("stamp") { |
+ command = stamp_command |
+ description = stamp_description |
+ } |
+ tool("copy") { |
+ command = copy_command |
+ description = copy_description |
+ } |
+ |
+ # When invoking this toolchain not as the default one, these args will be |
+ # passed to the build. They are ignored when this is the default toolchain. |
+ toolchain_args() { |
+ current_cpu = invoker.toolchain_cpu |
+ current_os = invoker.toolchain_os |
+ |
+ # These values need to be passed through unchanged. |
+ host_toolchain = host_toolchain |
+ target_os = target_os |
+ target_cpu = target_cpu |
+ |
+ if (defined(invoker.is_clang)) { |
+ is_clang = invoker.is_clang |
+ } |
+ if (defined(invoker.is_component_build)) { |
+ is_component_build = invoker.is_component_build |
+ } |
+ if (defined(invoker.is_nacl_glibc)) { |
+ is_nacl_glibc = invoker.is_nacl_glibc |
+ } |
+ if (defined(invoker.symbol_level)) { |
+ symbol_level = invoker.symbol_level |
+ } |
+ if (defined(invoker.use_allocator)) { |
+ use_allocator = invoker.use_allocator |
+ } |
+ if (defined(invoker.use_debug_fission)) { |
+ use_debug_fission = invoker.use_debug_fission |
+ } |
+ if (defined(invoker.use_gold)) { |
+ use_gold = invoker.use_gold |
+ } |
+ if (defined(invoker.use_sysroot)) { |
+ use_sysroot = invoker.use_sysroot |
+ } |
+ |
+ # Disable sanitizers for non-default toolchains. |
+ is_asan = false |
+ is_cfi = false |
+ is_lsan = false |
+ is_msan = false |
+ is_syzyasan = false |
+ is_tsan = false |
+ is_ubsan = false |
+ is_ubsan_vptr = false |
+ } |
+ |
+ forward_variables_from(invoker, [ "deps" ]) |
+ } |
+} |
+ |
+# This is a shorthand for gcc_toolchain instances based on the |
+# Chromium-built version of Clang. Only the toolchain_cpu and |
+# toolchain_os variables need to be specified by the invoker, and |
+# optionally toolprefix if it's a cross-compile case. Note that for |
+# a cross-compile case this toolchain requires a config to pass the |
+# appropriate -target option, or else it will actually just be doing |
+# a native compile. The invoker can optionally override use_gold too. |
+template("clang_toolchain") { |
+ assert(defined(invoker.toolchain_cpu), |
+ "clang_toolchain() must specify a \"toolchain_cpu\"") |
+ assert(defined(invoker.toolchain_os), |
+ "clang_toolchain() must specify a \"toolchain_os\"") |
+ if (defined(invoker.toolprefix)) { |
+ toolprefix = invoker.toolprefix |
+ } else { |
+ toolprefix = "" |
+ } |
+ |
+ gcc_toolchain(target_name) { |
+ prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", |
+ root_build_dir) |
+ cc = "$prefix/clang" |
+ cxx = "$prefix/clang++" |
+ ld = cxx |
+ is_clang = true |
+ |
+ readelf = "${toolprefix}readelf" |
+ ar = "${toolprefix}ar" |
+ nm = "${toolprefix}nm" |
+ |
+ forward_variables_from(invoker, |
+ [ |
+ "toolchain_cpu", |
+ "toolchain_os", |
+ "use_gold", |
+ "strip", |
+ ]) |
+ |
+ if (defined(invoker.use_debug_fission)) { |
+ use_debug_fission = invoker.use_debug_fission |
+ } |
+ } |
+} |