Commit 5a1b4b17 authored by grt's avatar grt Committed by Commit bot

Revert of [GN] Add JSON project writer (patchset #11 id:200001 of...

Revert of [GN] Add JSON project writer (patchset #11 id:200001 of https://codereview.chromium.org/2064533002/ )

Reason for revert:
Broke Win8 GYP (dbg) builder:
[822/12249] LINK_EMBED gn.exe
FAILED: gn.exe gn.exe.pdb
E:\b\depot_tools\python276_bin\python.exe gyp-win-tool link-with-manifests environment.x86 True gn.exe "E:\b\depot_tools\python276_bin\python.exe gyp-win-tool link-wrapper environment.x86 False link.exe /nologo /OUT:gn.exe @gn.exe.rsp" 1 mt.exe rc.exe "obj\tools\gn\gn.gn.exe.intermediate.manifest" obj\tools\gn\gn.gn.exe.generated.manifest ..\..\build\win\compatibility.manifest
gn_lib.lib(gn_lib.command_desc.obj) : error LNK2019: unresolved external symbol "public: static class std::unique_ptr<class base::DictionaryValue,struct std::default_delete<class base::DictionaryValue> > __cdecl DescBuilder::DescriptionForTarget(class Target const *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool,bool,bool)" (?DescriptionForTarget@DescBuilder@@SA?AV?$unique_ptr@VDictionaryValue@base@@U?$default_delete@VDictionaryValue@base@@@std@@@std@@PBVTarget@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@_N22@Z) referenced in function "bool __cdecl commands::`anonymous namespace'::PrintTarget(class Target const *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool,bool,bool,bool)" (?PrintTarget@?A0x51180473@commands@@YA_NPBVTarget@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_N222@Z)

gn_lib.lib(gn_lib.command_desc.obj) : error LNK2019: unresolved external symbol "public: static class std::unique_ptr<class base::DictionaryValue,struct std::default_delete<class base::DictionaryValue> > __cdecl DescBuilder::DescriptionForConfig(class Config const *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?DescriptionForConfig@DescBuilder@@SA?AV?$unique_ptr@VDictionaryValue@base@@U?$default_delete@VDictionaryValue@base@@@std@@@std@@PBVConfig@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@@Z) referenced in function "bool __cdecl commands::`anonymous namespace'::PrintConfig(class Config const *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool)" (?PrintConfig@?A0x51180473@commands@@YA_NPBVConfig@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_N@Z)

gn_lib.lib(gn_lib.command_gen.obj) : error LNK2019: unresolved external symbol "public: static bool __cdecl JSONProjectWriter::RunAndWriteFiles(class BuildSettings const *,class Builder const *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool,class Err *)" (?RunAndWriteFiles@JSONProjectWriter@@SA_NPBVBuildSettings@@PBVBuilder@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@222_NPAVErr@@@Z) referenced in function "bool __cdecl commands::`anonymous namespace'::RunIdeWriter(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class BuildSettings const *,class Builder *,class Err *)" (?RunIdeWriter@?A0x1eff038c@commands@@YA_NABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PBVBuildSettings@@PAVBuilder@@PAVErr@@@Z)

gn.exe : fatal error LNK1120: 3 unresolved externals

Traceback (most recent call last):

  File "gyp-win-tool", line 323, in <module>

    sys.exit(main(sys.argv[1:]))

  File "gyp-win-tool", line 29, in main

    exit_code = executor.Dispatch(args)

  File "gyp-win-tool", line 71, in Dispatch

    return getattr(self, method)(*args[1:])

  File "gyp-win-tool", line 179, in ExecLinkWithManifests

    subprocess.check_call(ldcmd + add_to_ld)

  File "E:\b\depot_tools\python276_bin\lib\subprocess.py", line 540, in check_call

    raise CalledProcessError(retcode, cmd)

subprocess.CalledProcessError: Command 'E:\b\depot_tools\python276_bin\python.exe gyp-win-tool link-wrapper environment.x86 False link.exe /nologo /OUT:gn.exe @gn.exe.rsp gn.exe.manifest.res' returned non-zero exit status 1120

Original issue's description:
> [GN] Add JSON project writer
>
> Output is a JSON file containing information about targets. The generator
> can also optionally invoke a python script on generated file.
>
> Example:
> gn gen --ide=json ./out-json --json-ide-script=//scripts/custom-ide-generator.py \
>     --ison-ide-script-args="additional script arguments"
>
> Also implements --format=json for gn desc as described in https://bugs.chromium.org/p/chromium/issues/detail?id=620132
>
> BUG=
>
> Committed: https://crrev.com/d2edeb9a743ad5a2046e655997277d3bb630db03
> Cr-Commit-Position: refs/heads/master@{#406064}

TBR=brettw@chromium.org,matej.knopp@gmail.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=

Review-Url: https://codereview.chromium.org/2160533004
Cr-Commit-Position: refs/heads/master@{#406074}
parent 4ade1038
...@@ -409,7 +409,6 @@ Martin Bednorz <m.s.bednorz@gmail.com> ...@@ -409,7 +409,6 @@ Martin Bednorz <m.s.bednorz@gmail.com>
Martina Kollarova <martina.kollarova@intel.com> Martina Kollarova <martina.kollarova@intel.com>
Masahiro Yado <yado.masa@gmail.com> Masahiro Yado <yado.masa@gmail.com>
Masaru Nishida <msr.i386@gmail.com> Masaru Nishida <msr.i386@gmail.com>
Matej Knopp <matej.knopp@gmail.com>
Matheus Bratfisch <matheusbrat@gmail.com> Matheus Bratfisch <matheusbrat@gmail.com>
Mathias Bynens <mathias@qiwi.be> Mathias Bynens <mathias@qiwi.be>
Mathieu Meisser <mmeisser@logitech.com> Mathieu Meisser <mmeisser@logitech.com>
......
...@@ -58,8 +58,6 @@ static_library("gn_lib") { ...@@ -58,8 +58,6 @@ static_library("gn_lib") {
"create_bundle_target_generator.h", "create_bundle_target_generator.h",
"deps_iterator.cc", "deps_iterator.cc",
"deps_iterator.h", "deps_iterator.h",
"desc_builder.cc",
"desc_builder.h",
"eclipse_writer.cc", "eclipse_writer.cc",
"eclipse_writer.h", "eclipse_writer.h",
"err.cc", "err.cc",
...@@ -103,8 +101,6 @@ static_library("gn_lib") { ...@@ -103,8 +101,6 @@ static_library("gn_lib") {
"input_file_manager.h", "input_file_manager.h",
"item.cc", "item.cc",
"item.h", "item.h",
"json_project_writer.cc",
"json_project_writer.h",
"label.cc", "label.cc",
"label.h", "label.h",
"label_pattern.cc", "label_pattern.cc",
......
...@@ -9,14 +9,18 @@ ...@@ -9,14 +9,18 @@
#include <sstream> #include <sstream>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/json/json_writer.h" #include "build/build_config.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "tools/gn/commands.h" #include "tools/gn/commands.h"
#include "tools/gn/config.h" #include "tools/gn/config.h"
#include "tools/gn/desc_builder.h" #include "tools/gn/config_values_extractors.h"
#include "tools/gn/deps_iterator.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/item.h"
#include "tools/gn/label.h"
#include "tools/gn/runtime_deps.h"
#include "tools/gn/setup.h" #include "tools/gn/setup.h"
#include "tools/gn/standard_out.h" #include "tools/gn/standard_out.h"
#include "tools/gn/substitution_writer.h"
#include "tools/gn/switches.h" #include "tools/gn/switches.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
#include "tools/gn/variables.h" #include "tools/gn/variables.h"
...@@ -28,258 +32,725 @@ namespace { ...@@ -28,258 +32,725 @@ namespace {
// Desc-specific command line switches. // Desc-specific command line switches.
const char kBlame[] = "blame"; const char kBlame[] = "blame";
const char kTree[] = "tree"; const char kTree[] = "tree";
const char kAll[] = "all";
// Prints the given directory in a nice way for the user to view.
// Prints value with specified indentation level std::string FormatSourceDir(const SourceDir& dir) {
void PrintValue(const base::Value* value, int indentLevel) { #if defined(OS_WIN)
std::string indent(indentLevel * 2, ' '); // On Windows we fix up system absolute paths to look like native ones.
const base::ListValue* list_value = nullptr; // Internally, they'll look like "/C:\foo\bar/"
const base::DictionaryValue* dict_value = nullptr; if (dir.is_system_absolute()) {
std::string string_value; std::string buf = dir.value();
bool bool_value = false; if (buf.size() > 3 && buf[2] == ':') {
if (value->GetAsList(&list_value)) { buf.erase(buf.begin()); // Erase beginning slash.
for (const auto& v : *list_value) { return buf;
PrintValue(v.get(), indentLevel);
}
} else if (value->GetAsString(&string_value)) {
OutputString(indent);
OutputString(string_value);
OutputString("\n");
} else if (value->GetAsBoolean(&bool_value)) {
OutputString(indent);
OutputString(bool_value ? "true" : "false");
OutputString("\n");
} else if (value->GetAsDictionary(&dict_value)) {
base::DictionaryValue::Iterator iter(*dict_value);
while (!iter.IsAtEnd()) {
OutputString(indent + iter.key() + "\n");
PrintValue(&iter.value(), indentLevel + 1);
iter.Advance();
} }
} else if (value->IsType(base::Value::TYPE_NULL)) {
OutputString(indent + "<null>\n");
} }
#endif
return dir.value();
}
void RecursiveCollectChildDeps(const Target* target,
std::set<const Target*>* result);
void RecursiveCollectDeps(const Target* target,
std::set<const Target*>* result) {
if (result->find(target) != result->end())
return; // Already did this target.
result->insert(target);
RecursiveCollectChildDeps(target, result);
} }
// Default handler for property void RecursiveCollectChildDeps(const Target* target,
void DefaultHandler(const std::string& name, const base::Value* value) { std::set<const Target*>* result) {
OutputString("\n"); for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
OutputString(name); RecursiveCollectDeps(pair.ptr, result);
OutputString("\n");
PrintValue(value, 1);
} }
// Specific handler for properties that need different treatment // Prints dependencies of the given target (not the target itself). If the
// set is non-null, new targets encountered will be added to the set, and if
// a dependency is in the set already, it will not be recused into. When the
// set is null, all dependencies will be printed.
void RecursivePrintDeps(const Target* target,
const Label& default_toolchain,
std::set<const Target*>* seen_targets,
int indent_level) {
// Combine all deps into one sorted list.
std::vector<LabelTargetPair> sorted_deps;
for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
sorted_deps.push_back(pair);
std::sort(sorted_deps.begin(), sorted_deps.end(),
LabelPtrLabelLess<Target>());
std::string indent(indent_level * 2, ' ');
for (const auto& pair : sorted_deps) {
const Target* cur_dep = pair.ptr;
OutputString(indent +
cur_dep->label().GetUserVisibleName(default_toolchain));
bool print_children = true;
if (seen_targets) {
if (seen_targets->find(cur_dep) == seen_targets->end()) {
// New target, mark it visited.
seen_targets->insert(cur_dep);
} else {
// Already seen.
print_children = false;
// Only print "..." if something is actually elided, which means that
// the current target has children.
if (!cur_dep->public_deps().empty() ||
!cur_dep->private_deps().empty() ||
!cur_dep->data_deps().empty())
OutputString("...");
}
}
// Prints label and property value on one line, capitalizing the label. OutputString("\n");
void LabelHandler(std::string name, const base::Value* value) { if (print_children) {
name[0] = base::ToUpperASCII(name[0]); RecursivePrintDeps(cur_dep, default_toolchain, seen_targets,
std::string string_value; indent_level + 1);
if (value->GetAsString(&string_value)) { }
OutputString(name + ": ", DECORATION_YELLOW);
OutputString(string_value + "\n");
} }
} }
void VisibilityHandler(const std::string& name, const base::Value* value) { void PrintDeps(const Target* target, bool display_header) {
const base::ListValue* list; const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
if (value->GetAsList(&list)) { Label toolchain_label = target->label().GetToolchainLabel();
if (list->empty()) {
base::StringValue str("(no visibility)"); // Tree mode is separate.
DefaultHandler(name, &str); if (cmdline->HasSwitch(kTree)) {
if (display_header)
OutputString("\nDependency tree\n");
if (cmdline->HasSwitch("all")) {
// Show all tree deps with no eliding.
RecursivePrintDeps(target, toolchain_label, nullptr, 1);
} else { } else {
DefaultHandler(name, value); // Don't recurse into duplicates.
std::set<const Target*> seen_targets;
RecursivePrintDeps(target, toolchain_label, &seen_targets, 1);
} }
return;
} }
}
void PublicHandler(const std::string& name, const base::Value* value) { // Collect the deps to display.
std::string p; if (cmdline->HasSwitch("all")) {
if (value->GetAsString(&p)) { // Show all dependencies.
if (p == "*") { if (display_header)
base::StringValue str("[All headers listed in the sources are public.]"); OutputString("\nAll recursive dependencies\n");
DefaultHandler(name, &str);
return; std::set<const Target*> all_deps;
RecursiveCollectChildDeps(target, &all_deps);
FilterAndPrintTargetSet(display_header, all_deps);
} else {
std::vector<const Target*> deps;
// Show direct dependencies only.
if (display_header) {
OutputString(
"\nDirect dependencies "
"(try also \"--all\", \"--tree\", or even \"--all --tree\")\n");
} }
for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
deps.push_back(pair.ptr);
std::sort(deps.begin(), deps.end());
FilterAndPrintTargets(display_header, &deps);
} }
DefaultHandler(name, value);
} }
void ConfigsHandler(const std::string& name, const base::Value* value) { // libs and lib_dirs are special in that they're inherited. We don't currently
bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); // implement a blame feature for this since the bottom-up inheritance makes
if (tree) // this difficult.
DefaultHandler(name + " tree (in order applying)", value); void PrintLibDirs(const Target* target, bool display_header) {
const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
if (lib_dirs.empty())
return;
if (display_header)
OutputString("\nlib_dirs\n");
for (size_t i = 0; i < lib_dirs.size(); i++)
OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n");
}
void PrintLibs(const Target* target, bool display_header) {
const OrderedSet<LibFile>& libs = target->all_libs();
if (libs.empty())
return;
if (display_header)
OutputString("\nlibs\n");
for (size_t i = 0; i < libs.size(); i++)
OutputString(" " + libs[i].value() + "\n");
}
void PrintPublic(const Target* target, bool display_header) {
if (display_header)
OutputString("\npublic\n");
if (target->all_headers_public()) {
OutputString(" [All headers listed in the sources are public.]\n");
return;
}
Target::FileList public_headers = target->public_headers();
std::sort(public_headers.begin(), public_headers.end());
for (const auto& hdr : public_headers)
OutputString(" " + hdr.value() + "\n");
}
void PrintCheckIncludes(const Target* target, bool display_header) {
if (display_header)
OutputString("\ncheck_includes\n");
if (target->check_includes())
OutputString(" true\n");
else else
DefaultHandler(name + " (in order applying, try also --tree)", value); OutputString(" false\n");
} }
void DepsHandler(const std::string& name, const base::Value* value) { void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) {
if (display_header)
OutputString("\nallow_circular_includes_from\n");
Label toolchain_label = target->label().GetToolchainLabel();
for (const auto& cur : target->allow_circular_includes_from())
OutputString(" " + cur.GetUserVisibleName(toolchain_label) + "\n");
}
void PrintVisibility(const Target* target, bool display_header) {
if (display_header)
OutputString("\nvisibility\n");
OutputString(target->visibility().Describe(2, false));
}
void PrintTestonly(const Target* target, bool display_header) {
if (display_header)
OutputString("\ntestonly\n");
if (target->testonly())
OutputString(" true\n");
else
OutputString(" false\n");
}
// Recursively prints subconfigs of a config.
void PrintSubConfigs(const Config* config, int indent_level) {
if (config->configs().empty())
return;
std::string indent(indent_level * 2, ' ');
Label toolchain_label = config->label().GetToolchainLabel();
for (const auto& pair : config->configs()) {
OutputString(
indent + pair.label.GetUserVisibleName(toolchain_label) + "\n");
PrintSubConfigs(pair.ptr, indent_level + 1);
}
}
// This allows configs stored as either std::vector<LabelConfigPair> or
// UniqueVector<LabelConfigPair> to be printed.
template <class VectorType>
void PrintConfigsVector(const Item* item,
const VectorType& configs,
const std::string& heading,
bool display_header) {
if (configs.empty())
return;
bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
if (tree) { // Don't sort since the order determines how things are processed.
DefaultHandler("Dependency tree", value); if (display_header) {
} else { if (tree)
if (!all) { OutputString("\n" + heading + " tree (in order applying)\n");
DefaultHandler( else
"Direct dependencies " OutputString("\n" + heading + " (in order applying, try also --tree)\n");
"(try also \"--all\", \"--tree\", or even \"--all --tree\")", }
value);
} else { Label toolchain_label = item->label().GetToolchainLabel();
DefaultHandler("All recursive dependencies", value); for (const auto& config : configs) {
} OutputString(" " + config.label.GetUserVisibleName(toolchain_label) +
"\n");
if (tree)
PrintSubConfigs(config.ptr, 2); // 2 = start with double-indent.
} }
} }
// Outputs need special processing when output patterns are present. void PrintConfigs(const Target* target, bool display_header) {
void ProcessOutputs(base::DictionaryValue* target) { PrintConfigsVector(target, target->configs().vector(), "configs",
base::ListValue* patterns = nullptr; display_header);
base::ListValue* outputs = nullptr; }
target->GetList("output_patterns", &patterns);
target->GetList(variables::kOutputs, &outputs); void PrintConfigs(const Config* config, bool display_header) {
PrintConfigsVector(config, config->configs().vector(), "configs",
display_header);
}
void PrintPublicConfigs(const Target* target, bool display_header) {
PrintConfigsVector(target, target->public_configs(),
"public_configs", display_header);
}
void PrintAllDependentConfigs(const Target* target, bool display_header) {
PrintConfigsVector(target, target->all_dependent_configs(),
"all_dependent_configs", display_header);
}
void PrintFileList(const Target::FileList& files,
const std::string& header,
bool indent_extra,
bool display_header) {
if (files.empty())
return;
if (display_header)
OutputString("\n" + header + "\n");
std::string indent = indent_extra ? " " : " ";
Target::FileList sorted = files;
std::sort(sorted.begin(), sorted.end());
for (const auto& elem : sorted)
OutputString(indent + elem.value() + "\n");
}
void PrintSources(const Target* target, bool display_header) {
PrintFileList(target->sources(), "sources", false, display_header);
}
if (outputs || patterns) { void PrintInputs(const Target* target, bool display_header) {
PrintFileList(target->inputs(), "inputs", false, display_header);
}
void PrintOutputs(const Target* target, bool display_header) {
if (display_header)
OutputString("\noutputs\n"); OutputString("\noutputs\n");
int indent = 1;
if (patterns) { if (target->output_type() == Target::ACTION) {
OutputString(" Output patterns\n"); // Action, print out outputs, don't apply sources to it.
indent = 2; for (const auto& elem : target->action_values().outputs().list()) {
PrintValue(patterns, indent); OutputString(" " + elem.AsString() + "\n");
}
} else if (target->output_type() == Target::CREATE_BUNDLE) {
std::vector<SourceFile> output_files;
target->bundle_data().GetOutputsAsSourceFiles(target->settings(),
&output_files);
PrintFileList(output_files, std::string(), true, false);
} else if (target->output_type() == Target::ACTION_FOREACH) {
const SubstitutionList& outputs = target->action_values().outputs();
if (!outputs.required_types().empty()) {
// Display the pattern and resolved pattern separately, since there are
// subtitutions used.
OutputString(" Output pattern\n");
for (const auto& elem : outputs.list())
OutputString(" " + elem.AsString() + "\n");
// Now display what that resolves to given the sources.
OutputString("\n Resolved output file list\n"); OutputString("\n Resolved output file list\n");
} }
if (outputs)
PrintValue(outputs, indent);
target->Remove("output_patterns", nullptr); // Resolved output list.
target->Remove(variables::kOutputs, nullptr); std::vector<SourceFile> output_files;
SubstitutionWriter::ApplyListToSources(target->settings(), outputs,
target->sources(), &output_files);
PrintFileList(output_files, std::string(), true, false);
} else {
DCHECK(target->IsBinary());
const Tool* tool = target->toolchain()->GetToolForTargetFinalOutput(target);
std::vector<OutputFile> output_files;
SubstitutionWriter::ApplyListToLinkerAsOutputFile(
target, tool, tool->outputs(), &output_files);
std::vector<SourceFile> output_files_as_source_file;
for (const OutputFile& output_file : output_files) {
output_files_as_source_file.push_back(
output_file.AsSourceFile(target->settings()->build_settings()));
}
PrintFileList(output_files_as_source_file, std::string(), true, false);
}
}
void PrintScript(const Target* target, bool display_header) {
if (display_header)
OutputString("\nscript\n");
OutputString(" " + target->action_values().script().value() + "\n");
}
void PrintArgs(const Target* target, bool display_header) {
if (display_header)
OutputString("\nargs\n");
for (const auto& elem : target->action_values().args().list()) {
OutputString(" " + elem.AsString() + "\n");
} }
} }
void PrintDepfile(const Target* target, bool display_header) {
if (target->action_values().depfile().empty())
return;
if (display_header)
OutputString("\ndepfile\n");
OutputString(" " + target->action_values().depfile().AsString() + "\n");
}
// Attribute the origin for attributing from where a target came from. Does
// nothing if the input is null or it does not have a location.
void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
if (!origin)
return;
Location location = origin->GetRange().begin();
out << " (Added by " + location.file()->name().value() << ":"
<< location.line_number() << ")\n";
}
// Templatized writer for writing out different config value types.
template<typename T> struct DescValueWriter {};
template<> struct DescValueWriter<std::string> {
void operator()(const std::string& str, std::ostream& out) const {
out << " " << str << "\n";
}
};
template<> struct DescValueWriter<SourceDir> {
void operator()(const SourceDir& dir, std::ostream& out) const {
out << " " << FormatSourceDir(dir) << "\n";
}
};
template<> struct DescValueWriter<LibFile> {
void operator()(const LibFile& lib, std::ostream& out) const {
if (lib.is_source_file())
out << " " << lib.source_file().value() << "\n";
else
out << " " << lib.value() << "\n";
}
};
// Writes a given config value type to the string, optionally with attribution.
// This should match RecursiveTargetConfigToStream in the order it traverses.
template<typename T> void OutputRecursiveTargetConfig(
const Target* target,
const char* header_name,
const std::vector<T>& (ConfigValues::* getter)() const) {
bool display_blame =
base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
DescValueWriter<T> writer;
std::ostringstream out;
for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
if ((iter.cur().*getter)().empty())
continue;
// Optional blame sub-head.
if (display_blame) {
const Config* config = iter.GetCurrentConfig();
if (config) {
// Source of this value is a config.
out << " From " << config->label().GetUserVisibleName(false) << "\n";
OutputSourceOfDep(iter.origin(), out);
} else {
// Source of this value is the target itself.
out << " From " << target->label().GetUserVisibleName(false) << "\n";
}
}
// Actual values.
ConfigValuesToStream(iter.cur(), getter, writer, out);
}
std::string out_str = out.str();
if (!out_str.empty()) {
if (header_name)
OutputString("\n" + std::string(header_name) + "\n");
OutputString(out_str);
}
}
template<typename T> void OutputConfigValueArray(
const ConfigValues& values,
const char* header_name,
const std::vector<T>& (ConfigValues::* getter)() const) {
std::ostringstream out;
DescValueWriter<T> writer;
for (const T& cur : (values.*getter)())
writer(cur, out);
std::string out_str = out.str();
if (!out_str.empty()) {
if (header_name)
OutputString("\n" + std::string(header_name) + "\n");
OutputString(out_str);
}
}
void PrintRuntimeDeps(const Target* target) {
bool display_blame =
base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
Label toolchain = target->label().GetToolchainLabel();
const Target* previous_from = NULL;
for (const auto& pair : ComputeRuntimeDeps(target)) {
if (display_blame) {
// Generally a target's runtime deps will be listed sequentially, so
// group them and don't duplicate the "from" label for two in a row.
if (previous_from == pair.second) {
OutputString(" "); // Just indent.
} else {
previous_from = pair.second;
OutputString("From ");
OutputString(pair.second->label().GetUserVisibleName(toolchain));
OutputString("\n "); // Make the file name indented.
}
}
OutputString(pair.first.value());
OutputString("\n");
}
}
// If "what" is empty, prints all PCH info. If "what" is nonempty, prints only
// the things that match (if any). Returns true if anything was printed.
bool PrintPrecompiledHeaderInfo(const ConfigValues& values,
const std::string& what,
bool display_headers) {
bool found_match = false;
if (what == variables::kPrecompiledHeader || what.empty()) {
if (!values.precompiled_header().empty()) {
if (display_headers)
OutputString("\nprecompiled_header\n");
OutputString(values.precompiled_header() + "\n");
}
found_match = true;
}
if (what == variables::kPrecompiledSource || what.empty()) {
if (!values.precompiled_source().is_null()) {
if (display_headers)
OutputString("\nprecompiled_source\n");
OutputString(values.precompiled_source().value() + "\n");
}
found_match = true;
}
return found_match;
}
bool PrintTarget(const Target* target, bool PrintTarget(const Target* target,
const std::string& what, const std::string& what,
bool single_target, bool display_target_header) {
bool all, if (display_target_header) {
bool tree, OutputString("Target: ", DECORATION_YELLOW);
bool blame) { OutputString(target->label().GetUserVisibleName(false) + "\n");
std::unique_ptr<base::DictionaryValue> dict = OutputString("Type: ", DECORATION_YELLOW);
DescBuilder::DescriptionForTarget(target, what, all, tree, blame); OutputString(std::string(
if (!what.empty() && dict->empty()) { Target::GetStringForOutputType(target->output_type())) + "\n");
OutputString("Don't know how to display \"" + what + "\" for \"" + OutputString("Toolchain: ", DECORATION_YELLOW);
Target::GetStringForOutputType(target->output_type()) + OutputString(
"\".\n"); target->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
return false; }
// Display headers when outputting everything.
bool display_headers = what.empty();
bool is_binary_output = target->IsBinary();
bool found_match = false;
// General target meta variables.
if (what.empty() || what == variables::kVisibility) {
PrintVisibility(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kTestonly) {
PrintTestonly(target, display_headers);
found_match = true;
}
// Binary target meta variables.
if (is_binary_output) {
if (what.empty() || what == variables::kCheckIncludes) {
PrintCheckIncludes(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kAllowCircularIncludesFrom) {
PrintAllowCircularIncludesFrom(target, display_headers);
found_match = true;
}
}
// Sources and inputs.
if (what.empty() || what == variables::kSources) {
PrintSources(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kPublic) {
PrintPublic(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kInputs) {
PrintInputs(target, display_headers);
found_match = true;
}
// Configs. Configs set directly on a target are only relevant for binary
// targets
if (is_binary_output && (what.empty() || what == variables::kConfigs)) {
PrintConfigs(target, display_headers);
found_match = true;
}
// Dependent/public configs can be applied to anything.
if (what.empty() || what == variables::kPublicConfigs) {
PrintPublicConfigs(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kAllDependentConfigs) {
PrintAllDependentConfigs(target, display_headers);
found_match = true;
}
// Action values.
if (target->output_type() == Target::ACTION ||
target->output_type() == Target::ACTION_FOREACH) {
if (what.empty() || what == variables::kScript) {
PrintScript(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kArgs) {
PrintArgs(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kDepfile) {
PrintDepfile(target, display_headers);
found_match = true;
}
}
// Outputs.
if (target->output_type() != Target::SOURCE_SET &&
target->output_type() != Target::GROUP) {
if (what.empty() || what == variables::kOutputs) {
PrintOutputs(target, display_headers);
found_match = true;
}
}
// Values from configs only apply to binary targets.
if (is_binary_output) {
#define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
if (what.empty() || what == #name) { \
OutputRecursiveTargetConfig<type>( \
target, display_headers ? #name : nullptr, &ConfigValues::name); \
found_match = true; \
}
CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
// Libs and lib_dirs are handled specially below.
#undef CONFIG_VALUE_ARRAY_HANDLER
found_match |= PrintPrecompiledHeaderInfo(target->config_values(),
what, display_headers);
} }
// Print single value, without any headers
if (!what.empty() && dict->size() == 1 && single_target) { // Deps
base::DictionaryValue::Iterator iter(*dict); if (what.empty() || what == "deps") {
PrintValue(&iter.value(), 0); PrintDeps(target, display_headers);
return true; found_match = true;
}
OutputString("Target ", DECORATION_YELLOW);
OutputString(target->label().GetUserVisibleName(false));
OutputString("\n");
std::unique_ptr<base::Value> v;
#define HANDLER(property, handler_name) \
if (dict->Remove(property, &v)) { \
handler_name(property, v.get()); \
}
// Entries with DefaultHandler are present to enforce order
HANDLER("type", LabelHandler);
HANDLER("toolchain", LabelHandler);
HANDLER(variables::kVisibility, VisibilityHandler);
HANDLER(variables::kTestonly, DefaultHandler);
HANDLER(variables::kCheckIncludes, DefaultHandler);
HANDLER(variables::kAllowCircularIncludesFrom, DefaultHandler);
HANDLER(variables::kSources, DefaultHandler);
HANDLER(variables::kPublic, PublicHandler);
HANDLER(variables::kInputs, DefaultHandler);
HANDLER(variables::kConfigs, ConfigsHandler);
HANDLER(variables::kPublicConfigs, ConfigsHandler);
HANDLER(variables::kAllDependentConfigs, ConfigsHandler);
HANDLER(variables::kScript, DefaultHandler);
HANDLER(variables::kArgs, DefaultHandler);
HANDLER(variables::kDepfile, DefaultHandler);
ProcessOutputs(dict.get());
HANDLER("bundle_data", DefaultHandler);
HANDLER(variables::kArflags, DefaultHandler);
HANDLER(variables::kAsmflags, DefaultHandler);
HANDLER(variables::kCflags, DefaultHandler);
HANDLER(variables::kCflagsC, DefaultHandler);
HANDLER(variables::kCflagsCC, DefaultHandler);
HANDLER(variables::kCflagsObjC, DefaultHandler);
HANDLER(variables::kCflagsObjCC, DefaultHandler);
HANDLER(variables::kDefines, DefaultHandler);
HANDLER(variables::kIncludeDirs, DefaultHandler);
HANDLER(variables::kLdflags, DefaultHandler);
HANDLER(variables::kPrecompiledHeader, DefaultHandler);
HANDLER(variables::kPrecompiledSource, DefaultHandler);
HANDLER(variables::kDeps, DepsHandler);
HANDLER(variables::kLibs, DefaultHandler);
HANDLER(variables::kLibDirs, DefaultHandler);
#undef HANDLER
// Process the rest (if any)
base::DictionaryValue::Iterator iter(*dict);
while (!iter.IsAtEnd()) {
DefaultHandler(iter.key(), &iter.value());
iter.Advance();
} }
// Runtime deps are special, print only when explicitly asked for and not in
// overview mode.
if (what == "runtime_deps") {
PrintRuntimeDeps(target);
found_match = true;
}
// Libs can be part of any target and get recursively pushed up the chain,
// so display them regardless of target type.
if (what.empty() || what == variables::kLibs) {
PrintLibs(target, display_headers);
found_match = true;
}
if (what.empty() || what == variables::kLibDirs) {
PrintLibDirs(target, display_headers);
found_match = true;
}
if (!found_match) {
OutputString("Don't know how to display \"" + what + "\" for \"" +
Target::GetStringForOutputType(target->output_type()) + "\".\n");
return false;
}
return true; return true;
} }
bool PrintConfig(const Config* config, bool PrintConfig(const Config* config,
const std::string& what, const std::string& what,
bool single_config) { bool display_config_header) {
std::unique_ptr<base::DictionaryValue> dict = const ConfigValues& values = config->resolved_values();
DescBuilder::DescriptionForConfig(config, what);
if (!what.empty() && dict->empty()) { if (display_config_header) {
OutputString("Don't know how to display \"" + what + "\" for a config.\n"); OutputString("Config: ", DECORATION_YELLOW);
return false; OutputString(config->label().GetUserVisibleName(false) + "\n");
} OutputString("Toolchain: ", DECORATION_YELLOW);
// Print single value, without any headers OutputString(
if (!what.empty() && dict->size() == 1 && single_config) { config->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
base::DictionaryValue::Iterator iter(*dict); if (what.empty() && !config->configs().empty()) {
PrintValue(&iter.value(), 0); OutputString(
return true; "(This is a composite config, the values below are after the\n"
"expansion of the child configs.)\n");
}
} }
OutputString("Config: ", DECORATION_YELLOW); // Display headers when outputting everything.
OutputString(config->label().GetUserVisibleName(false)); bool display_headers = what.empty();
OutputString("\n");
std::unique_ptr<base::Value> v; if (what.empty() || what == variables::kConfigs)
#define HANDLER(property, handler_name) \ PrintConfigs(config, display_headers);
if (dict->Remove(property, &v)) { \
handler_name(property, v.get()); \ #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
if (what.empty() || what == #name) { \
OutputConfigValueArray<type>(values, display_headers ? #name : nullptr, \
&ConfigValues::name); \
found_match = true; \
} }
HANDLER("toolchain", LabelHandler); bool found_match = false;
if (!config->configs().empty()) {
OutputString( CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
"(This is a composite config, the values below are after the\n" CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
"expansion of the child configs.)\n"); CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
} CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
HANDLER(variables::kArflags, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
HANDLER(variables::kAsmflags, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
HANDLER(variables::kCflags, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
HANDLER(variables::kCflagsC, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
HANDLER(variables::kCflagsCC, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
HANDLER(variables::kCflagsObjC, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
HANDLER(variables::kCflagsObjCC, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
HANDLER(variables::kDefines, DefaultHandler); CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
HANDLER(variables::kIncludeDirs, DefaultHandler);
HANDLER(variables::kLdflags, DefaultHandler);
HANDLER(variables::kLibs, DefaultHandler);
HANDLER(variables::kLibDirs, DefaultHandler);
HANDLER(variables::kPrecompiledHeader, DefaultHandler);
HANDLER(variables::kPrecompiledSource, DefaultHandler);
#undef HANDLER
#undef CONFIG_VALUE_ARRAY_HANDLER
// Handles all PCH-related variables.
found_match |= PrintPrecompiledHeaderInfo(config->resolved_values(),
what, display_headers);
if (!found_match) {
OutputString("Don't know how to display \"" + what + "\" for a config.\n");
return false;
}
return true; return true;
} }
...@@ -291,8 +762,7 @@ const char kDesc[] = "desc"; ...@@ -291,8 +762,7 @@ const char kDesc[] = "desc";
const char kDesc_HelpShort[] = const char kDesc_HelpShort[] =
"desc: Show lots of insightful information about a target or config."; "desc: Show lots of insightful information about a target or config.";
const char kDesc_Help[] = const char kDesc_Help[] =
"gn desc <out_dir> <label or pattern> [<what to show>] [--blame] " "gn desc <out_dir> <label or pattern> [<what to show>] [--blame]\n"
"[--format=json]\n"
"\n" "\n"
" Displays information about a given target or config. The build\n" " Displays information about a given target or config. The build\n"
" build parameters will be taken for the build in the given <out_dir>.\n" " build parameters will be taken for the build in the given <out_dir>.\n"
...@@ -344,9 +814,6 @@ const char kDesc_Help[] = ...@@ -344,9 +814,6 @@ const char kDesc_Help[] =
"\n" "\n"
ALL_TOOLCHAINS_SWITCH_HELP ALL_TOOLCHAINS_SWITCH_HELP
"\n" "\n"
" --format=json\n"
" Format the output as JSON instead of text.\n"
"\n"
"Target flags\n" "Target flags\n"
"\n" "\n"
" --blame\n" " --blame\n"
...@@ -455,52 +922,28 @@ int RunDesc(const std::vector<std::string>& args) { ...@@ -455,52 +922,28 @@ int RunDesc(const std::vector<std::string>& args) {
if (args.size() == 3) if (args.size() == 3)
what_to_print = args[2]; what_to_print = args[2];
bool json = cmdline->GetSwitchValueASCII("format") == "json"; bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
if (json) {
// Convert all targets/configs to JSON, serialize and print them
auto res = base::WrapUnique(new base::DictionaryValue());
if (!target_matches.empty()) {
for (const auto* target : target_matches) {
res->Set(target->label().GetUserVisibleName(
target->settings()->default_toolchain_label()),
DescBuilder::DescriptionForTarget(
target, what_to_print, cmdline->HasSwitch(kAll),
cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
}
} else if (!config_matches.empty()) {
for (const auto* config : config_matches) {
res->Set(config->label().GetUserVisibleName(false),
DescBuilder::DescriptionForConfig(config, what_to_print));
}
}
std::string s;
base::JSONWriter::WriteWithOptions(
*res.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
OutputString(s);
} else {
// Regular (non-json) formatted output
bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
bool printed_output = false;
for (const Target* target : target_matches) {
if (printed_output)
OutputString("\n\n");
printed_output = true;
if (!PrintTarget(target, what_to_print, !multiple_outputs,
cmdline->HasSwitch(kAll), cmdline->HasSwitch(kTree),
cmdline->HasSwitch(kBlame)))
return 1;
}
for (const Config* config : config_matches) {
if (printed_output)
OutputString("\n\n");
printed_output = true;
if (!PrintConfig(config, what_to_print, !multiple_outputs)) // Display headers for each target when printing all values, or when printing
return 1; // multiple targets or configs.
} bool display_item_header = multiple_outputs || what_to_print.empty();
bool printed_output = false;
for (const Target* target : target_matches) {
if (printed_output)
OutputString("\n\n");
printed_output = true;
if (!PrintTarget(target, what_to_print, display_item_header))
return 1;
}
for (const Config* config : config_matches) {
if (printed_output)
OutputString("\n\n");
printed_output = true;
if (!PrintConfig(config, what_to_print, display_item_header))
return 1;
} }
return 0; return 0;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "tools/gn/build_settings.h" #include "tools/gn/build_settings.h"
#include "tools/gn/commands.h" #include "tools/gn/commands.h"
#include "tools/gn/eclipse_writer.h" #include "tools/gn/eclipse_writer.h"
#include "tools/gn/json_project_writer.h"
#include "tools/gn/ninja_target_writer.h" #include "tools/gn/ninja_target_writer.h"
#include "tools/gn/ninja_writer.h" #include "tools/gn/ninja_writer.h"
#include "tools/gn/qt_creator_writer.h" #include "tools/gn/qt_creator_writer.h"
...@@ -37,14 +36,10 @@ const char kSwitchIdeValueVs[] = "vs"; ...@@ -37,14 +36,10 @@ const char kSwitchIdeValueVs[] = "vs";
const char kSwitchIdeValueVs2013[] = "vs2013"; const char kSwitchIdeValueVs2013[] = "vs2013";
const char kSwitchIdeValueVs2015[] = "vs2015"; const char kSwitchIdeValueVs2015[] = "vs2015";
const char kSwitchIdeValueXcode[] = "xcode"; const char kSwitchIdeValueXcode[] = "xcode";
const char kSwitchIdeValueJson[] = "json";
const char kSwitchNinjaExtraArgs[] = "ninja-extra-args"; const char kSwitchNinjaExtraArgs[] = "ninja-extra-args";
const char kSwitchRootTarget[] = "root-target"; const char kSwitchRootTarget[] = "root-target";
const char kSwitchSln[] = "sln"; const char kSwitchSln[] = "sln";
const char kSwitchWorkspace[] = "workspace"; const char kSwitchWorkspace[] = "workspace";
const char kSwitchJsonFileName[] = "json-file-name";
const char kSwitchJsonIdeScript[] = "json-ide-script";
const char kSwitchJsonIdeScriptArgs[] = "json-ide-script-args";
// Called on worker thread to write the ninja file. // Called on worker thread to write the ninja file.
void BackgroundDoWrite(const Target* target) { void BackgroundDoWrite(const Target* target) {
...@@ -118,7 +113,7 @@ void PrintInvalidGeneratedInput(const Builder* builder, ...@@ -118,7 +113,7 @@ void PrintInvalidGeneratedInput(const Builder* builder,
if (generator) { if (generator) {
err += "but this file was not generated by any dependencies of the " + err += "but this file was not generated by any dependencies of the " +
target_str + ". The target\nthat generates the file is:\n "; target_str + ". The target\nthat generates the file is:\n ";
err += generator->label().GetUserVisibleName(show_toolchains); err += generator->label().GetUserVisibleName(show_toolchains);
} else { } else {
err += "but no targets in the build generate that file."; err += "but no targets in the build generate that file.";
...@@ -171,12 +166,11 @@ bool RunIdeWriter(const std::string& ide, ...@@ -171,12 +166,11 @@ bool RunIdeWriter(const std::string& ide,
Err* err) { Err* err) {
const base::CommandLine* command_line = const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess(); base::CommandLine::ForCurrentProcess();
bool quiet = command_line->HasSwitch(switches::kQuiet);
base::ElapsedTimer timer; base::ElapsedTimer timer;
if (ide == kSwitchIdeValueEclipse) { if (ide == kSwitchIdeValueEclipse) {
bool res = EclipseWriter::RunAndWriteFile(build_settings, builder, err); bool res = EclipseWriter::RunAndWriteFile(build_settings, builder, err);
if (res && !quiet) { if (res && !command_line->HasSwitch(switches::kQuiet)) {
OutputString("Generating Eclipse settings took " + OutputString("Generating Eclipse settings took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) + base::Int64ToString(timer.Elapsed().InMilliseconds()) +
"ms\n"); "ms\n");
...@@ -195,7 +189,7 @@ bool RunIdeWriter(const std::string& ide, ...@@ -195,7 +189,7 @@ bool RunIdeWriter(const std::string& ide,
filters = command_line->GetSwitchValueASCII(kSwitchFilters); filters = command_line->GetSwitchValueASCII(kSwitchFilters);
bool res = VisualStudioWriter::RunAndWriteFiles( bool res = VisualStudioWriter::RunAndWriteFiles(
build_settings, builder, version, sln_name, filters, err); build_settings, builder, version, sln_name, filters, err);
if (res && !quiet) { if (res && !command_line->HasSwitch(switches::kQuiet)) {
OutputString("Generating Visual Studio projects took " + OutputString("Generating Visual Studio projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) + base::Int64ToString(timer.Elapsed().InMilliseconds()) +
"ms\n"); "ms\n");
...@@ -208,7 +202,7 @@ bool RunIdeWriter(const std::string& ide, ...@@ -208,7 +202,7 @@ bool RunIdeWriter(const std::string& ide,
command_line->GetSwitchValueASCII(kSwitchNinjaExtraArgs), command_line->GetSwitchValueASCII(kSwitchNinjaExtraArgs),
command_line->GetSwitchValueASCII(kSwitchFilters), build_settings, command_line->GetSwitchValueASCII(kSwitchFilters), build_settings,
builder, err); builder, err);
if (res && !quiet) { if (res && !command_line->HasSwitch(switches::kQuiet)) {
OutputString("Generating Xcode projects took " + OutputString("Generating Xcode projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) + base::Int64ToString(timer.Elapsed().InMilliseconds()) +
"ms\n"); "ms\n");
...@@ -220,32 +214,12 @@ bool RunIdeWriter(const std::string& ide, ...@@ -220,32 +214,12 @@ bool RunIdeWriter(const std::string& ide,
root_target = command_line->GetSwitchValueASCII(kSwitchRootTarget); root_target = command_line->GetSwitchValueASCII(kSwitchRootTarget);
bool res = QtCreatorWriter::RunAndWriteFile(build_settings, builder, err, bool res = QtCreatorWriter::RunAndWriteFile(build_settings, builder, err,
root_target); root_target);
if (res && !quiet) { if (res && !command_line->HasSwitch(switches::kQuiet)) {
OutputString("Generating QtCreator projects took " + OutputString("Generating QtCreator projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) + base::Int64ToString(timer.Elapsed().InMilliseconds()) +
"ms\n"); "ms\n");
} }
return res; return res;
} else if (ide == kSwitchIdeValueJson) {
std::string file_name =
command_line->GetSwitchValueASCII(kSwitchJsonFileName);
if (file_name.empty())
file_name = "project.json";
std::string exec_script =
command_line->GetSwitchValueASCII(kSwitchJsonIdeScript);
std::string exec_script_extra_args =
command_line->GetSwitchValueASCII(kSwitchJsonIdeScriptArgs);
std::string filters = command_line->GetSwitchValueASCII(kSwitchFilters);
bool res = JSONProjectWriter::RunAndWriteFiles(
build_settings, builder, file_name, exec_script, exec_script_extra_args,
filters, quiet, err);
if (res && !quiet) {
OutputString("Generating JSON projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) +
"ms\n");
}
return res;
} }
*err = Err(Location(), "Unknown IDE: " + ide); *err = Err(Location(), "Unknown IDE: " + ide);
...@@ -255,7 +229,8 @@ bool RunIdeWriter(const std::string& ide, ...@@ -255,7 +229,8 @@ bool RunIdeWriter(const std::string& ide,
} // namespace } // namespace
const char kGen[] = "gen"; const char kGen[] = "gen";
const char kGen_HelpShort[] = "gen: Generate ninja files."; const char kGen_HelpShort[] =
"gen: Generate ninja files.";
const char kGen_Help[] = const char kGen_Help[] =
"gn gen: Generate ninja files.\n" "gn gen: Generate ninja files.\n"
"\n" "\n"
...@@ -284,13 +259,12 @@ const char kGen_Help[] = ...@@ -284,13 +259,12 @@ const char kGen_Help[] =
" \"vs2015\" - Visual Studio 2015 project/solution files.\n" " \"vs2015\" - Visual Studio 2015 project/solution files.\n"
" \"xcode\" - Xcode workspace/solution files.\n" " \"xcode\" - Xcode workspace/solution files.\n"
" \"qtcreator\" - QtCreator project files.\n" " \"qtcreator\" - QtCreator project files.\n"
" \"json\" - JSON file containing target information\n"
"\n" "\n"
" --filters=<path_prefixes>\n" " --filters=<path_prefixes>\n"
" Semicolon-separated list of label patterns used to limit the set\n" " Semicolon-separated list of label patterns used to limit the set\n"
" of generated projects (see \"gn help label_pattern\"). Only\n" " of generated projects (see \"gn help label_pattern\"). Only\n"
" matching targets and their dependencies will be included in the\n" " matching targets and their dependencies will be included in the\n"
" solution. Only used for Visual Studio, Xcode and JSON.\n" " solution. Only used for Visual Studio and Xcode.\n"
"\n" "\n"
"Visual Studio Flags\n" "Visual Studio Flags\n"
"\n" "\n"
...@@ -331,27 +305,7 @@ const char kGen_Help[] = ...@@ -331,27 +305,7 @@ const char kGen_Help[] =
" properly define includes/defines for each file individually.\n" " properly define includes/defines for each file individually.\n"
" Instead, one set of includes/defines is generated for the entire\n" " Instead, one set of includes/defines is generated for the entire\n"
" project. This works fairly well but may still result in a few indexer\n" " project. This works fairly well but may still result in a few indexer\n"
" issues here and there.\n" " issues here and there.\n";
"\n"
"Generic JSON Output\n"
"\n"
" Dumps target information to JSON file and optionally invokes python\n"
" script on generated file. \n"
" See comments at the beginning of json_project_writer.cc and\n"
" desc_builder.cc for overview of JSON file format.\n"
"\n"
" --json-file-name=<json_file_name>\n"
" Overrides default file name (project.json) of generated JSON file.\n"
"\n"
" --json-ide-script=<path_to_python_script>\n"
" Executes python script after the JSON file is generated.\n"
" Path can be project absolute (//), system absolute (/) or\n"
" relative, in which case the output directory will be base.\n"
" Path to generated JSON file will be first argument when invoking\n"
" script.\n"
"\n"
" --json-ide-script-args=<argument>\n"
" Optional second argument that will passed to executed script.\n";
int RunGen(const std::vector<std::string>& args) { int RunGen(const std::vector<std::string>& args) {
base::ElapsedTimer timer; base::ElapsedTimer timer;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/values.h"
#include "tools/gn/builder.h" #include "tools/gn/builder.h"
#include "tools/gn/filesystem_utils.h" #include "tools/gn/filesystem_utils.h"
#include "tools/gn/item.h" #include "tools/gn/item.h"
...@@ -281,20 +280,22 @@ base::FilePath BuildFileForItem(const Item* item) { ...@@ -281,20 +280,22 @@ base::FilePath BuildFileForItem(const Item* item) {
return item->defined_from()->GetRange().begin().file()->physical_name(); return item->defined_from()->GetRange().begin().file()->physical_name();
} }
void PrintTargetsAsBuildfiles(const std::vector<const Target*>& targets, void PrintTargetsAsBuildfiles(bool indent,
base::ListValue* out) { const std::vector<const Target*>& targets) {
// Output the set of unique source files. // Output the set of unique source files.
std::set<std::string> unique_files; std::set<std::string> unique_files;
for (const Target* target : targets) for (const Target* target : targets)
unique_files.insert(FilePathToUTF8(BuildFileForItem(target))); unique_files.insert(FilePathToUTF8(BuildFileForItem(target)));
for (const std::string& file : unique_files) { for (const std::string& file : unique_files) {
out->AppendString(file); if (indent)
OutputString(" ");
OutputString(file + "\n");
} }
} }
void PrintTargetsAsLabels(const std::vector<const Target*>& targets, void PrintTargetsAsLabels(bool indent,
base::ListValue* out) { const std::vector<const Target*>& targets) {
// Putting the labels into a set automatically sorts them for us. // Putting the labels into a set automatically sorts them for us.
std::set<Label> unique_labels; std::set<Label> unique_labels;
for (auto* target : targets) for (auto* target : targets)
...@@ -306,13 +307,16 @@ void PrintTargetsAsLabels(const std::vector<const Target*>& targets, ...@@ -306,13 +307,16 @@ void PrintTargetsAsLabels(const std::vector<const Target*>& targets,
for (const Label& label : unique_labels) { for (const Label& label : unique_labels) {
// Print toolchain only for ones not in the default toolchain. // Print toolchain only for ones not in the default toolchain.
out->AppendString(label.GetUserVisibleName(label.GetToolchainLabel() != if (indent)
default_tc_label)); OutputString(" ");
OutputString(label.GetUserVisibleName(
label.GetToolchainLabel() != default_tc_label));
OutputString("\n");
} }
} }
void PrintTargetsAsOutputs(const std::vector<const Target*>& targets, void PrintTargetsAsOutputs(bool indent,
base::ListValue* out) { const std::vector<const Target*>& targets) {
if (targets.empty()) if (targets.empty())
return; return;
...@@ -332,7 +336,10 @@ void PrintTargetsAsOutputs(const std::vector<const Target*>& targets, ...@@ -332,7 +336,10 @@ void PrintTargetsAsOutputs(const std::vector<const Target*>& targets,
std::string result = RebasePath(output_as_source.value(), std::string result = RebasePath(output_as_source.value(),
build_settings->build_dir(), build_settings->build_dir(),
build_settings->root_path_utf8()); build_settings->root_path_utf8());
out->AppendString(result); if (indent)
OutputString(" ");
OutputString(result);
OutputString("\n");
} }
} }
...@@ -483,8 +490,7 @@ bool FilterPatternsFromString(const BuildSettings* build_settings, ...@@ -483,8 +490,7 @@ bool FilterPatternsFromString(const BuildSettings* build_settings,
return true; return true;
} }
void FilterAndPrintTargets(std::vector<const Target*>* targets, void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets) {
base::ListValue* out) {
if (targets->empty()) if (targets->empty())
return; return;
...@@ -498,40 +504,21 @@ void FilterAndPrintTargets(std::vector<const Target*>* targets, ...@@ -498,40 +504,21 @@ void FilterAndPrintTargets(std::vector<const Target*>* targets,
return; return;
switch (printing_mode) { switch (printing_mode) {
case TARGET_PRINT_BUILDFILE: case TARGET_PRINT_BUILDFILE:
PrintTargetsAsBuildfiles(*targets, out); PrintTargetsAsBuildfiles(indent, *targets);
break; break;
case TARGET_PRINT_LABEL: case TARGET_PRINT_LABEL:
PrintTargetsAsLabels(*targets, out); PrintTargetsAsLabels(indent, *targets);
break; break;
case TARGET_PRINT_OUTPUT: case TARGET_PRINT_OUTPUT:
PrintTargetsAsOutputs(*targets, out); PrintTargetsAsOutputs(indent, *targets);
break; break;
} }
} }
void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets) {
base::ListValue tmp;
FilterAndPrintTargets(targets, &tmp);
for (const auto& value : tmp) {
std::string string;
value->GetAsString(&string);
if (indent)
OutputString(" ");
OutputString(string);
OutputString("\n");
}
}
void FilterAndPrintTargetSet(bool indent, void FilterAndPrintTargetSet(bool indent,
const std::set<const Target*>& targets) { const std::set<const Target*>& targets) {
std::vector<const Target*> target_vector(targets.begin(), targets.end()); std::vector<const Target*> target_vector(targets.begin(), targets.end());
FilterAndPrintTargets(indent, &target_vector); FilterAndPrintTargets(indent, &target_vector);
} }
void FilterAndPrintTargetSet(const std::set<const Target*>& targets,
base::ListValue* out) {
std::vector<const Target*> target_vector(targets.begin(), targets.end());
FilterAndPrintTargets(&target_vector, out);
}
} // namespace commands } // namespace commands
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <vector> #include <vector>
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/values.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
#include "tools/gn/unique_vector.h" #include "tools/gn/unique_vector.h"
...@@ -180,13 +179,8 @@ bool FilterPatternsFromString(const BuildSettings* build_settings, ...@@ -180,13 +179,8 @@ bool FilterPatternsFromString(const BuildSettings* build_settings,
// //
// The vector will be modified so that only the printed targets will remain. // The vector will be modified so that only the printed targets will remain.
void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets); void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets);
void FilterAndPrintTargets(std::vector<const Target*>* targets,
base::ListValue* out);
void FilterAndPrintTargetSet(bool indent, void FilterAndPrintTargetSet(bool indent,
const std::set<const Target*>& targets); const std::set<const Target*>& targets);
void FilterAndPrintTargetSet(const std::set<const Target*>& targets,
base::ListValue* out);
// Extra help from command_check.cc // Extra help from command_check.cc
extern const char kNoGnCheck_Help[]; extern const char kNoGnCheck_Help[];
......
// Copyright (c) 2016 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 <set>
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "tools/gn/commands.h"
#include "tools/gn/config.h"
#include "tools/gn/config_values_extractors.h"
#include "tools/gn/deps_iterator.h"
#include "tools/gn/desc_builder.h"
#include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/runtime_deps.h"
#include "tools/gn/settings.h"
#include "tools/gn/substitution_writer.h"
#include "tools/gn/variables.h"
// Example structure of Value for single target
// (not applicable or empty fields will be ommitted depending on target type)
//
// target_properties = {
// "type" : "output_type", // matching Target::GetStringForOutputType
// "toolchain" : "toolchain_name",
// "visibility" : [ list of visibility pattern descriptions ],
// "test_only" : true or false,
// "check_includes": true or false,
// "allow_circular_includes_from": [ list of target names ],
// "sources" : [ list of source files ],
// "public" : either "*" or [ list of public headers],
// "inputs" : [ list of inputs for target ],
// "configs" : [ list of configs for this target ],
// "public_configs" : [ list of public configs for this taget],
// "all_dependent_configs", [ list of all dependent configs for this target],
// "script" : "script for action targets",
// "args" : [ argument list for action targets ],
// "depfile : "file name for action input dependencies",
// "outputs" : [ list of target outputs ],
// "arflags", "asmflags", "cflags", "cflags_c",
// "clfags_cc", "cflags_objc", "clfags_objcc" : [ list of flags],
// "defines" : [ list of preprocessor definitions ],
// "include_dirs" : [ list of include directories ],
// "precompiled_header" : "name of precompiled header file",
// "precompiled_source" : "path to precompiled source",
// "deps : [ list of target dependencies ],
// "libs" : [ list of libraries ],
// "lib_dirs" : [ list of library directories ]
// }
//
// Optionally, if "what" is specified while generating description, two other
// properties can be requested that are not included by default
//
// "runtime_deps" : [list of computed runtime dependencies]
// "source_outputs" : {
// "source_file x" : [ list of outputs for source file x ]
// "source_file y" : [ list of outputs for source file y ]
// ...
// }
namespace {
std::string FormatSourceDir(const SourceDir& dir) {
#if defined(OS_WIN)
// On Windows we fix up system absolute paths to look like native ones.
// Internally, they'll look like "/C:\foo\bar/"
if (dir.is_system_absolute()) {
std::string buf = dir.value();
if (buf.size() > 3 && buf[2] == ':') {
buf.erase(buf.begin()); // Erase beginning slash.
return buf;
}
}
#endif
return dir.value();
}
void RecursiveCollectChildDeps(const Target* target,
std::set<const Target*>* result);
void RecursiveCollectDeps(const Target* target,
std::set<const Target*>* result) {
if (result->find(target) != result->end())
return; // Already did this target.
result->insert(target);
RecursiveCollectChildDeps(target, result);
}
void RecursiveCollectChildDeps(const Target* target,
std::set<const Target*>* result) {
for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
RecursiveCollectDeps(pair.ptr, result);
}
// Common functionality for target and config description builder
class BaseDescBuilder {
public:
typedef std::unique_ptr<base::Value> ValuePtr;
BaseDescBuilder(const std::set<std::string>& what,
bool all,
bool tree,
bool blame)
: what_(what), all_(all), tree_(tree), blame_(blame) {}
protected:
virtual Label GetToolchainLabel() const = 0;
bool what(const std::string& w) const {
return what_.empty() || what_.find(w) != what_.end();
}
template <typename T>
ValuePtr RenderValue(const std::vector<T>& vector) {
auto res = base::WrapUnique(new base::ListValue());
for (const auto& v : vector)
res->Append(RenderValue(v));
return std::move(res);
}
ValuePtr RenderValue(const std::string& s, bool optional = false) {
return (s.empty() && optional) ? base::Value::CreateNullValue()
: ValuePtr(new base::StringValue(s));
}
ValuePtr RenderValue(const SourceDir& d) {
return d.is_null() ? base::Value::CreateNullValue()
: ValuePtr(new base::StringValue(FormatSourceDir(d)));
}
ValuePtr RenderValue(const SourceFile& f) {
return f.is_null() ? base::Value::CreateNullValue()
: ValuePtr(new base::StringValue(f.value()));
}
ValuePtr RenderValue(const LibFile& lib) {
if (lib.is_source_file())
return RenderValue(lib.source_file());
return RenderValue(lib.value());
}
template <class VectorType>
void FillInConfigVector(base::ListValue* out,
const VectorType& configs,
int indent = 0) {
for (const auto& config : configs) {
std::string name(indent * 2, ' ');
name.append(config.label.GetUserVisibleName(GetToolchainLabel()));
out->AppendString(name);
if (tree_)
FillInConfigVector(out, config.ptr->configs(), indent + 1);
}
}
void FillInPrecompiledHeader(base::DictionaryValue* out,
const ConfigValues& values) {
if (what(variables::kPrecompiledHeader) &&
!values.precompiled_header().empty()) {
out->Set(variables::kPrecompiledHeader,
RenderValue(values.precompiled_header(), true));
}
if (what(variables::kPrecompiledSource) &&
!values.precompiled_source().is_null()) {
out->Set(variables::kPrecompiledSource,
RenderValue(values.precompiled_source()));
}
}
std::set<std::string> what_;
bool all_;
bool tree_;
bool blame_;
};
class ConfigDescBuilder : public BaseDescBuilder {
public:
ConfigDescBuilder(const Config* config, const std::set<std::string>& what)
: BaseDescBuilder(what, false, false, false), config_(config) {}
std::unique_ptr<base::DictionaryValue> BuildDescription() {
auto res = base::WrapUnique(new base::DictionaryValue());
const ConfigValues& values = config_->resolved_values();
if (what_.empty())
res->SetString(
"toolchain",
config_->label().GetToolchainLabel().GetUserVisibleName(false));
if (what(variables::kConfigs) && !config_->configs().empty()) {
auto configs = base::WrapUnique(new base::ListValue());
FillInConfigVector(configs.get(), config_->configs().vector());
res->Set(variables::kConfigs, std::move(configs));
}
#define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
if (what(#name)) { \
ValuePtr ptr = \
render_config_value_array<type>(values, &ConfigValues::name); \
if (ptr) { \
res->Set(#name, std::move(ptr)); \
} \
}
CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
#undef CONFIG_VALUE_ARRAY_HANDLER
FillInPrecompiledHeader(res.get(), values);
return res;
}
protected:
Label GetToolchainLabel() const override {
return config_->label().GetToolchainLabel();
}
private:
template <typename T>
ValuePtr render_config_value_array(
const ConfigValues& values,
const std::vector<T>& (ConfigValues::*getter)() const) {
auto res = base::WrapUnique(new base::ListValue());
for (const T& cur : (values.*getter)())
res->Append(RenderValue(cur));
return res->empty() ? nullptr : std::move(res);
}
const Config* config_;
};
class TargetDescBuilder : public BaseDescBuilder {
public:
TargetDescBuilder(const Target* target,
const std::set<std::string>& what,
bool all,
bool tree,
bool blame)
: BaseDescBuilder(what, all, tree, blame), target_(target) {}
std::unique_ptr<base::DictionaryValue> BuildDescription() {
auto res = base::WrapUnique(new base::DictionaryValue());
bool is_binary_output = target_->IsBinary();
if (what_.empty()) {
res->SetString("type",
Target::GetStringForOutputType(target_->output_type()));
res->SetString(
"toolchain",
target_->label().GetToolchainLabel().GetUserVisibleName(false));
}
// General target meta variables.
if (what(variables::kVisibility))
res->Set(variables::kVisibility, target_->visibility().AsValue());
if (what(variables::kTestonly))
res->SetBoolean(variables::kTestonly, target_->testonly());
if (is_binary_output) {
if (what(variables::kCheckIncludes))
res->SetBoolean(variables::kCheckIncludes, target_->check_includes());
if (what(variables::kAllowCircularIncludesFrom)) {
auto labels = base::WrapUnique(new base::ListValue());
for (const auto& cur : target_->allow_circular_includes_from())
labels->AppendString(cur.GetUserVisibleName(GetToolchainLabel()));
res->Set(variables::kAllowCircularIncludesFrom, std::move(labels));
}
}
if (what(variables::kSources) && !target_->sources().empty())
res->Set(variables::kSources, RenderValue(target_->sources()));
if (what(variables::kOutputName) && !target_->output_name().empty())
res->SetString(variables::kOutputName, target_->output_name());
if (what(variables::kOutputDir) && !target_->output_dir().is_null())
res->Set(variables::kOutputDir, RenderValue(target_->output_dir()));
if (what(variables::kOutputExtension) && target_->output_extension_set())
res->SetString(variables::kOutputExtension, target_->output_extension());
if (what(variables::kPublic)) {
if (target_->all_headers_public())
res->SetString(variables::kPublic, "*");
else
res->Set(variables::kPublic, RenderValue(target_->public_headers()));
}
if (what(variables::kInputs) && !target_->inputs().empty())
res->Set(variables::kInputs, RenderValue(target_->inputs()));
if (is_binary_output && what(variables::kConfigs) &&
!target_->configs().empty()) {
auto configs = base::WrapUnique(new base::ListValue());
FillInConfigVector(configs.get(), target_->configs().vector());
res->Set(variables::kConfigs, std::move(configs));
}
if (what(variables::kPublicConfigs) && !target_->public_configs().empty()) {
auto configs = base::WrapUnique(new base::ListValue());
FillInConfigVector(configs.get(), target_->public_configs());
res->Set(variables::kPublicConfigs, std::move(configs));
}
if (what(variables::kAllDependentConfigs) &&
!target_->all_dependent_configs().empty()) {
auto configs = base::WrapUnique(new base::ListValue());
FillInConfigVector(configs.get(), target_->all_dependent_configs());
res->Set(variables::kAllDependentConfigs, std::move(configs));
}
// Action
if (target_->output_type() == Target::ACTION ||
target_->output_type() == Target::ACTION_FOREACH) {
if (what(variables::kScript))
res->SetString(variables::kScript,
target_->action_values().script().value());
if (what(variables::kArgs)) {
auto args = base::WrapUnique(new base::ListValue());
for (const auto& elem : target_->action_values().args().list())
args->AppendString(elem.AsString());
res->Set(variables::kArgs, std::move(args));
}
if (what(variables::kDepfile) &&
!target_->action_values().depfile().empty()) {
res->SetString(variables::kDepfile,
target_->action_values().depfile().AsString());
}
}
if (target_->output_type() != Target::SOURCE_SET &&
target_->output_type() != Target::GROUP &&
target_->output_type() != Target::BUNDLE_DATA) {
if (what(variables::kOutputs))
FillInOutputs(res.get());
}
// Source outputs are only included when specifically asked for it
if (what_.find("source_outputs") != what_.end())
FillInSourceOutputs(res.get());
if (target_->output_type() == Target::CREATE_BUNDLE && what("bundle_data"))
FillInBundle(res.get());
if (is_binary_output) {
#define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
if (what(#name)) { \
ValuePtr ptr = RenderConfigValues<type>(&ConfigValues::name); \
if (ptr) { \
res->Set(#name, std::move(ptr)); \
} \
}
CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
#undef CONFIG_VALUE_ARRAY_HANDLER
// Libs and lib_dirs are handled specially below.
FillInPrecompiledHeader(res.get(), target_->config_values());
}
if (what(variables::kDeps))
res->Set(variables::kDeps, RenderDeps());
// Runtime deps are special, print only when explicitly asked for and not in
// overview mode.
if (what_.find("runtime_deps") != what_.end())
res->Set("runtime_deps", RenderRuntimeDeps());
// libs and lib_dirs are special in that they're inherited. We don't
// currently
// implement a blame feature for this since the bottom-up inheritance makes
// this difficult.
// Libs can be part of any target and get recursively pushed up the chain,
// so display them regardless of target type.
if (what(variables::kLibs)) {
const OrderedSet<LibFile>& all_libs = target_->all_libs();
if (!all_libs.empty()) {
auto libs = base::WrapUnique(new base::ListValue());
for (size_t i = 0; i < all_libs.size(); i++)
libs->AppendString(all_libs[i].value());
res->Set(variables::kLibs, std::move(libs));
}
}
if (what(variables::kLibDirs)) {
const OrderedSet<SourceDir>& all_lib_dirs = target_->all_lib_dirs();
if (!all_lib_dirs.empty()) {
auto lib_dirs = base::WrapUnique(new base::ListValue());
for (size_t i = 0; i < all_lib_dirs.size(); i++)
lib_dirs->AppendString(FormatSourceDir(all_lib_dirs[i]));
res->Set(variables::kLibDirs, std::move(lib_dirs));
}
}
return res;
}
private:
// Prints dependencies of the given target (not the target itself). If the
// set is non-null, new targets encountered will be added to the set, and if
// a dependency is in the set already, it will not be recused into. When the
// set is null, all dependencies will be printed.
void RecursivePrintDeps(base::ListValue* out,
const Target* target,
std::set<const Target*>* seen_targets,
int indent_level) {
// Combine all deps into one sorted list.
std::vector<LabelTargetPair> sorted_deps;
for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
sorted_deps.push_back(pair);
std::sort(sorted_deps.begin(), sorted_deps.end(),
LabelPtrLabelLess<Target>());
std::string indent(indent_level * 2, ' ');
for (const auto& pair : sorted_deps) {
const Target* cur_dep = pair.ptr;
std::string str =
indent + cur_dep->label().GetUserVisibleName(GetToolchainLabel());
bool print_children = true;
if (seen_targets) {
if (seen_targets->find(cur_dep) == seen_targets->end()) {
// New target, mark it visited.
seen_targets->insert(cur_dep);
} else {
// Already seen.
print_children = false;
// Only print "..." if something is actually elided, which means that
// the current target has children.
if (!cur_dep->public_deps().empty() ||
!cur_dep->private_deps().empty() || !cur_dep->data_deps().empty())
str += "...";
}
}
out->AppendString(str);
if (print_children)
RecursivePrintDeps(out, cur_dep, seen_targets, indent_level + 1);
}
}
ValuePtr RenderDeps() {
auto res = base::WrapUnique(new base::ListValue());
// Tree mode is separate.
if (tree_) {
if (all_) {
// Show all tree deps with no eliding.
RecursivePrintDeps(res.get(), target_, nullptr, 0);
} else {
// Don't recurse into duplicates.
std::set<const Target*> seen_targets;
RecursivePrintDeps(res.get(), target_, &seen_targets, 0);
}
} else { // not tree
// Collect the deps to display.
if (all_) {
// Show all dependencies.
std::set<const Target*> all_deps;
RecursiveCollectChildDeps(target_, &all_deps);
commands::FilterAndPrintTargetSet(all_deps, res.get());
} else {
// Show direct dependencies only.
std::vector<const Target*> deps;
for (const auto& pair : target_->GetDeps(Target::DEPS_ALL))
deps.push_back(pair.ptr);
std::sort(deps.begin(), deps.end());
commands::FilterAndPrintTargets(&deps, res.get());
}
}
return std::move(res);
}
ValuePtr RenderRuntimeDeps() {
auto res = base::WrapUnique(new base::ListValue());
const Target* previous_from = NULL;
for (const auto& pair : ComputeRuntimeDeps(target_)) {
std::string str;
if (blame_) {
// Generally a target's runtime deps will be listed sequentially, so
// group them and don't duplicate the "from" label for two in a row.
if (previous_from == pair.second) {
str = " ";
} else {
previous_from = pair.second;
res->AppendString(
str + "From " +
pair.second->label().GetUserVisibleName(GetToolchainLabel()));
str = " ";
}
}
res->AppendString(str + pair.first.value());
}
return std::move(res);
}
void FillInSourceOutputs(base::DictionaryValue* res) {
auto dict = base::WrapUnique(new base::DictionaryValue());
for (const auto& source : target_->sources()) {
std::vector<OutputFile> outputs;
Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
if (target_->GetOutputFilesForSource(source, &tool_type, &outputs)) {
auto list = base::WrapUnique(new base::ListValue());
for (const auto& output : outputs)
list->AppendString(output.value());
dict->SetWithoutPathExpansion(source.value(), std::move(list));
}
}
res->Set("source_outputs", std::move(dict));
}
void FillInBundle(base::DictionaryValue* res) {
auto data = base::WrapUnique(new base::DictionaryValue());
const BundleData& bundle_data = target_->bundle_data();
const Settings* settings = target_->settings();
BundleData::SourceFiles sources;
bundle_data.GetSourceFiles(&sources);
data->Set("source_files", RenderValue(sources));
data->SetString("root_dir_output",
bundle_data.GetBundleRootDirOutput(settings).value());
data->Set("root_dir", RenderValue(bundle_data.root_dir()));
data->Set("resources_dir", RenderValue(bundle_data.resources_dir()));
data->Set("executable_dir", RenderValue(bundle_data.executable_dir()));
data->Set("plugins_dir", RenderValue(bundle_data.plugins_dir()));
data->SetString("product_type", bundle_data.product_type());
auto deps = base::WrapUnique(new base::ListValue());
for (const auto* dep : bundle_data.bundle_deps())
deps->AppendString(dep->label().GetUserVisibleName(GetToolchainLabel()));
data->Set("deps", std::move(deps));
res->Set("bundle_data", std::move(data));
}
void FillInOutputs(base::DictionaryValue* res) {
if (target_->output_type() == Target::ACTION) {
auto list = base::WrapUnique(new base::ListValue());
for (const auto& elem : target_->action_values().outputs().list())
list->AppendString(elem.AsString());
res->Set(variables::kOutputs, std::move(list));
} else if (target_->output_type() == Target::CREATE_BUNDLE) {
std::vector<SourceFile> output_files;
target_->bundle_data().GetOutputsAsSourceFiles(target_->settings(),
&output_files);
res->Set(variables::kOutputs, RenderValue(output_files));
} else if (target_->output_type() == Target::ACTION_FOREACH ||
target_->output_type() == Target::COPY_FILES) {
const SubstitutionList& outputs = target_->action_values().outputs();
if (!outputs.required_types().empty()) {
auto patterns = base::WrapUnique(new base::ListValue());
for (const auto& elem : outputs.list())
patterns->AppendString(elem.AsString());
res->Set("output_patterns", std::move(patterns));
}
std::vector<SourceFile> output_files;
SubstitutionWriter::ApplyListToSources(target_->settings(), outputs,
target_->sources(), &output_files);
res->Set(variables::kOutputs, RenderValue(output_files));
} else {
DCHECK(target_->IsBinary());
const Tool* tool =
target_->toolchain()->GetToolForTargetFinalOutput(target_);
std::vector<OutputFile> output_files;
SubstitutionWriter::ApplyListToLinkerAsOutputFile(
target_, tool, tool->outputs(), &output_files);
std::vector<SourceFile> output_files_as_source_file;
for (const OutputFile& output_file : output_files)
output_files_as_source_file.push_back(
output_file.AsSourceFile(target_->settings()->build_settings()));
res->Set(variables::kOutputs, RenderValue(output_files_as_source_file));
}
}
// Writes a given config value type to the string, optionally with
// attribution.
// This should match RecursiveTargetConfigToStream in the order it traverses.
template <class T>
ValuePtr RenderConfigValues(const std::vector<T>& (ConfigValues::*getter)()
const) {
auto res = base::WrapUnique(new base::ListValue());
for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
const std::vector<T>& vec = (iter.cur().*getter)();
if (vec.empty())
continue;
if (blame_) {
const Config* config = iter.GetCurrentConfig();
if (config) {
// Source of this value is a config.
std::string from =
"From " + config->label().GetUserVisibleName(false);
res->AppendString(from);
if (iter.origin()) {
Location location = iter.origin()->GetRange().begin();
from = " (Added by " + location.file()->name().value() + ":" +
base::IntToString(location.line_number()) + ")";
res->AppendString(from);
}
} else {
// Source of this value is the target itself.
std::string from =
"From " + target_->label().GetUserVisibleName(false);
res->AppendString(from);
}
}
for (const T& val : vec) {
ValuePtr rendered = RenderValue(val);
std::string str;
// Indent string values in blame mode
if (blame_ && rendered->GetAsString(&str)) {
str = " " + str;
rendered = base::WrapUnique(new base::StringValue(str));
}
res->Append(std::move(rendered));
}
}
return res->empty() ? nullptr : std::move(res);
}
Label GetToolchainLabel() const override {
return target_->label().GetToolchainLabel();
}
const Target* target_;
};
} // namespace
std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForTarget(
const Target* target,
const std::string& what,
bool all,
bool tree,
bool blame) {
std::set<std::string> w;
if (!what.empty())
w.insert(what);
TargetDescBuilder b(target, w, all, tree, blame);
return b.BuildDescription();
}
std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForConfig(
const Config* config,
const std::string& what) {
std::set<std::string> w;
if (!what.empty())
w.insert(what);
ConfigDescBuilder b(config, w);
return b.BuildDescription();
}
// Copyright (c) 2016 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_DESC_BUILDER_H_
#define TOOLS_GN_DESC_BUILDER_H_
#include "base/values.h"
#include "tools/gn/target.h"
class DescBuilder {
public:
// Creates Dictionary representation for given target
static std::unique_ptr<base::DictionaryValue> DescriptionForTarget(
const Target* target,
const std::string& what,
bool all,
bool tree,
bool blame);
// Creates Dictionary representation for given config
static std::unique_ptr<base::DictionaryValue> DescriptionForConfig(
const Config* config,
const std::string& what);
};
#endif
// Copyright (c) 2016 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/json_project_writer.h"
#include <iostream>
#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "tools/gn/builder.h"
#include "tools/gn/commands.h"
#include "tools/gn/deps_iterator.h"
#include "tools/gn/desc_builder.h"
#include "tools/gn/exec_process.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/settings.h"
// Structure of JSON output file
// {
// "build_settings" = {
// "root_path" : "absolute path of project root",
// "build_dir" : "build directory (project relative)",
// "default_toolchain" : "name of default toolchain"
// }
// "targets" = {
// "target x name" : { target x properties },
// "target y name" : { target y properties },
// ...
// }
// }
// See desc_builder.cc for overview of target properties
namespace {
void AddTargetDependencies(const Target* target,
std::set<const Target*>* deps) {
for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
if (deps->find(pair.ptr) == deps->end()) {
deps->insert(pair.ptr);
AddTargetDependencies(pair.ptr, deps);
}
}
}
// Filters targets according to filter string; Will also recursively
// add dependent targets.
bool FilterTargets(const BuildSettings* build_settings,
std::vector<const Target*>& all_targets,
std::vector<const Target*>* targets,
const std::string& dir_filter_string,
Err* err) {
if (dir_filter_string.empty()) {
*targets = all_targets;
} else {
targets->reserve(all_targets.size());
std::vector<LabelPattern> filters;
if (!commands::FilterPatternsFromString(build_settings, dir_filter_string,
&filters, err)) {
return false;
}
commands::FilterTargetsByPatterns(all_targets, filters, targets);
std::set<const Target*> target_set(targets->begin(), targets->end());
for (const auto* target : *targets)
AddTargetDependencies(target, &target_set);
targets->clear();
targets->insert(targets->end(), target_set.begin(), target_set.end());
}
// Sort the list of targets per-label to get a consistent ordering of them
// in the generated project (and thus stability of the file generated).
std::sort(targets->begin(), targets->end(),
[](const Target* a, const Target* b) {
return a->label().name() < b->label().name();
});
return true;
}
std::string RenderJSON(const BuildSettings* build_settings,
const Builder* builder,
std::vector<const Target*>& all_targets) {
Label default_toolchain_label;
auto targets = base::WrapUnique(new base::DictionaryValue());
for (const auto* target : all_targets) {
if (default_toolchain_label.is_null())
default_toolchain_label = target->settings()->default_toolchain_label();
auto description =
DescBuilder::DescriptionForTarget(target, "", false, false, false);
// Outputs need to be asked for separately.
auto outputs = DescBuilder::DescriptionForTarget(target, "source_outputs",
false, false, false);
base::DictionaryValue* outputs_value = nullptr;
if (outputs->GetDictionary("source_outputs", &outputs_value) &&
!outputs_value->empty()) {
description->MergeDictionary(outputs.get());
}
targets->Set(target->label().GetUserVisibleName(default_toolchain_label),
std::move(description));
}
auto settings = base::WrapUnique(new base::DictionaryValue());
settings->SetString("root_path", build_settings->root_path_utf8());
settings->SetString("build_dir", build_settings->build_dir().value());
settings->SetString("default_toolchain",
default_toolchain_label.GetUserVisibleName(false));
auto output = base::WrapUnique(new base::DictionaryValue());
output->Set("targets", std::move(targets));
output->Set("build_settings", std::move(settings));
std::string s;
base::JSONWriter::WriteWithOptions(
*output.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
return s;
}
bool InvokePython(const BuildSettings* build_settings,
const base::FilePath& python_script_path,
const std::string& python_script_extra_args,
const base::FilePath& output_path,
bool quiet,
Err* err) {
const base::FilePath& python_path = build_settings->python_path();
base::CommandLine cmdline(python_path);
cmdline.AppendArg("--");
cmdline.AppendArgPath(python_script_path);
cmdline.AppendArgPath(output_path);
if (!python_script_extra_args.empty()) {
cmdline.AppendArg(python_script_extra_args);
}
base::FilePath startup_dir =
build_settings->GetFullPath(build_settings->build_dir());
std::string output;
std::string stderr_output;
int exit_code = 0;
if (!internal::ExecProcess(cmdline, startup_dir, &output, &stderr_output,
&exit_code)) {
*err =
Err(Location(), "Could not execute python.",
"I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
return false;
}
if (!quiet) {
std::cout << output;
std::cerr << stderr_output;
}
if (exit_code != 0) {
*err = Err(Location(), "Python has quit with exit code " +
base::IntToString(exit_code) + ".");
return false;
}
return true;
}
} // namespace
bool JSONProjectWriter::RunAndWriteFiles(
const BuildSettings* build_settings,
const Builder* builder,
const std::string& file_name,
const std::string& exec_script,
const std::string& exec_script_extra_args,
const std::string& dir_filter_string,
bool quiet,
Err* err) {
SourceFile output_file = build_settings->build_dir().ResolveRelativeFile(
Value(nullptr, file_name), err);
if (output_file.is_null()) {
return false;
}
base::FilePath output_path = build_settings->GetFullPath(output_file);
std::vector<const Target*> all_targets = builder->GetAllResolvedTargets();
std::vector<const Target*> targets;
if (!FilterTargets(build_settings, all_targets, &targets, dir_filter_string,
err)) {
return false;
}
std::string json = RenderJSON(build_settings, builder, targets);
if (!ContentsEqual(output_path, json)) {
if (!WriteFileIfChanged(output_path, json, err)) {
return false;
}
if (!exec_script.empty()) {
SourceFile script_file;
if (exec_script[0] != '/') {
// Relative path, assume the base is in build_dir.
script_file = build_settings->build_dir().ResolveRelativeFile(
Value(nullptr, exec_script), err);
if (script_file.is_null()) {
return false;
}
} else {
script_file = SourceFile(exec_script);
}
base::FilePath script_path = build_settings->GetFullPath(script_file);
return InvokePython(build_settings, script_path, exec_script_extra_args,
output_path, quiet, err);
}
}
return true;
}
// Copyright (c) 2016 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_JSON_WRITER_H_
#define TOOLS_GN_JSON_WRITER_H_
#include "tools/gn/err.h"
#include "tools/gn/target.h"
class Builder;
class BuildSettings;
class JSONProjectWriter {
public:
static bool RunAndWriteFiles(const BuildSettings* build_setting,
const Builder* builder,
const std::string& file_name,
const std::string& exec_script,
const std::string& exec_script_extra_args,
const std::string& dir_filter_string,
bool quiet,
Err* err);
};
#endif
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "tools/gn/config_values_extractors.h" #include "tools/gn/config_values_extractors.h"
#include "tools/gn/deps_iterator.h" #include "tools/gn/deps_iterator.h"
#include "tools/gn/filesystem_utils.h" #include "tools/gn/filesystem_utils.h"
#include "tools/gn/functions.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/source_file_type.h" #include "tools/gn/source_file_type.h"
#include "tools/gn/substitution_writer.h" #include "tools/gn/substitution_writer.h"
...@@ -216,29 +215,29 @@ Target::~Target() { ...@@ -216,29 +215,29 @@ Target::~Target() {
const char* Target::GetStringForOutputType(OutputType type) { const char* Target::GetStringForOutputType(OutputType type) {
switch (type) { switch (type) {
case UNKNOWN: case UNKNOWN:
return "unknown"; return "Unknown";
case GROUP: case GROUP:
return functions::kGroup; return "Group";
case EXECUTABLE: case EXECUTABLE:
return functions::kExecutable; return "Executable";
case LOADABLE_MODULE: case LOADABLE_MODULE:
return functions::kLoadableModule; return "Loadable module";
case SHARED_LIBRARY: case SHARED_LIBRARY:
return functions::kSharedLibrary; return "Shared library";
case STATIC_LIBRARY: case STATIC_LIBRARY:
return functions::kStaticLibrary; return "Static library";
case SOURCE_SET: case SOURCE_SET:
return functions::kSourceSet; return "Source set";
case COPY_FILES: case COPY_FILES:
return functions::kCopy; return "Copy";
case ACTION: case ACTION:
return functions::kAction; return "Action";
case ACTION_FOREACH: case ACTION_FOREACH:
return functions::kActionForEach; return "ActionForEach";
case BUNDLE_DATA: case BUNDLE_DATA:
return functions::kBundleData; return "Bundle data";
case CREATE_BUNDLE: case CREATE_BUNDLE:
return functions::kCreateBundle; return "Create bundle";
default: default:
return ""; return "";
} }
......
...@@ -4,10 +4,8 @@ ...@@ -4,10 +4,8 @@
#include "tools/gn/visibility.h" #include "tools/gn/visibility.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/values.h"
#include "tools/gn/err.h" #include "tools/gn/err.h"
#include "tools/gn/filesystem_utils.h" #include "tools/gn/filesystem_utils.h"
#include "tools/gn/item.h" #include "tools/gn/item.h"
...@@ -85,14 +83,6 @@ std::string Visibility::Describe(int indent, bool include_brackets) const { ...@@ -85,14 +83,6 @@ std::string Visibility::Describe(int indent, bool include_brackets) const {
return result; return result;
} }
std::unique_ptr<base::Value> Visibility::AsValue() const {
auto* res = new base::ListValue();
for (const auto& pattern : patterns_)
res->AppendString(pattern.Describe());
return WrapUnique(res);
}
// static // static
bool Visibility::CheckItemVisibility(const Item* from, bool Visibility::CheckItemVisibility(const Item* from,
const Item* to, const Item* to,
...@@ -103,7 +93,7 @@ bool Visibility::CheckItemVisibility(const Item* from, ...@@ -103,7 +93,7 @@ bool Visibility::CheckItemVisibility(const Item* from,
"The item " + from->label().GetUserVisibleName(false) + "\n" "The item " + from->label().GetUserVisibleName(false) + "\n"
"can not depend on " + to_label + "\n" "can not depend on " + to_label + "\n"
"because it is not in " + to_label + "'s visibility list: " + "because it is not in " + to_label + "'s visibility list: " +
to->visibility().Describe(0, true)); to->visibility().Describe(0, true));
return false; return false;
} }
return true; return true;
......
...@@ -5,17 +5,12 @@ ...@@ -5,17 +5,12 @@
#ifndef TOOLS_GN_VISIBILITY_H_ #ifndef TOOLS_GN_VISIBILITY_H_
#define TOOLS_GN_VISIBILITY_H_ #define TOOLS_GN_VISIBILITY_H_
#include <memory>
#include <vector> #include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "tools/gn/label_pattern.h" #include "tools/gn/label_pattern.h"
#include "tools/gn/source_dir.h" #include "tools/gn/source_dir.h"
namespace base {
class Value;
}
class Err; class Err;
class Item; class Item;
class Label; class Label;
...@@ -48,9 +43,6 @@ class Visibility { ...@@ -48,9 +43,6 @@ class Visibility {
// result will end in a newline. // result will end in a newline.
std::string Describe(int indent, bool include_brackets) const; std::string Describe(int indent, bool include_brackets) const;
// Returns value representation of this visibility
std::unique_ptr<base::Value> AsValue() const;
// Helper function to check visibility between the given two items. If // Helper function to check visibility between the given two items. If
// to is invisible to from, returns false and sets the error. // to is invisible to from, returns false and sets the error.
static bool CheckItemVisibility(const Item* from, const Item* to, Err* err); static bool CheckItemVisibility(const Item* from, const Item* to, Err* err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment