diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-16 16:46:14 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-16 16:46:14 +0000 |
commit | e3730f817be9693b5ad140a002abff4cbaf674ec (patch) | |
tree | b0aa15b4099915ca23a673a11356b73db2321844 | |
parent | 5fb863442b955f859bee4baf67aeeaf4fdc4b6c4 (diff) | |
download | chromium_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
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[]; |