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