1if (is_fuchsia) {
2  import("//build/fuchsia/sdk.gni")
3}
4
5declare_args() {
6  host_ar = ar
7  host_cc = cc
8  host_cxx = cxx
9
10  if (is_android) {
11    _prefix = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin"
12    if (host_os == "win") {
13      target_ar = "$_prefix/llvm-ar.exe"
14      target_cc = "$_prefix/clang.exe --target=$ndk_target$ndk_api -fno-addrsig"
15      target_cxx =
16          "$_prefix/clang++.exe --target=$ndk_target$ndk_api -fno-addrsig"
17    } else {
18      target_ar = "$_prefix/llvm-ar"
19      target_cc = "$_prefix/$ndk_target$ndk_api-clang"
20      target_cxx = "$_prefix/$ndk_target$ndk_api-clang++"
21    }
22  } else if (is_fuchsia && using_fuchsia_sdk) {
23    target_ar = rebase_path("$fuchsia_toolchain_path/bin/llvm-ar")
24    target_cc = rebase_path("$fuchsia_toolchain_path/bin/clang")
25    target_cxx = rebase_path("$fuchsia_toolchain_path/bin/clang++")
26    cflags = "--sysroot=" +
27             rebase_path("$fuchsia_toolchain_path/$target_cpu/sysroot")
28    link = rebase_path("$fuchsia_toolchain_path/bin/ld.lld")
29  } else {
30    target_ar = ar
31    target_cc = cc
32    target_cxx = cxx
33  }
34
35  cc_wrapper = ""
36
37  # dsymutil seems to kill the machine when too many processes are run in
38  # parallel, so we need to use a pool to limit the concurrency when passing
39  # large -j to Ninja (e.g. Goma build). Unfortunately this is also one of the
40  # slowest steps in a build, so we don't want to limit too much. Use the number
41  # of CPUs as a default.
42  dlsymutil_pool_depth = exec_script("num_cpus.py", [], "value")
43
44  # Too many linkers running at once causes issues for some builders. Allow
45  # such builders to limit the number of concurrent link steps.
46  # link_pool_depth < 0 means no pool, 0 means cpu count, > 0 sets pool size.
47  link_pool_depth = -1
48}
49
50declare_args() {
51  host_link = host_cxx
52  target_link = target_cxx
53}
54
55# For 'shell' see https://ninja-build.org/manual.html#ref_rule_command
56if (host_os == "win") {
57  shell = "cmd.exe /c "
58  stamp = "$shell echo >"
59} else {
60  shell = ""
61  stamp = "touch"
62}
63
64if (current_toolchain == default_toolchain) {
65  pool("dsymutil_pool") {
66    depth = dlsymutil_pool_depth
67  }
68  if (0 <= link_pool_depth) {
69    pool("link_pool") {
70      if (link_pool_depth == 0) {
71        depth = exec_script("num_cpus.py", [], "value")
72      } else {
73        depth = link_pool_depth
74      }
75    }
76  }
77}
78
79toolchain("msvc") {
80  lib_switch = ""
81  lib_dir_switch = "/LIBPATH:"
82
83  bin = "$win_vc/Tools/MSVC/$win_toolchain_version/bin/HostX64/$target_cpu"
84
85  env_setup = ""
86  if (target_cpu == "x86") {
87    # Toolchain asset includes a script that configures for x86 building.
88    # We don't support x86 builds with local MSVC installations.
89    env_setup = "$shell $win_sdk/bin/SetEnv.cmd /x86 && "
90  } else if (target_cpu == "arm64") {
91    # ARM64 compiler is incomplete - it relies on DLLs located in the host toolchain directory.
92    env_setup = "$shell set \"PATH=%PATH%;$win_vc\\Tools\\MSVC\\$win_toolchain_version\\bin\\HostX64\\x64\" && "
93  }
94
95  cl_m32_flag = ""
96
97  if (clang_win != "") {
98    if (target_cpu == "x86") {
99      # cl.exe knows implicitly by the choice of executable that it's targeting
100      # x86, but clang-cl.exe needs to be told when targeting non-host
101      # platforms. (All our builders are x86-64, so x86 is always non-host.)
102      cl_m32_flag = "-m32"
103    }
104    if (host_os == "win") {
105      cl = "\"$clang_win/bin/clang-cl.exe\""
106      lib = "\"$clang_win/bin/lld-link.exe\" /lib"
107      link = "\"$clang_win/bin/lld-link.exe\""
108    } else {
109      cl = "\"$clang_win/bin/clang-cl\""
110      lib = "\"$clang_win/bin/lld-link\" /lib"
111      link = "\"$clang_win/bin/lld-link\""
112    }
113  } else {
114    cl = "\"$bin/cl.exe\""
115    lib = "\"$bin/lib.exe\""
116    link = "\"$bin/link.exe\""
117  }
118
119  tool("asm") {
120    _ml = "ml"
121    if (target_cpu == "x64") {
122      _ml += "64"
123    }
124    command = "$env_setup \"$bin/$_ml.exe\" {{asmflags}} /nologo /c /Fo {{output}} {{source}}"
125    outputs =
126        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
127    description = "assemble {{source}}"
128  }
129
130  tool("cc") {
131    precompiled_header_type = "msvc"
132    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
133
134    # Label names may have spaces so pdbname must be quoted.
135    command = "$env_setup $cc_wrapper $cl /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} $cl_m32_flag {{cflags_c}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
136    depsformat = "msvc"
137    outputs =
138        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
139    description = "compile {{source}}"
140  }
141
142  tool("cxx") {
143    precompiled_header_type = "msvc"
144    pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
145
146    # Label names may have spaces so pdbname must be quoted.
147    command = "$env_setup $cc_wrapper $cl /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} $cl_m32_flag {{cflags_cc}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
148    depsformat = "msvc"
149    outputs =
150        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
151    description = "compile {{source}}"
152  }
153
154  tool("alink") {
155    rspfile = "{{output}}.rsp"
156
157    command = "$env_setup $lib /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile"
158    outputs = [
159      # Ignore {{output_extension}} and always use .lib, there's no reason to
160      # allow targets to override this extension on Windows.
161      "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
162    ]
163    default_output_extension = ".lib"
164    default_output_dir = "{{target_out_dir}}"
165
166    # inputs_newline works around a fixed per-line buffer size in the linker.
167    rspfile_content = "{{inputs_newline}}"
168    description = "link {{output}}"
169    if (0 <= link_pool_depth) {
170      pool = ":link_pool($default_toolchain)"
171    }
172  }
173
174  tool("solink") {
175    dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
176    libname = "${dllname}.lib"
177    pdbname = "${dllname}.pdb"
178    rspfile = "${dllname}.rsp"
179
180    command = "$env_setup $link /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
181    outputs = [
182      dllname,
183      libname,
184      pdbname,
185    ]
186    default_output_extension = ".dll"
187    default_output_dir = "{{root_out_dir}}"
188
189    link_output = libname
190    depend_output = libname
191    runtime_outputs = [
192      dllname,
193      pdbname,
194    ]
195
196    # I don't quite understand this.  Aping Chrome's toolchain/win/BUILD.gn.
197    restat = true
198
199    # inputs_newline works around a fixed per-line buffer size in the linker.
200    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
201    description = "link {{output}}"
202    if (0 <= link_pool_depth) {
203      pool = ":link_pool($default_toolchain)"
204    }
205  }
206
207  tool("link") {
208    exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
209    pdbname = "$exename.pdb"
210    rspfile = "$exename.rsp"
211
212    command = "$env_setup $link /nologo /OUT:$exename /PDB:$pdbname @$rspfile"
213    default_output_extension = ".exe"
214    default_output_dir = "{{root_out_dir}}"
215    outputs = [ exename ]
216
217    # inputs_newline works around a fixed per-line buffer size in the linker.
218    rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
219    description = "link {{output}}"
220    if (0 <= link_pool_depth) {
221      pool = ":link_pool($default_toolchain)"
222    }
223  }
224
225  tool("stamp") {
226    command = "$stamp {{output}}"
227    description = "stamp {{output}}"
228  }
229
230  tool("copy") {
231    cp_py = rebase_path("../cp.py")
232    command = "$shell python \"$cp_py\" {{source}} {{output}}"
233    description = "copy {{source}} {{output}}"
234  }
235}
236
237template("gcc_like_toolchain") {
238  toolchain(target_name) {
239    ar = invoker.ar
240    cc = invoker.cc
241    cxx = invoker.cxx
242    link = invoker.link
243    lib_switch = "-l"
244    lib_dir_switch = "-L"
245
246    tool("cc") {
247      depfile = "{{output}}.d"
248      command = "$cc_wrapper $cc -MD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
249      depsformat = "gcc"
250      outputs =
251          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
252      description = "compile {{source}}"
253    }
254
255    tool("cxx") {
256      depfile = "{{output}}.d"
257      command = "$cc_wrapper $cxx -MD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
258      depsformat = "gcc"
259      outputs =
260          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
261      description = "compile {{source}}"
262    }
263
264    tool("objc") {
265      depfile = "{{output}}.d"
266      command = "$cc_wrapper $cc -MD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
267      depsformat = "gcc"
268      outputs =
269          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
270      description = "compile {{source}}"
271    }
272
273    tool("objcxx") {
274      depfile = "{{output}}.d"
275      command = "$cc_wrapper $cxx -MD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objcc}} -c {{source}} -o {{output}}"
276      depsformat = "gcc"
277      outputs =
278          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
279      description = "compile {{source}}"
280    }
281
282    tool("asm") {
283      depfile = "{{output}}.d"
284      command = "$cc_wrapper $cc -MD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
285      depsformat = "gcc"
286      outputs =
287          [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
288      description = "assemble {{source}}"
289    }
290
291    if (is_mac || is_ios) {
292      not_needed([ "ar" ])  # We use libtool instead.
293    }
294
295    tool("alink") {
296      if (is_mac || is_ios) {
297        command = "libtool -static -o {{output}} -no_warning_for_no_symbols {{inputs}}"
298      } else {
299        rspfile = "{{output}}.rsp"
300        rspfile_content = "{{inputs}}"
301        rm_py = rebase_path("../rm.py")
302        command = "$shell python \"$rm_py\" \"{{output}}\" && $ar rcs {{output}} @$rspfile"
303      }
304
305      outputs =
306          [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ]
307      default_output_extension = ".a"
308      output_prefix = "lib"
309      description = "link {{output}}"
310      if (0 <= link_pool_depth) {
311        pool = ":link_pool($default_toolchain)"
312      }
313    }
314
315    tool("solink") {
316      soname = "{{target_output_name}}{{output_extension}}"
317
318      rpath = "-Wl,-soname,$soname"
319      if (is_mac || is_ios) {
320        rpath = "-Wl,-install_name,@rpath/$soname"
321      }
322
323      rspfile = "{{output}}.rsp"
324      rspfile_content = "{{inputs}}"
325
326      # --start-group/--end-group let us link multiple .a {{inputs}}
327      # without worrying about their relative order on the link line.
328      #
329      # This is mostly important for traditional linkers like GNU ld and Gold.
330      # The Mac/iOS linker neither needs nor accepts these flags.
331      # LLD doesn't need these flags, but accepts and ignores them.
332      _start_group = "-Wl,--start-group"
333      _end_group = "-Wl,--end-group"
334      if (is_mac || is_ios || is_fuchsia) {
335        _start_group = ""
336        _end_group = ""
337      }
338
339      command = "$link -shared {{ldflags}} $_start_group @$rspfile {{frameworks}} {{solibs}} $_end_group {{libs}} $rpath -o {{output}}"
340      outputs = [ "{{root_out_dir}}/$soname" ]
341      output_prefix = "lib"
342      default_output_extension = ".so"
343      description = "link {{output}}"
344      if (0 <= link_pool_depth) {
345        pool = ":link_pool($default_toolchain)"
346      }
347    }
348
349    tool("link") {
350      exe_name = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
351      rspfile = "$exe_name.rsp"
352      rspfile_content = "{{inputs}}"
353
354      # --start-group/--end-group let us link multiple .a {{inputs}}
355      # without worrying about their relative order on the link line.
356      #
357      # This is mostly important for traditional linkers like GNU ld and Gold.
358      # The Mac/iOS linker neither needs nor accepts these flags.
359      # LLD doesn't need these flags, but accepts and ignores them.
360      _start_group = "-Wl,--start-group"
361      _end_group = "-Wl,--end-group"
362      if (is_mac || is_ios || is_fuchsia) {
363        _start_group = ""
364        _end_group = ""
365      }
366      command = "$link {{ldflags}} $_start_group @$rspfile {{frameworks}} {{solibs}} $_end_group {{libs}} -o $exe_name"
367
368      outputs = [ "$exe_name" ]
369      description = "link {{output}}"
370      if (0 <= link_pool_depth) {
371        pool = ":link_pool($default_toolchain)"
372      }
373    }
374
375    tool("stamp") {
376      command = "$stamp {{output}}"
377      description = "stamp {{output}}"
378    }
379
380    tool("copy") {
381      cp_py = rebase_path("../cp.py")
382      command = "python \"$cp_py\" {{source}} {{output}}"
383      description = "copy {{source}} {{output}}"
384    }
385
386    tool("copy_bundle_data") {
387      cp_py = rebase_path("../cp.py")
388      command = "python \"$cp_py\" {{source}} {{output}}"
389      description = "copy_bundle_data {{source}} {{output}}"
390    }
391
392    # We don't currently have any xcasset files so make this a NOP
393    tool("compile_xcassets") {
394      command = "true"
395      description = "compile_xcassets {{output}}"
396    }
397
398    toolchain_args = {
399      current_cpu = invoker.cpu
400      current_os = invoker.os
401    }
402  }
403}
404
405gcc_like_toolchain("gcc_like") {
406  cpu = current_cpu
407  os = current_os
408  ar = target_ar
409  cc = target_cc
410  cxx = target_cxx
411  link = target_link
412}
413
414gcc_like_toolchain("gcc_like_host") {
415  cpu = host_cpu
416  os = host_os
417  ar = host_ar
418  cc = host_cc
419  cxx = host_cxx
420  link = host_link
421}
422