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# This value will be inherited in the toolchain below. 6concurrent_links = exec_script("get_concurrent_links.py", [], "value") 7 8# This template defines a toolchain for something that works like gcc 9# (including clang). 10# 11# It requires the following variables specifying the executables to run: 12# - cc 13# - cxx 14# - ar 15# - ld 16# and the following which is used in the toolchain_args 17# - toolchain_cpu_arch (What "cpu_arch" should be set to when invoking a 18# build using this toolchain.) 19# - toolchain_os (What "os" should be set to when invoking a build using this 20# toolchain.) 21# 22# Optional parameters: 23# - libs_section_prefix 24# - libs_section_postfix 25# The contents of these strings, if specified, will be placed around 26# the libs section of the linker line. It allows one to inject libraries 27# at the beginning and end for all targets in a toolchain. 28# - solink_libs_section_prefix 29# - solink_libs_section_postfix 30# Same as libs_section_{pre,post}fix except used for solink instead of link. 31# - post_solink 32# The content of this string, if specified, will be appended to the solink 33# command. 34# - deps 35# Just forwarded to the toolchain definition. 36# - is_clang 37template("gcc_toolchain") { 38 toolchain(target_name) { 39 assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") 40 assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") 41 assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") 42 assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") 43 assert(defined(invoker.toolchain_cpu_arch), 44 "gcc_toolchain() must specify a \"toolchain_cpu_arch\"") 45 assert(defined(invoker.toolchain_os), 46 "gcc_toolchain() must specify a \"toolchain_os\"") 47 48 # We can't do string interpolation ($ in strings) on things with dots in 49 # them. To allow us to use $cc below, for example, we create copies of 50 # these values in our scope. 51 cc = invoker.cc 52 cxx = invoker.cxx 53 ar = invoker.ar 54 ld = invoker.ld 55 56 # Bring these into our scope for string interpolation with default values. 57 if (defined(invoker.libs_section_prefix)) { 58 libs_section_prefix = invoker.libs_section_prefix 59 } else { 60 libs_section_prefix = "" 61 } 62 63 if (defined(invoker.libs_section_postfix)) { 64 libs_section_postfix = invoker.libs_section_postfix 65 } else { 66 libs_section_postfix = "" 67 } 68 69 if (defined(invoker.solink_libs_section_prefix)) { 70 solink_libs_section_prefix = invoker.solink_libs_section_prefix 71 } else { 72 solink_libs_section_prefix = "" 73 } 74 75 if (defined(invoker.solink_libs_section_postfix)) { 76 solink_libs_section_postfix = invoker.solink_libs_section_postfix 77 } else { 78 solink_libs_section_postfix = "" 79 } 80 81 # These library switches can apply to all tools below. 82 lib_switch = "-l" 83 lib_dir_switch = "-L" 84 85 tool("cc") { 86 depfile = "{{output}}.d" 87 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 88 depsformat = "gcc" 89 description = "CC {{output}}" 90 outputs = [ 91 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", 92 ] 93 } 94 95 tool("cxx") { 96 depfile = "{{output}}.d" 97 command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" 98 depsformat = "gcc" 99 description = "CXX {{output}}" 100 outputs = [ 101 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", 102 ] 103 } 104 105 tool("asm") { 106 # For GCC we can just use the C compiler to compile assembly. 107 depfile = "{{output}}.d" 108 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 109 depsformat = "gcc" 110 description = "ASM {{output}}" 111 outputs = [ 112 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", 113 ] 114 } 115 116 tool("alink") { 117 rspfile = "{{output}}.rsp" 118 command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile" 119 description = "AR {{output}}" 120 rspfile_content = "{{inputs}}" 121 outputs = [ 122 "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" 123 ] 124 default_output_extension = ".a" 125 output_prefix = "lib" 126 } 127 128 tool("solink") { 129 soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". 130 sofile = "{{root_out_dir}}/$soname" # Possibly including toolchain dir. 131 rspfile = sofile + ".rsp" 132 133 # These variables are not built into GN but are helpers that implement 134 # (1) linking to produce a .so, (2) extracting the symbols from that file 135 # to a temporary file, (3) if the temporary file has differences from the 136 # existing .TOC file, overwrite it, otherwise, don't change it. 137 tocfile = sofile + ".TOC" 138 temporary_tocname = sofile + ".tmp" 139 link_command = "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile" 140 toc_command = "{ readelf -d $sofile | grep SONAME ; nm -gD -f p $soname | cut -f1-2 -d' '; } > $temporary_tocname" 141 replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi" 142 143 command = "$link_command && $toc_command && $replace_command" 144 if (defined(invoker.postsolink)) { 145 command += " && " + invoker.postsolink 146 } 147 rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" 148 149 description = "SOLINK $sofile" 150 151 # Use this for {{output_extension}} expansions unless a target manually 152 # overrides it (in which case {{output_extension}} will be what the target 153 # specifies). 154 default_output_extension = ".so" 155 156 output_prefix = "lib" 157 158 # Since the above commands only updates the .TOC file when it changes, ask 159 # Ninja to check if the timestamp actually changed to know if downstream 160 # dependencies should be recompiled. 161 restat = true 162 163 # Tell GN about the output files. It will link to the sofile but use the 164 # tocfile for dependency management. 165 outputs = [ 166 sofile, 167 tocfile, 168 ] 169 if (defined(invoker.solink_outputs)) { 170 outputs += invoker.solink_outputs 171 } 172 link_output = sofile 173 depend_output = tocfile 174 } 175 176 tool("link") { 177 outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" 178 rspfile = "$outfile.rsp" 179 command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" 180 if (defined(invoker.postlink)) { 181 command += " && " + invoker.postlink 182 } 183 description = "LINK $outfile" 184 rspfile_content = "{{inputs}}" 185 outputs = [ outfile ] 186 if (defined(invoker.link_outputs)) { 187 outputs += invoker.link_outputs 188 } 189 } 190 191 tool("stamp") { 192 command = "touch {{output}}" 193 description = "STAMP {{output}}" 194 } 195 196 tool("copy") { 197 command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" 198 description = "COPY {{source}} {{output}}" 199 } 200 201 # When invoking this toolchain not as the default one, these args will be 202 # passed to the build. They are ignored when this is the default toolchain. 203 toolchain_args() { 204 cpu_arch = invoker.toolchain_cpu_arch 205 os = invoker.toolchain_os 206 if (defined(invoker.is_clang)) { 207 is_clang = invoker.is_clang 208 } 209 } 210 211 if (defined(invoker.deps)) { 212 deps = invoker.deps 213 } 214 } 215} 216