| # Copyright (C) 2017 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import("//gn/perfetto.gni") |
| import("//gn/standalone/android.gni") |
| import("//gn/standalone/wasm.gni") |
| import("llvm.gni") |
| import("msvc.gni") |
| |
| # This file is evaluated once, within the context of the default toolchain, |
| # which is the target toolchain. |
| # Note: This means that is_android=true even on a mac when cross-compiling for |
| # Android. |
| assert(current_os == target_os && current_cpu == target_cpu, |
| "Assumptions on current_xxx in this file have been violated") |
| |
| declare_args() { |
| cc_wrapper = "" |
| |
| # These apply to both target and host toolchains. |
| extra_cflags = "" |
| extra_cxxflags = "" |
| extra_ldflags = "" |
| |
| # These apply only to the target toolchain. |
| extra_target_cflags = "" |
| extra_target_cxxflags = "" |
| extra_target_ldflags = "" |
| |
| # These apply only to the host toolchain. |
| extra_host_cflags = "" |
| extra_host_cxxflags = "" |
| extra_host_ldflags = "" |
| } |
| |
| # First of all determine the host toolchain. The user can override this by: |
| # 1. setting ar/cc/cxx vars in args.gn. |
| # 2. setting is_system_compiler=true in args.gn and the env vars AR/CC/CXX. |
| # This is used by OSSFuzz and CrOS ebuilds. |
| |
| _llvm_strip_wrapper = rebase_path("llvm-strip.py", root_build_dir) |
| |
| declare_args() { |
| sysroot = "" |
| gcc_toolchain = "" |
| ar = "ar" |
| linker = "" |
| strip = "" |
| |
| if (is_linux_host) { |
| linker = "gold" |
| if (linux_llvm_objcopy != "") { |
| # If we are using the hermetic clang toolchain llvm-objcopy from there as |
| # it works with Linux-arm cross toolchains. The |_llvm_strip_wrapper| is |
| # to set argv0 as llvm-strip. llvm-objcopy's frontend works differently |
| # when invoked as llvm-strip, pretending to be just 'strip'. |
| strip = "${_llvm_strip_wrapper} ${linux_llvm_objcopy}" |
| } else { |
| strip = "strip" |
| } |
| } else if (is_mac_host) { |
| strip = "strip -x" |
| } |
| |
| if (is_clang) { |
| if (is_linux_host && !is_system_compiler) { |
| cc = linux_clang_bin |
| cxx = linux_clangxx_bin |
| linker = linux_clang_linker |
| } else if (is_win_host && !is_system_compiler) { |
| cc = win_clang_bin |
| cxx = win_clangxx_bin |
| linker = win_clang_linker |
| } else { |
| cc = "clang" |
| cxx = "clang++" |
| linker = "" |
| } |
| } else if (is_win) { # MSVC |
| cc = "${win_msvc_bin_dir}\\cl.exe" |
| cxx = "${win_msvc_bin_dir}\\cl.exe" |
| linker = "${win_msvc_bin_dir}\\link.exe" |
| } else { # GCC |
| cc = "gcc" |
| cxx = "g++" |
| } |
| } |
| |
| # Then determine the target toolchain. |
| |
| declare_args() { |
| _default_target_sysroot = "" |
| target_gcc_toolchain = "" |
| |
| # |target_triplet| is the variable that the user can set via GN args. The user |
| # doesn't have to necessarily set it though. In most cases we can infer it |
| # by looking at target_os and target_cpu. |
| # |_target_triplet| is the final argument passed to the toolchain. |
| if (target_triplet != "") { |
| assert(is_cross_compiling) |
| |
| # If the user provides the target_triplet in gn args, respect that. |
| # Otherwise guess it looking at the target os and cpu variables. |
| _target_triplet = target_triplet |
| } else if (!is_cross_compiling) { |
| _target_triplet = "" |
| } else if (target_os == "mac" && target_cpu == "x64") { |
| _target_triplet = "x86_64-apple-darwin" |
| } else if (target_os == "mac" && target_cpu == "x86") { |
| _target_triplet = "i686-apple-darwin" |
| } else if (target_os == "mac" && target_cpu == "arm64") { |
| _target_triplet = "aarch64-apple-darwin" |
| } else if (target_os == "linux" && target_cpu == "arm64") { |
| _target_triplet = "aarch64-linux-gnu" |
| _default_target_sysroot = |
| rebase_path("//buildtools/debian_sid_arm64-sysroot", root_build_dir) |
| } else if (target_os == "linux" && target_cpu == "arm") { |
| _target_triplet = "arm-linux-gnueabihf" |
| _default_target_sysroot = |
| rebase_path("//buildtools/debian_sid_arm-sysroot", root_build_dir) |
| } else if (target_os == "linux" && target_cpu == "riscv64") { |
| _target_triplet = "riscv64-linux-gnu" |
| } else if (target_os == "linux" && target_cpu == "x64") { |
| _target_triplet = "x86_64-linux-gnu" |
| } else if (target_os == "linux" && target_cpu == "x86") { |
| # Chrome's packaging of clang uses i386 for x86 libs, so an i686 triplet |
| # fails to find the necessary sanitizer archives. |
| if (is_hermetic_clang && (is_asan || is_lsan)) { |
| _target_triplet = "i386-linux-gnu" |
| } else { |
| _target_triplet = "i686-linux-gnu" |
| } |
| } else if (target_os == "android" && target_cpu == "arm64") { |
| _target_triplet = "aarch64-linux-android" |
| } else if (target_os == "android" && target_cpu == "arm") { |
| _target_triplet = "arm-linux-androideabi" |
| } else if (target_os == "android" && target_cpu == "x86") { |
| _target_triplet = "i686-linux-android" |
| } else if (target_os == "android" && target_cpu == "x64") { |
| _target_triplet = "x86_64-linux-android" |
| } else { |
| assert( |
| false, |
| "Cannot guess the target triplet from the target_os and target_cpu combination. Please set the target_triplet GN arg explicitly. See https://clang.llvm.org/docs/CrossCompilation.html#target-triple") |
| } |
| } |
| |
| declare_args() { |
| if (sysroot != "") { |
| # If the user specifies a sysroot, use that for both host and target. |
| target_sysroot = sysroot |
| } else { |
| # If no explicit sysroot has been set, use the guessed sysroot from the ones |
| # pulled by //tools/install-build-deps (only for Linux). |
| target_sysroot = _default_target_sysroot |
| } |
| } |
| |
| declare_args() { |
| target_strip = "" |
| if (is_linux || is_android) { |
| target_linker = "gold" |
| } else { |
| target_linker = "" |
| } |
| |
| if (!is_cross_compiling || is_perfetto_build_generator || |
| is_system_compiler) { |
| target_ar = ar |
| target_cc = cc |
| target_cxx = cxx |
| target_linker = linker |
| target_strip = strip |
| } else { |
| target_ar = "ar" |
| if (is_android) { |
| target_ar = "$android_llvm_dir/bin/llvm-ar" |
| target_cc = "$android_llvm_dir/bin/clang" |
| target_cxx = "$android_llvm_dir/bin/clang++" |
| target_linker = "$android_llvm_dir/bin/ld.lld" |
| target_strip = "$android_llvm_dir/bin/llvm-strip" |
| } else { |
| assert(_target_triplet != "", |
| "target_triplet must be non-empty when cross-compiling") |
| target_strip = strip |
| if (is_clang) { |
| if (is_linux_host) { |
| target_cc = "${linux_clang_bin} --target=${_target_triplet}" |
| target_cxx = "${linux_clangxx_bin} --target=${_target_triplet}" |
| target_linker = "${linux_clang_linker} --target=${_target_triplet}" |
| } else { |
| target_cc = "clang --target=${_target_triplet}" |
| target_cxx = "clang++ --target=${_target_triplet}" |
| } |
| } else { # GCC |
| target_ar = "${_target_triplet}-ar" |
| target_cc = "${_target_triplet}-gcc" |
| target_cxx = "${_target_triplet}-g++" |
| } |
| } |
| } |
| } |
| |
| template("gcc_like_toolchain") { |
| toolchain(target_name) { |
| ar = invoker.ar |
| cc = invoker.cc |
| cxx = invoker.cxx |
| lib_switch = "-l" |
| lib_dir_switch = "-L" |
| ld_arg = "" |
| external_cflags = "" |
| external_cxxflags = "" |
| external_ldflags = "" |
| strip = "" |
| if (defined(invoker.linker) && invoker.linker != "") { |
| _invoker_linker = invoker.linker |
| ld_arg = "-fuse-ld=$_invoker_linker" |
| } |
| if (defined(invoker.sysroot) && invoker.sysroot != "") { |
| _invoker_sysroot = invoker.sysroot |
| cc = "$cc --sysroot=$_invoker_sysroot" |
| cxx = "$cxx --sysroot=$_invoker_sysroot" |
| } |
| if (defined(invoker.gcc_toolchain) && invoker.gcc_toolchain != "") { |
| assert(is_clang, "gcc_toolchain can be used only when using clang") |
| _invoker_gcc_toolchain = invoker.gcc_toolchain |
| ld_arg = "$ld_arg --gcc-toolchain=$_invoker_gcc_toolchain" |
| } |
| if (defined(invoker.external_cflags)) { |
| external_cflags = invoker.external_cflags |
| } |
| if (defined(invoker.external_cxxflags)) { |
| external_cxxflags = invoker.external_cxxflags |
| } |
| if (defined(invoker.external_ldflags)) { |
| external_ldflags = invoker.external_ldflags |
| } |
| if (defined(invoker.strip)) { |
| strip = invoker.strip |
| } |
| |
| tool("cc") { |
| depfile = "{{output}}.d" |
| command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} -c {{source}} -o {{output}}" |
| depsformat = "gcc" |
| outputs = |
| [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] |
| description = "compile {{source}}" |
| } |
| |
| tool("cxx") { |
| depfile = "{{output}}.d" |
| command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} ${external_cflags} ${external_cxxflags} -c {{source}} -o {{output}}" |
| depsformat = "gcc" |
| outputs = |
| [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] |
| description = "compile {{source}}" |
| } |
| |
| tool("asm") { |
| depfile = "{{output}}.d" |
| command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" |
| depsformat = "gcc" |
| outputs = |
| [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] |
| description = "assemble {{source}}" |
| } |
| |
| tool("alink") { |
| rspfile = "{{output}}.rsp" |
| if (is_mac && ar != "suppress_unused_ar_variable_warning") { |
| rspfile_content = "{{inputs_newline}}" |
| command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile" |
| } else { |
| rspfile_content = "{{inputs}}" |
| command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile" |
| } |
| outputs = |
| [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ] |
| default_output_extension = ".a" |
| output_prefix = "lib" |
| description = "link {{output}}" |
| } |
| |
| tool("solink") { |
| soname = "{{target_output_name}}{{output_extension}}" |
| unstripped_so = "{{root_out_dir}}/$soname" |
| rspfile = "$unstripped_so.rsp" |
| rspfile_content = "{{inputs}}" |
| rpath = "-Wl,-soname,$soname" |
| if (is_mac) { |
| rpath = "-Wl,-install_name,@rpath/$soname" |
| } |
| command = "$cc_wrapper $cxx $ld_arg -shared {{ldflags}} ${external_ldflags} @$rspfile {{solibs}} {{libs}} $rpath -o $unstripped_so" |
| outputs = [ unstripped_so ] |
| output_prefix = "lib" |
| default_output_extension = ".so" |
| description = "link $unstripped_so" |
| if (strip != "") { |
| stripped_so = "{{root_out_dir}}/stripped/$soname" |
| outputs += [ stripped_so ] |
| command += " && $strip -o $stripped_so $unstripped_so" |
| } |
| } |
| |
| tool("link") { |
| unstripped_exe = |
| "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" |
| rspfile = "$unstripped_exe.rsp" |
| rspfile_content = "{{inputs}}" |
| command = "$cc_wrapper $cxx $ld_arg {{ldflags}} ${external_ldflags} @$rspfile {{solibs}} {{libs}} -o $unstripped_exe" |
| outputs = [ unstripped_exe ] |
| description = "link $unstripped_exe" |
| if (strip != "") { |
| stripped_exe = "{{root_out_dir}}/stripped/{{target_output_name}}{{output_extension}}" |
| outputs += [ stripped_exe ] |
| command += " && $strip -o $stripped_exe $unstripped_exe" |
| } |
| } |
| |
| tool("stamp") { |
| command = "touch {{output}}" |
| description = "stamp {{output}}" |
| } |
| |
| tool("copy") { |
| command = "cp -af {{source}} {{output}}" |
| description = "COPY {{source}} {{output}}" |
| } |
| |
| toolchain_args = { |
| current_cpu = invoker.cpu |
| current_os = invoker.os |
| } |
| } |
| } |
| |
| gcc_like_toolchain("gcc_like") { |
| cpu = current_cpu |
| os = current_os |
| ar = target_ar |
| cc = target_cc |
| cxx = target_cxx |
| linker = target_linker |
| strip = target_strip |
| sysroot = target_sysroot |
| gcc_toolchain = target_gcc_toolchain |
| external_cflags = string_join(" ", |
| [ |
| extra_cflags, |
| extra_target_cflags, |
| ]) |
| external_cxxflags = string_join(" ", |
| [ |
| extra_cxxflags, |
| extra_target_cxxflags, |
| ]) |
| external_ldflags = string_join(" ", |
| [ |
| extra_ldflags, |
| extra_target_ldflags, |
| ]) |
| } |
| |
| gcc_like_toolchain("gcc_like_host") { |
| cpu = host_cpu |
| os = host_os |
| ar = ar |
| cc = cc |
| cxx = cxx |
| linker = linker |
| strip = strip |
| sysroot = sysroot |
| gcc_toolchain = gcc_toolchain |
| external_cflags = string_join(" ", |
| [ |
| extra_cflags, |
| extra_host_cflags, |
| ]) |
| external_cxxflags = string_join(" ", |
| [ |
| extra_cxxflags, |
| extra_host_cxxflags, |
| ]) |
| external_ldflags = string_join(" ", |
| [ |
| extra_ldflags, |
| extra_host_ldflags, |
| ]) |
| } |
| |
| gcc_like_toolchain("wasm") { |
| # emsdk_dir and em_config are defined in wasm.gni. |
| cpu = host_cpu |
| os = host_os |
| ar = "$emsdk_dir/emscripten/emar --em-config $em_config" |
| cc = "$emsdk_dir/emscripten/emcc --em-config $em_config" |
| cxx = "$emsdk_dir/emscripten/em++ --em-config $em_config" |
| strip = "" |
| } |
| |
| # This is used both for MSVC anc clang-cl. clang-cl cmdline interface pretends |
| # to be MSVC's cl.exe. |
| toolchain("msvc") { |
| lib_switch = "" |
| lib_dir_switch = "/LIBPATH:" |
| sys_lib_flags = string_join(" ", win_msvc_sys_lib_flags) |
| external_cflags = string_join(" ", |
| [ |
| extra_cflags, |
| extra_host_cflags, |
| ]) |
| |
| # Note: /showIncludes below is required for ninja, to build a complete |
| # dependency graph for headers. Removing it breaks incremental builds. |
| |
| tool("cc") { |
| precompiled_header_type = "msvc" |
| pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb" |
| command = "$cc_wrapper $cc /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} /c {{source}} /Fo{{output}} /Fd\"$pdbname\" /guard:cf /ZH:SHA_256" |
| depsformat = "msvc" |
| outputs = |
| [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] |
| description = "compile {{source}}" |
| } |
| |
| tool("cxx") { |
| precompiled_header_type = "msvc" |
| pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb" |
| command = "$cc_wrapper $cxx /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} ${external_cflags} /c {{source}} /Fo{{output}} /Fd\"$pdbname\" /guard:cf /ZH:SHA_256" |
| depsformat = "msvc" |
| outputs = |
| [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] |
| description = "compile {{source}}" |
| } |
| |
| tool("alink") { |
| rspfile = "{{output}}.rsp" |
| command = "$linker /lib /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile" |
| outputs = [ |
| # Ignore {{output_extension}} and always use .lib, there's no reason to |
| # allow targets to override this extension on Windows. |
| "{{root_out_dir}}/{{target_output_name}}{{output_extension}}", |
| ] |
| default_output_extension = ".lib" |
| default_output_dir = "{{target_out_dir}}" |
| |
| # inputs_newline works around a fixed per-line buffer size in the linker. |
| rspfile_content = "{{inputs_newline}}" |
| description = "link {{output}}" |
| } |
| |
| tool("solink") { |
| dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" |
| libname = "${dllname}.lib" |
| pdbname = "${dllname}.pdb" |
| rspfile = "${dllname}.rsp" |
| |
| command = "$linker /nologo /IMPLIB:$libname ${sys_lib_flags} /DLL /OUT:$dllname /PDB:$pdbname @$rspfile" |
| outputs = [ |
| dllname, |
| libname, |
| pdbname, |
| ] |
| default_output_extension = ".dll" |
| default_output_dir = "{{root_out_dir}}" |
| |
| link_output = libname |
| depend_output = libname |
| runtime_outputs = [ |
| dllname, |
| pdbname, |
| ] |
| |
| # Since the above commands only updates the .lib file when it changes, ask |
| # Ninja to check if the timestamp actually changed to know if downstream |
| # dependencies should be recompiled. |
| restat = true |
| |
| # inputs_newline works around a fixed per-line buffer size in the linker. |
| rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}" |
| description = "link {{output}}" |
| } |
| |
| tool("link") { |
| exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" |
| pdbname = "$exename.pdb" |
| rspfile = "$exename.rsp" |
| |
| command = "$linker /nologo /guard:cf /DYNAMICBASE /OUT:$exename ${sys_lib_flags} /DEBUG /PDB:$pdbname @$rspfile" |
| default_output_extension = ".exe" |
| default_output_dir = "{{root_out_dir}}" |
| outputs = [ exename ] |
| |
| # inputs_newline works around a fixed per-line buffer size in the linker. |
| rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}" |
| description = "link {{output}}" |
| } |
| |
| tool("stamp") { |
| command = "cmd /c type nul > \"{{output}}\"" |
| description = "stamp {{output}}" |
| } |
| |
| tool("copy") { |
| cp_py = rebase_path("../cp.py") |
| command = "cmd.exe /c python \"$cp_py\" {{source}} {{output}}" |
| description = "copy {{source}} {{output}}" |
| } |
| } |