summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 21:30:34 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 21:30:34 +0000
commit7ff2f5d2929d13bec977e4cd2cd5646413b2a592 (patch)
treed4edd94a70647061bd05ce50dee01b5fb928e0cb /tools
parent75ed8829d991b62b4943a29b0140d6803a70cac1 (diff)
downloadchromium_src-7ff2f5d2929d13bec977e4cd2cd5646413b2a592.zip
chromium_src-7ff2f5d2929d13bec977e4cd2cd5646413b2a592.tar.gz
chromium_src-7ff2f5d2929d13bec977e4cd2cd5646413b2a592.tar.bz2
Add the concept of a source set to GN.
A source set acts like a static library in most cases, but doesn't actually make the library. The object files will be added to targets that depend on it. I changed the default component mode to be a "source set" rather than a shared library in non-component mode. This fixes the script target writer unit test on Windows. BUG= R=scottmg@chromium.org Review URL: https://codereview.chromium.org/26267003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227596 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r--tools/gn/BUILD.gn1
-rw-r--r--tools/gn/functions.cc1
-rw-r--r--tools/gn/functions.h8
-rw-r--r--tools/gn/functions_target.cc75
-rw-r--r--tools/gn/gn.gyp1
-rw-r--r--tools/gn/ninja_binary_target_writer.cc171
-rw-r--r--tools/gn/ninja_binary_target_writer.h28
-rw-r--r--tools/gn/ninja_binary_target_writer_unittest.cc89
-rw-r--r--tools/gn/ninja_helper.cc1
-rw-r--r--tools/gn/ninja_script_target_writer_unittest.cc8
-rw-r--r--tools/gn/ninja_target_writer.cc3
-rw-r--r--tools/gn/output_file.h5
-rw-r--r--tools/gn/secondary/build/config/BUILDCONFIG.gn6
-rw-r--r--tools/gn/secondary/build/toolchain/nacl/BUILD.gn12
-rw-r--r--tools/gn/secondary/chrome/BUILD.gn8
-rw-r--r--tools/gn/target.cc3
-rw-r--r--tools/gn/target.h7
-rw-r--r--tools/gn/target_generator.cc4
18 files changed, 365 insertions, 66 deletions
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index e3d5301..9ff4081 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -161,6 +161,7 @@ test("gn_unittests") {
"function_rebase_path_unittest.cc",
"input_conversion_unittest.cc",
"label_unittest.cc",
+ "ninja_binary_target_writer_unittest.cc",
"ninja_copy_target_writer_unittest.cc",
"ninja_helper_unittest.cc",
"ninja_script_target_writer_unittest.cc",
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index bac4b8e..acc8fe9 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -567,6 +567,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(SetDefaultToolchain)
INSERT_FUNCTION(SetSourcesAssignmentFilter)
INSERT_FUNCTION(SharedLibrary)
+ INSERT_FUNCTION(SourceSet)
INSERT_FUNCTION(StaticLibrary)
INSERT_FUNCTION(Template)
INSERT_FUNCTION(Test)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index 9c419cc..4a7833a 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -194,6 +194,14 @@ Value RunSharedLibrary(Scope* scope,
BlockNode* block,
Err* err);
+extern const char kSourceSet[];
+extern const char kSourceSet_Help[];
+Value RunSourceSet(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ BlockNode* block,
+ Err* err);
+
extern const char kStaticLibrary[];
extern const char kStaticLibrary_Help[];
Value RunStaticLibrary(Scope* scope,
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index 94a04e4..fc968e5 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -58,18 +58,19 @@ const char kComponent[] = "component";
const char kComponent_Help[] =
"component: Declare a component target.\n"
"\n"
- " A component is either a shared library or a static library depending\n"
- " on the component mode. This allows a project to separate out a build\n"
- " into shared libraries for faster devlopment (link time is reduced)\n"
- " but to switch to a static build for releases (for better performance).\n"
+ " A component is a shared library, static library, or source set\n"
+ " depending on the component mode. This allows a project to separate\n"
+ " out a build into shared libraries for faster devlopment (link time is\n"
+ " reduced) but to switch to a static build for releases (for better\n"
+ " performance).\n"
"\n"
" To use this function you must set the value of the \"component_mode\n"
- " variable to the string \"shared_library\" or \"static_library\". It is\n"
- " an error to call \"component\" without defining the mode (typically\n"
- " this is done in the master build configuration file).\n"
- "\n"
- " See \"gn help shared_library\" and \"gn help static_library\" for\n"
- " more details.\n";
+ " variable to one of the following strings:\n"
+ " - \"shared_library\"\n"
+ " - \"static_library\"\n"
+ " - \"source_set\"\n"
+ " It is an error to call \"component\" without defining the mode\n"
+ " (typically this is done in the master build configuration file).\n";
Value RunComponent(Scope* scope,
const FunctionCallNode* function,
@@ -90,7 +91,8 @@ Value RunComponent(Scope* scope,
}
if (component_mode_value->type() != Value::STRING ||
(component_mode_value->string_value() != functions::kSharedLibrary &&
- component_mode_value->string_value() != functions::kStaticLibrary)) {
+ component_mode_value->string_value() != functions::kStaticLibrary &&
+ component_mode_value->string_value() != functions::kSourceSet)) {
*err = Err(function->function(), "Invalid component mode set.", helptext);
return Value();
}
@@ -339,12 +341,63 @@ Value RunSharedLibrary(Scope* scope,
block, err);
}
+// source_set ------------------------------------------------------------------
+
+extern const char kSourceSet[] = "source_set";
+extern const char kSourceSet_Help[] =
+ "source_set: Declare a source set target.\n"
+ "\n"
+ " A source set is a collection of sources that get compiled, but are not\n"
+ " linked to produce any kind of library. Instead, the resulting object\n"
+ " files are implicitly added to the linker line of all targets that\n"
+ " depend on the source set.\n"
+ "\n"
+ " In most cases, a source set will behave like a static library, except\n"
+ " no actual library file will be produced. This will make the build go\n"
+ " a little faster by skipping creation of a large static library, while\n"
+ " maintaining the organizational benefits of focused build targets.\n"
+ "\n"
+ " The main difference between a source set and a static library is\n"
+ " around handling of exported symbols. Most linkers assume declaring\n"
+ " a function exported means exported from the static library. The linker\n"
+ " can then do dead code elimination to delete code not reachable from\n"
+ " exported functions.\n"
+ "\n"
+ " A source set will not do this code elimination since there is no link\n"
+ " step. This allows you to link many sources sets into a shared library\n"
+ " and have the \"exported symbol\" notation indicate \"export from the\n"
+ " final shared library and not from the intermediate targets.\" There is\n"
+ " no way to express this concept when linking multiple static libraries\n"
+ " into a shared library.\n"
+ "\n"
+ "Variables\n"
+ "\n"
+ CONFIG_VALUES_VARS_HELP
+ DEPS_VARS
+ DEPENDENT_CONFIG_VARS
+ GENERAL_TARGET_VARS;
+
+Value RunSourceSet(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ BlockNode* block,
+ Err* err) {
+ return ExecuteGenericTarget(functions::kSourceSet, scope, function, args,
+ block, err);
+}
+
// static_library --------------------------------------------------------------
const char kStaticLibrary[] = "static_library";
const char kStaticLibrary_Help[] =
"static_library: Declare a static library target.\n"
"\n"
+ " Make a \".a\" / \".lib\" file.\n"
+ "\n"
+ " If you only need the static library for intermediate results in the\n"
+ " build, you should consider a source_set instead since it will skip\n"
+ " the (potentially slow) step of creating the intermediate library file.\n"
+ "\n"
"Variables\n"
"\n"
CONFIG_VALUES_VARS_HELP
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index fb5a53e..c19d2ef 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -171,6 +171,7 @@
'function_rebase_path_unittest.cc',
'input_conversion_unittest.cc',
'label_unittest.cc',
+ 'ninja_binary_target_writer_unittest.cc',
'ninja_helper_unittest.cc',
'ninja_copy_target_writer_unittest.cc',
'ninja_script_target_writer_unittest.cc',
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index 60d3a6a..9241021 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -79,7 +79,6 @@ Toolchain::ToolType GetToolTypeForTarget(const Target* target) {
case Target::EXECUTABLE:
return Toolchain::TYPE_LINK;
default:
- NOTREACHED();
return Toolchain::TYPE_NONE;
}
}
@@ -103,7 +102,10 @@ void NinjaBinaryTargetWriter::Run() {
std::vector<OutputFile> obj_files;
WriteSources(&obj_files);
- WriteLinkerStuff(obj_files);
+ if (target_->output_type() == Target::SOURCE_SET)
+ WriteSourceSetStamp(obj_files);
+ else
+ WriteLinkerStuff(obj_files);
}
void NinjaBinaryTargetWriter::WriteCompilerVars() {
@@ -309,40 +311,26 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
<< helper_.GetRulePrefix(GetToolchain())
<< Toolchain::ToolTypeToName(tool_type_);
+ std::set<OutputFile> extra_object_files;
+ std::vector<const Target*> linkable_deps;
+ std::vector<const Target*> non_linkable_deps;
+ GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
+
// Object files.
for (size_t i = 0; i < object_files.size(); i++) {
out_ << " ";
path_output_.WriteFile(out_, object_files[i]);
}
-
- // Library inputs (deps and inherited static libraries).
- //
- // Static libraries since they're just a collection of the object files so
- // don't need libraries linked with them, but we still need to go through
- // the list and find non-linkable data deps in the "deps" section. We'll
- // collect all non-linkable deps and put it in the implicit deps below.
- std::vector<const Target*> extra_data_deps;
- const std::vector<const Target*>& deps = target_->deps();
- const std::set<const Target*>& inherited = target_->inherited_libraries();
- for (size_t i = 0; i < deps.size(); i++) {
- if (inherited.find(deps[i]) != inherited.end())
- continue;
- if (target_->output_type() != Target::STATIC_LIBRARY &&
- deps[i]->IsLinkable()) {
- out_ << " ";
- path_output_.WriteFile(out_, helper_.GetTargetOutputFile(deps[i]));
- } else {
- extra_data_deps.push_back(deps[i]);
- }
+ for (std::set<OutputFile>::iterator i = extra_object_files.begin();
+ i != extra_object_files.end(); ++i) {
+ out_ << " ";
+ path_output_.WriteFile(out_, *i);
}
- for (std::set<const Target*>::const_iterator i = inherited.begin();
- i != inherited.end(); ++i) {
- if (target_->output_type() == Target::STATIC_LIBRARY) {
- extra_data_deps.push_back(*i);
- } else {
- out_ << " ";
- path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i));
- }
+
+ // Libs.
+ for (size_t i = 0; i < linkable_deps.size(); i++) {
+ out_ << " ";
+ path_output_.WriteFile(out_, helper_.GetTargetOutputFile(linkable_deps[i]));
}
// External link deps from GYP. This is indexed by a label with no toolchain.
@@ -357,22 +345,123 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
}
// Append data dependencies as implicit dependencies.
+ WriteImplicitDependencies(non_linkable_deps);
+
+ out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::WriteSourceSetStamp(
+ const std::vector<OutputFile>& object_files) {
+ // The stamp rule for source sets is generally not used, since targets that
+ // depend on this will reference the object files directly. However, writing
+ // this rule allows the user to type the name of the target and get a build
+ // which can be convenient for development.
+ out_ << "build ";
+ path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
+ out_ << ": "
+ << helper_.GetRulePrefix(target_->settings()->toolchain())
+ << "stamp";
+
+ std::set<OutputFile> extra_object_files;
+ std::vector<const Target*> linkable_deps;
+ std::vector<const Target*> non_linkable_deps;
+ GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
+
+ // The classifier should never put extra object files in a source set:
+ // any source sets that we depend on should appear in our non-linkable
+ // deps instead.
+ DCHECK(extra_object_files.empty());
+
+ for (size_t i = 0; i < object_files.size(); i++) {
+ out_ << " ";
+ path_output_.WriteFile(out_, object_files[i]);
+ }
+
+ // Append data dependencies as implicit dependencies.
+ WriteImplicitDependencies(non_linkable_deps);
+
+ out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::GetDeps(
+ std::set<OutputFile>* extra_object_files,
+ std::vector<const Target*>* linkable_deps,
+ std::vector<const Target*>* non_linkable_deps) const {
+ const std::vector<const Target*>& deps = target_->deps();
+ const std::set<const Target*>& inherited = target_->inherited_libraries();
+
+ // Normal deps.
+ for (size_t i = 0; i < deps.size(); i++) {
+ if (inherited.find(deps[i]) != inherited.end())
+ continue; // Don't add dupes.
+ ClassifyDependency(deps[i], extra_object_files,
+ linkable_deps, non_linkable_deps);
+ }
+
+ // Inherited libraries.
+ for (std::set<const Target*>::const_iterator i = inherited.begin();
+ i != inherited.end(); ++i) {
+ ClassifyDependency(*i, extra_object_files,
+ linkable_deps, non_linkable_deps);
+ }
+
+ // Data deps.
const std::vector<const Target*>& datadeps = target_->datadeps();
+ for (size_t i = 0; i < datadeps.size(); i++)
+ non_linkable_deps->push_back(datadeps[i]);
+}
+
+void NinjaBinaryTargetWriter::ClassifyDependency(
+ const Target* dep,
+ std::set<OutputFile>* extra_object_files,
+ std::vector<const Target*>* linkable_deps,
+ std::vector<const Target*>* non_linkable_deps) const {
+ // Only these types of outputs have libraries linked into them. Child deps of
+ // static libraries get pushed up the dependency tree until one of these is
+ // reached, and source sets don't link at all.
+ bool can_link_libs =
+ (target_->output_type() == Target::EXECUTABLE ||
+ target_->output_type() == Target::SHARED_LIBRARY);
+
+ if (dep->output_type() == Target::SOURCE_SET) {
+ if (target_->output_type() == Target::SOURCE_SET) {
+ // When a source set depends on another source set, add it as a data
+ // dependency so if the user says "ninja second_source_set" it will
+ // also compile the first (what you would expect) even though we'll
+ // never do anything with the first one's files.
+ non_linkable_deps->push_back(dep);
+ } else {
+ // Linking in a source set, copy its object files.
+ for (size_t i = 0; i < dep->sources().size(); i++) {
+ SourceFileType input_file_type = GetSourceFileType(
+ dep->sources()[i], dep->settings()->target_os());
+ if (input_file_type != SOURCE_UNKNOWN &&
+ input_file_type != SOURCE_H) {
+ // Note we need to specify the target as the source_set target
+ // itself, since this is used to prefix the object file name.
+ extra_object_files->insert(helper_.GetOutputFileForSource(
+ dep, dep->sources()[i], input_file_type));
+ }
+ }
+ }
+ } else if (can_link_libs && dep->IsLinkable()) {
+ linkable_deps->push_back(dep);
+ } else {
+ non_linkable_deps->push_back(dep);
+ }
+}
+
+void NinjaBinaryTargetWriter::WriteImplicitDependencies(
+ const std::vector<const Target*>& non_linkable_deps) {
const std::vector<SourceFile>& data = target_->data();
- if (!extra_data_deps.empty() || !datadeps.empty() || !data.empty()) {
+ if (!non_linkable_deps.empty() || !data.empty()) {
out_ << " ||";
- // Non-linkable deps in the deps section above.
- for (size_t i = 0; i < extra_data_deps.size(); i++) {
+ // Non-linkable targets.
+ for (size_t i = 0; i < non_linkable_deps.size(); i++) {
out_ << " ";
path_output_.WriteFile(out_,
- helper_.GetTargetOutputFile(extra_data_deps[i]));
- }
-
- // Data deps.
- for (size_t i = 0; i < datadeps.size(); i++) {
- out_ << " ";
- path_output_.WriteFile(out_, helper_.GetTargetOutputFile(datadeps[i]));
+ helper_.GetTargetOutputFile(non_linkable_deps[i]));
}
// Data files.
@@ -382,6 +471,4 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
path_output_.WriteFile(out_, data[i]);
}
}
-
- out_ << std::endl;
}
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h
index 047ed2a..8c57ffb 100644
--- a/tools/gn/ninja_binary_target_writer.h
+++ b/tools/gn/ninja_binary_target_writer.h
@@ -19,6 +19,8 @@ class NinjaBinaryTargetWriter : public NinjaTargetWriter {
virtual void Run() OVERRIDE;
private:
+ typedef std::set<OutputFile> OutputFileSet;
+
void WriteCompilerVars();
void WriteSources(std::vector<OutputFile>* object_files);
void WriteLinkerStuff(const std::vector<OutputFile>& object_files);
@@ -29,6 +31,32 @@ class NinjaBinaryTargetWriter : public NinjaTargetWriter {
const OutputFile& internal_output_file,
const std::vector<OutputFile>& object_files);
+ // Writes the stamp line for a source set. These are not linked.
+ void WriteSourceSetStamp(const std::vector<OutputFile>& object_files);
+
+ // Gets all target dependencies and classifies them, as well as accumulates
+ // object files from source sets we need to link.
+ void GetDeps(std::set<OutputFile>* extra_object_files,
+ std::vector<const Target*>* linkable_deps,
+ std::vector<const Target*>* non_linkable_deps) const;
+
+ // Classifies the dependency as linkable or nonlinkable with the current
+ // target, adding it to the appropriate vector. If the dependency is a source
+ // set we should link in, the source set's object files will be appended to
+ // |extra_object_files|.
+ void ClassifyDependency(const Target* dep,
+ std::set<OutputFile>* extra_object_files,
+ std::vector<const Target*>* linkable_deps,
+ std::vector<const Target*>* non_linkable_deps) const;
+
+ // Writes the implicit dependencies for the link or stamp line. This is
+ // the "||" and everything following it on the ninja line.
+ //
+ // The implicit dependencies are the non-linkable deps passed in as an
+ // argument, plus the data file depdencies in the target.
+ void WriteImplicitDependencies(
+ const std::vector<const Target*>& non_linkable_deps);
+
Toolchain::ToolType tool_type_;
DISALLOW_COPY_AND_ASSIGN(NinjaBinaryTargetWriter);
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
new file mode 100644
index 0000000..f57bb19
--- /dev/null
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -0,0 +1,89 @@
+// 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 <sstream>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/ninja_binary_target_writer.h"
+#include "tools/gn/test_with_scope.h"
+
+TEST(NinjaBinaryTargetWriter, SourceSet) {
+ TestWithScope setup;
+ setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+ setup.settings()->set_target_os(Settings::WIN);
+
+ Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+ target.set_output_type(Target::SOURCE_SET);
+ target.sources().push_back(SourceFile("//foo/input1.cc"));
+ target.sources().push_back(SourceFile("//foo/input2.cc"));
+ target.OnResolved();
+
+ // Source set itself.
+ {
+ std::ostringstream out;
+ NinjaBinaryTargetWriter writer(&target, out);
+ writer.Run();
+
+ // TODO(brettw) I think we'll need to worry about backslashes here
+ // depending if we're on actual Windows or Linux pretending to be Windows.
+ const char expected_win[] =
+ "arch = environment.x86\n"
+ "defines =\n"
+ "includes =\n"
+ "cflags =\n"
+ "cflags_c =\n"
+ "cflags_cc =\n"
+ "cflags_objc =\n"
+ "cflags_objcc =\n"
+ "\n"
+ "build obj/foo/bar.input1.obj: tc_cxx ../../foo/input1.cc\n"
+ "build obj/foo/bar.input2.obj: tc_cxx ../../foo/input2.cc\n"
+ "\n"
+ "build obj/foo/bar.stamp: tc_stamp obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n";
+ std::string out_str = out.str();
+#if defined(OS_WIN)
+ std::replace(out_str.begin(), out_str.end(), '\\', '/');
+#endif
+ EXPECT_EQ(expected_win, out_str);
+ }
+
+ // A shared library that depends on the source set.
+ Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
+ shlib_target.set_output_type(Target::SHARED_LIBRARY);
+ shlib_target.deps().push_back(&target);
+ shlib_target.OnResolved();
+
+ {
+ std::ostringstream out;
+ NinjaBinaryTargetWriter writer(&shlib_target, out);
+ writer.Run();
+
+ // TODO(brettw) I think we'll need to worry about backslashes here
+ // depending if we're on actual Windows or Linux pretending to be Windows.
+ const char expected_win[] =
+ "arch = environment.x86\n"
+ "defines =\n"
+ "includes =\n"
+ "cflags =\n"
+ "cflags_c =\n"
+ "cflags_cc =\n"
+ "cflags_objc =\n"
+ "cflags_objcc =\n"
+ "\n"
+ "\n"
+ "manifests = obj/foo/shlib.intermediate.manifest\n"
+ "ldflags = /MANIFEST /ManifestFile:obj/foo/shlib.intermediate.manifest\n"
+ "libs =\n"
+ "build shlib.dll shlib.dll.lib: tc_solink obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n"
+ " soname = shlib.dll\n"
+ " lib = shlib.dll\n"
+ " dll = shlib.dll\n"
+ " implibflag = /IMPLIB:shlib.dll.lib\n\n";
+ std::string out_str = out.str();
+#if defined(OS_WIN)
+ std::replace(out_str.begin(), out_str.end(), '\\', '/');
+#endif
+ EXPECT_EQ(expected_win, out_str);
+ }
+}
diff --git a/tools/gn/ninja_helper.cc b/tools/gn/ninja_helper.cc
index 9af5c38..d90b698 100644
--- a/tools/gn/ninja_helper.cc
+++ b/tools/gn/ninja_helper.cc
@@ -132,6 +132,7 @@ OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
const char* extension;
if (target->output_type() == Target::GROUP ||
+ target->output_type() == Target::SOURCE_SET ||
target->output_type() == Target::COPY_FILES ||
target->output_type() == Target::CUSTOM) {
extension = "stamp";
diff --git a/tools/gn/ninja_script_target_writer_unittest.cc b/tools/gn/ninja_script_target_writer_unittest.cc
index 9fa018e..2057f07 100644
--- a/tools/gn/ninja_script_target_writer_unittest.cc
+++ b/tools/gn/ninja_script_target_writer_unittest.cc
@@ -113,6 +113,10 @@ TEST(NinjaScriptTargetWriter, InvokeOverSources) {
// Windows.
{
+ // Note: we use forward slashes here so that the output will be the same on
+ // Linux and Windows.
+ setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
+ "C:/python/python.exe")));
setup.settings()->set_target_os(Settings::WIN);
std::ostringstream out;
@@ -124,11 +128,11 @@ TEST(NinjaScriptTargetWriter, InvokeOverSources) {
const char expected_win[] =
"arch = environment.x86\n"
"rule __foo_bar___rule\n"
- " command = $pythonpath gyp-win-tool action-wrapper $arch __foo_bar___rule.$unique_name.rsp\n"
+ " command = C:/python/python.exe gyp-win-tool action-wrapper $arch __foo_bar___rule.$unique_name.rsp\n"
" description = CUSTOM //foo:bar()\n"
" restat = 1\n"
" rspfile = __foo_bar___rule.$unique_name.rsp\n"
- " rspfile_content = $pythonpath ../../foo/script.py -i ${source} \"--out=foo$ bar${source_name_part}.o\"\n"
+ " rspfile_content = C:/python/python.exe ../../foo/script.py -i ${source} \"--out=foo$ bar${source_name_part}.o\"\n"
"\n"
"build input1.out: __foo_bar___rule../../foo/input1.txt | ../../foo/included.txt\n"
" unique_name = 0\n"
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 82a022e..3eccb18 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -79,7 +79,8 @@ void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
writer.Run();
} else if (target->output_type() == Target::EXECUTABLE ||
target->output_type() == Target::STATIC_LIBRARY ||
- target->output_type() == Target::SHARED_LIBRARY) {
+ target->output_type() == Target::SHARED_LIBRARY ||
+ target->output_type() == Target::SOURCE_SET) {
NinjaBinaryTargetWriter writer(target, file);
writer.Run();
} else {
diff --git a/tools/gn/output_file.h b/tools/gn/output_file.h
index 9c5e4b2..2e7a0ce 100644
--- a/tools/gn/output_file.h
+++ b/tools/gn/output_file.h
@@ -33,9 +33,12 @@ class OutputFile {
bool operator!=(const OutputFile& other) const {
return value_ != other.value_;
}
+ bool operator<(const OutputFile& other) const {
+ return value_ < other.value_;
+ }
private:
std::string value_;
};
-#endif
+#endif // TOOLS_GN_OUTPUT_FILE_H_
diff --git a/tools/gn/secondary/build/config/BUILDCONFIG.gn b/tools/gn/secondary/build/config/BUILDCONFIG.gn
index e48f896..d2e609d 100644
--- a/tools/gn/secondary/build/config/BUILDCONFIG.gn
+++ b/tools/gn/secondary/build/config/BUILDCONFIG.gn
@@ -162,7 +162,7 @@ set_sources_assignment_filter(sources_assignment_filter)
if (is_component_build) {
component_mode = "shared_library"
} else {
- component_mode = "static_library"
+ component_mode = "source_set"
}
toolkit_uses_gtk = is_linux
@@ -266,6 +266,10 @@ set_defaults("shared_library") {
}
}
+set_defaults("source_set") {
+ configs = native_compiler_configs
+}
+
# ==============================================================================
# TOOLCHAIN SETUP
# ==============================================================================
diff --git a/tools/gn/secondary/build/toolchain/nacl/BUILD.gn b/tools/gn/secondary/build/toolchain/nacl/BUILD.gn
index 2e2fc7f..b5fe248 100644
--- a/tools/gn/secondary/build/toolchain/nacl/BUILD.gn
+++ b/tools/gn/secondary/build/toolchain/nacl/BUILD.gn
@@ -38,6 +38,18 @@ toolchain("x86_newlib") {
#pool = "link_pool"
}
+ if (is_win) {
+ tool("stamp") {
+ command = "$python_path gyp-win-tool stamp \$out"
+ description = "STAMP \$out"
+ }
+ } else {
+ tool("stamp") {
+ command = "touch \$out"
+ description = "STAMP \$out"
+ }
+ }
+
toolchain_args() {
is_nacl = true
diff --git a/tools/gn/secondary/chrome/BUILD.gn b/tools/gn/secondary/chrome/BUILD.gn
index 133bf82..4e6df28 100644
--- a/tools/gn/secondary/chrome/BUILD.gn
+++ b/tools/gn/secondary/chrome/BUILD.gn
@@ -96,7 +96,7 @@ static_library("common") {
}
# TODO(brettw) move to browser/devtools/BUILD.gn
-static_library("debugger") {
+source_set("debugger") {
sources = [
"browser/devtools/adb/android_rsa.cc",
"browser/devtools/adb/android_rsa.h",
@@ -167,15 +167,15 @@ static_library("debugger") {
}
-static_library("plugin") {
+source_set("plugin") {
external = true
}
-static_library("renderer") {
+source_set("renderer") {
external = true
}
-static_library("utility") {
+source_set("utility") {
external = true
}
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index ec35a05..a380156 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -188,7 +188,8 @@ void Target::PullDependentTargetInfo(std::set<const Config*>* unique_configs) {
// Direct dependent libraries.
if (dep->output_type() == STATIC_LIBRARY ||
- dep->output_type() == SHARED_LIBRARY)
+ dep->output_type() == SHARED_LIBRARY ||
+ dep->output_type() == SOURCE_SET)
inherited_libraries_.insert(dep);
// Inherited libraries and flags are inherited across static library
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 92e8fe0..1bb51a6 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -32,6 +32,7 @@ class Target : public Item {
EXECUTABLE,
SHARED_LIBRARY,
STATIC_LIBRARY,
+ SOURCE_SET,
COPY_FILES,
CUSTOM,
};
@@ -175,9 +176,9 @@ class Target : public Item {
bool external_;
- // Libraries from transitive deps. Libraries need to be linked only
- // with the end target (executable, shared library). These do not get
- // pushed beyond shared library boundaries.
+ // Static libraries and source sets from transitive deps. These things need
+ // to be linked only with the end target (executable, shared library). These
+ // do not get pushed beyond shared library boundaries.
std::set<const Target*> inherited_libraries_;
// These libs and dirs are inherited from statically linked deps and all
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index b32bbe1..f32245a 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -100,6 +100,10 @@ void TargetGenerator::GenerateTarget(Scope* scope,
BinaryTargetGenerator generator(target, scope, function_token,
Target::SHARED_LIBRARY, err);
generator.Run();
+ } else if (output_type == functions::kSourceSet) {
+ BinaryTargetGenerator generator(target, scope, function_token,
+ Target::SOURCE_SET, err);
+ generator.Run();
} else if (output_type == functions::kStaticLibrary) {
BinaryTargetGenerator generator(target, scope, function_token,
Target::STATIC_LIBRARY, err);