• 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
52declare_args() {
53  sysroot = ""
54  gcc_toolchain = ""
55  ar = "ar"
56  linker = ""
57
58  if (is_linux_host) {
59    linker = "gold"
60  }
61
62  if (is_clang) {
63    if (is_linux_host && !is_system_compiler) {
64      cc = linux_clang_bin
65      cxx = linux_clangxx_bin
66      linker = linux_clang_linker
67    } else if (is_win_host && !is_system_compiler) {
68      cc = win_clang_bin
69      cxx = win_clangxx_bin
70      linker = win_clang_linker
71    } else {
72      cc = "clang"
73      cxx = "clang++"
74      linker = ""
75    }
76  } else if (is_win) {  # MSVC
77    cc = "${win_msvc_bin_dir}\\cl.exe"
78    cxx = "${win_msvc_bin_dir}\\cl.exe"
79    linker = "${win_msvc_bin_dir}\\link.exe"
80  } else {  # GCC
81    cc = "gcc"
82    cxx = "g++"
83  }
84}
85
86# Then determine the target toolchain.
87
88declare_args() {
89  target_sysroot = sysroot
90  target_gcc_toolchain = ""
91
92  # |target_triplet| is the variable that the user can set via GN args. The user
93  # doesn't have to necessarily set it though. In most cases we can infer it
94  # by looking at target_os and target_cpu.
95  # |_target_triplet| is the final argument passed to the toolchain.
96  if (target_triplet != "") {
97    assert(is_cross_compiling)
98
99    # If the user provides the target_triplet in gn args, respect that.
100    # Otherwise guess it looking at the target os and cpu variables.
101    _target_triplet = target_triplet
102  } else if (!is_cross_compiling) {
103    _target_triplet = ""
104  } else if (target_os == "mac" && target_cpu == "x64") {
105    _target_triplet = "x86_64-apple-darwin"
106  } else if (target_os == "mac" && target_cpu == "x86") {
107    _target_triplet = "i686-apple-darwin"
108  } else if (target_os == "linux" && target_cpu == "arm64") {
109    _target_triplet = "aarch64-linux-gnu"
110  } else if (target_os == "linux" && target_cpu == "arm") {
111    _target_triplet = "arm-linux-gnueabi"
112  } else if (target_os == "linux" && target_cpu == "x64") {
113    _target_triplet = "x86_64-linux-gnu"
114  } else if (target_os == "linux" && target_cpu == "x86") {
115    _target_triplet = "i686-linux-gnu"
116  } else if (target_os == "android" && target_cpu == "arm64") {
117    _target_triplet = "aarch64-linux-android"
118  } else if (target_os == "android" && target_cpu == "arm") {
119    _target_triplet = "arm-linux-androideabi"
120  } else if (target_os == "android" && target_cpu == "x86") {
121    _target_triplet = "i686-linux-android"
122  } else if (target_os == "android" && target_cpu == "x64") {
123    _target_triplet = "x86_64-linux-android"
124  } else {
125    assert(
126        false,
127        "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")
128  }
129}
130
131declare_args() {
132  if (is_linux || is_android) {
133    target_linker = "gold"
134  } else {
135    target_linker = ""
136  }
137
138  if (!is_cross_compiling || is_perfetto_build_generator ||
139      is_system_compiler) {
140    target_ar = ar
141    target_cc = cc
142    target_cxx = cxx
143    target_linker = linker
144  } else {
145    target_ar = "ar"
146    if (is_android) {
147      target_ar = "$android_toolchain_root/bin/$android_abi_target-ar"
148      target_cc = "$android_llvm_dir/bin/clang"
149      target_cxx = "$android_llvm_dir/bin/clang++"
150      target_linker = "$android_llvm_dir/bin/ld.lld"
151    } else {
152      assert(_target_triplet != "",
153             "target_triplet must be non-empty when cross-compiling")
154      if (is_clang) {
155        if (is_linux_host) {
156          target_cc = "${linux_clang_bin} --target=${_target_triplet}"
157          target_cxx = "${linux_clangxx_bin} --target=${_target_triplet}"
158          target_linker = "${linux_clang_linker} --target=${_target_triplet}"
159        } else {
160          target_cc = "clang --target=${_target_triplet}"
161          target_cxx = "clang++ --target=${_target_triplet}"
162        }
163      } else {  # GCC
164        target_ar = "${_target_triplet}-ar"
165        target_cc = "${_target_triplet}-gcc"
166        target_cxx = "${_target_triplet}-g++"
167      }
168    }
169  }
170}
171
172template("gcc_like_toolchain") {
173  toolchain(target_name) {
174    ar = invoker.ar
175    cc = invoker.cc
176    cxx = invoker.cxx
177    lib_switch = "-l"
178    lib_dir_switch = "-L"
179    ld_arg = ""
180    external_cflags = ""
181    external_cxxflags = ""
182    external_ldflags = ""
183    if (defined(invoker.linker) && invoker.linker != "") {
184      _invoker_linker = invoker.linker
185      ld_arg = "-fuse-ld=$_invoker_linker"
186    }
187    if (defined(invoker.sysroot) && invoker.sysroot != "") {
188      _invoker_sysroot = invoker.sysroot
189      cc = "$cc --sysroot=$_invoker_sysroot"
190      cxx = "$cxx --sysroot=$_invoker_sysroot"
191    }
192    if (defined(invoker.gcc_toolchain) && invoker.gcc_toolchain != "") {
193      assert(is_clang, "gcc_toolchain can be used only when using clang")
194      _invoker_gcc_toolchain = invoker.gcc_toolchain
195      ld_arg = "$ld_arg --gcc-toolchain=$_invoker_gcc_toolchain"
196    }
197    if (defined(invoker.external_cflags)) {
198      external_cflags = invoker.external_cflags
199    }
200    if (defined(invoker.external_cxxflags)) {
201      external_cxxflags = invoker.external_cxxflags
202    }
203    if (defined(invoker.external_ldflags)) {
204      external_ldflags = invoker.external_ldflags
205    }
206
207    tool("cc") {
208      depfile = "{{output}}.d"
209      command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} -c {{source}} -o {{output}}"
210      depsformat = "gcc"
211      outputs =
212          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
213      description = "compile {{source}}"
214    }
215
216    tool("cxx") {
217      depfile = "{{output}}.d"
218      command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}  ${external_cflags} ${external_cxxflags} -c {{source}} -o {{output}}"
219      depsformat = "gcc"
220      outputs =
221          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
222      description = "compile {{source}}"
223    }
224
225    tool("asm") {
226      depfile = "{{output}}.d"
227      command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
228      depsformat = "gcc"
229      outputs =
230          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
231      description = "assemble {{source}}"
232    }
233
234    tool("alink") {
235      rspfile = "{{output}}.rsp"
236      if (is_mac && ar != "suppress_unused_ar_variable_warning") {
237        rspfile_content = "{{inputs_newline}}"
238        command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile"
239      } else {
240        rspfile_content = "{{inputs}}"
241        command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile"
242      }
243      outputs =
244          [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ]
245      default_output_extension = ".a"
246      output_prefix = "lib"
247      description = "link {{output}}"
248    }
249
250    tool("solink") {
251      soname = "{{target_output_name}}{{output_extension}}"
252
253      rpath = "-Wl,-soname,$soname"
254      if (is_mac) {
255        rpath = "-Wl,-install_name,@rpath/$soname"
256      }
257
258      command = "$cc_wrapper $cxx $ld_arg -shared {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} $rpath -o {{output}}"
259      outputs = [ "{{root_out_dir}}/$soname" ]
260      output_prefix = "lib"
261      default_output_extension = ".so"
262      description = "link {{output}}"
263    }
264
265    tool("link") {
266      command = "$cc_wrapper $cxx $ld_arg {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} -o {{output}}"
267      outputs =
268          [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ]
269      description = "link {{output}}"
270    }
271
272    tool("stamp") {
273      command = "touch {{output}}"
274      description = "stamp {{output}}"
275    }
276
277    tool("copy") {
278      command = "cp -af {{source}} {{output}}"
279      description = "COPY {{source}} {{output}}"
280    }
281
282    toolchain_args = {
283      current_cpu = invoker.cpu
284      current_os = invoker.os
285    }
286  }
287}
288
289gcc_like_toolchain("gcc_like") {
290  cpu = current_cpu
291  os = current_os
292  ar = target_ar
293  cc = target_cc
294  cxx = target_cxx
295  linker = target_linker
296  sysroot = target_sysroot
297  gcc_toolchain = target_gcc_toolchain
298  external_cflags = string_join(" ",
299                                [
300                                  extra_cflags,
301                                  extra_target_cflags,
302                                ])
303  external_cxxflags = string_join(" ",
304                                  [
305                                    extra_cxxflags,
306                                    extra_target_cxxflags,
307                                  ])
308  external_ldflags = string_join(" ",
309                                 [
310                                   extra_ldflags,
311                                   extra_target_ldflags,
312                                 ])
313}
314
315gcc_like_toolchain("gcc_like_host") {
316  cpu = host_cpu
317  os = host_os
318  ar = ar
319  cc = cc
320  cxx = cxx
321  linker = linker
322  sysroot = sysroot
323  gcc_toolchain = gcc_toolchain
324  external_cflags = string_join(" ",
325                                [
326                                  extra_cflags,
327                                  extra_host_cflags,
328                                ])
329  external_cxxflags = string_join(" ",
330                                  [
331                                    extra_cxxflags,
332                                    extra_host_cxxflags,
333                                  ])
334  external_ldflags = string_join(" ",
335                                 [
336                                   extra_ldflags,
337                                   extra_host_ldflags,
338                                 ])
339}
340
341gcc_like_toolchain("wasm") {
342  # emsdk_dir and em_config are defined in wasm.gni.
343  cpu = host_cpu
344  os = host_os
345  ar = "$emsdk_dir/emscripten/emar --em-config $em_config"
346  cc = "$emsdk_dir/emscripten/emcc --em-config $em_config"
347  cxx = "$emsdk_dir/emscripten/em++ --em-config $em_config"
348}
349
350# This is used both for MSVC anc clang-cl. clang-cl cmdline interface pretends
351# to be MSVC's cl.exe.
352toolchain("msvc") {
353  lib_switch = ""
354  lib_dir_switch = "/LIBPATH:"
355
356  sys_lib_flags = "/LIBPATH:\"${win_sdk_lib_dir}\\ucrt\\x64\" "
357  sys_lib_flags += "/LIBPATH:\"${win_sdk_lib_dir}\\um\\x64\" "
358  sys_lib_flags += "/LIBPATH:\"${win_msvc_lib_dir}\" "
359
360  # Note: /showIncludes below is required for ninja, to build a complete
361  # dependency graph for headers. Removing it breaks incremental builds.
362
363  tool("cc") {
364    precompiled_header_type = "msvc"
365    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
366    command = "$cc_wrapper $cc /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
367    depsformat = "msvc"
368    outputs =
369        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
370    description = "compile {{source}}"
371  }
372
373  tool("cxx") {
374    precompiled_header_type = "msvc"
375    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
376    command = "$cc_wrapper $cxx /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
377    depsformat = "msvc"
378    outputs =
379        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
380    description = "compile {{source}}"
381  }
382
383  tool("alink") {
384    rspfile = "{{output}}.rsp"
385    command = "$linker /lib /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile"
386    outputs = [
387      # Ignore {{output_extension}} and always use .lib, there's no reason to
388      # allow targets to override this extension on Windows.
389      "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
390    ]
391    default_output_extension = ".lib"
392    default_output_dir = "{{target_out_dir}}"
393
394    # inputs_newline works around a fixed per-line buffer size in the linker.
395    rspfile_content = "{{inputs_newline}}"
396    description = "link {{output}}"
397  }
398
399  tool("solink") {
400    dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
401    libname = "${dllname}.lib"
402    pdbname = "${dllname}.pdb"
403    rspfile = "${dllname}.rsp"
404
405    command = "$linker /nologo /IMPLIB:$libname ${sys_lib_flags} /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
406    outputs = [
407      dllname,
408      libname,
409      pdbname,
410    ]
411    default_output_extension = ".dll"
412    default_output_dir = "{{root_out_dir}}"
413
414    link_output = libname
415    depend_output = libname
416    runtime_outputs = [
417      dllname,
418      pdbname,
419    ]
420
421    # Since the above commands only updates the .lib file when it changes, ask
422    # Ninja to check if the timestamp actually changed to know if downstream
423    # dependencies should be recompiled.
424    restat = true
425
426    # inputs_newline works around a fixed per-line buffer size in the linker.
427    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
428    description = "link {{output}}"
429  }
430
431  tool("link") {
432    exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
433    pdbname = "$exename.pdb"
434    rspfile = "$exename.rsp"
435
436    command =
437        "$linker /nologo /OUT:$exename ${sys_lib_flags} /PDB:$pdbname @$rspfile"
438    default_output_extension = ".exe"
439    default_output_dir = "{{root_out_dir}}"
440    outputs = [ exename ]
441
442    # inputs_newline works around a fixed per-line buffer size in the linker.
443    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
444    description = "link {{output}}"
445  }
446
447  tool("stamp") {
448    command = "cmd /c type nul > \"{{output}}\""
449    description = "stamp {{output}}"
450  }
451
452  tool("copy") {
453    cp_py = rebase_path("../cp.py")
454    command = "cmd.exe /c python \"$cp_py\" {{source}} {{output}}"
455    description = "copy {{source}} {{output}}"
456  }
457}
458