mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
228 lines
9.0 KiB
C++
228 lines
9.0 KiB
C++
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "tools/gn/functions.h"
|
|
|
|
#include "tools/gn/parse_tree.h"
|
|
#include "tools/gn/scope.h"
|
|
#include "tools/gn/template.h"
|
|
#include "tools/gn/value.h"
|
|
|
|
namespace functions {
|
|
|
|
const char kTemplate[] = "template";
|
|
const char kTemplate_HelpShort[] =
|
|
"template: Define a template rule.";
|
|
const char kTemplate_Help[] =
|
|
R"(template: Define a template rule.
|
|
|
|
A template defines a custom name that acts like a function. It provides a way
|
|
to add to the built-in target types.
|
|
|
|
The template() function is used to declare a template. To invoke the
|
|
template, just use the name of the template like any other target type.
|
|
|
|
Often you will want to declare your template in a special file that other
|
|
files will import (see "gn help import") so your template rule can be shared
|
|
across build files.
|
|
|
|
Variables and templates:
|
|
|
|
When you call template() it creates a closure around all variables currently
|
|
in scope with the code in the template block. When the template is invoked,
|
|
the closure will be executed.
|
|
|
|
When the template is invoked, the code in the caller is executed and passed
|
|
to the template code as an implicit "invoker" variable. The template uses
|
|
this to read state out of the invoking code.
|
|
|
|
One thing explicitly excluded from the closure is the "current directory"
|
|
against which relative file names are resolved. The current directory will be
|
|
that of the invoking code, since typically that code specifies the file
|
|
names. This means all files internal to the template should use absolute
|
|
names.
|
|
|
|
A template will typically forward some or all variables from the invoking
|
|
scope to a target that it defines. Often, such variables might be optional.
|
|
Use the pattern:
|
|
|
|
if (defined(invoker.deps)) {
|
|
deps = invoker.deps
|
|
}
|
|
|
|
The function forward_variables_from() provides a shortcut to forward one or
|
|
more or possibly all variables in this manner:
|
|
|
|
forward_variables_from(invoker, ["deps", "public_deps"])
|
|
|
|
Target naming
|
|
|
|
Your template should almost always define a built-in target with the name the
|
|
template invoker specified. For example, if you have an IDL template and
|
|
somebody does:
|
|
idl("foo") {...
|
|
you will normally want this to expand to something defining a source_set or
|
|
static_library named "foo" (among other things you may need). This way, when
|
|
another target specifies a dependency on "foo", the static_library or
|
|
source_set will be linked.
|
|
|
|
It is also important that any other targets your template expands to have
|
|
unique names, or you will get collisions.
|
|
|
|
Access the invoking name in your template via the implicit "target_name"
|
|
variable. This should also be the basis for how other targets that a template
|
|
expands to ensure uniqueness.
|
|
|
|
A typical example would be a template that defines an action to generate some
|
|
source files, and a source_set to compile that source. Your template would
|
|
name the source_set "target_name" because that's what you want external
|
|
targets to depend on to link your code. And you would name the action
|
|
something like "${target_name}_action" to make it unique. The source set
|
|
would have a dependency on the action to make it run.
|
|
|
|
Overriding builtin targets
|
|
|
|
You can use template to redefine a built-in target in which case your template
|
|
takes a precedence over the built-in one. All uses of the target from within
|
|
the template definition will refer to the built-in target which makes it
|
|
possible to extend the behavior of the built-in target:
|
|
|
|
template("shared_library") {
|
|
shared_library(shlib) {
|
|
forward_variables_from(invoker, [ "*" ])
|
|
...
|
|
}
|
|
}
|
|
|
|
Example of defining a template
|
|
|
|
template("my_idl") {
|
|
# Be nice and help callers debug problems by checking that the variables
|
|
# the template requires are defined. This gives a nice message rather than
|
|
# giving the user an error about an undefined variable in the file defining
|
|
# the template
|
|
#
|
|
# You can also use defined() to give default values to variables
|
|
# unspecified by the invoker.
|
|
assert(defined(invoker.sources),
|
|
"Need sources in $target_name listing the idl files.")
|
|
|
|
# Name of the intermediate target that does the code gen. This must
|
|
# incorporate the target name so it's unique across template
|
|
# instantiations.
|
|
code_gen_target_name = target_name + "_code_gen"
|
|
|
|
# Intermediate target to convert IDL to C source. Note that the name is
|
|
# based on the name the invoker of the template specified. This way, each
|
|
# time the template is invoked we get a unique intermediate action name
|
|
# (since all target names are in the global scope).
|
|
action_foreach(code_gen_target_name) {
|
|
# Access the scope defined by the invoker via the implicit "invoker"
|
|
# variable.
|
|
sources = invoker.sources
|
|
|
|
# Note that we need an absolute path for our script file name. The
|
|
# current directory when executing this code will be that of the invoker
|
|
# (this is why we can use the "sources" directly above without having to
|
|
# rebase all of the paths). But if we need to reference a script relative
|
|
# to the template file, we'll need to use an absolute path instead.
|
|
script = "//tools/idl/idl_code_generator.py"
|
|
|
|
# Tell GN how to expand output names given the sources.
|
|
# See "gn help source_expansion" for more.
|
|
outputs = [ "$target_gen_dir/{{source_name_part}}.cc",
|
|
"$target_gen_dir/{{source_name_part}}.h" ]
|
|
}
|
|
|
|
# Name the source set the same as the template invocation so instancing
|
|
# this template produces something that other targets can link to in their
|
|
# deps.
|
|
source_set(target_name) {
|
|
# Generates the list of sources, we get these from the action_foreach
|
|
# above.
|
|
sources = get_target_outputs(":$code_gen_target_name")
|
|
|
|
# This target depends on the files produced by the above code gen target.
|
|
deps = [ ":$code_gen_target_name" ]
|
|
}
|
|
}
|
|
|
|
Example of invoking the resulting template
|
|
|
|
# This calls the template code above, defining target_name to be
|
|
# "foo_idl_files" and "invoker" to be the set of stuff defined in the curly
|
|
# brackets.
|
|
my_idl("foo_idl_files") {
|
|
# Goes into the template as "invoker.sources".
|
|
sources = [ "foo.idl", "bar.idl" ]
|
|
}
|
|
|
|
# Here is a target that depends on our template.
|
|
executable("my_exe") {
|
|
# Depend on the name we gave the template call above. Internally, this will
|
|
# produce a dependency from executable to the source_set inside the
|
|
# template (since it has this name), which will in turn depend on the code
|
|
# gen action.
|
|
deps = [ ":foo_idl_files" ]
|
|
}
|
|
)";
|
|
|
|
Value RunTemplate(Scope* scope,
|
|
const FunctionCallNode* function,
|
|
const std::vector<Value>& args,
|
|
BlockNode* block,
|
|
Err* err) {
|
|
// Of course you can have configs and targets in a template. But here, we're
|
|
// not actually executing the block, only declaring it. Marking the template
|
|
// declaration as non-nestable means that you can't put it inside a target,
|
|
// for example.
|
|
NonNestableBlock non_nestable(scope, function, "template");
|
|
if (!non_nestable.Enter(err))
|
|
return Value();
|
|
|
|
// TODO(brettw) determine if the function is built-in and throw an error if
|
|
// it is.
|
|
if (args.size() != 1) {
|
|
*err = Err(function->function(),
|
|
"Need exactly one string arg to template.");
|
|
return Value();
|
|
}
|
|
if (!args[0].VerifyTypeIs(Value::STRING, err))
|
|
return Value();
|
|
std::string template_name = args[0].string_value();
|
|
|
|
const Template* existing_template = scope->GetTemplate(template_name);
|
|
if (existing_template) {
|
|
*err = Err(function, "Duplicate template definition.",
|
|
"A template with this name was already defined.");
|
|
err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
|
|
"Previous definition."));
|
|
return Value();
|
|
}
|
|
|
|
scope->AddTemplate(template_name, new Template(scope, function));
|
|
|
|
// The template object above created a closure around the variables in the
|
|
// current scope. The template code will execute in that context when it's
|
|
// invoked. But this means that any variables defined above that are used
|
|
// by the template won't get marked used just by defining the template. The
|
|
// result can be spurious unused variable errors.
|
|
//
|
|
// The "right" thing to do would be to walk the syntax tree inside the
|
|
// template, find all identifier references, and mark those variables used.
|
|
// This is annoying and error-prone to implement and takes extra time to run
|
|
// for this narrow use case.
|
|
//
|
|
// Templates are most often defined in .gni files which don't get
|
|
// used-variable checking anyway, and this case is annoying enough that the
|
|
// incremental value of unused variable checking isn't worth the
|
|
// alternatives. So all values in scope before this template definition are
|
|
// exempted from unused variable checking.
|
|
scope->MarkAllUsed();
|
|
|
|
return Value();
|
|
}
|
|
|
|
} // namespace functions
|