Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame^] | 1 | # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | import("//build/config/nacl/config.gni") |
| 6 | import("//build/config/sanitizers/sanitizers.gni") |
| 7 | import("//build/toolchain/cc_wrapper.gni") |
| 8 | import("//build/toolchain/goma.gni") |
| 9 | import("//build/toolchain/toolchain.gni") |
| 10 | |
| 11 | # "concurrent_links" is a toolchain variable. By computing it here rather than |
| 12 | # inside the toolchain, the exec_script will only get run once rather than |
| 13 | # each time the toolchain template is invoked. |
| 14 | if (allow_posix_link_time_opt || is_cfi) { |
| 15 | concurrent_links_ = |
| 16 | exec_script("get_concurrent_links.py", [ "--lto" ], "value") |
| 17 | } else { |
| 18 | concurrent_links_ = exec_script("get_concurrent_links.py", [], "value") |
| 19 | } |
| 20 | |
| 21 | # This template defines a toolchain for something that works like gcc |
| 22 | # (including clang). |
| 23 | # |
| 24 | # It requires the following variables specifying the executables to run: |
| 25 | # - cc |
| 26 | # - cxx |
| 27 | # - ar |
| 28 | # - ld |
| 29 | # and the following which is used in the toolchain_args |
| 30 | # - toolchain_cpu (What "current_cpu" should be set to when invoking a |
| 31 | # build using this toolchain.) |
| 32 | # - toolchain_os (What "current_os" should be set to when invoking a |
| 33 | # build using this toolchain.) |
| 34 | # |
| 35 | # Optional parameters that control the tools: |
| 36 | # |
| 37 | # - libs_section_prefix |
| 38 | # - libs_section_postfix |
| 39 | # The contents of these strings, if specified, will be placed around |
| 40 | # the libs section of the linker line. It allows one to inject libraries |
| 41 | # at the beginning and end for all targets in a toolchain. |
| 42 | # - solink_libs_section_prefix |
| 43 | # - solink_libs_section_postfix |
| 44 | # Same as libs_section_{pre,post}fix except used for solink instead of link. |
| 45 | # - link_outputs |
| 46 | # The content of this array, if specified, will be added to the list of |
| 47 | # outputs from the link command. This can be useful in conjunction with |
| 48 | # the post_link parameter. |
| 49 | # - post_link |
| 50 | # The content of this string, if specified, will be run as a separate |
| 51 | # command following the the link command. |
| 52 | # - deps |
| 53 | # Just forwarded to the toolchain definition. |
| 54 | # - executable_extension |
| 55 | # If this string is specified it will be used for the file extension |
| 56 | # for an executable, rather than using no extension; targets will |
| 57 | # still be able to override the extension using the output_extension |
| 58 | # variable. |
| 59 | # - rebuild_define |
| 60 | # The contents of this string, if specified, will be passed as a #define |
| 61 | # to the toolchain. It can be used to force recompiles whenever a |
| 62 | # toolchain is updated. |
| 63 | # - shlib_extension |
| 64 | # If this string is specified it will be used for the file extension |
| 65 | # for a shared library, rather than default value specified in |
| 66 | # toolchain.gni |
| 67 | # - strip |
| 68 | # Location of the strip executable. When specified, strip will be run on |
| 69 | # all shared libraries and executables as they are built. The pre-stripped |
| 70 | # artifacts will be put in lib.unstripped/ and exe.unstripped/. |
| 71 | # |
| 72 | # Optional build argument contols. |
| 73 | # |
| 74 | # - clear_sanitizers |
| 75 | # When set to true, is_asan, is_msan, etc.will all be set to false. Often |
| 76 | # secondary toolchains do not want to run with sanitizers. |
| 77 | # - is_clang |
| 78 | # Whether to use clang instead of gcc. |
| 79 | # - is_component_build |
| 80 | # Whether to forcibly enable or disable component builds for this |
| 81 | # toolchain; if not specified, the toolchain will inherit the |
| 82 | # default setting. |
| 83 | # - is_nacl_glibc |
| 84 | # Whether NaCl code is built using Glibc instead of Newlib. |
| 85 | # - cc_wrapper |
| 86 | # Override the global cc_wrapper setting. e.g. "ccache" or "icecc". |
| 87 | # useful to opt-out of cc_wrapper in a particular toolchain by setting |
| 88 | # cc_wrapper = "" in it. |
| 89 | # - use_goma |
| 90 | # Override the global use_goma setting, useful to opt-out of goma in a |
| 91 | # particular toolchain by setting use_gome = false in it. |
| 92 | # - use_gold |
| 93 | # Override the global use_gold setting, useful if the particular |
| 94 | # toolchain has a custom link step that is not actually using Gold. |
| 95 | template("gcc_toolchain") { |
| 96 | toolchain(target_name) { |
| 97 | assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") |
| 98 | assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") |
| 99 | assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") |
| 100 | assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") |
| 101 | assert(defined(invoker.toolchain_cpu), |
| 102 | "gcc_toolchain() must specify a \"toolchain_cpu\"") |
| 103 | assert(defined(invoker.toolchain_os), |
| 104 | "gcc_toolchain() must specify a \"toolchain_os\"") |
| 105 | |
| 106 | concurrent_links = concurrent_links_ |
| 107 | |
| 108 | if (defined(invoker.cc_wrapper)) { |
| 109 | cc_wrapper = invoker.cc_wrapper |
| 110 | } |
| 111 | if (defined(invoker.use_goma)) { |
| 112 | use_goma = invoker.use_goma |
| 113 | } |
| 114 | if (use_goma) { |
| 115 | assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.") |
| 116 | compiler_prefix = "$goma_dir/gomacc " |
| 117 | } else if (cc_wrapper != "") { |
| 118 | compiler_prefix = cc_wrapper + " " |
| 119 | } else { |
| 120 | compiler_prefix = "" |
| 121 | } |
| 122 | |
| 123 | # This define changes when the toolchain changes, forcing a rebuild. |
| 124 | # Nothing should ever use this define. |
| 125 | if (defined(invoker.rebuild_define)) { |
| 126 | rebuild_string = "-D" + invoker.rebuild_define + " " |
| 127 | } else { |
| 128 | rebuild_string = "" |
| 129 | } |
| 130 | |
| 131 | cc = compiler_prefix + invoker.cc |
| 132 | cxx = compiler_prefix + invoker.cxx |
| 133 | ar = invoker.ar |
| 134 | ld = invoker.ld |
| 135 | if (defined(invoker.readelf)) { |
| 136 | readelf = invoker.readelf |
| 137 | } else { |
| 138 | readelf = "readelf" |
| 139 | } |
| 140 | if (defined(invoker.nm)) { |
| 141 | nm = invoker.nm |
| 142 | } else { |
| 143 | nm = "nm" |
| 144 | } |
| 145 | |
| 146 | if (defined(invoker.shlib_extension)) { |
| 147 | default_shlib_extension = invoker.shlib_extension |
| 148 | } else { |
| 149 | default_shlib_extension = shlib_extension |
| 150 | } |
| 151 | |
| 152 | if (defined(invoker.executable_extension)) { |
| 153 | default_executable_extension = invoker.executable_extension |
| 154 | } else { |
| 155 | default_executable_extension = "" |
| 156 | } |
| 157 | |
| 158 | # Bring these into our scope for string interpolation with default values. |
| 159 | if (defined(invoker.libs_section_prefix)) { |
| 160 | libs_section_prefix = invoker.libs_section_prefix |
| 161 | } else { |
| 162 | libs_section_prefix = "" |
| 163 | } |
| 164 | |
| 165 | if (defined(invoker.libs_section_postfix)) { |
| 166 | libs_section_postfix = invoker.libs_section_postfix |
| 167 | } else { |
| 168 | libs_section_postfix = "" |
| 169 | } |
| 170 | |
| 171 | if (defined(invoker.solink_libs_section_prefix)) { |
| 172 | solink_libs_section_prefix = invoker.solink_libs_section_prefix |
| 173 | } else { |
| 174 | solink_libs_section_prefix = "" |
| 175 | } |
| 176 | |
| 177 | if (defined(invoker.solink_libs_section_postfix)) { |
| 178 | solink_libs_section_postfix = invoker.solink_libs_section_postfix |
| 179 | } else { |
| 180 | solink_libs_section_postfix = "" |
| 181 | } |
| 182 | |
| 183 | # These library switches can apply to all tools below. |
| 184 | lib_switch = "-l" |
| 185 | lib_dir_switch = "-L" |
| 186 | |
| 187 | # Object files go in this directory. |
| 188 | object_subdir = "{{target_out_dir}}/{{label_name}}" |
| 189 | |
| 190 | tool("cc") { |
| 191 | depfile = "{{output}}.d" |
| 192 | command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" |
| 193 | depsformat = "gcc" |
| 194 | description = "CC {{output}}" |
| 195 | outputs = [ |
| 196 | "$object_subdir/{{source_name_part}}.o", |
| 197 | ] |
| 198 | } |
| 199 | |
| 200 | tool("cxx") { |
| 201 | depfile = "{{output}}.d" |
| 202 | command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" |
| 203 | depsformat = "gcc" |
| 204 | description = "CXX {{output}}" |
| 205 | outputs = [ |
| 206 | "$object_subdir/{{source_name_part}}.o", |
| 207 | ] |
| 208 | } |
| 209 | |
| 210 | tool("asm") { |
| 211 | # For GCC we can just use the C compiler to compile assembly. |
| 212 | depfile = "{{output}}.d" |
| 213 | command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" |
| 214 | depsformat = "gcc" |
| 215 | description = "ASM {{output}}" |
| 216 | outputs = [ |
| 217 | "$object_subdir/{{source_name_part}}.o", |
| 218 | ] |
| 219 | } |
| 220 | |
| 221 | tool("alink") { |
| 222 | rspfile = "{{output}}.rsp" |
| 223 | |
| 224 | # This needs a Python script to avoid using simple sh features in this |
| 225 | # command, in case the host does not use a POSIX shell (e.g. compiling |
| 226 | # POSIX-like toolchains such as NaCl on Windows). |
| 227 | ar_wrapper = |
| 228 | rebase_path("//build/toolchain/gcc_ar_wrapper.py", root_build_dir) |
| 229 | command = "$python_path \"$ar_wrapper\" --output={{output}} --ar=\"$ar\" {{arflags}} rcsD @\"$rspfile\"" |
| 230 | description = "AR {{output}}" |
| 231 | rspfile_content = "{{inputs}}" |
| 232 | outputs = [ |
| 233 | "{{output_dir}}/{{target_output_name}}{{output_extension}}", |
| 234 | ] |
| 235 | |
| 236 | # Shared libraries go in the target out directory by default so we can |
| 237 | # generate different targets with the same name and not have them collide. |
| 238 | default_output_dir = "{{target_out_dir}}" |
| 239 | default_output_extension = ".a" |
| 240 | output_prefix = "lib" |
| 241 | } |
| 242 | |
| 243 | tool("solink") { |
| 244 | soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". |
| 245 | sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir. |
| 246 | rspfile = sofile + ".rsp" |
| 247 | |
| 248 | if (defined(invoker.strip)) { |
| 249 | unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" |
| 250 | } else { |
| 251 | unstripped_sofile = sofile |
| 252 | } |
| 253 | |
| 254 | # These variables are not built into GN but are helpers that |
| 255 | # implement (1) linking to produce a .so, (2) extracting the symbols |
| 256 | # from that file (3) if the extracted list differs from the existing |
| 257 | # .TOC file, overwrite it, otherwise, don't change it. |
| 258 | tocfile = sofile + ".TOC" |
| 259 | |
| 260 | link_command = "$ld -shared {{ldflags}} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" |
| 261 | |
| 262 | assert(defined(readelf), "to solink you must have a readelf") |
| 263 | assert(defined(nm), "to solink you must have an nm") |
| 264 | strip_switch = "" |
| 265 | if (defined(invoker.strip)) { |
| 266 | strip_switch = "--strip=${invoker.strip}" |
| 267 | } |
| 268 | |
| 269 | # This needs a Python script to avoid using a complex shell command |
| 270 | # requiring sh control structures, pipelines, and POSIX utilities. |
| 271 | # The host might not have a POSIX shell and utilities (e.g. Windows). |
| 272 | solink_wrapper = rebase_path("//build/toolchain/gcc_solink_wrapper.py") |
| 273 | command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch --sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\" -- $link_command" |
| 274 | |
| 275 | rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" |
| 276 | |
| 277 | description = "SOLINK $sofile" |
| 278 | |
| 279 | # Use this for {{output_extension}} expansions unless a target manually |
| 280 | # overrides it (in which case {{output_extension}} will be what the target |
| 281 | # specifies). |
| 282 | default_output_extension = default_shlib_extension |
| 283 | |
| 284 | default_output_dir = "{{root_out_dir}}" |
| 285 | if (shlib_subdir != ".") { |
| 286 | default_output_dir += "/$shlib_subdir" |
| 287 | } |
| 288 | |
| 289 | output_prefix = "lib" |
| 290 | |
| 291 | # Since the above commands only updates the .TOC file when it changes, ask |
| 292 | # Ninja to check if the timestamp actually changed to know if downstream |
| 293 | # dependencies should be recompiled. |
| 294 | restat = true |
| 295 | |
| 296 | # Tell GN about the output files. It will link to the sofile but use the |
| 297 | # tocfile for dependency management. |
| 298 | outputs = [ |
| 299 | sofile, |
| 300 | tocfile, |
| 301 | ] |
| 302 | if (sofile != unstripped_sofile) { |
| 303 | outputs += [ unstripped_sofile ] |
| 304 | } |
| 305 | link_output = sofile |
| 306 | depend_output = tocfile |
| 307 | } |
| 308 | |
| 309 | tool("solink_module") { |
| 310 | soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". |
| 311 | sofile = "{{output_dir}}/$soname" |
| 312 | rspfile = sofile + ".rsp" |
| 313 | |
| 314 | if (defined(invoker.strip)) { |
| 315 | unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" |
| 316 | } else { |
| 317 | unstripped_sofile = sofile |
| 318 | } |
| 319 | |
| 320 | command = "$ld -shared {{ldflags}} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" |
| 321 | |
| 322 | if (defined(invoker.strip)) { |
| 323 | strip_command = "${invoker.strip} --strip-unneeded -o \"$sofile\" \"$unstripped_sofile\"" |
| 324 | command += " && " + strip_command |
| 325 | } |
| 326 | rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" |
| 327 | |
| 328 | description = "SOLINK_MODULE $sofile" |
| 329 | |
| 330 | # Use this for {{output_extension}} expansions unless a target manually |
| 331 | # overrides it (in which case {{output_extension}} will be what the target |
| 332 | # specifies). |
| 333 | if (defined(invoker.loadable_module_extension)) { |
| 334 | default_output_extension = invoker.loadable_module_extension |
| 335 | } else { |
| 336 | default_output_extension = default_shlib_extension |
| 337 | } |
| 338 | |
| 339 | default_output_dir = "{{root_out_dir}}" |
| 340 | if (shlib_subdir != ".") { |
| 341 | default_output_dir += "/$shlib_subdir" |
| 342 | } |
| 343 | |
| 344 | output_prefix = "lib" |
| 345 | |
| 346 | outputs = [ |
| 347 | sofile, |
| 348 | ] |
| 349 | if (sofile != unstripped_sofile) { |
| 350 | outputs += [ unstripped_sofile ] |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | tool("link") { |
| 355 | exename = "{{target_output_name}}{{output_extension}}" |
| 356 | outfile = "{{output_dir}}/$exename" |
| 357 | rspfile = "$outfile.rsp" |
| 358 | unstripped_outfile = outfile |
| 359 | |
| 360 | # Use this for {{output_extension}} expansions unless a target manually |
| 361 | # overrides it (in which case {{output_extension}} will be what the target |
| 362 | # specifies). |
| 363 | default_output_extension = default_executable_extension |
| 364 | |
| 365 | default_output_dir = "{{root_out_dir}}" |
| 366 | |
| 367 | if (defined(invoker.strip)) { |
| 368 | unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" |
| 369 | } |
| 370 | |
| 371 | command = "$ld {{ldflags}} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" |
| 372 | if (defined(invoker.strip)) { |
| 373 | link_wrapper = |
| 374 | rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir) |
| 375 | command = "$python_path \"$link_wrapper\" --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\" --output=\"$outfile\" -- $command" |
| 376 | } |
| 377 | description = "LINK $outfile" |
| 378 | rspfile_content = "{{inputs}}" |
| 379 | outputs = [ |
| 380 | outfile, |
| 381 | ] |
| 382 | if (outfile != unstripped_outfile) { |
| 383 | outputs += [ unstripped_outfile ] |
| 384 | } |
| 385 | if (defined(invoker.link_outputs)) { |
| 386 | outputs += invoker.link_outputs |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | # These two are really entirely generic, but have to be repeated in |
| 391 | # each toolchain because GN doesn't allow a template to be used here. |
| 392 | # See //build/toolchain/toolchain.gni for details. |
| 393 | tool("stamp") { |
| 394 | command = stamp_command |
| 395 | description = stamp_description |
| 396 | } |
| 397 | tool("copy") { |
| 398 | command = copy_command |
| 399 | description = copy_description |
| 400 | } |
| 401 | |
| 402 | # When invoking this toolchain not as the default one, these args will be |
| 403 | # passed to the build. They are ignored when this is the default toolchain. |
| 404 | toolchain_args() { |
| 405 | current_cpu = invoker.toolchain_cpu |
| 406 | current_os = invoker.toolchain_os |
| 407 | |
| 408 | # These values need to be passed through unchanged. |
| 409 | host_toolchain = host_toolchain |
| 410 | target_os = target_os |
| 411 | target_cpu = target_cpu |
| 412 | |
| 413 | if (defined(invoker.is_clang)) { |
| 414 | is_clang = invoker.is_clang |
| 415 | } |
| 416 | if (defined(invoker.is_component_build)) { |
| 417 | is_component_build = invoker.is_component_build |
| 418 | } |
| 419 | if (defined(invoker.is_nacl_glibc)) { |
| 420 | is_nacl_glibc = invoker.is_nacl_glibc |
| 421 | } |
| 422 | if (defined(invoker.symbol_level)) { |
| 423 | symbol_level = invoker.symbol_level |
| 424 | } |
| 425 | if (defined(invoker.use_allocator)) { |
| 426 | use_allocator = invoker.use_allocator |
| 427 | } |
| 428 | if (defined(invoker.use_gold)) { |
| 429 | use_gold = invoker.use_gold |
| 430 | } |
| 431 | |
| 432 | if (defined(invoker.clear_sanitizers) && invoker.clear_sanitizers) { |
| 433 | is_asan = false |
| 434 | is_cfi = false |
| 435 | is_lsan = false |
| 436 | is_msan = false |
| 437 | is_syzyasan = false |
| 438 | is_tsan = false |
| 439 | is_ubsan = false |
| 440 | is_ubsan_vptr = false |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | forward_variables_from(invoker, [ "deps" ]) |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | # This is a shorthand for gcc_toolchain instances based on the |
| 449 | # Chromium-built version of Clang. Only the toolchain_cpu and |
| 450 | # toolchain_os variables need to be specified by the invoker, and |
| 451 | # optionally toolprefix if it's a cross-compile case. Note that for |
| 452 | # a cross-compile case this toolchain requires a config to pass the |
| 453 | # appropriate -target option, or else it will actually just be doing |
| 454 | # a native compile. The invoker can optionally override use_gold too. |
| 455 | template("clang_toolchain") { |
| 456 | assert(defined(invoker.toolchain_cpu), |
| 457 | "clang_toolchain() must specify a \"toolchain_cpu\"") |
| 458 | assert(defined(invoker.toolchain_os), |
| 459 | "clang_toolchain() must specify a \"toolchain_os\"") |
| 460 | if (defined(invoker.toolprefix)) { |
| 461 | toolprefix = invoker.toolprefix |
| 462 | } else { |
| 463 | toolprefix = "" |
| 464 | } |
| 465 | |
| 466 | gcc_toolchain(target_name) { |
| 467 | prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", |
| 468 | root_build_dir) |
| 469 | cc = "$prefix/clang" |
| 470 | cxx = "$prefix/clang++" |
| 471 | ld = cxx |
| 472 | is_clang = true |
| 473 | |
| 474 | readelf = "${toolprefix}readelf" |
| 475 | ar = "${toolprefix}ar" |
| 476 | nm = "${toolprefix}nm" |
| 477 | |
| 478 | forward_variables_from(invoker, |
| 479 | [ |
| 480 | "toolchain_cpu", |
| 481 | "toolchain_os", |
| 482 | "use_gold", |
| 483 | "strip", |
| 484 | ]) |
| 485 | } |
| 486 | } |