• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2017 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import("//gn/perfetto.gni")
16import("//gn/standalone/android.gni")
17import("//gn/standalone/wasm.gni")
18import("llvm.gni")
19import("msvc.gni")
20
21# This file is evaluated once, within the context of the default toolchain,
22# which is the target toolchain.
23# Note: This means that is_android=true even on a mac when cross-compiling for
24# Android.
25assert(current_os == target_os && current_cpu == target_cpu,
26       "Assumptions on current_xxx in this file have been violated")
27
28declare_args() {
29  cc_wrapper = ""
30
31  # These apply to both target and host toolchains.
32  extra_cflags = ""
33  extra_cxxflags = ""
34  extra_ldflags = ""
35
36  # These apply only to the target toolchain.
37  extra_target_cflags = ""
38  extra_target_cxxflags = ""
39  extra_target_ldflags = ""
40
41  # These apply only to the host toolchain.
42  extra_host_cflags = ""
43  extra_host_cxxflags = ""
44  extra_host_ldflags = ""
45}
46
47# First of all determine the host toolchain. The user can override this by:
48# 1. setting ar/cc/cxx vars in args.gn.
49# 2. setting is_system_compiler=true in args.gn and the env vars AR/CC/CXX.
50#    This is used by OSSFuzz and CrOS ebuilds.
51
52_llvm_strip_wrapper = rebase_path("llvm-strip.py", root_build_dir)
53
54declare_args() {
55  sysroot = ""
56  gcc_toolchain = ""
57  ar = "ar"
58  linker = ""
59  strip = ""
60
61  if (is_linux_host) {
62    linker = "gold"
63    if (linux_llvm_objcopy != "") {
64      # If we are using the hermetic clang toolchain llvm-objcopy from there as
65      # it works with Linux-arm cross toolchains. The |_llvm_strip_wrapper| is
66      # to set argv0 as llvm-strip. llvm-objcopy's frontend works differently
67      # when invoked as llvm-strip, pretending to be just 'strip'.
68      strip = "${_llvm_strip_wrapper} ${linux_llvm_objcopy}"
69    } else {
70      strip = "strip"
71    }
72  } else if (is_mac_host) {
73    strip = "strip -x"
74  }
75
76  if (is_clang) {
77    if (is_linux_host && !is_system_compiler) {
78      cc = linux_clang_bin
79      cxx = linux_clangxx_bin
80      linker = linux_clang_linker
81    } else if (is_win_host && !is_system_compiler) {
82      cc = win_clang_bin
83      cxx = win_clangxx_bin
84      linker = win_clang_linker
85    } else {
86      cc = "clang"
87      cxx = "clang++"
88      linker = ""
89    }
90  } else if (is_win) {  # MSVC
91    cc = "${win_msvc_bin_dir}\\cl.exe"
92    cxx = "${win_msvc_bin_dir}\\cl.exe"
93    linker = "${win_msvc_bin_dir}\\link.exe"
94  } else {  # GCC
95    cc = "gcc"
96    cxx = "g++"
97  }
98}
99
100# Then determine the target toolchain.
101
102declare_args() {
103  _default_target_sysroot = ""
104  target_gcc_toolchain = ""
105
106  # |target_triplet| is the variable that the user can set via GN args. The user
107  # doesn't have to necessarily set it though. In most cases we can infer it
108  # by looking at target_os and target_cpu.
109  # |_target_triplet| is the final argument passed to the toolchain.
110  if (target_triplet != "") {
111    assert(is_cross_compiling)
112
113    # If the user provides the target_triplet in gn args, respect that.
114    # Otherwise guess it looking at the target os and cpu variables.
115    _target_triplet = target_triplet
116  } else if (!is_cross_compiling) {
117    _target_triplet = ""
118  } else if (target_os == "mac" && target_cpu == "x64") {
119    _target_triplet = "x86_64-apple-darwin"
120  } else if (target_os == "mac" && target_cpu == "x86") {
121    _target_triplet = "i686-apple-darwin"
122  } else if (target_os == "mac" && target_cpu == "arm64") {
123    _target_triplet = "aarch64-apple-darwin"
124  } else if (target_os == "linux" && target_cpu == "arm64") {
125    _target_triplet = "aarch64-linux-gnu"
126    _default_target_sysroot =
127        rebase_path("//buildtools/debian_sid_arm64-sysroot", root_build_dir)
128  } else if (target_os == "linux" && target_cpu == "arm") {
129    _target_triplet = "arm-linux-gnueabihf"
130    _default_target_sysroot =
131        rebase_path("//buildtools/debian_sid_arm-sysroot", root_build_dir)
132  } else if (target_os == "linux" && target_cpu == "riscv64") {
133    _target_triplet = "riscv64-linux-gnu"
134  } else if (target_os == "linux" && target_cpu == "x64") {
135    _target_triplet = "x86_64-linux-gnu"
136  } else if (target_os == "linux" && target_cpu == "x86") {
137    # Chrome's packaging of clang uses i386 for x86 libs, so an i686 triplet
138    # fails to find the necessary sanitizer archives.
139    if (is_hermetic_clang && (is_asan || is_lsan)) {
140      _target_triplet = "i386-linux-gnu"
141    } else {
142      _target_triplet = "i686-linux-gnu"
143    }
144  } else if (target_os == "android" && target_cpu == "arm64") {
145    _target_triplet = "aarch64-linux-android"
146  } else if (target_os == "android" && target_cpu == "arm") {
147    _target_triplet = "arm-linux-androideabi"
148  } else if (target_os == "android" && target_cpu == "x86") {
149    _target_triplet = "i686-linux-android"
150  } else if (target_os == "android" && target_cpu == "x64") {
151    _target_triplet = "x86_64-linux-android"
152  } else {
153    assert(
154        false,
155        "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")
156  }
157}
158
159declare_args() {
160  if (sysroot != "") {
161    # If the user specifies a sysroot, use that for both host and target.
162    target_sysroot = sysroot
163  } else {
164    # If no explicit sysroot has been set, use the guessed sysroot from the ones
165    # pulled by //tools/install-build-deps (only for Linux).
166    target_sysroot = _default_target_sysroot
167  }
168}
169
170declare_args() {
171  target_strip = ""
172  if (is_linux || is_android) {
173    target_linker = "gold"
174  } else {
175    target_linker = ""
176  }
177
178  if (!is_cross_compiling || is_perfetto_build_generator ||
179      is_system_compiler) {
180    target_ar = ar
181    target_cc = cc
182    target_cxx = cxx
183    target_linker = linker
184    target_strip = strip
185  } else {
186    target_ar = "ar"
187    if (is_android) {
188      target_ar = "$android_llvm_dir/bin/llvm-ar"
189      target_cc = "$android_llvm_dir/bin/clang"
190      target_cxx = "$android_llvm_dir/bin/clang++"
191      target_linker = "$android_llvm_dir/bin/ld.lld"
192      target_strip = "$android_llvm_dir/bin/llvm-strip"
193    } else {
194      assert(_target_triplet != "",
195             "target_triplet must be non-empty when cross-compiling")
196      target_strip = strip
197      if (is_clang) {
198        if (is_linux_host) {
199          target_cc = "${linux_clang_bin} --target=${_target_triplet}"
200          target_cxx = "${linux_clangxx_bin} --target=${_target_triplet}"
201          target_linker = "${linux_clang_linker} --target=${_target_triplet}"
202        } else {
203          target_cc = "clang --target=${_target_triplet}"
204          target_cxx = "clang++ --target=${_target_triplet}"
205        }
206      } else {  # GCC
207        target_ar = "${_target_triplet}-ar"
208        target_cc = "${_target_triplet}-gcc"
209        target_cxx = "${_target_triplet}-g++"
210      }
211    }
212  }
213}
214
215template("gcc_like_toolchain") {
216  toolchain(target_name) {
217    ar = invoker.ar
218    cc = invoker.cc
219    cxx = invoker.cxx
220    lib_switch = "-l"
221    lib_dir_switch = "-L"
222    ld_arg = ""
223    external_cflags = ""
224    external_cxxflags = ""
225    external_ldflags = ""
226    strip = ""
227    if (defined(invoker.linker) && invoker.linker != "") {
228      _invoker_linker = invoker.linker
229      ld_arg = "-fuse-ld=$_invoker_linker"
230    }
231    if (defined(invoker.sysroot) && invoker.sysroot != "") {
232      _invoker_sysroot = invoker.sysroot
233      cc = "$cc --sysroot=$_invoker_sysroot"
234      cxx = "$cxx --sysroot=$_invoker_sysroot"
235    }
236    if (defined(invoker.gcc_toolchain) && invoker.gcc_toolchain != "") {
237      assert(is_clang, "gcc_toolchain can be used only when using clang")
238      _invoker_gcc_toolchain = invoker.gcc_toolchain
239      ld_arg = "$ld_arg --gcc-toolchain=$_invoker_gcc_toolchain"
240    }
241    if (defined(invoker.external_cflags)) {
242      external_cflags = invoker.external_cflags
243    }
244    if (defined(invoker.external_cxxflags)) {
245      external_cxxflags = invoker.external_cxxflags
246    }
247    if (defined(invoker.external_ldflags)) {
248      external_ldflags = invoker.external_ldflags
249    }
250    if (defined(invoker.strip)) {
251      strip = invoker.strip
252    }
253
254    tool("cc") {
255      depfile = "{{output}}.d"
256      command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} -c {{source}} -o {{output}}"
257      depsformat = "gcc"
258      outputs =
259          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
260      description = "compile {{source}}"
261    }
262
263    tool("cxx") {
264      depfile = "{{output}}.d"
265      command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}  ${external_cflags} ${external_cxxflags} -c {{source}} -o {{output}}"
266      depsformat = "gcc"
267      outputs =
268          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
269      description = "compile {{source}}"
270    }
271
272    tool("asm") {
273      depfile = "{{output}}.d"
274      command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
275      depsformat = "gcc"
276      outputs =
277          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
278      description = "assemble {{source}}"
279    }
280
281    tool("alink") {
282      rspfile = "{{output}}.rsp"
283      if (is_mac && ar != "suppress_unused_ar_variable_warning") {
284        rspfile_content = "{{inputs_newline}}"
285        command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile"
286      } else {
287        rspfile_content = "{{inputs}}"
288        command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile"
289      }
290      outputs =
291          [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ]
292      default_output_extension = ".a"
293      output_prefix = "lib"
294      description = "link {{output}}"
295    }
296
297    tool("solink") {
298      soname = "{{target_output_name}}{{output_extension}}"
299      unstripped_so = "{{root_out_dir}}/$soname"
300      rspfile = "$unstripped_so.rsp"
301      rspfile_content = "{{inputs}}"
302      rpath = "-Wl,-soname,$soname"
303      if (is_mac) {
304        rpath = "-Wl,-install_name,@rpath/$soname"
305      }
306      command = "$cc_wrapper $cxx $ld_arg -shared {{ldflags}} ${external_ldflags} @$rspfile {{solibs}} {{libs}} $rpath -o $unstripped_so"
307      outputs = [ unstripped_so ]
308      output_prefix = "lib"
309      default_output_extension = ".so"
310      description = "link $unstripped_so"
311      if (strip != "") {
312        stripped_so = "{{root_out_dir}}/stripped/$soname"
313        outputs += [ stripped_so ]
314        command += " && $strip -o $stripped_so $unstripped_so"
315      }
316    }
317
318    tool("link") {
319      unstripped_exe =
320          "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
321      rspfile = "$unstripped_exe.rsp"
322      rspfile_content = "{{inputs}}"
323      command = "$cc_wrapper $cxx $ld_arg {{ldflags}} ${external_ldflags} @$rspfile {{solibs}} {{libs}} -o $unstripped_exe"
324      outputs = [ unstripped_exe ]
325      description = "link $unstripped_exe"
326      if (strip != "") {
327        stripped_exe = "{{root_out_dir}}/stripped/{{target_output_name}}{{output_extension}}"
328        outputs += [ stripped_exe ]
329        command += " && $strip -o $stripped_exe $unstripped_exe"
330      }
331    }
332
333    tool("stamp") {
334      command = "touch {{output}}"
335      description = "stamp {{output}}"
336    }
337
338    tool("copy") {
339      command = "cp -af {{source}} {{output}}"
340      description = "COPY {{source}} {{output}}"
341    }
342
343    toolchain_args = {
344      current_cpu = invoker.cpu
345      current_os = invoker.os
346    }
347  }
348}
349
350gcc_like_toolchain("gcc_like") {
351  cpu = current_cpu
352  os = current_os
353  ar = target_ar
354  cc = target_cc
355  cxx = target_cxx
356  linker = target_linker
357  strip = target_strip
358  sysroot = target_sysroot
359  gcc_toolchain = target_gcc_toolchain
360  external_cflags = string_join(" ",
361                                [
362                                  extra_cflags,
363                                  extra_target_cflags,
364                                ])
365  external_cxxflags = string_join(" ",
366                                  [
367                                    extra_cxxflags,
368                                    extra_target_cxxflags,
369                                  ])
370  external_ldflags = string_join(" ",
371                                 [
372                                   extra_ldflags,
373                                   extra_target_ldflags,
374                                 ])
375}
376
377gcc_like_toolchain("gcc_like_host") {
378  cpu = host_cpu
379  os = host_os
380  ar = ar
381  cc = cc
382  cxx = cxx
383  linker = linker
384  strip = strip
385  sysroot = sysroot
386  gcc_toolchain = gcc_toolchain
387  external_cflags = string_join(" ",
388                                [
389                                  extra_cflags,
390                                  extra_host_cflags,
391                                ])
392  external_cxxflags = string_join(" ",
393                                  [
394                                    extra_cxxflags,
395                                    extra_host_cxxflags,
396                                  ])
397  external_ldflags = string_join(" ",
398                                 [
399                                   extra_ldflags,
400                                   extra_host_ldflags,
401                                 ])
402}
403
404gcc_like_toolchain("wasm") {
405  # emsdk_dir and em_config are defined in wasm.gni.
406  cpu = host_cpu
407  os = host_os
408  ar = "$emsdk_dir/emscripten/emar --em-config $em_config"
409  cc = "$emsdk_dir/emscripten/emcc --em-config $em_config"
410  cxx = "$emsdk_dir/emscripten/em++ --em-config $em_config"
411  strip = ""
412}
413
414# This is used both for MSVC anc clang-cl. clang-cl cmdline interface pretends
415# to be MSVC's cl.exe.
416toolchain("msvc") {
417  lib_switch = ""
418  lib_dir_switch = "/LIBPATH:"
419  sys_lib_flags = string_join(" ", win_msvc_sys_lib_flags)
420  external_cflags = string_join(" ",
421                                [
422                                  extra_cflags,
423                                  extra_host_cflags,
424                                ])
425
426  # Note: /showIncludes below is required for ninja, to build a complete
427  # dependency graph for headers. Removing it breaks incremental builds.
428
429  tool("cc") {
430    precompiled_header_type = "msvc"
431    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
432    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"
433    depsformat = "msvc"
434    outputs =
435        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
436    description = "compile {{source}}"
437  }
438
439  tool("cxx") {
440    precompiled_header_type = "msvc"
441    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
442    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"
443    depsformat = "msvc"
444    outputs =
445        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
446    description = "compile {{source}}"
447  }
448
449  tool("alink") {
450    rspfile = "{{output}}.rsp"
451    command = "$linker /lib /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile"
452    outputs = [
453      # Ignore {{output_extension}} and always use .lib, there's no reason to
454      # allow targets to override this extension on Windows.
455      "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
456    ]
457    default_output_extension = ".lib"
458    default_output_dir = "{{target_out_dir}}"
459
460    # inputs_newline works around a fixed per-line buffer size in the linker.
461    rspfile_content = "{{inputs_newline}}"
462    description = "link {{output}}"
463  }
464
465  tool("solink") {
466    dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
467    libname = "${dllname}.lib"
468    pdbname = "${dllname}.pdb"
469    rspfile = "${dllname}.rsp"
470
471    command = "$linker /nologo /IMPLIB:$libname ${sys_lib_flags} /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
472    outputs = [
473      dllname,
474      libname,
475      pdbname,
476    ]
477    default_output_extension = ".dll"
478    default_output_dir = "{{root_out_dir}}"
479
480    link_output = libname
481    depend_output = libname
482    runtime_outputs = [
483      dllname,
484      pdbname,
485    ]
486
487    # Since the above commands only updates the .lib file when it changes, ask
488    # Ninja to check if the timestamp actually changed to know if downstream
489    # dependencies should be recompiled.
490    restat = true
491
492    # inputs_newline works around a fixed per-line buffer size in the linker.
493    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
494    description = "link {{output}}"
495  }
496
497  tool("link") {
498    exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
499    pdbname = "$exename.pdb"
500    rspfile = "$exename.rsp"
501
502    command = "$linker /nologo /guard:cf /DYNAMICBASE /OUT:$exename ${sys_lib_flags} /DEBUG /PDB:$pdbname @$rspfile"
503    default_output_extension = ".exe"
504    default_output_dir = "{{root_out_dir}}"
505    outputs = [ exename ]
506
507    # inputs_newline works around a fixed per-line buffer size in the linker.
508    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
509    description = "link {{output}}"
510  }
511
512  tool("stamp") {
513    command = "cmd /c type nul > \"{{output}}\""
514    description = "stamp {{output}}"
515  }
516
517  tool("copy") {
518    cp_py = rebase_path("../cp.py")
519    command = "cmd.exe /c python \"$cp_py\" {{source}} {{output}}"
520    description = "copy {{source}} {{output}}"
521  }
522}
523