Home | History | Annotate | Download | only in win
      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/sanitizers/sanitizers.gni")
      6 import("//build/config/win/visual_studio_version.gni")
      7 import("//build/toolchain/goma.gni")
      8 import("//build/toolchain/toolchain.gni")
      9 
     10 # Should only be running on Windows.
     11 assert(is_win)
     12 
     13 # Setup the Visual Studio state.
     14 #
     15 # Its arguments are the VS path and the compiler wrapper tool. It will write
     16 # "environment.x86" and "environment.x64" to the build directory and return a
     17 # list to us.
     18 gyp_win_tool_path =
     19     rebase_path("//tools/gyp/pylib/gyp/win_tool.py", root_build_dir)
     20 
     21 if (use_goma) {
     22   goma_prefix = "$goma_dir/gomacc.exe "
     23 } else {
     24   goma_prefix = ""
     25 }
     26 
     27 # This value will be inherited in the toolchain below.
     28 concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
     29 
     30 # Copy the VS runtime DLL for the default toolchain to the root build directory
     31 # so things will run.
     32 if (current_toolchain == default_toolchain) {
     33   if (is_debug) {
     34     configuration_name = "Debug"
     35   } else {
     36     configuration_name = "Release"
     37   }
     38   exec_script("../../vs_toolchain.py",
     39               [
     40                 "copy_dlls",
     41                 rebase_path(root_build_dir),
     42                 configuration_name,
     43                 target_cpu,
     44               ])
     45 }
     46 
     47 # Parameters:
     48 #  toolchain_cpu: current_cpu to pass as a build arg
     49 #  toolchain_os: current_os to pass as a build arg
     50 #  environment: File name of environment file.
     51 template("msvc_toolchain") {
     52   if (defined(invoker.concurrent_links)) {
     53     concurrent_links = invoker.concurrent_links
     54   }
     55 
     56   env = invoker.environment
     57 
     58   if (invoker.is_clang && host_os != "win") {
     59     # This toolchain definition uses response files for compilations.  GN uses
     60     # the quoting rules of the host OS, while clang-cl always defaults to
     61     # cmd.exe quoting rules for parsing response files.  Tell clang-cl to use
     62     # POSIX quoting rules, so it can understand what GN generates.
     63     cl = "${invoker.cl} --rsp-quoting=posix"
     64   } else {
     65     cl = invoker.cl
     66   }
     67 
     68   if (use_lld) {
     69     if (host_os == "win") {
     70       lld_link = "lld-link.exe"
     71     } else {
     72       lld_link = "lld-link"
     73     }
     74     prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
     75                          root_build_dir)
     76 
     77     # lld-link includes a replacement for lib.exe that can produce thin
     78     # archives and understands bitcode (for lto builds).
     79     lib = "$prefix/$lld_link /lib /llvmlibthin"
     80     link = "$prefix/$lld_link"
     81   } else {
     82     lib = "lib.exe"
     83     link = "link.exe"
     84   }
     85 
     86   # If possible, pass system includes as flags to the compiler.  When that's
     87   # not possible, load a full environment file (containing %INCLUDE% and
     88   # %PATH%) -- e.g. 32-bit MSVS builds require %PATH% to be set and just passing
     89   # in a list of include directories isn't enough.
     90   if (defined(invoker.sys_include_flags)) {
     91     env_wrapper = ""
     92     sys_include_flags = "${invoker.sys_include_flags} "  # Note trailing space.
     93   } else {
     94     # clang-cl doesn't need this env hoop, so omit it there.
     95     assert(!invoker.is_clang)
     96     env_wrapper = "ninja -t msvc -e $env -- "  # Note trailing space.
     97     sys_include_flags = ""
     98   }
     99 
    100   toolchain(target_name) {
    101     # Make these apply to all tools below.
    102     lib_switch = ""
    103     lib_dir_switch = "/LIBPATH:"
    104 
    105     # Object files go in this directory.
    106     object_subdir = "{{target_out_dir}}/{{label_name}}"
    107 
    108     tool("cc") {
    109       rspfile = "{{output}}.rsp"
    110       precompiled_header_type = "msvc"
    111       pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
    112 
    113       # Label names may have spaces in them so the pdbname must be quoted. The
    114       # source and output don't need to be quoted because GN knows they're a
    115       # full file name and will quote automatically when necessary.
    116       command = "$env_wrapper$cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
    117       depsformat = "msvc"
    118       description = "CC {{output}}"
    119       outputs = [
    120         "$object_subdir/{{source_name_part}}.obj",
    121       ]
    122       rspfile_content = "$sys_include_flags{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
    123     }
    124 
    125     tool("cxx") {
    126       rspfile = "{{output}}.rsp"
    127       precompiled_header_type = "msvc"
    128 
    129       # The PDB name needs to be different between C and C++ compiled files.
    130       pdbname = "{{target_out_dir}}/{{label_name}}_cc.pdb"
    131 
    132       # See comment in CC tool about quoting.
    133       command = "$env_wrapper$cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
    134       depsformat = "msvc"
    135       description = "CXX {{output}}"
    136       outputs = [
    137         "$object_subdir/{{source_name_part}}.obj",
    138       ]
    139       rspfile_content = "$sys_include_flags{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
    140     }
    141 
    142     tool("rc") {
    143       command = "$python_path gyp-win-tool rc-wrapper $env rc.exe {{defines}} {{include_dirs}} /fo{{output}} {{source}}"
    144       outputs = [
    145         "$object_subdir/{{source_name_part}}.res",
    146       ]
    147       description = "RC {{output}}"
    148     }
    149 
    150     tool("asm") {
    151       if (invoker.toolchain_cpu == "x64") {
    152         ml = "ml64.exe"
    153       } else {
    154         ml = "ml.exe"
    155       }
    156       command = "$python_path gyp-win-tool asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} /c /Fo{{output}} {{source}}"
    157       description = "ASM {{output}}"
    158       outputs = [
    159         "$object_subdir/{{source_name_part}}.obj",
    160       ]
    161     }
    162 
    163     tool("alink") {
    164       rspfile = "{{output}}.rsp"
    165       command = "$python_path gyp-win-tool link-wrapper $env False $lib /nologo {{arflags}} /OUT:{{output}} @$rspfile"
    166       description = "LIB {{output}}"
    167       outputs = [
    168         # Ignore {{output_extension}} and always use .lib, there's no reason to
    169         # allow targets to override this extension on Windows.
    170         "{{output_dir}}/{{target_output_name}}.lib",
    171       ]
    172       default_output_extension = ".lib"
    173       default_output_dir = "{{target_out_dir}}"
    174 
    175       # The use of inputs_newline is to work around a fixed per-line buffer
    176       # size in the linker.
    177       rspfile_content = "{{inputs_newline}}"
    178     }
    179 
    180     tool("solink") {
    181       dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"  # e.g. foo.dll
    182       libname = "${dllname}.lib"  # e.g. foo.dll.lib
    183       rspfile = "${dllname}.rsp"
    184 
    185       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"
    186 
    187       default_output_extension = ".dll"
    188       default_output_dir = "{{root_out_dir}}"
    189       description = "LINK(DLL) {{output}}"
    190       outputs = [
    191         dllname,
    192         libname,
    193       ]
    194       link_output = libname
    195       depend_output = libname
    196       runtime_link_output = dllname
    197 
    198       # Since the above commands only updates the .lib file when it changes, ask
    199       # Ninja to check if the timestamp actually changed to know if downstream
    200       # dependencies should be recompiled.
    201       restat = true
    202 
    203       # The use of inputs_newline is to work around a fixed per-line buffer
    204       # size in the linker.
    205       rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}"
    206     }
    207 
    208     tool("solink_module") {
    209       dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"  # e.g. foo.dll
    210       rspfile = "${dllname}.rsp"
    211 
    212       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"
    213 
    214       default_output_extension = ".dll"
    215       default_output_dir = "{{root_out_dir}}"
    216       description = "LINK_MODULE(DLL) {{output}}"
    217       outputs = [
    218         dllname,
    219       ]
    220 
    221       # The use of inputs_newline is to work around a fixed per-line buffer
    222       # size in the linker.
    223       rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}"
    224     }
    225 
    226     tool("link") {
    227       rspfile = "{{output}}.rsp"
    228 
    229       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /OUT:{{output}} /PDB:{{output}}.pdb @$rspfile"
    230 
    231       default_output_extension = ".exe"
    232       default_output_dir = "{{root_out_dir}}"
    233       description = "LINK {{output}}"
    234       outputs = [
    235         "{{output_dir}}/{{target_output_name}}{{output_extension}}",
    236       ]
    237 
    238       # The use of inputs_newline is to work around a fixed per-line buffer
    239       # size in the linker.
    240       rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
    241     }
    242 
    243     # These two are really entirely generic, but have to be repeated in
    244     # each toolchain because GN doesn't allow a template to be used here.
    245     # See //build/toolchain/toolchain.gni for details.
    246     tool("stamp") {
    247       command = stamp_command
    248       description = stamp_description
    249     }
    250     tool("copy") {
    251       command = copy_command
    252       description = copy_description
    253     }
    254 
    255     # When invoking this toolchain not as the default one, these args will be
    256     # passed to the build. They are ignored when this is the default toolchain.
    257     toolchain_args() {
    258       current_cpu = invoker.toolchain_cpu
    259       if (defined(invoker.toolchain_os)) {
    260         current_os = invoker.toolchain_os
    261       }
    262 
    263       # These share a name with global variables that are already defined, and
    264       # forward_variables_from won't clobber the existing value, so we need to
    265       # set it explicitly.
    266       if (defined(invoker.is_clang)) {
    267         is_clang = invoker.is_clang
    268       }
    269       if (defined(invoker.is_component_build)) {
    270         is_component_build = invoker.is_component_build
    271       }
    272 
    273       # This value needs to be passed through unchanged.
    274       host_toolchain = host_toolchain
    275     }
    276   }
    277 }
    278 
    279 if (is_clang) {
    280   sys_include_prefix = "-imsvc"
    281 } else {
    282   # MSVC doesn't have the concept of system headers.
    283   sys_include_prefix = "/I"
    284 }
    285 
    286 if (host_os == "win") {
    287   clang_cl = "clang-cl.exe"
    288 } else {
    289   clang_cl = "clang-cl"
    290 }
    291 
    292 # 32-bit toolchains. Only define these when the target architecture is 32-bit
    293 # since we don't do any 32-bit cross compiles when targeting 64-bit (the
    294 # build does generate some 64-bit stuff from 32-bit target builds).
    295 if (target_cpu == "x86") {
    296   x86_toolchain_data = exec_script("setup_toolchain.py",
    297                                    [
    298                                      visual_studio_path,
    299                                      gyp_win_tool_path,
    300                                      windows_sdk_path,
    301                                      visual_studio_runtime_dirs,
    302                                      "x86",
    303                                      "${sys_include_prefix}",
    304                                    ],
    305                                    "scope")
    306 
    307   msvc_toolchain("x86") {
    308     environment = "environment.x86"
    309     toolchain_cpu = "x86"
    310     cl = "${goma_prefix}\"${x86_toolchain_data.vc_bin_dir}/cl.exe\""
    311     is_clang = false
    312   }
    313 
    314   msvc_toolchain("clang_x86") {
    315     environment = "environment.x86"
    316     toolchain_cpu = "x86"
    317     prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
    318                          root_build_dir)
    319     cl = "${goma_prefix}$prefix/${clang_cl}"
    320     toolchain_os = "win"
    321     is_clang = true
    322     sys_include_flags = "${x86_toolchain_data.include_flags}"
    323   }
    324 }
    325 
    326 # 64-bit toolchains.
    327 x64_toolchain_data = exec_script("setup_toolchain.py",
    328                                  [
    329                                    visual_studio_path,
    330                                    gyp_win_tool_path,
    331                                    windows_sdk_path,
    332                                    visual_studio_runtime_dirs,
    333                                    "x64",
    334                                    "${sys_include_prefix}",
    335                                  ],
    336                                  "scope")
    337 
    338 template("win_x64_toolchains") {
    339   # TODO(mcgrathr): These assignments are only required because of
    340   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
    341   concurrent_links = invoker.concurrent_links
    342   goma_prefix = invoker.goma_prefix
    343   x64_toolchain_data = invoker.x64_toolchain_data
    344   clang_cl = invoker.clang_cl
    345 
    346   msvc_toolchain(target_name) {
    347     environment = "environment.x64"
    348     toolchain_cpu = "x64"
    349     cl = "${goma_prefix}\"${x64_toolchain_data.vc_bin_dir}/cl.exe\""
    350     is_clang = false
    351 
    352     # This shares a name with a global and forward_variables_from won't clobber
    353     # the existing value, so we need to set it explicitly.
    354     if (defined(invoker.is_component_build)) {
    355       is_component_build = invoker.is_component_build
    356     }
    357   }
    358 
    359   msvc_toolchain("clang_" + target_name) {
    360     environment = "environment.x64"
    361     toolchain_cpu = "x64"
    362     prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
    363                          root_build_dir)
    364     cl = "${goma_prefix}$prefix/${clang_cl}"
    365     toolchain_os = "win"
    366     is_clang = true
    367     sys_include_flags = "${x64_toolchain_data.include_flags}"
    368 
    369     # This shares a name with a global and forward_variables_from won't clobber
    370     # the existing value, so we need to set it explicitly.
    371     if (defined(invoker.is_component_build)) {
    372       is_component_build = invoker.is_component_build
    373     }
    374   }
    375 }
    376 
    377 win_x64_toolchains("x64") {
    378   # TODO(mcgrathr): These assignments are only required because of
    379   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
    380   concurrent_links = concurrent_links
    381   goma_prefix = goma_prefix
    382   x64_toolchain_data = x64_toolchain_data
    383 }
    384 
    385 # The nacl_win64 toolchain is nearly identical to the plain x64 toolchain.
    386 # It's used solely for building nacl64.exe (//components/nacl/broker:nacl64).
    387 # The only reason it's a separate toolchain is so that it can force
    388 # is_component_build to false in the toolchain_args() block, because
    389 # building nacl64.exe in component style does not work.
    390 win_x64_toolchains("nacl_win64") {
    391   is_component_build = false
    392 
    393   # TODO(mcgrathr): These assignments are only required because of
    394   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
    395   concurrent_links = concurrent_links
    396   goma_prefix = goma_prefix
    397   x64_toolchain_data = x64_toolchain_data
    398   clang_cl = clang_cl
    399 }
    400 
    401 # WinRT toolchains. Only define these when targeting them.
    402 #
    403 # NOTE: This is currently broken because it references vc_bin_dir. brettw@
    404 # changed this around a bit, and I don't know what this should be set to
    405 # in terms of what setup_toolchain returns for a certain CPU architecture.
    406 if (target_os == "winrt_81" || target_os == "winrt_81_phone" ||
    407     target_os == "winrt_10") {
    408   msvc_toolchain("winrt_x86") {
    409     environment = "environment.winrt_x86"
    410     cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
    411     is_clang = false
    412 
    413     toolchain_cpu = "x86"
    414     toolchain_os = current_os
    415   }
    416 
    417   msvc_toolchain("winrt_x64") {
    418     environment = "environment.winrt_x64"
    419     cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
    420     is_clang = false
    421 
    422     toolchain_cpu = "x64"
    423     toolchain_os = current_os
    424   }
    425 }
    426