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# TODO(brettw) Use "gcc_toolchain.gni" like the Linux toolchains. This requires 6# some enhancements since the commands on Mac are slightly different than on 7# Linux. 8 9import("../goma.gni") 10import("//build/config/ios/ios_sdk.gni") 11import("//build/config/mac/mac_sdk.gni") 12 13assert(host_os == "mac") 14 15import("//build/toolchain/goma.gni") 16import("//build/toolchain/toolchain.gni") 17 18if (use_goma) { 19 goma_prefix = "$goma_dir/gomacc " 20} else { 21 goma_prefix = "" 22} 23 24# This will copy the gyp-mac-tool to the build directory. We pass in the source 25# file of the mac tool. 26gyp_mac_tool_source = 27 rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", root_build_dir) 28exec_script("setup_toolchain.py", [ gyp_mac_tool_source ]) 29 30# Shared toolchain definition. Invocations should set toolchain_os to set the 31# build args in this definition. 32template("mac_toolchain") { 33 toolchain(target_name) { 34 assert(defined(invoker.cc), "mac_toolchain() must specify a \"cc\" value") 35 assert(defined(invoker.cxx), "mac_toolchain() must specify a \"cxx\" value") 36 assert(defined(invoker.ld), "mac_toolchain() must specify a \"ld\" value") 37 assert(defined(invoker.toolchain_cpu), 38 "mac_toolchain() must specify a \"toolchain_cpu\"") 39 assert(defined(invoker.toolchain_os), 40 "mac_toolchain() must specify a \"toolchain_os\"") 41 42 # We can't do string interpolation ($ in strings) on things with dots in 43 # them. To allow us to use $cc below, for example, we create copies of 44 # these values in our scope. 45 cc = invoker.cc 46 cxx = invoker.cxx 47 ld = invoker.ld 48 49 # Make these apply to all tools below. 50 lib_switch = "-l" 51 lib_dir_switch = "-L" 52 53 # Object files go in this directory. Use label_name instead of 54 # target_output_name since labels will generally have no spaces and will be 55 # unique in the directory. 56 object_subdir = "{{target_out_dir}}/{{label_name}}" 57 58 tool("cc") { 59 depfile = "{{output}}.d" 60 precompiled_header_type = "gcc" 61 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 62 depsformat = "gcc" 63 description = "CC {{output}}" 64 outputs = [ 65 "$object_subdir/{{source_name_part}}.o", 66 ] 67 } 68 69 tool("cxx") { 70 depfile = "{{output}}.d" 71 precompiled_header_type = "gcc" 72 command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" 73 depsformat = "gcc" 74 description = "CXX {{output}}" 75 outputs = [ 76 "$object_subdir/{{source_name_part}}.o", 77 ] 78 } 79 80 tool("asm") { 81 # For GCC we can just use the C compiler to compile assembly. 82 depfile = "{{output}}.d" 83 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" 84 depsformat = "gcc" 85 description = "ASM {{output}}" 86 outputs = [ 87 "$object_subdir/{{source_name_part}}.o", 88 ] 89 } 90 91 tool("objc") { 92 depfile = "{{output}}.d" 93 precompiled_header_type = "gcc" 94 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}" 95 depsformat = "gcc" 96 description = "OBJC {{output}}" 97 outputs = [ 98 "$object_subdir/{{source_name_part}}.o", 99 ] 100 } 101 102 tool("objcxx") { 103 depfile = "{{output}}.d" 104 precompiled_header_type = "gcc" 105 command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}" 106 depsformat = "gcc" 107 description = "OBJCXX {{output}}" 108 outputs = [ 109 "$object_subdir/{{source_name_part}}.o", 110 ] 111 } 112 113 tool("alink") { 114 command = "rm -f {{output}} && ./gyp-mac-tool filter-libtool libtool -static {{arflags}} -o {{output}} {{inputs}}" 115 description = "LIBTOOL-STATIC {{output}}" 116 outputs = [ 117 "{{output_dir}}/{{target_output_name}}{{output_extension}}", 118 ] 119 default_output_dir = "{{target_out_dir}}" 120 default_output_extension = ".a" 121 output_prefix = "lib" 122 } 123 124 tool("solink") { 125 dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}" # eg "./libfoo.dylib" 126 rspfile = dylib + ".rsp" 127 128 # These variables are not built into GN but are helpers that implement 129 # (1) linking to produce a .dylib, (2) extracting the symbols from that 130 # file to a temporary file, (3) if the temporary file has differences from 131 # the existing .TOC file, overwrite it, otherwise, don't change it. 132 # 133 # As a special case, if the library reexports symbols from other dynamic 134 # libraries, we always update the .TOC and skip the temporary file and 135 # diffing steps, since that library always needs to be re-linked. 136 tocname = dylib + ".TOC" 137 temporary_tocname = dylib + ".tmp" 138 139 does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB" 140 141 link_command = "$ld -shared " 142 if (is_component_build) { 143 link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" " 144 } 145 link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{libs}} {{solibs}}" 146 147 replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\"" 148 extract_toc_command = "{ otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; nm -gP \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }" 149 150 command = "if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi" 151 152 rspfile_content = "{{inputs_newline}}" 153 154 description = "SOLINK {{output}}" 155 156 # Use this for {{output_extension}} expansions unless a target manually 157 # overrides it (in which case {{output_extension}} will be what the target 158 # specifies). 159 default_output_dir = "{{root_out_dir}}" 160 default_output_extension = ".dylib" 161 162 output_prefix = "lib" 163 164 # Since the above commands only updates the .TOC file when it changes, ask 165 # Ninja to check if the timestamp actually changed to know if downstream 166 # dependencies should be recompiled. 167 restat = true 168 169 # Tell GN about the output files. It will link to the dylib but use the 170 # tocname for dependency management. 171 outputs = [ 172 dylib, 173 tocname, 174 ] 175 link_output = dylib 176 depend_output = tocname 177 } 178 179 tool("solink_module") { 180 sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" # eg "./libfoo.so" 181 rspfile = sofile + ".rsp" 182 183 link_command = 184 "$ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\"" 185 if (is_component_build) { 186 link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}" 187 } 188 link_command += " {{solibs}} {{libs}}" 189 command = link_command 190 191 rspfile_content = "{{inputs_newline}}" 192 193 description = "SOLINK_MODULE {{output}}" 194 195 # Use this for {{output_extension}} expansions unless a target manually 196 # overrides it (in which case {{output_extension}} will be what the target 197 # specifies). 198 default_output_dir = "{{root_out_dir}}" 199 default_output_extension = ".so" 200 201 outputs = [ 202 sofile, 203 ] 204 } 205 206 tool("link") { 207 outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 208 rspfile = "$outfile.rsp" 209 210 # Note about --filelist: Apple's linker reads the file list file and 211 # interprets each newline-separated chunk of text as a file name. It 212 # doesn't do the things one would expect from the shell like unescaping 213 # or handling quotes. In contrast, when Ninja finds a file name with 214 # spaces, it single-quotes them in $inputs_newline as it would normally 215 # do for command-line arguments. Thus any source names with spaces, or 216 # label names with spaces (which GN bases the output paths on) will be 217 # corrupted by this process. Don't use spaces for source files or labels. 218 command = "$ld {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{solibs}} {{libs}}" 219 description = "LINK $outfile" 220 rspfile_content = "{{inputs_newline}}" 221 outputs = [ 222 outfile, 223 ] 224 225 default_output_dir = "{{root_out_dir}}" 226 } 227 228 # These two are really entirely generic, but have to be repeated in 229 # each toolchain because GN doesn't allow a template to be used here. 230 # See //build/toolchain/toolchain.gni for details. 231 tool("stamp") { 232 command = stamp_command 233 description = stamp_description 234 } 235 tool("copy") { 236 command = copy_command 237 description = copy_description 238 } 239 240 tool("copy_bundle_data") { 241 _tool = rebase_path("//build/toolchain/mac/copy_bundle_data.py", 242 root_build_dir) 243 command = "python $_tool {{source}} {{output}}" 244 description = "COPY_BUNDLE_DATA {{source}} {{output}}" 245 } 246 tool("compile_xcassets") { 247 if (is_ios) { 248 _configuration = "Release" 249 if (is_debug) { 250 _configuration = "Debug" 251 } 252 253 _compile_xcassets_env = 254 "IPHONEOS_DEPLOYMENT_TARGET=$ios_deployment_target " + 255 "CONFIGURATION=$ios_sdk_name-$_configuration " + 256 "CONTENTS_FOLDER_PATH=\$(dirname {{output}})" 257 } else { 258 _compile_xcassets_env = 259 "MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target " + 260 "UNLOCALIZED_RESOURCES_FOLDER_PATH=\$(dirname {{output}})" 261 } 262 263 command = "rm -f {{output}} && " + 264 "env $_compile_xcassets_env ./gyp-mac-tool compile-xcassets " + 265 "{} {{inputs}}" 266 description = "COMPILE_XCASSETS {{output}}" 267 } 268 269 toolchain_args() { 270 current_cpu = invoker.toolchain_cpu 271 current_os = invoker.toolchain_os 272 273 # These values need to be passed through unchanged. 274 host_toolchain = host_toolchain 275 target_os = target_os 276 target_cpu = target_cpu 277 278 if (defined(invoker.is_clang)) { 279 is_clang = invoker.is_clang 280 } 281 } 282 } 283} 284 285mac_toolchain("clang_arm") { 286 toolchain_cpu = "arm" 287 toolchain_os = "mac" 288 prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", 289 root_build_dir) 290 cc = "${goma_prefix}$prefix/clang" 291 cxx = "${goma_prefix}$prefix/clang++" 292 ld = cxx 293 is_clang = true 294} 295 296mac_toolchain("ios_clang_arm") { 297 toolchain_cpu = "arm" 298 toolchain_os = "mac" 299 300 # TODO(GYP): We need to support being able to use the version of clang 301 # shipped w/ XCode instead of the one pulled from upstream. 302 prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", 303 root_build_dir) 304 cc = "${goma_prefix}$prefix/clang" 305 cxx = "${goma_prefix}$prefix/clang++" 306 ld = cxx 307 is_clang = true 308} 309 310mac_toolchain("ios_clang_armv7") { 311 toolchain_cpu = "armv7" 312 toolchain_os = "mac" 313 314 # TODO(GYP): We need to support being able to use the version of clang 315 # shipped w/ XCode instead of the one pulled from upstream. 316 prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", 317 root_build_dir) 318 cc = "${goma_prefix}$prefix/clang" 319 cxx = "${goma_prefix}$prefix/clang++" 320 ld = cxx 321 is_clang = true 322} 323 324mac_toolchain("ios_clang_arm64") { 325 toolchain_cpu = "arm64" 326 toolchain_os = "mac" 327 328 # TODO(GYP): We need to support being able to use the version of clang 329 # shipped w/ XCode instead of the one pulled from upstream. 330 prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", 331 root_build_dir) 332 cc = "${goma_prefix}$prefix/clang" 333 cxx = "${goma_prefix}$prefix/clang++" 334 ld = cxx 335 is_clang = true 336} 337 338mac_toolchain("arm") { 339 toolchain_cpu = "arm" 340 toolchain_os = "mac" 341 cc = "${goma_prefix}/gcc" 342 cxx = "${goma_prefix}/g++" 343 ld = cxx 344 is_clang = false 345} 346 347mac_toolchain("clang_x64") { 348 toolchain_cpu = "x64" 349 toolchain_os = "mac" 350 prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", 351 root_build_dir) 352 cc = "${goma_prefix}$prefix/clang" 353 cxx = "${goma_prefix}$prefix/clang++" 354 ld = cxx 355 is_clang = true 356} 357 358mac_toolchain("x64") { 359 toolchain_cpu = "x64" 360 toolchain_os = "mac" 361 cc = "${goma_prefix}/gcc" 362 cxx = "${goma_prefix}/g++" 363 ld = cxx 364 is_clang = false 365} 366