Home | History | Annotate | Download | only in gn
      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 
     14 namespace functions {
     15 
     16 namespace {
     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.
     20 const 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.
     24 bool 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 
     39 const char kToolchain[] = "toolchain";
     40 const char kToolchain_HelpShort[] =
     41     "toolchain: Defines a toolchain.";
     42 const 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 
     89 Value 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 
    134 const char kTool[] = "tool";
    135 const char kTool_HelpShort[] =
    136     "tool: Specify arguments to a toolchain tool.";
    137 const 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 
    187 Value 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 
    242 extern const char kToolchainArgs[] = "toolchain_args";
    243 extern const char kToolchainArgs_HelpShort[] =
    244     "toolchain_args: Set build arguments for toolchain build setup.";
    245 extern 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 
    280 Value 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