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#include "tools/gn/err.h" 6#include "tools/gn/functions.h" 7#include "tools/gn/parse_tree.h" 8#include "tools/gn/scheduler.h" 9#include "tools/gn/scope.h" 10#include "tools/gn/settings.h" 11#include "tools/gn/toolchain.h" 12#include "tools/gn/variables.h" 13 14namespace functions { 15 16namespace { 17 18// This is jsut a unique value to take the address of to use as the key for 19// the toolchain property on a scope. 20const int kToolchainPropertyKey = 0; 21 22// Reads the given string from the scope (if present) and puts the result into 23// dest. If the value is not a string, sets the error and returns false. 24bool ReadString(Scope& scope, const char* var, std::string* dest, Err* err) { 25 const Value* v = scope.GetValue(var, true); 26 if (!v) 27 return true; // Not present is fine. 28 29 if (!v->VerifyTypeIs(Value::STRING, err)) 30 return false; 31 *dest = v->string_value(); 32 return true; 33} 34 35} // namespace 36 37// toolchain ------------------------------------------------------------------- 38 39const char kToolchain[] = "toolchain"; 40const char kToolchain_HelpShort[] = 41 "toolchain: Defines a toolchain."; 42const char kToolchain_Help[] = 43 "toolchain: Defines a toolchain.\n" 44 "\n" 45 " A toolchain is a set of commands and build flags used to compile the\n" 46 " source code. You can have more than one toolchain in use at once in\n" 47 " a build.\n" 48 "\n" 49 " A toolchain specifies the commands to run for various input file\n" 50 " types via the \"tool\" call (see \"gn help tool\") and specifies\n" 51 " arguments to be passed to the toolchain build via the\n" 52 " \"toolchain_args\" call (see \"gn help toolchain_args\").\n" 53 "\n" 54 "Invoking targets in toolchains:\n" 55 "\n" 56 " By default, when a target depends on another, there is an implicit\n" 57 " toolchain label that is inherited, so the dependee has the same one\n" 58 " as the dependent.\n" 59 "\n" 60 " You can override this and refer to any other toolchain by explicitly\n" 61 " labeling the toolchain to use. For example:\n" 62 " datadeps = [ \"//plugins:mine(//toolchains:plugin_toolchain)\" ]\n" 63 " The string \"//build/toolchains:plugin_toolchain\" is a label that\n" 64 " identifies the toolchain declaration for compiling the sources.\n" 65 "\n" 66 " To load a file in an alternate toolchain, GN does the following:\n" 67 "\n" 68 " 1. Loads the file with the toolchain definition in it (as determined\n" 69 " by the toolchain label).\n" 70 " 2. Re-runs the master build configuration file, applying the\n" 71 " arguments specified by the toolchain_args section of the toolchain\n" 72 " definition (see \"gn help toolchain_args\").\n" 73 " 3. Loads the destination build file in the context of the\n" 74 " configuration file in the previous step.\n" 75 "\n" 76 "Example:\n" 77 " toolchain(\"plugin_toolchain\") {\n" 78 " tool(\"cc\") {\n" 79 " command = \"gcc $in\"\n" 80 " }\n" 81 "\n" 82 " toolchain_args() {\n" 83 " is_plugin = true\n" 84 " is_32bit = true\n" 85 " is_64bit = false\n" 86 " }\n" 87 " }\n"; 88 89Value RunToolchain(Scope* scope, 90 const FunctionCallNode* function, 91 const std::vector<Value>& args, 92 BlockNode* block, 93 Err* err) { 94 if (!EnsureNotProcessingImport(function, scope, err) || 95 !EnsureNotProcessingBuildConfig(function, scope, err)) 96 return Value(); 97 98 // Note that we don't want to use MakeLabelForScope since that will include 99 // the toolchain name in the label, and toolchain labels don't themselves 100 // have toolchain names. 101 const SourceDir& input_dir = scope->GetSourceDir(); 102 Label label(input_dir, args[0].string_value()); 103 if (g_scheduler->verbose_logging()) 104 g_scheduler->Log("Definining toolchain", label.GetUserVisibleName(false)); 105 106 // This object will actually be copied into the one owned by the toolchain 107 // manager, but that has to be done in the lock. 108 scoped_ptr<Toolchain> toolchain(new Toolchain(scope->settings(), label)); 109 toolchain->set_defined_from(function); 110 toolchain->visibility().SetPublic(); 111 112 Scope block_scope(scope); 113 block_scope.SetProperty(&kToolchainPropertyKey, toolchain.get()); 114 block->ExecuteBlockInScope(&block_scope, err); 115 block_scope.SetProperty(&kToolchainPropertyKey, NULL); 116 if (err->has_error()) 117 return Value(); 118 119 if (!block_scope.CheckForUnusedVars(err)) 120 return Value(); 121 122 // Save this target for the file. 123 Scope::ItemVector* collector = scope->GetItemCollector(); 124 if (!collector) { 125 *err = Err(function, "Can't define a toolchain in this context."); 126 return Value(); 127 } 128 collector->push_back(new scoped_ptr<Item>(toolchain.PassAs<Item>())); 129 return Value(); 130} 131 132// tool ------------------------------------------------------------------------ 133 134const char kTool[] = "tool"; 135const char kTool_HelpShort[] = 136 "tool: Specify arguments to a toolchain tool."; 137const char kTool_Help[] = 138 "tool: Specify arguments to a toolchain tool.\n" 139 "\n" 140 " tool(<command type>) { <command flags> }\n" 141 "\n" 142 " Used inside a toolchain definition to define a command to run for a\n" 143 " given file type. See also \"gn help toolchain\".\n" 144 "\n" 145 "Command types:\n" 146 " The following values may be passed to the tool() function for the type\n" 147 " of the command:\n" 148 "\n" 149 " \"cc\", \"cxx\", \"objc\", \"objcxx\", \"asm\", \"alink\", \"solink\",\n" 150 " \"link\", \"stamp\", \"copy\"\n" 151 "\n" 152 "Command flags:\n" 153 "\n" 154 " These variables may be specified in the { } block after the tool call.\n" 155 " They are passed directly to Ninja. See the ninja documentation for how\n" 156 " they work. Don't forget to backslash-escape $ required by Ninja to\n" 157 " prevent GN from doing variable expansion.\n" 158 "\n" 159 " command, depfile, deps, description, pool, restat, rspfile,\n" 160 " rspfile_content\n" 161 "\n" 162 " Additionally, lib_prefix and lib_dir_prefix may be used for the link\n" 163 " tools. These strings will be prepended to the libraries and library\n" 164 " search directories, respectively, because linkers differ on how to\n" 165 " specify them.\n" 166 "\n" 167 " Note: On Mac libraries with names ending in \".framework\" will be\n" 168 " added to the link like with a \"-framework\" switch and the lib prefix\n" 169 " will be ignored.\n" 170 "\n" 171 "Example:\n" 172 " toolchain(\"my_toolchain\") {\n" 173 " # Put these at the top to apply to all tools below.\n" 174 " lib_prefix = \"-l\"\n" 175 " lib_dir_prefix = \"-L\"\n" 176 "\n" 177 " tool(\"cc\") {\n" 178 " command = \"gcc \\$in -o \\$out\"\n" 179 " description = \"GCC \\$in\"\n" 180 " }\n" 181 " tool(\"cxx\") {\n" 182 " command = \"g++ \\$in -o \\$out\"\n" 183 " description = \"G++ \\$in\"\n" 184 " }\n" 185 " }\n"; 186 187Value RunTool(Scope* scope, 188 const FunctionCallNode* function, 189 const std::vector<Value>& args, 190 BlockNode* block, 191 Err* err) { 192 // Find the toolchain definition we're executing inside of. The toolchain 193 // function will set a property pointing to it that we'll pick up. 194 Toolchain* toolchain = reinterpret_cast<Toolchain*>( 195 scope->GetProperty(&kToolchainPropertyKey, NULL)); 196 if (!toolchain) { 197 *err = Err(function->function(), "tool() called outside of toolchain().", 198 "The tool() function can only be used inside a toolchain() " 199 "definition."); 200 return Value(); 201 } 202 203 if (!EnsureSingleStringArg(function, args, err)) 204 return Value(); 205 const std::string& tool_name = args[0].string_value(); 206 Toolchain::ToolType tool_type = Toolchain::ToolNameToType(tool_name); 207 if (tool_type == Toolchain::TYPE_NONE) { 208 *err = Err(args[0], "Unknown tool type"); 209 return Value(); 210 } 211 212 // Run the tool block. 213 Scope block_scope(scope); 214 block->ExecuteBlockInScope(&block_scope, err); 215 if (err->has_error()) 216 return Value(); 217 218 // Extract the stuff we need. 219 Toolchain::Tool t; 220 if (!ReadString(block_scope, "command", &t.command, err) || 221 !ReadString(block_scope, "depfile", &t.depfile, err) || 222 !ReadString(block_scope, "deps", &t.deps, err) || 223 !ReadString(block_scope, "description", &t.description, err) || 224 !ReadString(block_scope, "lib_dir_prefix", &t.lib_dir_prefix, err) || 225 !ReadString(block_scope, "lib_prefix", &t.lib_prefix, err) || 226 !ReadString(block_scope, "pool", &t.pool, err) || 227 !ReadString(block_scope, "restat", &t.restat, err) || 228 !ReadString(block_scope, "rspfile", &t.rspfile, err) || 229 !ReadString(block_scope, "rspfile_content", &t.rspfile_content, err)) 230 return Value(); 231 232 // Make sure there weren't any vars set in this tool that were unused. 233 if (!block_scope.CheckForUnusedVars(err)) 234 return Value(); 235 236 toolchain->SetTool(tool_type, t); 237 return Value(); 238} 239 240// toolchain_args -------------------------------------------------------------- 241 242extern const char kToolchainArgs[] = "toolchain_args"; 243extern const char kToolchainArgs_HelpShort[] = 244 "toolchain_args: Set build arguments for toolchain build setup."; 245extern const char kToolchainArgs_Help[] = 246 "toolchain_args: Set build arguments for toolchain build setup.\n" 247 "\n" 248 " Used inside a toolchain definition to pass arguments to an alternate\n" 249 " toolchain's invocation of the build.\n" 250 "\n" 251 " When you specify a target using an alternate toolchain, the master\n" 252 " build configuration file is re-interpreted in the context of that\n" 253 " toolchain (see \"gn help toolchain\"). The toolchain_args function\n" 254 " allows you to control the arguments passed into this alternate\n" 255 " invocation of the build.\n" 256 "\n" 257 " Any default system arguments or arguments passed in on the command-\n" 258 " line will also be passed to the alternate invocation unless explicitly\n" 259 " overridden by toolchain_args.\n" 260 "\n" 261 " The toolchain_args will be ignored when the toolchain being defined\n" 262 " is the default. In this case, it's expected you want the default\n" 263 " argument values.\n" 264 "\n" 265 " See also \"gn help buildargs\" for an overview of these arguments.\n" 266 "\n" 267 "Example:\n" 268 " toolchain(\"my_weird_toolchain\") {\n" 269 " ...\n" 270 " toolchain_args() {\n" 271 " # Override the system values for a generic Posix system.\n" 272 " is_win = false\n" 273 " is_posix = true\n" 274 "\n" 275 " # Pass this new value for specific setup for my toolchain.\n" 276 " is_my_weird_system = true\n" 277 " }\n" 278 " }\n"; 279 280Value RunToolchainArgs(Scope* scope, 281 const FunctionCallNode* function, 282 const std::vector<Value>& args, 283 BlockNode* block, 284 Err* err) { 285 // Find the toolchain definition we're executing inside of. The toolchain 286 // function will set a property pointing to it that we'll pick up. 287 Toolchain* toolchain = reinterpret_cast<Toolchain*>( 288 scope->GetProperty(&kToolchainPropertyKey, NULL)); 289 if (!toolchain) { 290 *err = Err(function->function(), 291 "toolchain_args() called outside of toolchain().", 292 "The toolchain_args() function can only be used inside a " 293 "toolchain() definition."); 294 return Value(); 295 } 296 297 if (!args.empty()) { 298 *err = Err(function->function(), "This function takes no arguments."); 299 return Value(); 300 } 301 302 // This function makes a new scope with various variable sets on it, which 303 // we then save on the toolchain to use when re-invoking the build. 304 Scope block_scope(scope); 305 block->ExecuteBlockInScope(&block_scope, err); 306 if (err->has_error()) 307 return Value(); 308 309 Scope::KeyValueMap values; 310 block_scope.GetCurrentScopeValues(&values); 311 toolchain->args() = values; 312 313 return Value(); 314} 315 316} // namespace functions 317