summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-16 16:46:14 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-16 16:46:14 +0000
commite3730f817be9693b5ad140a002abff4cbaf674ec (patch)
treeb0aa15b4099915ca23a673a11356b73db2321844
parent5fb863442b955f859bee4baf67aeeaf4fdc4b6c4 (diff)
downloadchromium_src-e3730f817be9693b5ad140a002abff4cbaf674ec.zip
chromium_src-e3730f817be9693b5ad140a002abff4cbaf674ec.tar.gz
chromium_src-e3730f817be9693b5ad140a002abff4cbaf674ec.tar.bz2
GYP generator for GN.
This creates a GYP generator for GN. The GN build is run twice, once for debug and once for release mode. The resulting targets are paired to find the debug/release version of each one, and we write out the results as a GYP file. Since a GN build can change anything based on the debug/release status, including changing the file list, and GYP can't there are a bunch of checks to make sure that the source files and deps don't vary between the debug and release version of the same target. I split the Setup class apart so I can make duplicate Setup classes base on an original one (I use this to configure a release build based on the debug one). I added some copy constructors to the necessary classes so this would work. This reads in the GYP_DEFINES and configures the GN build in the same way. The mapping between GYP_DEFINES and gl flags is hardcoded. I had to write some parsing code for the GYP_DEFINES which is unfortunate. I added a new GN variable "gyp_file" for targets to set the GYP file that they should be written to. I added a parameter for the Windows SDK path that matches the GYP build. This removes the old "GYP" command. I commented out all of the grit rules. These aren't helping anything right now and just slow down testing. BUG=307571 R=scottmg@chromium.org Review URL: https://codereview.chromium.org/26561005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228933 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--tools/gn/BUILD.gn12
-rw-r--r--tools/gn/args.cc15
-rw-r--r--tools/gn/args.h4
-rw-r--r--tools/gn/build_settings.cc16
-rw-r--r--tools/gn/build_settings.h17
-rw-r--r--tools/gn/command_gyp.cc549
-rw-r--r--tools/gn/escape.cc6
-rw-r--r--tools/gn/escape.h4
-rw-r--r--tools/gn/gn.gyp6
-rw-r--r--tools/gn/gyp_binary_target_writer.cc291
-rw-r--r--tools/gn/gyp_binary_target_writer.h47
-rw-r--r--tools/gn/gyp_helper.cc105
-rw-r--r--tools/gn/gyp_helper.h41
-rw-r--r--tools/gn/gyp_target_writer.cc69
-rw-r--r--tools/gn/gyp_target_writer.h47
-rw-r--r--tools/gn/ninja_binary_target_writer.cc11
-rw-r--r--tools/gn/ninja_build_writer.cc2
-rw-r--r--tools/gn/ninja_target_writer.cc7
-rw-r--r--tools/gn/secondary/BUILD.gn2
-rw-r--r--tools/gn/secondary/build/config/BUILDCONFIG.gn2
-rw-r--r--tools/gn/secondary/build/config/win/BUILD.gn14
-rw-r--r--tools/gn/secondary/chrome/BUILD.gn212
-rw-r--r--tools/gn/secondary/net/BUILD.gn10
-rw-r--r--tools/gn/secondary/testing/BUILD.gn3
-rw-r--r--tools/gn/setup.cc95
-rw-r--r--tools/gn/setup.h67
-rw-r--r--tools/gn/source_dir.cc7
-rw-r--r--tools/gn/source_file.cc18
-rw-r--r--tools/gn/target.h5
-rw-r--r--tools/gn/target_generator.cc12
-rw-r--r--tools/gn/target_generator.h1
-rw-r--r--tools/gn/variables.cc7
-rw-r--r--tools/gn/variables.h4
33 files changed, 1203 insertions, 505 deletions
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index 9ff4081..3cbb7ff 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -1,3 +1,9 @@
+# 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.
+
+gyp_file = "gn.gyp"
+
static_library("gn_lib") {
sources = [
"args.cc",
@@ -46,6 +52,12 @@ static_library("gn_lib") {
"function_write_file.cc",
"group_target_generator.cc",
"group_target_generator.h",
+ "gyp_binary_target_writer.cc",
+ "gyp_binary_target_writer.h",
+ "gyp_helper.cc",
+ "gyp_helper.h",
+ "gyp_target_writer.cc",
+ "gyp_target_writer.h",
"import_manager.cc",
"import_manager.h",
"input_conversion.cc",
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
index 64069f4..18afaa6 100644
--- a/tools/gn/args.cc
+++ b/tools/gn/args.cc
@@ -52,14 +52,25 @@ const char kBuildArgs_Help[] =
Args::Args() {
}
+Args::Args(const Args& other)
+ : overrides_(other.overrides_),
+ all_overrides_(other.all_overrides_),
+ declared_arguments_(other.declared_arguments_) {
+}
+
Args::~Args() {
}
+void Args::AddArgOverride(const char* name, const Value& value) {
+ overrides_[base::StringPiece(name)] = value;
+ all_overrides_[base::StringPiece(name)] = value;
+}
+
void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) {
for (Scope::KeyValueMap::const_iterator i = overrides.begin();
i != overrides.end(); ++i) {
- overrides_.insert(*i);
- all_overrides_.insert(*i);
+ overrides_[i->first] = i->second;
+ all_overrides_[i->first] = i->second;
}
}
diff --git a/tools/gn/args.h b/tools/gn/args.h
index d3225ca..5abc127 100644
--- a/tools/gn/args.h
+++ b/tools/gn/args.h
@@ -23,10 +23,12 @@ extern const char kBuildArgs_Help[];
class Args {
public:
Args();
+ Args(const Args& other);
~Args();
// Specifies overrides of the build arguments. These are normally specified
// on the command line.
+ void AddArgOverride(const char* name, const Value& value);
void AddArgOverrides(const Scope::KeyValueMap& overrides);
// Sets up the root scope for a toolchain. This applies the default system
@@ -82,7 +84,7 @@ class Args {
// the user set variables on the command line that are not used anywhere.
mutable Scope::KeyValueMap declared_arguments_;
- DISALLOW_COPY_AND_ASSIGN(Args);
+ Args& operator=(const Args& other); // Disallow assignment.
};
#endif // TOOLS_GN_ARGS_H_
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index b6ae49c..2ac7389 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -13,6 +13,22 @@ BuildSettings::BuildSettings()
toolchain_manager_(this) {
}
+BuildSettings::BuildSettings(const BuildSettings& other)
+ : root_path_(other.root_path_),
+ root_path_utf8_(other.root_path_utf8_),
+ secondary_source_path_(other.secondary_source_path_),
+ using_external_generator_(other.using_external_generator_),
+ python_path_(other.python_path_),
+ build_config_file_(other.build_config_file_),
+ build_dir_(other.build_dir_),
+ build_to_source_dir_string_(other.build_to_source_dir_string_),
+ build_args_(other.build_args_),
+ target_resolved_callback_(), // Don't copy.
+ item_tree_(),
+ target_manager_(this),
+ toolchain_manager_(this) {
+}
+
BuildSettings::~BuildSettings() {
}
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h
index 7622057..fc175df 100644
--- a/tools/gn/build_settings.h
+++ b/tools/gn/build_settings.h
@@ -25,9 +25,9 @@ class OutputFile;
class BuildSettings {
public:
typedef base::Callback<void(const Target*)> TargetResolvedCallback;
- typedef std::multimap<Label, OutputFile> AdditionalLibsMap;
BuildSettings();
+ BuildSettings(const BuildSettings& other);
~BuildSettings();
// Absolute path of the source root on the local system. Everything is
@@ -106,18 +106,6 @@ class BuildSettings {
target_resolved_callback_ = cb;
}
- // When using_external_generator is set, this will be populated with
- // known linker dependencies for each target. The mapping is from .ninja
- // files to library (.a, .so, .dll, etc.) files needed by that target.
- //
- // When generating a GN binary that depends on some GYP-generated targets,
- // we need to know the GYP target's recursive set of libraries so we can in
- // turn link them into the final binary.
- AdditionalLibsMap& external_link_deps() { return external_link_deps_; }
- const AdditionalLibsMap& external_link_deps() const {
- return external_link_deps_;
- }
-
private:
base::FilePath root_path_;
std::string root_path_utf8_;
@@ -129,7 +117,6 @@ class BuildSettings {
SourceDir build_dir_;
std::string build_to_source_dir_string_;
Args build_args_;
- AdditionalLibsMap external_link_deps_;
TargetResolvedCallback target_resolved_callback_;
@@ -138,7 +125,7 @@ class BuildSettings {
mutable TargetManager target_manager_;
mutable ToolchainManager toolchain_manager_;
- DISALLOW_COPY_AND_ASSIGN(BuildSettings);
+ BuildSettings& operator=(const BuildSettings& other); // Disallow.
};
#endif // TOOLS_GN_BUILD_SETTINGS_H_
diff --git a/tools/gn/command_gyp.cc b/tools/gn/command_gyp.cc
index bc5ab5d..9c00513 100644
--- a/tools/gn/command_gyp.cc
+++ b/tools/gn/command_gyp.cc
@@ -2,357 +2,313 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <algorithm>
-#include <fstream>
+#include <iostream>
+#include <map>
+#include <utility>
+#include <vector>
-#include "base/atomicops.h"
-#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/process/launch.h"
+#include "base/environment.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "tools/gn/build_settings.h"
#include "tools/gn/commands.h"
#include "tools/gn/err.h"
-#include "tools/gn/filesystem_utils.h"
-#include "tools/gn/ninja_target_writer.h"
-#include "tools/gn/ninja_writer.h"
-#include "tools/gn/output_file.h"
-#include "tools/gn/path_output.h"
+#include "tools/gn/gyp_helper.h"
+#include "tools/gn/gyp_target_writer.h"
+#include "tools/gn/item_node.h"
+#include "tools/gn/location.h"
#include "tools/gn/setup.h"
+#include "tools/gn/source_file.h"
#include "tools/gn/standard_out.h"
+#include "tools/gn/target.h"
namespace commands {
namespace {
-// Suppress output on success.
-const char kSwitchQuiet[] = "q";
-
-// Skip actually executing GYP. This is for when you're working on the GN
-// build and don't want to wait for GYP to regenerate. All GN files are
-// regenerated, but the GYP ones are not.
-const char kSwitchNoGyp[] = "no-gyp";
-
-// Where to have GYP write its outputs.
-const char kDirOut[] = "out.gn";
-
-// We'll do the GN build to here.
-const char kBuildSourceDir[] = "//out.gn/Debug/";
-
-// File that GYP will write dependency information to.
-const char kGypDepsSourceFileName[] = "//out.gn/gyp_deps.txt";
-
-void TargetResolvedCallback(base::subtle::Atomic32* write_counter,
- const Target* target) {
- base::subtle::NoBarrier_AtomicIncrement(write_counter, 1);
- NinjaTargetWriter::RunAndWriteFile(target);
-}
-
-bool SimpleNinjaParse(const std::string& data,
- std::set<std::string>* subninjas,
- size_t* first_subninja_offset) {
- const size_t kSubninjaPrefixLen = 10;
- const char kSubninjaPrefix[kSubninjaPrefixLen + 1] = "\nsubninja ";
-
- *first_subninja_offset = std::string::npos;
- size_t next_subninja = 0;
- while ((next_subninja = data.find(kSubninjaPrefix, next_subninja)) !=
- std::string::npos) {
- if (*first_subninja_offset == std::string::npos)
- *first_subninja_offset = next_subninja;
-
- size_t line_end = data.find('\n', next_subninja + 1);
- if (line_end == std::string::npos)
- return false;
-
- std::string filename = data.substr(
- next_subninja + kSubninjaPrefixLen,
- line_end - next_subninja - kSubninjaPrefixLen);
- TrimWhitespaceASCII(filename, TRIM_ALL, &filename);
-#if defined(OS_WIN)
- // We always want our array to use forward slashes.
- std::replace(filename.begin(), filename.end(), '\\', '/');
-#endif
- subninjas->insert(filename);
-
- next_subninja = line_end;
+typedef GypTargetWriter::TargetPair TargetPair;
+typedef std::map<Label, TargetPair> CorrelatedTargetsMap;
+typedef std::map<SourceFile, std::vector<TargetPair> > GroupedTargetsMap;
+typedef std::map<std::string, std::string> StringStringMap;
+
+// Groups targets sharing the same label between debug and release.
+void CorrelateTargets(const std::vector<const Target*>& debug_targets,
+ const std::vector<const Target*>& release_targets,
+ CorrelatedTargetsMap* correlated) {
+ for (size_t i = 0; i < debug_targets.size(); i++) {
+ const Target* target = debug_targets[i];
+ (*correlated)[target->label()].debug = target;
+ }
+ for (size_t i = 0; i < release_targets.size(); i++) {
+ const Target* target = release_targets[i];
+ (*correlated)[target->label()].release = target;
}
- return *first_subninja_offset != std::string::npos;
}
-bool FixupBuildNinja(const BuildSettings* build_settings,
- const base::FilePath& buildfile) {
- std::string contents;
- if (!base::ReadFileToString(buildfile, &contents)) {
- Err(Location(), "Could not load " + FilePathToUTF8(buildfile))
- .PrintToStdout();
+// Verifies that both debug and release variants match. They can differ only
+// by flags.
+bool EnsureTargetsMatch(const TargetPair& pair, Err* err) {
+ // Check that both debug and release made this target.
+ if (!pair.debug || !pair.release) {
+ const Target* non_null_one = pair.debug ? pair.debug : pair.release;
+ *err = Err(Location(), "The debug and release builds did not both generate "
+ "a target with the name\n" +
+ non_null_one->label().GetUserVisibleName(true));
return false;
}
- std::set<std::string> subninjas;
- size_t first_subninja_offset = 0;
- if (!SimpleNinjaParse(contents, &subninjas, &first_subninja_offset)) {
- Err(Location(), "Could not parse " + FilePathToUTF8(buildfile))
- .PrintToStdout();
+ // Check the flags that determine if and where we write the GYP file.
+ if (pair.debug->item_node()->should_generate() !=
+ pair.release->item_node()->should_generate() ||
+ pair.debug->external() != pair.release->external() ||
+ pair.debug->gyp_file() != pair.release->gyp_file()) {
+ *err = Err(Location(), "The metadata for the target\n" +
+ pair.debug->label().GetUserVisibleName(true) +
+ "\ndoesn't match between the debug and release builds.");
return false;
}
- // Write toolchain files.
- std::vector<const Settings*> all_settings;
- if (!NinjaWriter::RunAndWriteToolchainFiles(
- build_settings, subninjas, &all_settings))
+ // Check that the sources match.
+ if (pair.debug->sources().size() != pair.release->sources().size()) {
+ *err = Err(Location(), "The source file count for the target\n" +
+ pair.debug->label().GetUserVisibleName(true) +
+ "\ndoesn't have the same number of files between the debug and "
+ "release builds.");
return false;
+ }
+ for (size_t i = 0; i < pair.debug->sources().size(); i++) {
+ if (pair.debug->sources()[i] != pair.release->sources()[i]) {
+ *err = Err(Location(), "The debug and release version of the target \n" +
+ pair.debug->label().GetUserVisibleName(true) +
+ "\ndon't agree on the file\n" +
+ pair.debug->sources()[i].value());
+ return false;
+ }
+ }
- // Copy first part of buildfile to the output.
- std::ofstream file;
- file.open(FilePathToUTF8(buildfile).c_str(),
- std::ios_base::out | std::ios_base::binary);
- if (file.fail()) {
- Err(Location(), "Could not write " + FilePathToUTF8(buildfile))
- .PrintToStdout();
+ // Check that the deps match.
+ if (pair.debug->deps().size() != pair.release->deps().size()) {
+ *err = Err(Location(), "The source file count for the target\n" +
+ pair.debug->label().GetUserVisibleName(true) +
+ "\ndoesn't have the same number of deps between the debug and "
+ "release builds.");
return false;
}
- file.write(contents.data(), first_subninja_offset);
-
- // Add refs for our toolchains to the original build.ninja.
- NinjaHelper helper(build_settings);
- PathOutput path_output(build_settings->build_dir(), ESCAPE_NINJA, true);
- file << "\n# GN-added toolchain files.\n";
- for (size_t i = 0; i < all_settings.size(); i++) {
- file << "subninja ";
- path_output.WriteFile(file,
- helper.GetNinjaFileForToolchain(all_settings[i]));
- file << std::endl;
+ for (size_t i = 0; i < pair.debug->deps().size(); i++) {
+ if (pair.debug->deps()[i]->label() != pair.release->deps()[i]->label()) {
+ *err = Err(Location(), "The debug and release version of the target \n" +
+ pair.debug->label().GetUserVisibleName(true) +
+ "\ndon't agree on the dep\n" +
+ pair.debug->deps()[i]->label().GetUserVisibleName(true));
+ return false;
+ }
}
- file << "\n# GYP-written subninjas.";
- // Write remaining old subninjas from original file.
- file.write(&contents[first_subninja_offset],
- contents.size() - first_subninja_offset);
return true;
}
-bool RunGyp(const BuildSettings* build_settings) {
- if (!CommandLine::ForCurrentProcess()->HasSwitch(kSwitchQuiet))
- OutputString("Running GYP...\n");
-
- const base::FilePath& python_path = build_settings->python_path();
-
- // Construct the command line. Note that AppendArgPath and AppendSwitchPath
- // don't preserve the relative ordering, and we need the python file to be
- // first, so we have to convert switch values to strings before appending.
- //
- // Note that GYP will get confused if this path is quoted, so don't quote it
- // and hope that there are no spaces!
- CommandLine cmdline(python_path);
- cmdline.AppendArgPath(
- build_settings->GetFullPath(SourceFile("//build/gyp_chromium.py")));
-
- // Override the default output directory so we can coexist in parallel
- // with a normal Ninja GYP build.
- cmdline.AppendArg("-G");
- cmdline.AppendArg(std::string("output_dir=") + kDirOut);
-
- // Force the Ninja generator.
- cmdline.AppendArg("-f");
- cmdline.AppendArg("ninja");
-
- // Write deps for libraries so we can pick them up.
- cmdline.AppendArg("-G");
- cmdline.AppendArg("link_deps_file=" + FilePathToUTF8(
- build_settings->GetFullPath(SourceFile(kGypDepsSourceFileName))));
-
- std::string output;
- if (!base::GetAppOutput(cmdline, &output)) {
- Err(Location(), "GYP execution failed.", output).PrintToStdout();
- return false;
+// Python uses shlex.split, which we partially emulate here.
+//
+// Advances to the next "word" in a GYP_DEFINES entry. This is something
+// separated by whitespace or '='. We allow backslash escaping and quoting.
+// The return value will be the index into the array immediately following the
+// word, and the contents of the word will be placed into |*word|.
+size_t GetNextGypDefinesWord(const std::string& defines,
+ size_t cur,
+ std::string* word) {
+ size_t i = cur;
+ bool is_quoted = false;
+ if (cur < defines.size() && defines[cur] == '"') {
+ i++;
+ is_quoted = true;
}
- return true;
+
+ for (; i < defines.size(); i++) {
+ // Handle certain escape sequences: \\, \", \<space>.
+ if (defines[i] == '\\' && i < defines.size() - 1 &&
+ (defines[i + 1] == '\\' ||
+ defines[i + 1] == ' ' ||
+ defines[i + 1] == '=' ||
+ defines[i + 1] == '"')) {
+ i++;
+ word->push_back(defines[i]);
+ continue;
+ }
+ if (is_quoted && defines[i] == '"') {
+ // Got to the end of the quoted sequence.
+ return i + 1;
+ }
+ if (!is_quoted && (defines[i] == ' ' || defines[i] == '=')) {
+ return i;
+ }
+ word->push_back(defines[i]);
+ }
+ return i;
}
-} // namespace
+// Advances to the beginning of the next word, or the size of the string if
+// the end was encountered.
+size_t AdvanceToNextGypDefinesWord(const std::string& defines, size_t cur) {
+ while (cur < defines.size() && defines[cur] == ' ')
+ cur++;
+ return cur;
+}
-// Converts a GYP qualified target which looks like:
-// "/home/you/src/third_party/icu/icu.gyp:icui18n#target" to a GN label like
-// "//third_party/icu:icui18n". On failure returns an empty label and sets the
-// error.
-Label GypQualifiedTargetToLabel(const std::string& source_root_prefix,
- const base::StringPiece& target,
- Err* err) {
- // Prefix should end in canonical path separator.
- const char kSep = static_cast<char>(base::FilePath::kSeparators[0]);
- DCHECK(source_root_prefix[source_root_prefix.size() - 1] == kSep);
-
- if (!target.starts_with(source_root_prefix)) {
- *err = Err(Location(), "GYP deps parsing failed.",
- "The line was \"" + target.as_string() + "\" and it should have "
- "started with \"" + source_root_prefix + "\"");
- return Label();
- }
+// The GYP defines looks like:
+// component=shared_library
+// component=shared_library foo=1
+// component=shared_library foo=1 windows_sdk_dir="C:\Program Files\..."
+StringStringMap GetGypDefines() {
+ StringStringMap result;
- size_t begin = source_root_prefix.size();
- size_t colon = target.find(':', begin);
- if (colon == std::string::npos) {
- *err = Err(Location(), "Expected :", target.as_string());
- return Label();
- }
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string defines;
+ if (!env->GetVar("GYP_DEFINES", &defines) || defines.empty())
+ return result;
- size_t octothorpe = target.find('#', colon);
- if (octothorpe == std::string::npos) {
- *err = Err(Location(), "Expected #", target.as_string());
- return Label();
- }
+ size_t cur = 0;
+ while (cur < defines.size()) {
+ std::string key;
+ cur = AdvanceToNextGypDefinesWord(defines, cur);
+ cur = GetNextGypDefinesWord(defines, cur, &key);
+
+ // The words should be separated by an equals.
+ cur = AdvanceToNextGypDefinesWord(defines, cur);
+ if (cur == defines.size())
+ break;
+ if (defines[cur] != '=')
+ continue;
+ cur++; // Skip over '='.
- // This will look like "third_party/icu/icu.gyp"
- base::StringPiece gyp_file = target.substr(begin, colon - begin);
+ std::string value;
+ cur = AdvanceToNextGypDefinesWord(defines, cur);
+ cur = GetNextGypDefinesWord(defines, cur, &value);
- // Strip the file name from the end to get "third_party/icu".
- size_t last_sep = gyp_file.find_last_of(kSep);
- if (last_sep == std::string::npos) {
- *err = Err(Location(), "Expected path separator.", target.as_string());
- return Label();
+ result[key] = value;
}
- base::StringPiece path = gyp_file.substr(0, last_sep);
- SourceDir dir("//" + path.as_string());
-
- base::StringPiece name = target.substr(colon + 1, octothorpe - colon - 1);
- return Label(dir, name);
+ return result;
}
-// Parses the link deps file, filling the given map. Returns true on sucess.
-// On failure fills the error and returns false.
-//
-// Example format for each line:
-// /home/you/src/third_party/icu/icu.gyp:icui18n#target lib/libi18n.so
-bool ParseLinkDepsFile(const BuildSettings* build_settings,
- const std::string& contents,
- BuildSettings::AdditionalLibsMap* deps,
- Err* err) {
- std::string source_root_prefix = FilePathToUTF8(build_settings->root_path());
- source_root_prefix.push_back(base::FilePath::kSeparators[0]);
+// Returns a set of args from known GYP define values.
+Scope::KeyValueMap GetArgsFromGypDefines() {
+ StringStringMap gyp_defines = GetGypDefines();
- size_t cur = 0;
- while (cur < contents.size()) {
- // The source file is everything up to the space.
- size_t space = contents.find(' ', cur);
- if (space == std::string::npos)
- break;
- Label source(GypQualifiedTargetToLabel(
- source_root_prefix,
- base::StringPiece(&contents[cur], space - cur),
- err));
- if (source.is_null())
- return false;
+ Scope::KeyValueMap result;
- // The library file is everything between the space and EOL.
- cur = space + 1;
- size_t eol = contents.find('\n', cur);
- if (eol == std::string::npos) {
- *err = Err(Location(), "Expected newline at end of link deps file.");
- return false;
- }
- OutputFile lib(contents.substr(cur, eol - cur));
+ if (gyp_defines["component"] == "shared_library") {
+ result["is_component_build"] = Value(NULL, true);
+ } else {
+ result["is_component_build"] = Value(NULL, false);
+ }
- deps->insert(std::make_pair(source, lib));
- cur = eol + 1;
+ // Windows SDK path. GYP and the GN build use the same name.
+ const char kWinSdkPath[] = "windows_sdk_path";
+ if (gyp_defines[kWinSdkPath].empty())
+ result[kWinSdkPath] = Value(NULL, gyp_defines[kWinSdkPath]);
+
+ return result;
+}
+
+// Returns the number of targets, number of GYP files.
+std::pair<int, int> WriteGypFiles(
+ const BuildSettings& debug_settings,
+ const BuildSettings& release_settings,
+ Err* err) {
+ // Group all targets by output GYP file name.
+ std::vector<const Target*> debug_targets;
+ std::vector<const Target*> release_targets;
+ debug_settings.target_manager().GetAllTargets(&debug_targets);
+ release_settings.target_manager().GetAllTargets(&release_targets);
+
+ // Match up the debug and release version of each target by label.
+ CorrelatedTargetsMap correlated;
+ CorrelateTargets(debug_targets, release_targets, &correlated);
+
+ GypHelper helper;
+ GroupedTargetsMap grouped_targets;
+ int target_count = 0;
+ for (CorrelatedTargetsMap::iterator i = correlated.begin();
+ i != correlated.end(); ++i) {
+ const TargetPair& pair = i->second;
+ if (!EnsureTargetsMatch(pair, err))
+ return std::make_pair(0, 0);
+
+ if (!pair.debug->item_node()->should_generate())
+ continue; // Skip non-generated ones.
+ if (pair.debug->external())
+ continue; // Skip external ones.
+ if (pair.debug->gyp_file().is_null())
+ continue; // Skip ones without GYP files.
+
+ target_count++;
+ grouped_targets[helper.GetGypFileForTarget(pair.debug, err)].push_back(
+ pair);
+ if (err->has_error())
+ return std::make_pair(0, 0);
}
- return true;
+
+ // Write each GYP file.
+ for (GroupedTargetsMap::iterator i = grouped_targets.begin();
+ i != grouped_targets.end(); ++i) {
+ GypTargetWriter::WriteFile(i->first, i->second, err);
+ if (err->has_error())
+ return std::make_pair(0, 0);
+ }
+
+ return std::make_pair(target_count,
+ static_cast<int>(grouped_targets.size()));
}
+} // namespace
+
+// Suppress output on success.
+const char kSwitchQuiet[] = "q";
+
const char kGyp[] = "gyp";
const char kGyp_HelpShort[] =
- "gyp: Run GYP and then GN.";
-const char kGyp_Help[] =
- "gyp: Run GYP and then GN.\n"
- "\n"
- " Generate a hybrid GYP/GN build where some targets are generated by\n"
- " each of the tools. As long as target names and locations match between\n"
- " the two tools, they can depend on each other.\n"
- "\n"
- " When GN is run in this mode, it will not write out any targets\n"
- " annotated with \"external = true\". Otherwise, GYP targets with the\n"
- " same name and location will be overwritten.\n"
- "\n"
- " References to the GN ninja files will be inserted into the\n"
- " GYP-generated build.ninja file.\n"
- "\n"
- "Option:\n"
- " --no-gyp\n"
- " Don't actually run GYP or modify build.ninja. This is used when\n"
- " working on the GN build when it is known that no GYP files have\n"
- " changed and you want it to run faster.\n";
-
-// Note: partially duplicated from command_gen.cc.
+ "gyp: Make GYP files from GN.";
+const char kGyp_Help[] = "Doooooom.\n";
+
int RunGyp(const std::vector<std::string>& args) {
const CommandLine* cmdline = CommandLine::ForCurrentProcess();
- bool no_gyp = cmdline->HasSwitch(kSwitchNoGyp);
-
- // Deliberately leaked to avoid expensive process teardown.
- Setup* setup = new Setup;
- if (!setup->DoSetup())
- return 1;
-
- setup->build_settings().SetBuildDir(SourceDir(kBuildSourceDir));
- setup->build_settings().set_using_external_generator(true);
-
- // Provide a way for buildfiles to know we're doing a GYP build.
- /*
- Scope::KeyValueMap variable_overrides;
- variable_overrides["is_gyp"] = Value(NULL, true);
- setup->build_settings().build_args().AddArgOverrides(variable_overrides);
- */
-
- base::FilePath link_deps_file =
- setup->build_settings().GetFullPath(SourceFile(kGypDepsSourceFileName));
- if (!no_gyp)
- base::DeleteFile(link_deps_file, false);
base::TimeTicks begin_time = base::TimeTicks::Now();
- if (!no_gyp) {
- if (!RunGyp(&setup->build_settings()))
- return 1;
- }
- base::TimeTicks end_gyp_time = base::TimeTicks::Now();
- // Read in the GYP link dependencies.
- std::string link_deps_contents;
- if (!base::ReadFileToString(link_deps_file, &link_deps_contents)) {
- Err(Location(), "Couldn't load link deps file.",
- FilePathToUTF8(link_deps_file)).PrintToStdout();
+ // Deliberately leaked to avoid expensive process teardown.
+ Setup* setup_debug = new Setup;
+ if (!setup_debug->DoSetup())
return 1;
- }
- Err err;
- if (!ParseLinkDepsFile(&setup->build_settings(),
- link_deps_contents,
- &setup->build_settings().external_link_deps(), &err)) {
- err.PrintToStdout();
+ const char kIsDebug[] = "is_debug";
+ setup_debug->build_settings().build_args().AddArgOverrides(
+ GetArgsFromGypDefines());
+ setup_debug->build_settings().build_args().AddArgOverride(
+ kIsDebug, Value(NULL, true));
+
+ // Make a release build based on the debug one. We use a new directory for
+ // the build output so that they don't stomp on each other.
+ DependentSetup* setup_release = new DependentSetup(*setup_debug);
+ setup_release->build_settings().build_args().AddArgOverride(
+ kIsDebug, Value(NULL, false));
+ setup_release->build_settings().SetBuildDir(
+ SourceDir(setup_release->build_settings().build_dir().value() +
+ "gn_release.tmp/"));
+
+ // Run both debug and release builds in parallel.
+ setup_release->RunPreMessageLoop();
+ if (!setup_debug->Run())
return 1;
- }
-
- if (!cmdline->HasSwitch(kSwitchQuiet))
- OutputString("Running GN...\n");
-
- // Cause the load to also generate the ninja files for each target. We wrap
- // the writing to maintain a counter.
- base::subtle::Atomic32 write_counter = 0;
- setup->build_settings().set_target_resolved_callback(
- base::Bind(&TargetResolvedCallback, &write_counter));
-
- // Do the actual load. This will also write out the target ninja files.
- if (!setup->Run())
+ if (!setup_release->RunPostMessageLoop())
return 1;
- // Integrate with the GYP build.
- if (!no_gyp) {
- base::FilePath ninja_buildfile(setup->build_settings().GetFullPath(
- SourceFile(setup->build_settings().build_dir().value() +
- "build.ninja")));
- if (!FixupBuildNinja(&setup->build_settings(), ninja_buildfile))
- return 1;
+ Err err;
+ std::pair<int, int> counts = WriteGypFiles(setup_debug->build_settings(),
+ setup_release->build_settings(),
+ &err);
+ if (err.has_error()) {
+ err.PrintToStdout();
+ return 1;
}
// Timing info.
@@ -361,15 +317,12 @@ int RunGyp(const std::vector<std::string>& args) {
OutputString("Done. ", DECORATION_GREEN);
std::string stats = "Wrote " +
- base::IntToString(static_cast<int>(write_counter)) +
- " targets from " +
+ base::IntToString(counts.first) + " targets to " +
+ base::IntToString(counts.second) + " GYP files read from " +
base::IntToString(
- setup->scheduler().input_file_manager()->GetInputFileCount()) +
- " files in " +
- base::IntToString((end_time - end_gyp_time).InMilliseconds()) + "ms " +
- "(GYP took " +
- base::IntToString((end_gyp_time - begin_time).InMilliseconds()) +
- "ms)\n";
+ setup_debug->scheduler().input_file_manager()->GetInputFileCount())
+ + " GN files in " +
+ base::IntToString((end_time - begin_time).InMilliseconds()) + "ms\n";
OutputString(stats);
}
diff --git a/tools/gn/escape.cc b/tools/gn/escape.cc
index f00bb63..e10e24a 100644
--- a/tools/gn/escape.cc
+++ b/tools/gn/escape.cc
@@ -42,6 +42,9 @@ void EscapeStringToString(const base::StringPiece& str,
}
}
dest->push_back(' ');
+ } else if (str[i] == '\'' && (options.mode & ESCAPE_JSON)) {
+ dest->push_back('\\');
+ dest->push_back('\'');
#if defined(OS_WIN)
} else if (str[i] == '/' && options.convert_slashes) {
// Convert slashes on Windows if requested.
@@ -52,6 +55,9 @@ void EscapeStringToString(const base::StringPiece& str,
dest->push_back('\\');
dest->push_back('\\');
#endif
+ } else if (str[i] == '\\' && (options.mode & ESCAPE_JSON)) {
+ dest->push_back('\\');
+ dest->push_back('\\');
} else {
dest->push_back(str[i]);
}
diff --git a/tools/gn/escape.h b/tools/gn/escape.h
index ce0d471..1e4fa68 100644
--- a/tools/gn/escape.h
+++ b/tools/gn/escape.h
@@ -20,7 +20,9 @@ enum EscapingMode {
ESCAPE_SHELL = 2,
// For writing shell commands to ninja files.
- ESCAPE_NINJA_SHELL = ESCAPE_NINJA | ESCAPE_SHELL
+ ESCAPE_NINJA_SHELL = ESCAPE_NINJA | ESCAPE_SHELL,
+
+ ESCAPE_JSON = 4,
};
struct EscapeOptions {
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index c19d2ef..5dc4c5e 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -56,6 +56,12 @@
'function_write_file.cc',
'group_target_generator.cc',
'group_target_generator.h',
+ 'gyp_binary_target_writer.cc',
+ 'gyp_binary_target_writer.h',
+ 'gyp_helper.cc',
+ 'gyp_helper.h',
+ 'gyp_target_writer.cc',
+ 'gyp_target_writer.h',
'import_manager.cc',
'import_manager.h',
'input_conversion.cc',
diff --git a/tools/gn/gyp_binary_target_writer.cc b/tools/gn/gyp_binary_target_writer.cc
new file mode 100644
index 0000000..8cc0e6c
--- /dev/null
+++ b/tools/gn/gyp_binary_target_writer.cc
@@ -0,0 +1,291 @@
+// 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/gyp_binary_target_writer.h"
+
+#include <set>
+
+#include "tools/gn/config_values_extractors.h"
+#include "tools/gn/err.h"
+#include "tools/gn/escape.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/target.h"
+
+namespace {
+
+// This functor is used to capture the output of RecursiveTargetConfigToStream
+// in an vector.
+struct StringAccumulator {
+ StringAccumulator(std::vector<std::string>* result_in) : result(result_in) {}
+
+ void operator()(const std::string& s, std::ostream&) const {
+ result->push_back(s);
+ }
+
+ std::vector<std::string>* result;
+};
+
+// Writes the given array with the given name. The indent should be the
+// indenting for the name, the values will be indented 2 spaces from there.
+// Writes nothing if there is nothing in the array.
+void WriteArray(std::ostream& out,
+ const char* name,
+ const std::vector<std::string>& values,
+ int indent) {
+ if (values.empty())
+ return;
+
+ EscapeOptions options;
+ options.mode = ESCAPE_JSON;
+
+ std::string indent_str(indent, ' ');
+ out << indent_str << "'" << name << "': [";
+ for (size_t i = 0; i < values.size(); i++) {
+ out << " '";
+ EscapeStringToStream(out, values[i], options);
+ out << "',";
+ }
+ out << " ],\n";
+}
+
+struct StringWriter {
+ StringWriter() {
+ options.mode = ESCAPE_JSON;
+ }
+
+ void operator()(const std::string& s, std::ostream& out) const {
+ out << " '";
+ EscapeStringToStream(out, s, options);
+ out << "',";
+ }
+
+ EscapeOptions options;
+};
+
+struct IncludeWriter {
+ IncludeWriter(const GypHelper& h) : helper(h) {
+ options.mode = ESCAPE_JSON;
+ }
+
+ void operator()(const SourceDir& d, std::ostream& out) const {
+ out << " '";
+ EscapeStringToStream(out, helper.GetDirReference(d, false), options);
+ out << "',";
+ }
+
+ const GypHelper& helper;
+ EscapeOptions options;
+};
+
+// Returns the value from the already-filled in cflags_* for the optimization
+// level to set in the GYP file. Additionally, this removes the flag from the
+// given vector so we don't get duplicates.
+std::string GetVCOptimization(std::vector<std::string>* cflags) {
+ // Searches for the "/O?" option and returns the corresponding GYP value.
+ for (size_t i = 0; i < cflags->size(); i++) {
+ const std::string& cur = (*cflags)[i];
+ if (cur.size() == 3 && cur[0] == '/' && cur[1] == 'O') {
+ char level = cur[2];
+ cflags->erase(cflags->begin() + i); // Invalidates |cur|!
+ switch (level) {
+ case 'd': return "'0'";
+ case '1': return "'1'";
+ case '2': return "'2'";
+ case 'x': return "'3'";
+ default: return "'2'";
+ }
+ }
+ }
+ return "'2'"; // Default value.
+}
+
+} // namespace
+
+GypBinaryTargetWriter::GypBinaryTargetWriter(const Target* debug_target,
+ const Target* release_target,
+ std::ostream& out)
+ : GypTargetWriter(debug_target, out),
+ release_target_(release_target) {
+}
+
+GypBinaryTargetWriter::~GypBinaryTargetWriter() {
+}
+
+void GypBinaryTargetWriter::Run() {
+ out_ << " {\n";
+
+ WriteName();
+ WriteType();
+
+ out_ << " 'configurations': {\n";
+ out_ << " 'Debug': {\n";
+ WriteFlags(target_);
+ out_ << " },\n";
+ out_ << " 'Release': {\n";
+ WriteFlags(release_target_);
+ out_ << " },\n";
+ out_ << " 'Debug_x64': {},\n";
+ out_ << " 'Release_x64': {},\n";
+ out_ << " },\n";
+
+ WriteSources();
+ WriteDeps();
+
+ out_ << " },\n";
+}
+
+void GypBinaryTargetWriter::WriteName() {
+ std::string name = helper_.GetNameForTarget(target_);
+ out_ << " 'target_name': '";
+ out_ << name;
+ out_ << "',\n";
+
+ std::string product_name;
+ if (target_->output_name().empty())
+ product_name = target_->label().name();
+ else
+ product_name = name;
+
+ // TODO(brettw) GN knows not to prefix targets starting with "lib" with
+ // another "lib" on Linux, but GYP doesn't. We need to rename applicable
+ // targets here.
+
+ out_ << " 'product_name': '" << product_name << "',\n";
+}
+
+void GypBinaryTargetWriter::WriteType() {
+ out_ << " 'type': ";
+ switch (target_->output_type()) {
+ case Target::EXECUTABLE:
+ out_ << "'executable',\n";
+ break;
+ case Target::STATIC_LIBRARY:
+ out_ << "'static_library',\n";
+ break;
+ case Target::SHARED_LIBRARY:
+ out_ << "'shared_library',\n";
+ break;
+ case Target::SOURCE_SET:
+ out_ << "'static_library',\n"; // TODO(brettw) fixme.
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ if (target_->hard_dep())
+ out_ << " 'hard_dependency': 1,\n";
+}
+
+void GypBinaryTargetWriter::WriteFlags(const Target* target) {
+ WriteDefines(target);
+ WriteIncludes(target);
+ if (target->settings()->IsWin())
+ WriteVCFlags(target);
+}
+
+void GypBinaryTargetWriter::WriteDefines(const Target* target) {
+ out_ << " 'defines': [";
+ RecursiveTargetConfigToStream<std::string>(target, &ConfigValues::defines,
+ StringWriter(), out_);
+ out_ << " ],\n";
+}
+
+void GypBinaryTargetWriter::WriteIncludes(const Target* target) {
+ out_ << " 'include_dirs': [";
+ RecursiveTargetConfigToStream<SourceDir>(target, &ConfigValues::include_dirs,
+ IncludeWriter(helper_), out_);
+ out_ << " ],\n";
+}
+
+void GypBinaryTargetWriter::WriteVCFlags(const Target* target) {
+ // C flags.
+ out_ << " 'msvs_settings': {\n";
+ out_ << " 'VCCLCompilerTool': {\n";
+
+ std::vector<std::string> cflags;
+ StringAccumulator acc(&cflags);
+ RecursiveTargetConfigToStream<std::string>(target, &ConfigValues::cflags,
+ acc, out_);
+ // GYP always uses the VC optimization flag to add a /O? on Visual Studio.
+ // This can produce duplicate values. So look up the GYP value corresponding
+ // to the flags used, and set the same one.
+ std::string optimization = GetVCOptimization(&cflags);
+ WriteArray(out_, "AdditionalOptions", cflags, 14);
+ // TODO(brettw) cflags_c and cflags_cc!
+ out_ << " 'Optimization': " << optimization << ",\n";
+ out_ << " },\n";
+
+ // Linker tool stuff.
+ out_ << " 'VCLinkerTool': {\n";
+
+ // ...Library dirs.
+ EscapeOptions escape_options;
+ escape_options.mode = ESCAPE_JSON;
+ const OrderedSet<SourceDir> all_lib_dirs = target->all_lib_dirs();
+ if (!all_lib_dirs.empty()) {
+ out_ << " 'AdditionalLibraryDirectories': [";
+ for (size_t i = 0; i < all_lib_dirs.size(); i++) {
+ out_ << " '";
+ EscapeStringToStream(out_,
+ helper_.GetDirReference(all_lib_dirs[i], false),
+ escape_options);
+ out_ << "',";
+ }
+ out_ << " ],\n";
+ }
+
+ // ...Libraries.
+ const OrderedSet<std::string> all_libs = target->all_libs();
+ if (!all_libs.empty()) {
+ out_ << " 'AdditionalDependencies': [";
+ for (size_t i = 0; i < all_libs.size(); i++) {
+ out_ << " '";
+ EscapeStringToStream(out_, all_libs[i], escape_options);
+ out_ << "',";
+ }
+ out_ << " ],\n";
+ }
+
+ // ...LD flags.
+ // TODO(brettw) EnableUAC defaults to on and needs to be set. Also
+ // UACExecutionLevel and UACUIAccess depends on that and defaults to 0/false.
+ std::vector<std::string> ldflags;
+ acc.result = &ldflags;
+ RecursiveTargetConfigToStream<std::string>(target, &ConfigValues::ldflags,
+ acc, out_);
+ WriteArray(out_, "AdditionalOptions", ldflags, 14);
+ out_ << " },\n";
+
+ out_ << " },\n";
+}
+
+void GypBinaryTargetWriter::WriteSources() {
+ out_ << " 'sources': [\n";
+
+ const Target::FileList& sources = target_->sources();
+ for (size_t i = 0; i < sources.size(); i++) {
+ const SourceFile& input_file = sources[i];
+ out_ << " '" << helper_.GetFileReference(input_file) << "',\n";
+ }
+
+ out_ << " ],\n";
+}
+
+void GypBinaryTargetWriter::WriteDeps() {
+ const std::vector<const Target*>& deps = target_->deps();
+ if (deps.empty())
+ return;
+
+ EscapeOptions escape_options;
+ escape_options.mode = ESCAPE_JSON;
+
+ out_ << " 'dependencies': [\n";
+ for (size_t i = 0; i < deps.size(); i++) {
+ out_ << " '";
+ EscapeStringToStream(out_, helper_.GetFullRefForTarget(deps[i]),
+ escape_options);
+ out_ << "',\n";
+ }
+ out_ << " ],\n";
+}
diff --git a/tools/gn/gyp_binary_target_writer.h b/tools/gn/gyp_binary_target_writer.h
new file mode 100644
index 0000000..625a306
--- /dev/null
+++ b/tools/gn/gyp_binary_target_writer.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef TOOLS_GN_GYP_BINARY_TARGET_WRITER_H_
+#define TOOLS_GN_GYP_BINARY_TARGET_WRITER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "tools/gn/gyp_target_writer.h"
+#include "tools/gn/toolchain.h"
+
+// Writes a portion of a .gyp file for a binary target type (an executable, a
+// shared library, or a static library).
+class GypBinaryTargetWriter : public GypTargetWriter {
+ public:
+ GypBinaryTargetWriter(const Target* debug_target,
+ const Target* release_target,
+ std::ostream& out);
+ virtual ~GypBinaryTargetWriter();
+
+ virtual void Run() OVERRIDE;
+
+ private:
+ void WriteName();
+ void WriteType();
+
+ // The flags can vary between debug and release, so we must pass in the
+ // correct debug or release target to the functions.
+ void WriteFlags(const Target* target);
+ void WriteDefines(const Target* target);
+ void WriteIncludes(const Target* target);
+ void WriteVCFlags(const Target* target);
+
+ void WriteSources();
+ void WriteDeps();
+
+ // The normal |target_| in the base class stores the debug version.
+ const Target* release_target_;
+
+ DISALLOW_COPY_AND_ASSIGN(GypBinaryTargetWriter);
+};
+
+#endif // TOOLS_GN_GYP_BINARY_TARGET_WRITER_H_
+
diff --git a/tools/gn/gyp_helper.cc b/tools/gn/gyp_helper.cc
new file mode 100644
index 0000000..f69ed8f
--- /dev/null
+++ b/tools/gn/gyp_helper.cc
@@ -0,0 +1,105 @@
+// 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/gyp_helper.h"
+
+#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/source_file.h"
+#include "tools/gn/target.h"
+#include "tools/gn/toolchain.h"
+
+GypHelper::GypHelper() {
+}
+
+GypHelper::~GypHelper() {
+}
+
+SourceFile GypHelper::GetGypFileForTarget(const Target* target,
+ Err* err) const {
+ // Use the manually specified one if its there.
+ if (!target->gyp_file().is_null())
+ return target->gyp_file();
+
+ // Otherwise inherit the directory name.
+ const std::string& dir = target->label().dir().value();
+ size_t last_slash = dir.size() - 1;
+ std::string dir_name;
+ if (last_slash > 0) {
+ size_t next_to_last_slash = dir.rfind('/', last_slash - 1);
+ if (next_to_last_slash != std::string::npos) {
+ dir_name = dir.substr(next_to_last_slash + 1,
+ last_slash - next_to_last_slash - 1);
+ }
+ }
+ if (dir_name.empty()) {
+ *err = Err(Location(), "Need to specify a gyp_file value for " +
+ target->label().GetUserVisibleName(false) + "\n"
+ "since I can't make up one with no name.");
+ return SourceFile();
+ }
+
+ return SourceFile(dir + dir_name + ".gyp");
+}
+
+std::string GypHelper::GetNameForTarget(const Target* target) const {
+ const Toolchain* toolchain = target->settings()->toolchain();
+ if (toolchain->is_default())
+ return target->label().name(); // Default toolchain has no suffix.
+ return target->label().name() + "_" + toolchain->label().name();
+}
+
+std::string GypHelper::GetFullRefForTarget(const Target* target) const {
+ Err err;
+ SourceFile gypfile = GetGypFileForTarget(target, &err);
+ CHECK(gypfile.is_source_absolute()) <<
+ "GYP files should not be system-absolute: " << gypfile.value();
+
+ std::string ret("<(DEPTH)/");
+ // Trim off the leading double-slash.
+ ret.append(&gypfile.value()[2], gypfile.value().size() - 2);
+ ret.push_back(':');
+ ret.append(GetNameForTarget(target));
+
+ return ret;
+}
+
+std::string GypHelper::GetFileReference(const SourceFile& file) const {
+ std::string ret;
+ if (file.is_null())
+ return ret;
+
+ // Use FilePath's resolver to get the system paths out (on Windows this
+ // requires special handling). Since it's absolute, it doesn't matter what
+ // we pass in as the source root.
+ if (file.is_system_absolute())
+ return FilePathToUTF8(file.Resolve(base::FilePath()));
+
+ // Source root relative, strip the "//".
+ ret.assign("<(DEPTH)/");
+ ret.append(&file.value()[2], file.value().size() - 2);
+ return ret;
+}
+
+std::string GypHelper::GetDirReference(const SourceDir& dir,
+ bool include_slash) const {
+ std::string ret;
+ if (dir.is_null())
+ return ret;
+
+ if (dir.is_system_absolute()) {
+ ret = FilePathToUTF8(dir.Resolve(base::FilePath()));
+ } else {
+ ret.assign("<(DEPTH)/");
+ ret.append(&dir.value()[2], dir.value().size() - 2);
+ }
+
+ // Optionally trim the slash off the end.
+ if (!ret.empty() && !include_slash &&
+ (ret[ret.size() - 1] == '/' || ret[ret.size() - 1] == '\\'))
+ ret.resize(ret.size() - 1);
+
+ return ret;
+}
diff --git a/tools/gn/gyp_helper.h b/tools/gn/gyp_helper.h
new file mode 100644
index 0000000..d3b15ec
--- /dev/null
+++ b/tools/gn/gyp_helper.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef TOOLS_GN_GYP_HELPER_H_
+#define TOOLS_GN_GYP_HELPER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class Err;
+class SourceDir;
+class SourceFile;
+class Target;
+
+// Danger this class is NOT threadsafe and reads the targets in a
+// non-threadsafe way, so this should only be used in single-threaded mode.
+class GypHelper {
+ public:
+ GypHelper();
+ ~GypHelper();
+
+ SourceFile GetGypFileForTarget(const Target* target, Err* err) const;
+
+ // Returns the name part of the given target. Example "base". This will
+ // include toolchain info for non-default toolchains.
+ std::string GetNameForTarget(const Target* target) const;
+
+ // Returns a full reference to the given target, including the GYP file
+ // and name. Example "<(DEPTH)/base/base.gyp:base".
+ std::string GetFullRefForTarget(const Target* target) const;
+
+ std::string GetFileReference(const SourceFile& file) const;
+ std::string GetDirReference(const SourceDir& dir, bool include_slash) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GypHelper);
+};
+
+#endif // TOOLS_GN_GYP_HELPER_H_
diff --git a/tools/gn/gyp_target_writer.cc b/tools/gn/gyp_target_writer.cc
new file mode 100644
index 0000000..eec2b89
--- /dev/null
+++ b/tools/gn/gyp_target_writer.cc
@@ -0,0 +1,69 @@
+// 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/gyp_target_writer.h"
+
+#include <iostream>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "tools/gn/build_settings.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/gyp_binary_target_writer.h"
+#include "tools/gn/scheduler.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/target.h"
+
+GypTargetWriter::GypTargetWriter(const Target* target, std::ostream& out)
+ : settings_(target->settings()),
+ target_(target),
+ out_(out) {
+}
+
+GypTargetWriter::~GypTargetWriter() {
+}
+
+// static
+void GypTargetWriter::WriteFile(const SourceFile& gyp_file,
+ const std::vector<TargetPair>& targets,
+ Err* err) {
+ if (targets.empty())
+ return;
+ const BuildSettings* debug_build_settings =
+ targets[0].debug->settings()->build_settings();
+
+ std::stringstream file;
+ file << "# Generated by GN. Do not edit.\n\n";
+ file << "{\n";
+ file << " 'skip_includes': 1,\n";
+ file << " 'targets': [\n";
+
+ for (size_t i = 0; i < targets.size(); i++) {
+ switch (targets[i].debug->output_type()) {
+ case Target::COPY_FILES:
+ case Target::CUSTOM:
+ case Target::GROUP:
+ break; // TODO(brettw)
+ case Target::EXECUTABLE:
+ case Target::STATIC_LIBRARY:
+ case Target::SHARED_LIBRARY:
+ case Target::SOURCE_SET: {
+ GypBinaryTargetWriter writer(targets[i].debug, targets[i].release,
+ file);
+ writer.Run();
+ break;
+ }
+ default:
+ CHECK(0);
+ }
+ }
+
+ file << " ],\n}\n";
+
+ base::FilePath gyp_file_path = debug_build_settings->GetFullPath(gyp_file);
+ std::string contents = file.str();
+ file_util::WriteFile(gyp_file_path, contents.c_str(),
+ static_cast<int>(contents.size()));
+}
+
diff --git a/tools/gn/gyp_target_writer.h b/tools/gn/gyp_target_writer.h
new file mode 100644
index 0000000..1496fbd
--- /dev/null
+++ b/tools/gn/gyp_target_writer.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef TOOLS_GN_GYP_TARGET_WRITER_H_
+#define TOOLS_GN_GYP_TARGET_WRITER_H_
+
+#include <iosfwd>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "tools/gn/gyp_helper.h"
+
+class Err;
+class Settings;
+class SourceFile;
+class Target;
+
+class GypTargetWriter {
+ public:
+ struct TargetPair {
+ TargetPair() : debug(NULL), release(NULL) {}
+ const Target* debug;
+ const Target* release;
+ };
+
+ GypTargetWriter(const Target* target, std::ostream& out);
+ virtual ~GypTargetWriter();
+
+ static void WriteFile(const SourceFile& gyp_file,
+ const std::vector<TargetPair>& targets,
+ Err* err);
+
+ virtual void Run() = 0;
+
+ protected:
+ const Settings* settings_; // Non-owning.
+ const Target* target_; // Non-owning.
+ std::ostream& out_;
+
+ GypHelper helper_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GypTargetWriter);
+};
+
+#endif // TOOLS_GN_GYP_TARGET_WRITER_H_
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index 9241021..aefb513 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -333,17 +333,6 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
path_output_.WriteFile(out_, helper_.GetTargetOutputFile(linkable_deps[i]));
}
- // External link deps from GYP. This is indexed by a label with no toolchain.
- typedef BuildSettings::AdditionalLibsMap LibsMap;
- const LibsMap& libs = settings_->build_settings()->external_link_deps();
- Label libs_key(target_->label().dir(), target_->label().name());
- LibsMap::const_iterator libs_end = libs.upper_bound(libs_key);
- for (LibsMap::const_iterator i = libs.lower_bound(libs_key);
- i != libs_end; ++i) {
- out_ << " ";
- path_output_.WriteFile(out_, i->second);
- }
-
// Append data dependencies as implicit dependencies.
WriteImplicitDependencies(non_linkable_deps);
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index 9b0d305..c246a42 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -122,7 +122,7 @@ bool NinjaBuildWriter::RunAndWriteFile(
void NinjaBuildWriter::WriteNinjaRules() {
out_ << "rule gn\n";
out_ << " command = " << GetSelfInvocationCommand(build_settings_) << "\n";
- out_ << " description = GN the world\n\n";
+ out_ << " description = Regenerating ninja files\n\n";
out_ << "build build.ninja: gn\n"
<< " depfile = build.ninja.d\n";
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 3eccb18..4bbc1f5 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -59,13 +59,6 @@ void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
// It's rediculously faster to write to a string and then write that to
// disk in one operation than to use an fstream here.
std::stringstream file;
- if (file.fail()) {
- g_scheduler->FailWithError(
- Err(Location(), "Error writing ninja file.",
- "Unable to open \"" + FilePathToUTF8(ninja_file) + "\"\n"
- "for writing."));
- return;
- }
// Call out to the correct sub-type of writer.
if (target->output_type() == Target::COPY_FILES) {
diff --git a/tools/gn/secondary/BUILD.gn b/tools/gn/secondary/BUILD.gn
index baf8664..f0cf42a 100644
--- a/tools/gn/secondary/BUILD.gn
+++ b/tools/gn/secondary/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+gyp_file = "root.gyp"
+
group("root") {
deps = [
"//base(//build/toolchain/nacl:x86_newlib)",
diff --git a/tools/gn/secondary/build/config/BUILDCONFIG.gn b/tools/gn/secondary/build/config/BUILDCONFIG.gn
index d2e609d..8ee3547 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 = "source_set"
+ component_mode = "static_library"
}
toolkit_uses_gtk = is_linux
diff --git a/tools/gn/secondary/build/config/win/BUILD.gn b/tools/gn/secondary/build/config/win/BUILD.gn
index dee1be6..efdc5ab 100644
--- a/tools/gn/secondary/build/config/win/BUILD.gn
+++ b/tools/gn/secondary/build/config/win/BUILD.gn
@@ -2,7 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-win_sdk_dir = "C:\Program Files (x86)\Windows Kits\8.0"
+declare_args() {
+ windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.0"
+}
# Compiler setup for the Windows SDK. Applied to all targets.
config("sdk") {
@@ -24,9 +26,9 @@ config("sdk") {
]
include_dirs = [
- "$win_sdk_dir\Include\shared",
- "$win_sdk_dir\Include\um",
- "$win_sdk_dir\Include\winrt",
+ "$windows_sdk_path\Include\shared",
+ "$windows_sdk_path\Include\um",
+ "$windows_sdk_path\Include\winrt",
]
}
@@ -37,13 +39,13 @@ config("sdk_link") {
if (is_64bit) {
ldflags = [ "/MACHINE:X64" ]
- libs = [ "$win_sdk_dir\Lib\win8\um\x64" ]
+ libs = [ "$windows_sdk_path\Lib\win8\um\x64" ]
} else {
ldflags = [
"/MACHINE:X86",
"/SAFESEH", # Not compatible with x64 so use only for x86.
]
- lib_dirs = [ "$win_sdk_dir\Lib\win8\um\x86" ]
+ lib_dirs = [ "$windows_sdk_path\Lib\win8\um\x86" ]
#if (!is_asan) { TODO(brettw) Address Sanitizer
# ldflags += "/largeaddressaware"
diff --git a/tools/gn/secondary/chrome/BUILD.gn b/tools/gn/secondary/chrome/BUILD.gn
index 4e6df28..1d6217e 100644
--- a/tools/gn/secondary/chrome/BUILD.gn
+++ b/tools/gn/secondary/chrome/BUILD.gn
@@ -130,10 +130,10 @@ source_set("debugger") {
]
deps = [
- ":chrome_extra_resources",
- ":chrome_resources",
- ":chrome_strings",
- ":theme_resources",
+# ":chrome_extra_resources",
+# ":chrome_resources",
+# ":chrome_strings",
+# ":theme_resources",
"//base",
"//net",
"//net:http_server",
@@ -204,105 +204,105 @@ custom("about_credits") {
# Resources --------------------------------------------------------------------
-group("chrome_resources") {
- deps = [
- ":browser_resources",
- ":common_resources",
- ":renderer_resources",
- ]
-}
-grit("browser_resources") {
- source = "browser/browser_resources.grd"
- grit_flags = [ "-E", "about_credits_file=$build_relative_about_credits_file" ]
- deps = [ ":about_credits" ]
-}
-grit("common_resources") {
- source = "common/common_resources.grd"
-}
-grit("renderer_resources") {
- source = "renderer/resources/renderer_resources.grd"
-}
-
-group("chrome_strings") {
- deps = [
- ":locale_settings",
- ":chromium_strings",
- ":generated_resources",
- ":google_chrome_strings",
- ]
-}
-grit("locale_settings") {
- source = "app/resources/locale_settings.grd"
-}
-grit("chromium_strings") {
- source = "app/chromium_strings.grd"
-}
-grit("generated_resources") {
- source = "app/generated_resources.grd"
-}
-grit("google_chrome_strings") {
- source = "app/google_chrome_strings.grd"
-}
-
-group("chrome_extra_resources") {
- deps = [
- ":memory_internals_resources",
- ":net_internals_resources",
- ":signin_internals_resources",
- ":sync_internals_resources",
- ":translate_internals_resources",
- ]
-
- if (!is_ios) {
- deps += [
- ":component_extension_resources",
- ":devtools_discovery_page_resources",
- ":options_resources",
- ":quota_internals_resources",
- ":sync_file_system_internals_resources",
- ]
- }
-}
-grit("component_extension_resources") {
- source = "browser/resources/component_extension_resources.grd"
-}
-grit("devtools_discovery_page_resources") {
- source = "browser/devtools/frontend/devtools_discovery_page_resources.grd"
-}
-grit("memory_internals_resources") {
- source = "browser/resources/memory_internals_resources.grd"
-}
-grit("quota_internals_resources") {
- source = "browser/resources/quota_internals_resources.grd"
-}
-grit("net_internals_resources") {
- source = "browser/resources/net_internals_resources.grd"
-}
-grit("options_resources") {
- source = "browser/resources/options_resources.grd"
-}
-grit("signin_internals_resources") {
- source = "browser/resources/signin_internals_resources.grd"
-}
-grit("sync_file_system_internals_resources") {
- source = "browser/resources/sync_file_system_internals_resources.grd"
-}
-grit("sync_internals_resources") {
- source = "browser/resources/sync_internals_resources.grd"
-}
-grit("translate_internals_resources") {
- source = "browser/resources/translate_internals_resources.grd"
-}
-
-group("theme_resources") {
- deps = [
- ":theme_resources_gen",
- #"//ui:ui_resources",
- ]
-}
-
-# TODO(brettw) rename "app_theme_resources" or something when we don't support
-# GYP any more. This name is required to match the GYP build.
-grit("theme_resources_gen") {
- source = "app/theme/theme_resources.grd"
-}
+#group("chrome_resources") {
+# deps = [
+# ":browser_resources",
+# ":common_resources",
+# ":renderer_resources",
+# ]
+#}
+#grit("browser_resources") {
+# source = "browser/browser_resources.grd"
+# grit_flags = [ "-E", "about_credits_file=$build_relative_about_credits_file" ]
+# deps = [ ":about_credits" ]
+#}
+#grit("common_resources") {
+# source = "common/common_resources.grd"
+#}
+#grit("renderer_resources") {
+# source = "renderer/resources/renderer_resources.grd"
+#}
+#
+#group("chrome_strings") {
+# deps = [
+# ":locale_settings",
+# ":chromium_strings",
+# ":generated_resources",
+# ":google_chrome_strings",
+# ]
+#}
+#grit("locale_settings") {
+# source = "app/resources/locale_settings.grd"
+#}
+#grit("chromium_strings") {
+# source = "app/chromium_strings.grd"
+#}
+#grit("generated_resources") {
+# source = "app/generated_resources.grd"
+#}
+#grit("google_chrome_strings") {
+# source = "app/google_chrome_strings.grd"
+#}
+#
+#group("chrome_extra_resources") {
+# deps = [
+# ":memory_internals_resources",
+# ":net_internals_resources",
+# ":signin_internals_resources",
+# ":sync_internals_resources",
+# ":translate_internals_resources",
+# ]
+#
+# if (!is_ios) {
+# deps += [
+# ":component_extension_resources",
+# ":devtools_discovery_page_resources",
+# ":options_resources",
+# ":quota_internals_resources",
+# ":sync_file_system_internals_resources",
+# ]
+# }
+#}
+#grit("component_extension_resources") {
+# source = "browser/resources/component_extension_resources.grd"
+#}
+#grit("devtools_discovery_page_resources") {
+# source = "browser/devtools/frontend/devtools_discovery_page_resources.grd"
+#}
+#grit("memory_internals_resources") {
+# source = "browser/resources/memory_internals_resources.grd"
+#}
+#grit("quota_internals_resources") {
+# source = "browser/resources/quota_internals_resources.grd"
+#}
+#grit("net_internals_resources") {
+# source = "browser/resources/net_internals_resources.grd"
+#}
+#grit("options_resources") {
+# source = "browser/resources/options_resources.grd"
+#}
+#grit("signin_internals_resources") {
+# source = "browser/resources/signin_internals_resources.grd"
+#}
+#grit("sync_file_system_internals_resources") {
+# source = "browser/resources/sync_file_system_internals_resources.grd"
+#}
+#grit("sync_internals_resources") {
+# source = "browser/resources/sync_internals_resources.grd"
+#}
+#grit("translate_internals_resources") {
+# source = "browser/resources/translate_internals_resources.grd"
+#}
+#
+#group("theme_resources") {
+# deps = [
+# ":theme_resources_gen",
+# #"//ui:ui_resources",
+# ]
+#}
+#
+## TODO(brettw) rename "app_theme_resources" or something when we don't support
+## GYP any more. This name is required to match the GYP build.
+#grit("theme_resources_gen") {
+# source = "app/theme/theme_resources.grd"
+#}
diff --git a/tools/gn/secondary/net/BUILD.gn b/tools/gn/secondary/net/BUILD.gn
index 4d332f5..4cf8eec 100644
--- a/tools/gn/secondary/net/BUILD.gn
+++ b/tools/gn/secondary/net/BUILD.gn
@@ -1057,7 +1057,7 @@ component("net") {
defines = [ "NET_IMPLEMENTATION" ]
deps = [
- ":net_resources",
+ #":net_resources",
"//base",
"//base:base_i18n",
"//base/third_party/dynamic_annotations",
@@ -1197,10 +1197,10 @@ component("net") {
}
}
-grit("net_resources") {
- external = true
- source = "base/net_resources.grd"
-}
+#grit("net_resources") {
+# external = true
+# source = "base/net_resources.grd"
+#}
static_library("http_server") {
external = true
diff --git a/tools/gn/secondary/testing/BUILD.gn b/tools/gn/secondary/testing/BUILD.gn
index 08f3c4d..38b992c 100644
--- a/tools/gn/secondary/testing/BUILD.gn
+++ b/tools/gn/secondary/testing/BUILD.gn
@@ -14,6 +14,7 @@ config("gtest_config") {
# TODO(brettw) move to testing/gtest/BUILD.gn
static_library("gtest") {
external = true
+ gyp_file = "gtest.gyp"
sources = [
"gtest/include/gtest/gtest-death-test.h",
"gtest/include/gtest/gtest-message.h",
@@ -60,6 +61,7 @@ config("gmock_config") {
# TODO(brettw) move to testing/gmock/BUILD.gn
static_library("gmock") {
+ gyp_file = "gmock.gyp"
external = true
sources = [
# Sources based on files in r173 of gmock.
@@ -96,6 +98,7 @@ static_library("gmock") {
# TODO(brettw) move to testing/gmock/BUILD.gn
static_library("gmock_main") {
external = true
+ gyp_file = "gmock.gyp"
sources = [ "src/gmock_main.cc" ]
deps = [ ":gmock" ]
}
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index b94a4ae..add7101 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -153,8 +153,55 @@ base::FilePath ExtractDepotToolsFromPath() {
} // namespace
+// CommonSetup -----------------------------------------------------------------
+
+CommonSetup::CommonSetup()
+ : check_for_bad_items_(true) {
+}
+
+CommonSetup::CommonSetup(const CommonSetup& other)
+ : build_settings_(other.build_settings_),
+ check_for_bad_items_(other.check_for_bad_items_) {
+}
+
+CommonSetup::~CommonSetup() {
+}
+
+void CommonSetup::RunPreMessageLoop() {
+ // Load the root build file.
+ build_settings_.toolchain_manager().StartLoadingUnlocked(
+ SourceFile("//BUILD.gn"));
+}
+
+bool CommonSetup::RunPostMessageLoop() {
+ Err err;
+ if (check_for_bad_items_) {
+ err = build_settings_.item_tree().CheckForBadItems();
+ if (err.has_error()) {
+ err.PrintToStdout();
+ return false;
+ }
+ }
+
+ if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) {
+ err.PrintToStdout();
+ return false;
+ }
+
+ // Write out tracing and timing if requested.
+ const CommandLine* cmdline = CommandLine::ForCurrentProcess();
+ if (cmdline->HasSwitch(kTimeSwitch))
+ PrintLongHelp(SummarizeTraces());
+ if (cmdline->HasSwitch(kTracelogSwitch))
+ SaveTraces(cmdline->GetSwitchValuePath(kTracelogSwitch));
+
+ return true;
+}
+
+// Setup -----------------------------------------------------------------------
+
Setup::Setup()
- : check_for_bad_items_(true),
+ : CommonSetup(),
empty_toolchain_(Label()),
empty_settings_(&empty_build_settings_, &empty_toolchain_, std::string()),
dotfile_scope_(&empty_settings_) {
@@ -198,34 +245,10 @@ bool Setup::DoSetup() {
}
bool Setup::Run() {
- // Load the root build file and start runnung.
- build_settings_.toolchain_manager().StartLoadingUnlocked(
- SourceFile("//BUILD.gn"));
+ RunPreMessageLoop();
if (!scheduler_.Run())
return false;
-
- Err err;
- if (check_for_bad_items_) {
- err = build_settings_.item_tree().CheckForBadItems();
- if (err.has_error()) {
- err.PrintToStdout();
- return false;
- }
- }
-
- if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) {
- err.PrintToStdout();
- return false;
- }
-
- // Write out tracing and timing if requested.
- const CommandLine* cmdline = CommandLine::ForCurrentProcess();
- if (cmdline->HasSwitch(kTimeSwitch))
- PrintLongHelp(SummarizeTraces());
- if (cmdline->HasSwitch(kTracelogSwitch))
- SaveTraces(cmdline->GetSwitchValuePath(kTracelogSwitch));
-
- return true;
+ return RunPostMessageLoop();
}
bool Setup::FillArguments(const CommandLine& cmdline) {
@@ -395,3 +418,21 @@ bool Setup::FillOtherConfig(const CommandLine& cmdline) {
return true;
}
+
+// DependentSetup --------------------------------------------------------------
+
+DependentSetup::DependentSetup(const Setup& main_setup)
+ : CommonSetup(main_setup) {
+}
+
+DependentSetup::~DependentSetup() {
+}
+
+void DependentSetup::RunPreMessageLoop() {
+ CommonSetup::RunPreMessageLoop();
+}
+
+bool DependentSetup::RunPostMessageLoop() {
+ return CommonSetup::RunPostMessageLoop();
+}
+
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index bd7166d..c2b3d82 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -23,26 +23,51 @@ class ParseNode;
extern const char kDotfile_Help[];
+// Base class for code shared between Setup and DependentSetup.
+class CommonSetup {
+ public:
+ virtual ~CommonSetup();
+
+ // When true (the default), Run() will check for unresolved dependencies and
+ // cycles upon completion. When false, such errors will be ignored.
+ void set_check_for_bad_items(bool s) { check_for_bad_items_ = s; }
+
+ BuildSettings& build_settings() { return build_settings_; }
+
+ protected:
+ CommonSetup();
+ CommonSetup(const CommonSetup& other);
+
+ // Performs the two sets of operations to run the generation before and after
+ // the message loop is run.
+ void RunPreMessageLoop();
+ bool RunPostMessageLoop();
+
+ protected:
+ BuildSettings build_settings_;
+
+ bool check_for_bad_items_;
+
+ private:
+ CommonSetup& operator=(const CommonSetup& other); // Disallow.
+};
+
// Helper class to setup the build settings and environment for the various
// commands to run.
-class Setup {
+class Setup : public CommonSetup {
public:
Setup();
- ~Setup();
+ virtual ~Setup();
// Configures the build for the current command line. On success returns
// true. On failure, prints the error and returns false.
bool DoSetup();
- // When true (the default), Run() will check for unresolved dependencies and
- // cycles upon completion. When false, such errors will be ignored.
- void set_check_for_bad_items(bool s) { check_for_bad_items_ = s; }
-
// Runs the load, returning true on success. On failure, prints the error
- // and returns false.
+ // and returns false. This includes both RunPreMessageLoop() and
+ // RunPostMessageLoop().
bool Run();
- BuildSettings& build_settings() { return build_settings_; }
Scheduler& scheduler() { return scheduler_; }
private:
@@ -61,11 +86,8 @@ class Setup {
bool FillOtherConfig(const CommandLine& cmdline);
- BuildSettings build_settings_;
Scheduler scheduler_;
- bool check_for_bad_items_;
-
// These empty settings and toolchain are used to interpret the command line
// and dot file.
BuildSettings empty_build_settings_;
@@ -89,4 +111,27 @@ class Setup {
DISALLOW_COPY_AND_ASSIGN(Setup);
};
+// A dependent setup allows one to do more than one build at a time. You would
+// make a dependent setup which clones the state of the main one, make any
+// necessary changes, and then run it.
+//
+// The way to run both at the same time is:
+// dependent_setup.RunPreMessageLoop();
+// main_setup.Run();
+// dependent_setup.RunPostMessageLoop();
+// so that the main setup executes the message loop, but both are run.
+class DependentSetup : public CommonSetup {
+ public:
+ DependentSetup(const Setup& main_setup);
+ virtual ~DependentSetup();
+
+ // These are the two parts of Run() in the regular setup, not including the
+ // call to actually run the message loop.
+ void RunPreMessageLoop();
+ bool RunPostMessageLoop();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DependentSetup);
+};
+
#endif // TOOLS_GN_SETUP_H_
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 52ebfd5..025f428 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -116,7 +116,12 @@ base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const {
std::string converted;
if (is_system_absolute()) {
- converted = value_;
+ if (value_.size() > 2 && value_[2] == ':') {
+ // Windows path, strip the leading slash.
+ converted.assign(&value_[1], value_.size() - 1);
+ } else {
+ converted.assign(value_);
+ }
ConvertPathToSystem(&converted);
return base::FilePath(UTF8ToFilePath(converted));
}
diff --git a/tools/gn/source_file.cc b/tools/gn/source_file.cc
index 62f8fb1..e5d6775 100644
--- a/tools/gn/source_file.cc
+++ b/tools/gn/source_file.cc
@@ -46,22 +46,18 @@ base::FilePath SourceFile::Resolve(const base::FilePath& source_root) const {
return base::FilePath();
std::string converted;
-#if defined(OS_WIN)
if (is_system_absolute()) {
- converted.assign(&value_[1], value_.size() - 1);
- DCHECK(converted.size() > 2 && converted[1] == ':')
- << "Expecting Windows absolute file path with a drive letter: "
- << value_;
+ if (value_.size() > 2 && value_[2] == ':') {
+ // Windows path, strip the leading slash.
+ converted.assign(&value_[1], value_.size() - 1);
+ } else {
+ converted.assign(value_);
+ }
+ ConvertPathToSystem(&converted);
return base::FilePath(UTF8ToFilePath(converted));
}
converted.assign(&value_[2], value_.size() - 2);
ConvertPathToSystem(&converted);
return source_root.Append(UTF8ToFilePath(converted));
-#else
- if (is_system_absolute())
- return base::FilePath(value_);
- converted.assign(&value_[2], value_.size() - 2);
- return source_root.Append(converted);
-#endif
}
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 1bb51a6..8dfc4cc 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -140,6 +140,9 @@ class Target : public Item {
const OrderedSet<SourceDir>& all_lib_dirs() const { return all_lib_dirs_; }
const OrderedSet<std::string>& all_libs() const { return all_libs_; }
+ const SourceFile& gyp_file() const { return gyp_file_; }
+ void set_gyp_file(const SourceFile& gf) { gyp_file_ = gf; }
+
private:
// Pulls necessary information from dependents to this one when all
// dependencies have been resolved.
@@ -189,7 +192,7 @@ class Target : public Item {
ConfigValues config_values_; // Used for all binary targets.
ScriptValues script_values_; // Used for script (CUSTOM) targets.
- SourceDir destdir_;
+ SourceFile gyp_file_;
bool generated_;
const Token* generator_function_; // Who generated this: for error messages.
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index f32245a..d5bcfe2 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -41,6 +41,7 @@ void TargetGenerator::Run() {
FillDependentConfigs();
FillData();
FillDependencies();
+ FillGypFile();
// To type-specific generation.
DoRun();
@@ -178,6 +179,17 @@ void TargetGenerator::FillDependencies() {
FillHardDep();
}
+void TargetGenerator::FillGypFile() {
+ const Value* gyp_file_value = scope_->GetValue(variables::kGypFile, true);
+ if (!gyp_file_value)
+ return;
+ if (!gyp_file_value->VerifyTypeIs(Value::STRING, err_))
+ return;
+
+ target_->set_gyp_file(scope_->GetSourceDir().ResolveRelativeFile(
+ gyp_file_value->string_value()));
+}
+
void TargetGenerator::FillHardDep() {
const Value* hard_dep_value = scope_->GetValue(variables::kHardDep, true);
if (!hard_dep_value)
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index a8cad2d..074061d 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -67,6 +67,7 @@ class TargetGenerator {
void FillDependentConfigs(); // Includes all types of dependent configs.
void FillData();
void FillDependencies(); // Includes data dependencies.
+ void FillGypFile();
void FillHardDep();
// Reads configs/deps from the given var name, and uses the given setting on
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 7c2cb35..886a1f7 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -455,6 +455,12 @@ const char kForwardDependentConfigsFrom_Help[] =
" forward_dependent_configs_from = deps\n"
" }\n";
+const char kGypFile[] = "gyp_file";
+const char kGypFile_HelpShort[] =
+ "gyp_file: [file name] Name of GYP file to write to in GYP mode.";
+const char kGypFile_Help[] =
+ "gyp_file: Name of GYP file to write to in GYP mode.\n";
+
const char kHardDep[] = "hard_dep";
const char kHardDep_HelpShort[] =
"hard_dep: [boolean] Indicates a target should be built before dependees.";
@@ -726,6 +732,7 @@ const VariableInfoMap& GetTargetVariables() {
INSERT_VARIABLE(DirectDependentConfigs)
INSERT_VARIABLE(External)
INSERT_VARIABLE(ForwardDependentConfigsFrom)
+ INSERT_VARIABLE(GypFile)
INSERT_VARIABLE(HardDep)
INSERT_VARIABLE(IncludeDirs)
INSERT_VARIABLE(Ldflags)
diff --git a/tools/gn/variables.h b/tools/gn/variables.h
index 2e8d0b4..2962a51 100644
--- a/tools/gn/variables.h
+++ b/tools/gn/variables.h
@@ -127,6 +127,10 @@ extern const char kForwardDependentConfigsFrom[];
extern const char kForwardDependentConfigsFrom_HelpShort[];
extern const char kForwardDependentConfigsFrom_Help[];
+extern const char kGypFile[];
+extern const char kGypFile_HelpShort[];
+extern const char kGypFile_Help[];
+
extern const char kHardDep[];
extern const char kHardDep_HelpShort[];
extern const char kHardDep_Help[];