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