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 52declare_args() { 53 sysroot = "" 54 gcc_toolchain = "" 55 ar = "ar" 56 linker = "" 57 58 if (is_linux_host) { 59 linker = "gold" 60 } 61 62 if (is_clang) { 63 if (is_linux_host && !is_system_compiler) { 64 cc = linux_clang_bin 65 cxx = linux_clangxx_bin 66 linker = linux_clang_linker 67 } else if (is_win_host && !is_system_compiler) { 68 cc = win_clang_bin 69 cxx = win_clangxx_bin 70 linker = win_clang_linker 71 } else { 72 cc = "clang" 73 cxx = "clang++" 74 linker = "" 75 } 76 } else if (is_win) { # MSVC 77 cc = "${win_msvc_bin_dir}\\cl.exe" 78 cxx = "${win_msvc_bin_dir}\\cl.exe" 79 linker = "${win_msvc_bin_dir}\\link.exe" 80 } else { # GCC 81 cc = "gcc" 82 cxx = "g++" 83 } 84} 85 86# Then determine the target toolchain. 87 88declare_args() { 89 target_sysroot = sysroot 90 target_gcc_toolchain = "" 91 92 # |target_triplet| is the variable that the user can set via GN args. The user 93 # doesn't have to necessarily set it though. In most cases we can infer it 94 # by looking at target_os and target_cpu. 95 # |_target_triplet| is the final argument passed to the toolchain. 96 if (target_triplet != "") { 97 assert(is_cross_compiling) 98 99 # If the user provides the target_triplet in gn args, respect that. 100 # Otherwise guess it looking at the target os and cpu variables. 101 _target_triplet = target_triplet 102 } else if (!is_cross_compiling) { 103 _target_triplet = "" 104 } else if (target_os == "mac" && target_cpu == "x64") { 105 _target_triplet = "x86_64-apple-darwin" 106 } else if (target_os == "mac" && target_cpu == "x86") { 107 _target_triplet = "i686-apple-darwin" 108 } else if (target_os == "linux" && target_cpu == "arm64") { 109 _target_triplet = "aarch64-linux-gnu" 110 } else if (target_os == "linux" && target_cpu == "arm") { 111 _target_triplet = "arm-linux-gnueabi" 112 } else if (target_os == "linux" && target_cpu == "x64") { 113 _target_triplet = "x86_64-linux-gnu" 114 } else if (target_os == "linux" && target_cpu == "x86") { 115 _target_triplet = "i686-linux-gnu" 116 } else if (target_os == "android" && target_cpu == "arm64") { 117 _target_triplet = "aarch64-linux-android" 118 } else if (target_os == "android" && target_cpu == "arm") { 119 _target_triplet = "arm-linux-androideabi" 120 } else if (target_os == "android" && target_cpu == "x86") { 121 _target_triplet = "i686-linux-android" 122 } else if (target_os == "android" && target_cpu == "x64") { 123 _target_triplet = "x86_64-linux-android" 124 } else { 125 assert( 126 false, 127 "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") 128 } 129} 130 131declare_args() { 132 if (is_linux || is_android) { 133 target_linker = "gold" 134 } else { 135 target_linker = "" 136 } 137 138 if (!is_cross_compiling || is_perfetto_build_generator || 139 is_system_compiler) { 140 target_ar = ar 141 target_cc = cc 142 target_cxx = cxx 143 target_linker = linker 144 } else { 145 target_ar = "ar" 146 if (is_android) { 147 target_ar = "$android_toolchain_root/bin/$android_abi_target-ar" 148 target_cc = "$android_llvm_dir/bin/clang" 149 target_cxx = "$android_llvm_dir/bin/clang++" 150 target_linker = "$android_llvm_dir/bin/ld.lld" 151 } else { 152 assert(_target_triplet != "", 153 "target_triplet must be non-empty when cross-compiling") 154 if (is_clang) { 155 if (is_linux_host) { 156 target_cc = "${linux_clang_bin} --target=${_target_triplet}" 157 target_cxx = "${linux_clangxx_bin} --target=${_target_triplet}" 158 target_linker = "${linux_clang_linker} --target=${_target_triplet}" 159 } else { 160 target_cc = "clang --target=${_target_triplet}" 161 target_cxx = "clang++ --target=${_target_triplet}" 162 } 163 } else { # GCC 164 target_ar = "${_target_triplet}-ar" 165 target_cc = "${_target_triplet}-gcc" 166 target_cxx = "${_target_triplet}-g++" 167 } 168 } 169 } 170} 171 172template("gcc_like_toolchain") { 173 toolchain(target_name) { 174 ar = invoker.ar 175 cc = invoker.cc 176 cxx = invoker.cxx 177 lib_switch = "-l" 178 lib_dir_switch = "-L" 179 ld_arg = "" 180 external_cflags = "" 181 external_cxxflags = "" 182 external_ldflags = "" 183 if (defined(invoker.linker) && invoker.linker != "") { 184 _invoker_linker = invoker.linker 185 ld_arg = "-fuse-ld=$_invoker_linker" 186 } 187 if (defined(invoker.sysroot) && invoker.sysroot != "") { 188 _invoker_sysroot = invoker.sysroot 189 cc = "$cc --sysroot=$_invoker_sysroot" 190 cxx = "$cxx --sysroot=$_invoker_sysroot" 191 } 192 if (defined(invoker.gcc_toolchain) && invoker.gcc_toolchain != "") { 193 assert(is_clang, "gcc_toolchain can be used only when using clang") 194 _invoker_gcc_toolchain = invoker.gcc_toolchain 195 ld_arg = "$ld_arg --gcc-toolchain=$_invoker_gcc_toolchain" 196 } 197 if (defined(invoker.external_cflags)) { 198 external_cflags = invoker.external_cflags 199 } 200 if (defined(invoker.external_cxxflags)) { 201 external_cxxflags = invoker.external_cxxflags 202 } 203 if (defined(invoker.external_ldflags)) { 204 external_ldflags = invoker.external_ldflags 205 } 206 207 tool("cc") { 208 depfile = "{{output}}.d" 209 command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} -c {{source}} -o {{output}}" 210 depsformat = "gcc" 211 outputs = 212 [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] 213 description = "compile {{source}}" 214 } 215 216 tool("cxx") { 217 depfile = "{{output}}.d" 218 command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} ${external_cflags} ${external_cxxflags} -c {{source}} -o {{output}}" 219 depsformat = "gcc" 220 outputs = 221 [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] 222 description = "compile {{source}}" 223 } 224 225 tool("asm") { 226 depfile = "{{output}}.d" 227 command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" 228 depsformat = "gcc" 229 outputs = 230 [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] 231 description = "assemble {{source}}" 232 } 233 234 tool("alink") { 235 rspfile = "{{output}}.rsp" 236 if (is_mac && ar != "suppress_unused_ar_variable_warning") { 237 rspfile_content = "{{inputs_newline}}" 238 command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile" 239 } else { 240 rspfile_content = "{{inputs}}" 241 command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile" 242 } 243 outputs = 244 [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ] 245 default_output_extension = ".a" 246 output_prefix = "lib" 247 description = "link {{output}}" 248 } 249 250 tool("solink") { 251 soname = "{{target_output_name}}{{output_extension}}" 252 253 rpath = "-Wl,-soname,$soname" 254 if (is_mac) { 255 rpath = "-Wl,-install_name,@rpath/$soname" 256 } 257 258 command = "$cc_wrapper $cxx $ld_arg -shared {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} $rpath -o {{output}}" 259 outputs = [ "{{root_out_dir}}/$soname" ] 260 output_prefix = "lib" 261 default_output_extension = ".so" 262 description = "link {{output}}" 263 } 264 265 tool("link") { 266 command = "$cc_wrapper $cxx $ld_arg {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} -o {{output}}" 267 outputs = 268 [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ] 269 description = "link {{output}}" 270 } 271 272 tool("stamp") { 273 command = "touch {{output}}" 274 description = "stamp {{output}}" 275 } 276 277 tool("copy") { 278 command = "cp -af {{source}} {{output}}" 279 description = "COPY {{source}} {{output}}" 280 } 281 282 toolchain_args = { 283 current_cpu = invoker.cpu 284 current_os = invoker.os 285 } 286 } 287} 288 289gcc_like_toolchain("gcc_like") { 290 cpu = current_cpu 291 os = current_os 292 ar = target_ar 293 cc = target_cc 294 cxx = target_cxx 295 linker = target_linker 296 sysroot = target_sysroot 297 gcc_toolchain = target_gcc_toolchain 298 external_cflags = string_join(" ", 299 [ 300 extra_cflags, 301 extra_target_cflags, 302 ]) 303 external_cxxflags = string_join(" ", 304 [ 305 extra_cxxflags, 306 extra_target_cxxflags, 307 ]) 308 external_ldflags = string_join(" ", 309 [ 310 extra_ldflags, 311 extra_target_ldflags, 312 ]) 313} 314 315gcc_like_toolchain("gcc_like_host") { 316 cpu = host_cpu 317 os = host_os 318 ar = ar 319 cc = cc 320 cxx = cxx 321 linker = linker 322 sysroot = sysroot 323 gcc_toolchain = gcc_toolchain 324 external_cflags = string_join(" ", 325 [ 326 extra_cflags, 327 extra_host_cflags, 328 ]) 329 external_cxxflags = string_join(" ", 330 [ 331 extra_cxxflags, 332 extra_host_cxxflags, 333 ]) 334 external_ldflags = string_join(" ", 335 [ 336 extra_ldflags, 337 extra_host_ldflags, 338 ]) 339} 340 341gcc_like_toolchain("wasm") { 342 # emsdk_dir and em_config are defined in wasm.gni. 343 cpu = host_cpu 344 os = host_os 345 ar = "$emsdk_dir/emscripten/emar --em-config $em_config" 346 cc = "$emsdk_dir/emscripten/emcc --em-config $em_config" 347 cxx = "$emsdk_dir/emscripten/em++ --em-config $em_config" 348} 349 350# This is used both for MSVC anc clang-cl. clang-cl cmdline interface pretends 351# to be MSVC's cl.exe. 352toolchain("msvc") { 353 lib_switch = "" 354 lib_dir_switch = "/LIBPATH:" 355 356 sys_lib_flags = "/LIBPATH:\"${win_sdk_lib_dir}\\ucrt\\x64\" " 357 sys_lib_flags += "/LIBPATH:\"${win_sdk_lib_dir}\\um\\x64\" " 358 sys_lib_flags += "/LIBPATH:\"${win_msvc_lib_dir}\" " 359 360 # Note: /showIncludes below is required for ninja, to build a complete 361 # dependency graph for headers. Removing it breaks incremental builds. 362 363 tool("cc") { 364 precompiled_header_type = "msvc" 365 pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb" 366 command = "$cc_wrapper $cc /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\"" 367 depsformat = "msvc" 368 outputs = 369 [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] 370 description = "compile {{source}}" 371 } 372 373 tool("cxx") { 374 precompiled_header_type = "msvc" 375 pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb" 376 command = "$cc_wrapper $cxx /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\"" 377 depsformat = "msvc" 378 outputs = 379 [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] 380 description = "compile {{source}}" 381 } 382 383 tool("alink") { 384 rspfile = "{{output}}.rsp" 385 command = "$linker /lib /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile" 386 outputs = [ 387 # Ignore {{output_extension}} and always use .lib, there's no reason to 388 # allow targets to override this extension on Windows. 389 "{{root_out_dir}}/{{target_output_name}}{{output_extension}}", 390 ] 391 default_output_extension = ".lib" 392 default_output_dir = "{{target_out_dir}}" 393 394 # inputs_newline works around a fixed per-line buffer size in the linker. 395 rspfile_content = "{{inputs_newline}}" 396 description = "link {{output}}" 397 } 398 399 tool("solink") { 400 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 401 libname = "${dllname}.lib" 402 pdbname = "${dllname}.pdb" 403 rspfile = "${dllname}.rsp" 404 405 command = "$linker /nologo /IMPLIB:$libname ${sys_lib_flags} /DLL /OUT:$dllname /PDB:$pdbname @$rspfile" 406 outputs = [ 407 dllname, 408 libname, 409 pdbname, 410 ] 411 default_output_extension = ".dll" 412 default_output_dir = "{{root_out_dir}}" 413 414 link_output = libname 415 depend_output = libname 416 runtime_outputs = [ 417 dllname, 418 pdbname, 419 ] 420 421 # Since the above commands only updates the .lib file when it changes, ask 422 # Ninja to check if the timestamp actually changed to know if downstream 423 # dependencies should be recompiled. 424 restat = true 425 426 # inputs_newline works around a fixed per-line buffer size in the linker. 427 rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}" 428 description = "link {{output}}" 429 } 430 431 tool("link") { 432 exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" 433 pdbname = "$exename.pdb" 434 rspfile = "$exename.rsp" 435 436 command = 437 "$linker /nologo /OUT:$exename ${sys_lib_flags} /PDB:$pdbname @$rspfile" 438 default_output_extension = ".exe" 439 default_output_dir = "{{root_out_dir}}" 440 outputs = [ exename ] 441 442 # inputs_newline works around a fixed per-line buffer size in the linker. 443 rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}" 444 description = "link {{output}}" 445 } 446 447 tool("stamp") { 448 command = "cmd /c type nul > \"{{output}}\"" 449 description = "stamp {{output}}" 450 } 451 452 tool("copy") { 453 cp_py = rebase_path("../cp.py") 454 command = "cmd.exe /c python \"$cp_py\" {{source}} {{output}}" 455 description = "copy {{source}} {{output}}" 456 } 457} 458