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 13 namespace functions { 14 15 namespace { 16 17 // This is jsut a unique value to take the address of to use as the key for 18 // the toolchain property on a scope. 19 const int kToolchainPropertyKey = 0; 20 21 // Reads the given string from the scope (if present) and puts the result into 22 // dest. If the value is not a string, sets the error and returns false. 23 bool ReadString(Scope& scope, const char* var, std::string* dest, Err* err) { 24 const Value* v = scope.GetValue(var, true); 25 if (!v) 26 return true; // Not present is fine. 27 28 if (!v->VerifyTypeIs(Value::STRING, err)) 29 return false; 30 *dest = v->string_value(); 31 return true; 32 } 33 34 } // namespace 35 36 // toolchain ------------------------------------------------------------------- 37 38 const char kToolchain[] = "toolchain"; 39 const char kToolchain_Help[] = 40 "TODO(brettw) write this."; 41 42 Value RunToolchain(Scope* scope, 43 const FunctionCallNode* function, 44 const std::vector<Value>& args, 45 BlockNode* block, 46 Err* err) { 47 if (!EnsureNotProcessingImport(function, scope, err) || 48 !EnsureNotProcessingBuildConfig(function, scope, err)) 49 return Value(); 50 51 // Note that we don't want to use MakeLabelForScope since that will include 52 // the toolchain name in the label, and toolchain labels don't themselves 53 // have toolchain names. 54 const SourceDir& input_dir = SourceDirForFunctionCall(function); 55 Label label(input_dir, args[0].string_value(), SourceDir(), std::string()); 56 if (g_scheduler->verbose_logging()) 57 g_scheduler->Log("Generating toolchain", label.GetUserVisibleName(false)); 58 59 // This object will actually be copied into the one owned by the toolchain 60 // manager, but that has to be done in the lock. 61 Toolchain toolchain(label); 62 63 Scope block_scope(scope); 64 block_scope.SetProperty(&kToolchainPropertyKey, &toolchain); 65 block->ExecuteBlockInScope(&block_scope, err); 66 block_scope.SetProperty(&kToolchainPropertyKey, NULL); 67 if (err->has_error()) 68 return Value(); 69 if (!block_scope.CheckForUnusedVars(err)) 70 return Value(); 71 72 const BuildSettings* build_settings = scope->settings()->build_settings(); 73 { 74 // Save the toolchain definition in the toolchain manager and mark the 75 // corresponding item in the dependency tree resolved so that targets 76 // that depend on this toolchain know it's ready. 77 base::AutoLock lock(build_settings->item_tree().lock()); 78 build_settings->toolchain_manager().SetToolchainDefinitionLocked( 79 toolchain, function->GetRange(), err); 80 build_settings->item_tree().MarkItemDefinedLocked(build_settings, label, 81 err); 82 } 83 return Value(); 84 } 85 86 // tool ------------------------------------------------------------------------ 87 88 const char kTool[] = "tool"; 89 const char kTool_Help[] = 90 "TODO(brettw) write this."; 91 92 Value RunTool(Scope* scope, 93 const FunctionCallNode* function, 94 const std::vector<Value>& args, 95 BlockNode* block, 96 Err* err) { 97 // Find the toolchain definition we're executing inside of. The toolchain 98 // function will set a property pointing to it that we'll pick up. 99 Toolchain* toolchain = reinterpret_cast<Toolchain*>( 100 scope->GetProperty(&kToolchainPropertyKey, NULL)); 101 if (!toolchain) { 102 *err = Err(function->function(), "tool() called outside of toolchain().", 103 "The tool() function can only be used inside a toolchain() " 104 "definition."); 105 return Value(); 106 } 107 108 if (!EnsureSingleStringArg(function, args, err)) 109 return Value(); 110 const std::string& tool_name = args[0].string_value(); 111 Toolchain::ToolType tool_type = Toolchain::ToolNameToType(tool_name); 112 if (tool_type == Toolchain::TYPE_NONE) { 113 *err = Err(args[0], "Unknown tool type"); 114 return Value(); 115 } 116 117 // Run the tool block. 118 Scope block_scope(scope); 119 block->ExecuteBlockInScope(&block_scope, err); 120 if (err->has_error()) 121 return Value(); 122 123 // Extract the stuff we need. 124 Toolchain::Tool t; 125 if (!ReadString(block_scope, "command", &t.command, err) || 126 !ReadString(block_scope, "depfile", &t.depfile, err) || 127 !ReadString(block_scope, "deps", &t.deps, err) || 128 !ReadString(block_scope, "description", &t.description, err) || 129 !ReadString(block_scope, "pool", &t.pool, err) || 130 !ReadString(block_scope, "restat", &t.restat, err) || 131 !ReadString(block_scope, "rspfile", &t.rspfile, err) || 132 !ReadString(block_scope, "rspfile_content", &t.rspfile_content, err)) 133 return Value(); 134 135 // Make sure there weren't any vars set in this tool that were unused. 136 if (!block_scope.CheckForUnusedVars(err)) 137 return Value(); 138 139 toolchain->SetTool(tool_type, t); 140 return Value(); 141 } 142 143 } // namespace functions 144