summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@qt.io>2017-01-09 13:28:49 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-04 10:20:59 +0200
commitdc8b97a4affb646a8ee508d404f684a1e97c2eea (patch)
tree2b218f0aa870ce2493c822b43873a4b971938cef
parent5e25b04f055676df117338de22f5bf00601b57a1 (diff)
downloadqtwebengine-chromium-dc8b97a4affb646a8ee508d404f684a1e97c2eea.tar.gz
Add rsp target writer
Rsp writer is able to dump link data in form of set of response files which have objects, archives, defines, linker flags or libs. Task-number: QTBUG-95590 Change-Id: Id153effb43fb7b70e38d9eca881e12018cbed729 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rwxr-xr-xgn/build/gen.py2
-rw-r--r--gn/src/gn/escape.cc47
-rw-r--r--gn/src/gn/escape.h3
-rw-r--r--gn/src/gn/ninja_action_target_writer.cc2
-rw-r--r--gn/src/gn/ninja_binary_target_writer.cc18
-rw-r--r--gn/src/gn/ninja_binary_target_writer.h2
-rw-r--r--gn/src/gn/ninja_c_binary_target_writer.cc17
-rw-r--r--gn/src/gn/ninja_target_writer.cc1
-rw-r--r--gn/src/gn/rsp_target_writer.cc253
-rw-r--r--gn/src/gn/rsp_target_writer.h67
-rw-r--r--gn/src/gn/rsp_target_writer_unittest.cc170
-rw-r--r--gn/src/gn/target.cc6
-rw-r--r--gn/src/gn/target.h4
-rw-r--r--gn/src/gn/target_generator.cc24
-rw-r--r--gn/src/gn/target_generator.h1
-rw-r--r--gn/src/gn/variables.cc24
-rw-r--r--gn/src/gn/variables.h4
17 files changed, 639 insertions, 6 deletions
diff --git a/gn/build/gen.py b/gn/build/gen.py
index 38d4ec253f4..15a177a254b 100755
--- a/gn/build/gen.py
+++ b/gn/build/gen.py
@@ -635,6 +635,7 @@ def WriteGNNinja(path, platform, host, options):
'src/gn/parser.cc',
'src/gn/path_output.cc',
'src/gn/pattern.cc',
+ 'src/gn/rsp_target_writer.cc',
'src/gn/pool.cc',
'src/gn/qt_creator_writer.cc',
'src/gn/runtime_deps.cc',
@@ -753,6 +754,7 @@ def WriteGNNinja(path, platform, host, options):
'src/gn/parser_unittest.cc',
'src/gn/path_output_unittest.cc',
'src/gn/pattern_unittest.cc',
+ 'src/gn/rsp_target_writer_unittest.cc',
'src/gn/runtime_deps_unittest.cc',
'src/gn/scope_per_file_provider_unittest.cc',
'src/gn/scope_unittest.cc',
diff --git a/gn/src/gn/escape.cc b/gn/src/gn/escape.cc
index 3c8dc3f498a..d7c2dce6bb2 100644
--- a/gn/src/gn/escape.cc
+++ b/gn/src/gn/escape.cc
@@ -239,6 +239,51 @@ size_t EscapeStringToString_PosixNinjaFork(const std::string_view& str,
return i;
}
+size_t EscapeStringToString_Command(const std::string_view& str,
+ const EscapeOptions& options,
+ char* dchp,
+ bool* needed_quoting) {
+ std::string dstr;
+ std::string* dest = &dstr;
+ if (str.find_first_of(" \"") == std::string::npos) {
+ // Simple case, don't quote.
+ dest->append(str.data(), str.size());
+ } else {
+ if (!options.inhibit_quoting)
+ dest->push_back('"');
+ for (size_t i = 0; i < str.size(); i++) {
+ // Count backslashes in case they're followed by a quote.
+ size_t backslash_count = 0;
+ while (i < str.size() && str[i] == '\\') {
+ i++;
+ backslash_count++;
+ }
+ if (i == str.size()) {
+ // Backslashes at end of string. Backslash-escape all of them since
+ // they'll be followed by a quote.
+ dest->append(backslash_count * 2, '\\');
+ } else if (str[i] == '"') {
+ // 0 or more backslashes followed by a quote. Backslash-escape the
+ // backslashes, then backslash-escape the quote.
+ dest->append(backslash_count * 2 + 1, '\\');
+ dest->push_back('"');
+ } else {
+ // Non-special Windows character. Add any
+ // backslashes we read previously, these are literals.
+ dest->append(backslash_count, '\\');
+ dest->push_back(str[i]);
+ }
+ }
+
+ if (!options.inhibit_quoting)
+ dest->push_back('"');
+ if (needed_quoting)
+ *needed_quoting = true;
+ }
+ memcpy(dchp, dstr.c_str(), dstr.size());
+ return dstr.size();
+}
+
// Escapes |str| into |dest| and returns the number of characters written.
size_t EscapeStringToString(const std::string_view& str,
const EscapeOptions& options,
@@ -278,6 +323,8 @@ size_t EscapeStringToString(const std::string_view& str,
}
case ESCAPE_NINJA_PREFORMATTED_COMMAND:
return EscapeStringToString_NinjaPreformatted(str, dest);
+ case ESCAPE_COMMAND:
+ return EscapeStringToString_Command(str, options, dest, needed_quoting);
default:
NOTREACHED();
}
diff --git a/gn/src/gn/escape.h b/gn/src/gn/escape.h
index 31f972edb4d..f749ba1656f 100644
--- a/gn/src/gn/escape.h
+++ b/gn/src/gn/escape.h
@@ -36,6 +36,9 @@ enum EscapingMode {
// Parameters use shell quoting and shell escaping of quotes, with ‘"’ and ‘\’
// being the only special characters.
ESCAPE_COMPILATION_DATABASE,
+
+ // Like ESCAPE_NINJA_COMMAND but without ninja string escaping
+ ESCAPE_COMMAND,
};
enum EscapingPlatform {
diff --git a/gn/src/gn/ninja_action_target_writer.cc b/gn/src/gn/ninja_action_target_writer.cc
index c48da06cf6e..2ceac904a3c 100644
--- a/gn/src/gn/ninja_action_target_writer.cc
+++ b/gn/src/gn/ninja_action_target_writer.cc
@@ -107,7 +107,7 @@ std::string NinjaActionTargetWriter::WriteRuleDefinition() {
// there will be only one invocation so we can use a simple name.
std::string target_label = target_->label().GetUserVisibleName(true);
std::string custom_rule_name(target_label);
- base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
+ base::ReplaceChars(custom_rule_name, "+:/()", "_", &custom_rule_name);
custom_rule_name.append("_rule");
const SubstitutionList& args = target_->action_values().args();
diff --git a/gn/src/gn/ninja_binary_target_writer.cc b/gn/src/gn/ninja_binary_target_writer.cc
index e4b06520759..ed5d926624a 100644
--- a/gn/src/gn/ninja_binary_target_writer.cc
+++ b/gn/src/gn/ninja_binary_target_writer.cc
@@ -4,8 +4,8 @@
#include "gn/ninja_binary_target_writer.h"
+#include <list>
#include <sstream>
-
#include "base/strings/string_util.h"
#include "gn/config_values_extractors.h"
#include "gn/deps_iterator.h"
@@ -15,6 +15,7 @@
#include "gn/ninja_rust_binary_target_writer.h"
#include "gn/ninja_target_command_util.h"
#include "gn/ninja_utils.h"
+#include "gn/rsp_target_writer.h"
#include "gn/settings.h"
#include "gn/string_utils.h"
#include "gn/substitution_writer.h"
@@ -48,6 +49,21 @@ void NinjaBinaryTargetWriter::Run() {
NinjaCBinaryTargetWriter writer(target_, out_);
writer.Run();
+
+ const std::vector<std::string> types = target_->rsp_types();
+ if (!types.empty()) {
+ for (const std::string& str_type : types) {
+ base::FilePath p_file(
+ target_->settings()->build_settings()->GetFullPath(SourceFile(
+ target_->settings()->build_settings()->build_dir().value() +
+ target_->label().name() + "_" + str_type + ".rsp")));
+ std::stringstream p_stream;
+ const RspTargetWriter::Type& type = RspTargetWriter::strToType(str_type);
+ RspTargetWriter p_writer(&writer, target_, type, p_stream);
+ p_writer.Run();
+ WriteFileIfChanged(p_file, p_stream.str(), nullptr);
+ }
+ }
}
std::vector<OutputFile> NinjaBinaryTargetWriter::WriteInputsStampAndGetDep(
diff --git a/gn/src/gn/ninja_binary_target_writer.h b/gn/src/gn/ninja_binary_target_writer.h
index 76a8a4eb798..3e5e7d9ee6f 100644
--- a/gn/src/gn/ninja_binary_target_writer.h
+++ b/gn/src/gn/ninja_binary_target_writer.h
@@ -83,6 +83,8 @@ class NinjaBinaryTargetWriter : public NinjaTargetWriter {
private:
DISALLOW_COPY_AND_ASSIGN(NinjaBinaryTargetWriter);
+ friend class CMakeLinkWriter;
+ friend class RspTargetWriter;
};
#endif // TOOLS_GN_NINJA_BINARY_TARGET_WRITER_H_
diff --git a/gn/src/gn/ninja_c_binary_target_writer.cc b/gn/src/gn/ninja_c_binary_target_writer.cc
index 17f9c0855da..54f2f967f55 100644
--- a/gn/src/gn/ninja_c_binary_target_writer.cc
+++ b/gn/src/gn/ninja_c_binary_target_writer.cc
@@ -695,10 +695,17 @@ void NinjaCBinaryTargetWriter::WriteLinkerStuff(
target_, tool_, tool_->outputs(), &output_files);
out_ << "build";
- path_output_.WriteFiles(out_, output_files);
- out_ << ": " << rule_prefix_
- << Tool::GetToolTypeForTargetFinalOutput(target_);
+ if (target_->rsp_types().empty()) {
+ path_output_.WriteFiles(out_, output_files);
+ out_ << ": " << rule_prefix_
+ << Tool::GetToolTypeForTargetFinalOutput(target_);
+ } else {
+ out_ << " ";
+ path_output_.WriteFile(out_, OutputFile(target_->label().name() + ".stamp"));
+ out_ << ": " << rule_prefix_;
+ out_ << GeneralTool::kGeneralToolStamp << " |";
+ }
ClassifiedDeps classified_deps = GetClassifiedDeps();
@@ -795,7 +802,9 @@ void NinjaCBinaryTargetWriter::WriteLinkerStuff(
// Append implicit dependencies collected above.
if (!implicit_deps.empty()) {
- out_ << " |";
+ if (target_->rsp_types().empty()) {
+ out_ << " |";
+ }
path_output_.WriteFiles(out_, implicit_deps);
}
diff --git a/gn/src/gn/ninja_target_writer.cc b/gn/src/gn/ninja_target_writer.cc
index 7eefc1229f7..aab6c491e0d 100644
--- a/gn/src/gn/ninja_target_writer.cc
+++ b/gn/src/gn/ninja_target_writer.cc
@@ -16,6 +16,7 @@
#include "gn/ninja_action_target_writer.h"
#include "gn/ninja_binary_target_writer.h"
#include "gn/ninja_bundle_data_target_writer.h"
+#include "gn/ninja_c_binary_target_writer.h"
#include "gn/ninja_copy_target_writer.h"
#include "gn/ninja_create_bundle_target_writer.h"
#include "gn/ninja_generated_file_target_writer.h"
diff --git a/gn/src/gn/rsp_target_writer.cc b/gn/src/gn/rsp_target_writer.cc
new file mode 100644
index 00000000000..695e64f9695
--- /dev/null
+++ b/gn/src/gn/rsp_target_writer.cc
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// 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 "gn/rsp_target_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "gn/config_values_extractors.h"
+#include "gn/deps_iterator.h"
+#include "gn/ninja_c_binary_target_writer.h"
+#include "gn/ninja_target_command_util.h"
+#include "gn/output_file.h"
+#include "gn/settings.h"
+#include "gn/target.h"
+
+RspTargetWriter::RspTargetWriter(const NinjaCBinaryTargetWriter* writer,
+ const Target* target,
+ Type type,
+ std::ostream& out)
+ : type_(type), target_(target), nwriter_(writer), out_(out) {}
+RspTargetWriter::~RspTargetWriter() {}
+
+// Based on similar function in qt_creator_writer.cc
+static void CollectDeps(std::set<const Target*>& deps, const Target* target) {
+ for (const auto& dep : target->GetDeps(Target::DEPS_ALL)) {
+ const Target* dep_target = dep.ptr;
+ if (deps.count(dep_target))
+ continue;
+ deps.insert(dep_target);
+ CollectDeps(deps, dep_target);
+ }
+}
+
+void RspTargetWriter::Run() {
+ CHECK(target_->output_type() == Target::SHARED_LIBRARY ||
+ target_->output_type() == Target::STATIC_LIBRARY)
+ << "RspTargetWriter only supports libraries";
+
+ std::vector<SourceFile> other_files;
+ std::vector<OutputFile> tool_outputs;
+ NinjaBinaryTargetWriter::ClassifiedDeps cdeps = nwriter_->GetClassifiedDeps();
+
+ std::set<const Target*> deps;
+ deps.insert(target_);
+ CollectDeps(deps, target_);
+ const Settings* settings = target_->settings();
+ const CTool* tool =
+ target_->toolchain()->GetToolForTargetFinalOutput(target_)->AsC();
+
+ std::string prefix(
+ settings->build_settings()->build_dir().SourceWithNoTrailingSlash());
+ prefix.append("/");
+#if defined(OS_WIN)
+ prefix.erase(prefix.begin());
+#endif
+ switch (type_) {
+ case NONE:
+ return;
+ case DEFINES: {
+ for (const auto& target : deps) {
+ for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
+ for (std::string define : it.cur().defines()) {
+ out_ << define << " ";
+ }
+ }
+ }
+ out_.flush();
+ } break;
+ case OBJECTS: {
+ PathOutput path_output(settings->build_settings()->build_dir(),
+ settings->build_settings()->root_path_utf8(),
+ ESCAPE_NONE);
+ std::vector<SourceFile> object_files;
+ object_files.reserve(target_->sources().size());
+
+ for (const auto& source : target_->sources()) {
+ const char* tool_type = nullptr;
+ if (!target_->GetOutputFilesForSource(source, &tool_type,
+ &tool_outputs)) {
+ if (source.type() == SourceFile::SOURCE_DEF)
+ other_files.push_back(source);
+ continue; // No output for this source.
+ }
+ object_files.push_back(
+ tool_outputs[0].AsSourceFile(settings->build_settings()));
+ }
+ if (target_->config_values().has_precompiled_headers()) {
+ const CTool* tool =
+ target_->toolchain()->GetTool(CTool::kCToolCxx)->AsC();
+ if (tool && tool->precompiled_header_type() == CTool::PCH_MSVC) {
+ GetPCHOutputFiles(target_, CTool::kCToolCxx, &tool_outputs);
+ if (!tool_outputs.empty())
+ object_files.push_back(
+ tool_outputs[0].AsSourceFile(settings->build_settings()));
+ }
+ }
+ for (const auto& file : object_files) {
+ out_ << "\"" << prefix;
+ path_output.WriteFile(out_, file);
+ out_ << "\"\n";
+ }
+ for (const auto& file : cdeps.extra_object_files) {
+ out_ << "\"" << prefix;
+ path_output.WriteFile(out_, file);
+ out_ << "\"\n";
+ }
+ out_.flush();
+ } break;
+ case LFLAGS: {
+ EscapeOptions opts;
+ opts.mode = ESCAPE_COMMAND;
+ // First the ldflags from the target and its config.
+ RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
+ opts, out_);
+ // library dirs
+ const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
+
+ if (!all_lib_dirs.empty()) {
+ PathOutput lib_path_output(settings->build_settings()->build_dir(),
+ settings->build_settings()->root_path_utf8(),
+ ESCAPE_COMMAND);
+ for (size_t i = 0; i < all_lib_dirs.size(); i++) {
+ out_ << " -L\"";
+ lib_path_output.WriteDir(out_, all_lib_dirs[i],
+ PathOutput::DIR_NO_LAST_SLASH);
+ out_ << "\"";
+ }
+ out_.flush();
+ }
+ } break;
+ case ARCHIVES: {
+ PathOutput path_output(settings->build_settings()->build_dir(),
+ settings->build_settings()->root_path_utf8(),
+ ESCAPE_NONE);
+ std::vector<OutputFile> solibs;
+ for (const Target* cur : cdeps.linkable_deps) {
+ if (cur->dependency_output_file().value() !=
+ cur->link_output_file().value()) {
+ solibs.push_back(cur->link_output_file());
+ } else {
+ out_ << "\"" << prefix;
+ path_output.WriteFile(out_, cur->link_output_file());
+ out_ << "\"\n";
+ }
+ }
+ out_.flush();
+
+ CHECK(solibs.empty()) << "Unhandled solibs";
+ } break;
+ case LIBS: {
+ EscapeOptions lib_escape_opts;
+ lib_escape_opts.mode = ESCAPE_COMMAND;
+
+ const OrderedSet<LibFile> all_libs = target_->all_libs();
+ const std::string framework_ending(".framework");
+ for (size_t i = 0; i < all_libs.size(); i++) {
+ const LibFile& lib_file = all_libs[i];
+ const std::string& lib_value = lib_file.value();
+ if (lib_file.is_source_file()) {
+ PathOutput lib_path_output(
+ settings->build_settings()->build_dir(),
+ settings->build_settings()->root_path_utf8(), ESCAPE_COMMAND);
+ out_ << "\"";
+ lib_path_output.WriteFile(out_, lib_file.source_file());
+ out_ << "\"";
+ } else if (base::EndsWith(lib_value, framework_ending,
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ out_ << " -framework ";
+ EscapeStringToStream(
+ out_,
+ lib_value.substr(0, lib_value.size() - framework_ending.size()),
+ lib_escape_opts);
+ } else {
+ out_ << " " << tool->lib_switch();
+ EscapeStringToStream(out_, lib_value, lib_escape_opts);
+ }
+ }
+ const OrderedSet<std::string> all_frameworks = target_->all_frameworks();
+ for (size_t i = 0; i < all_frameworks.size(); i++) {
+ const std::string& lib_value = all_frameworks[i];
+ out_ << " -framework ";
+ EscapeStringToStream(
+ out_,
+ lib_value.substr(0, lib_value.size() - framework_ending.size()),
+ lib_escape_opts);
+ }
+ const OrderedSet<std::string> weak_frameworks =
+ target_->all_weak_frameworks();
+ for (size_t i = 0; i < weak_frameworks.size(); i++) {
+ const std::string& lib_value = weak_frameworks[i];
+ out_ << " -weak_framework ";
+ EscapeStringToStream(
+ out_,
+ lib_value.substr(0, lib_value.size() - framework_ending.size()),
+ lib_escape_opts);
+ }
+ out_.flush();
+ }
+ }
+}
+
+RspTargetWriter::Type RspTargetWriter::strToType(const std::string& str) {
+ static std::unordered_map<std::string, RspTargetWriter::Type> const types = {
+ {"objects", RspTargetWriter::OBJECTS},
+ {"archives", RspTargetWriter::ARCHIVES},
+ {"defines", RspTargetWriter::DEFINES},
+ {"lflags", RspTargetWriter::LFLAGS},
+ {"libs", RspTargetWriter::LIBS}};
+ auto it = types.find(str);
+ if (it != types.end()) {
+ return it->second;
+ }
+ return RspTargetWriter::NONE;
+}
diff --git a/gn/src/gn/rsp_target_writer.h b/gn/src/gn/rsp_target_writer.h
new file mode 100644
index 00000000000..d49520b94b2
--- /dev/null
+++ b/gn/src/gn/rsp_target_writer.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOOLS_GN_RSP_TARGET_WRITER_H_
+#define TOOLS_GN_RSP_TARGET_WRITER_H_
+
+#include <iosfwd>
+#include "gn/path_output.h"
+
+class Target;
+class NinjaCBinaryTargetWriter;
+
+class RspTargetWriter {
+ public:
+ enum Type { NONE, OBJECTS, ARCHIVES, DEFINES, LFLAGS, LIBS };
+ RspTargetWriter(const NinjaCBinaryTargetWriter* writer,
+ const Target* target,
+ Type type,
+ std::ostream& out);
+ ~RspTargetWriter();
+ void Run();
+ static Type strToType(const std::string& str);
+
+ private:
+ Type type_;
+ const Target* target_;
+ const NinjaCBinaryTargetWriter* nwriter_;
+ std::ostream& out_;
+};
+
+#endif // TOOLS_GN_RSP_TARGET_WRITER_H_
diff --git a/gn/src/gn/rsp_target_writer_unittest.cc b/gn/src/gn/rsp_target_writer_unittest.cc
new file mode 100644
index 00000000000..d93e8de3c72
--- /dev/null
+++ b/gn/src/gn/rsp_target_writer_unittest.cc
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gn/rsp_target_writer.h"
+#include <iostream>
+#include "gn/ninja_c_binary_target_writer.h"
+#include "gn/test_with_scheduler.h"
+#include "gn/test_with_scope.h"
+#include "util/test/test.h"
+
+using RspTargetWriterTest = TestWithScheduler;
+
+TEST_F(RspTargetWriterTest, WriteRspInfo) {
+ TestWithScope setup;
+ Err err;
+
+ setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+
+ Target source_set_target(setup.settings(),
+ Label(SourceDir("//foo1/"), "foo1"));
+ source_set_target.set_output_type(Target::SOURCE_SET);
+ source_set_target.visibility().SetPublic();
+ source_set_target.sources().push_back(SourceFile("//foo1/input1.cc"));
+ source_set_target.sources().push_back(SourceFile("//foo1/input2.cc"));
+ source_set_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(source_set_target.OnResolved(&err));
+
+ TestTarget static_lib_target1(setup, "//foo5:bar", Target::STATIC_LIBRARY);
+ static_lib_target1.sources().push_back(SourceFile("//foo5/input1.cc"));
+ static_lib_target1.config_values().arflags().push_back("--bar");
+ static_lib_target1.set_complete_static_lib(true);
+ ASSERT_TRUE(static_lib_target1.OnResolved(&err));
+
+ TestTarget static_lib_target2(setup, "//foo6:bar", Target::STATIC_LIBRARY);
+ static_lib_target2.sources().push_back(SourceFile("//foo6/input1.cc"));
+ static_lib_target2.config_values().arflags().push_back("--bar");
+ static_lib_target2.set_complete_static_lib(true);
+ ASSERT_TRUE(static_lib_target2.OnResolved(&err));
+
+ Target shared_lib_target(setup.settings(),
+ Label(SourceDir("//foo2/"), "foo2"));
+
+ shared_lib_target.rsp_types().push_back("NOTUSED");
+ shared_lib_target.set_output_type(Target::SHARED_LIBRARY);
+ shared_lib_target.set_output_extension(std::string("so.1"));
+ shared_lib_target.set_output_dir(SourceDir("//out/Debug/foo/"));
+ shared_lib_target.sources().push_back(SourceFile("//foo2/input1.cc"));
+ shared_lib_target.sources().push_back(SourceFile("//foo2/input 2.cc"));
+ shared_lib_target.sources().push_back(SourceFile("//foo 2/input 3.cc"));
+ shared_lib_target.config_values().libs().push_back(
+ LibFile(SourceFile("//foo/libfoo3.a")));
+ shared_lib_target.config_values().libs().push_back(LibFile("foo4"));
+ shared_lib_target.config_values().lib_dirs().push_back(
+ SourceDir("//foo/bar/"));
+ shared_lib_target.public_deps().push_back(
+ LabelTargetPair(&source_set_target));
+ shared_lib_target.public_deps().push_back(
+ LabelTargetPair(&static_lib_target1));
+ shared_lib_target.public_deps().push_back(
+ LabelTargetPair(&static_lib_target2));
+ shared_lib_target.config_values().ldflags().push_back("-fooBAR");
+ shared_lib_target.config_values().ldflags().push_back("/INCREMENTAL:NO");
+ shared_lib_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(shared_lib_target.OnResolved(&err));
+
+ std::ostringstream ninja_out;
+ NinjaCBinaryTargetWriter writer(&shared_lib_target, ninja_out);
+ writer.Run();
+
+ const char ninja_expected[] =
+ "defines =\n"
+ "include_dirs =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/foo2\n"
+ "target_output_name = libfoo2\n"
+ "\n"
+ "build obj/foo2/libfoo2.input1.o: cxx ../../foo2/input1.cc\n"
+ "build obj/foo2/libfoo2.input$ 2.o: cxx ../../foo2/input$ 2.cc\n"
+ "build obj/foo$ 2/libfoo2.input$ 3.o: cxx ../../foo$ 2/input$ 3.cc\n"
+ "\n"
+ "build foo2.stamp: stamp | obj/foo2/libfoo2.input1.o "
+ "obj/foo2/libfoo2.input$ 2.o"
+ " obj/foo$ 2/libfoo2.input$ 3.o"
+ " obj/foo1/foo1.input1.o obj/foo1/foo1.input2.o obj/foo5/libbar.a "
+ "obj/foo6/libbar.a"
+ " ../../foo/libfoo3.a || obj/foo1/foo1.stamp\n"
+ " ldflags = -fooBAR /INCREMENTAL$:NO -L../../foo/bar\n"
+ " libs = ../../foo/libfoo3.a -lfoo4\n"
+ " frameworks =\n"
+ " swiftmodules =\n"
+ " output_extension = .so.1\n"
+ " output_dir = foo\n";
+
+ std::ostringstream objects_out;
+ RspTargetWriter rsp_object_writer(&writer, &shared_lib_target,
+ RspTargetWriter::OBJECTS, objects_out);
+ rsp_object_writer.Run();
+
+ const char objects_expected[] =
+ "\"//out/Debug/obj/foo2/libfoo2.input1.o\"\n"
+ "\"//out/Debug/obj/foo2/libfoo2.input 2.o\"\n"
+ "\"//out/Debug/obj/foo 2/libfoo2.input 3.o\"\n"
+ "\"//out/Debug/obj/foo1/foo1.input1.o\"\n"
+ "\"//out/Debug/obj/foo1/foo1.input2.o\"\n";
+
+ EXPECT_EQ(objects_expected, objects_out.str());
+
+ std::ostringstream lflags_out;
+ RspTargetWriter rsp_lflags_writer(&writer, &shared_lib_target,
+ RspTargetWriter::LFLAGS, lflags_out);
+ rsp_lflags_writer.Run();
+
+ const char lflags_expected[] = " -fooBAR /INCREMENTAL:NO -L\"../../foo/bar\"";
+
+ EXPECT_EQ(lflags_expected, lflags_out.str());
+
+ std::ostringstream archives_out;
+ RspTargetWriter rsp_archive_writer(&writer, &shared_lib_target,
+ RspTargetWriter::ARCHIVES, archives_out);
+ rsp_archive_writer.Run();
+
+ const char archives_expected[] =
+ "\"//out/Debug/obj/foo5/libbar.a\"\n"
+ "\"//out/Debug/obj/foo6/libbar.a\"\n";
+ EXPECT_EQ(archives_expected, archives_out.str());
+
+ std::ostringstream libs_out;
+ RspTargetWriter rsp_libs_writer(&writer, &shared_lib_target,
+ RspTargetWriter::LIBS, libs_out);
+ rsp_libs_writer.Run();
+
+ const char libs_expected[] = "\"../../foo/libfoo3.a\" -lfoo4";
+ EXPECT_EQ(libs_expected, libs_out.str());
+}
diff --git a/gn/src/gn/target.cc b/gn/src/gn/target.cc
index dd71abbcc06..6223afca9fc 100644
--- a/gn/src/gn/target.cc
+++ b/gn/src/gn/target.cc
@@ -833,6 +833,9 @@ bool Target::FillOutputFiles(Err* err) {
link_output_file_ = dependency_output_file_ =
SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
this, tool, tool->outputs().list()[0]);
+ if (!rsp_types().empty()) {
+ dependency_output_file_ = OutputFile(label().name() + ".stamp");
+ }
break;
case RUST_PROC_MACRO:
case SHARED_LIBRARY:
@@ -870,6 +873,9 @@ bool Target::FillOutputFiles(Err* err) {
SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
this, tool, tool->outputs().list()[0]);
}
+ if (!rsp_types().empty()) {
+ dependency_output_file_ = OutputFile(label().name() + ".stamp");
+ }
break;
case UNKNOWN:
default:
diff --git a/gn/src/gn/target.h b/gn/src/gn/target.h
index 03f456cdb33..0004d096075 100644
--- a/gn/src/gn/target.h
+++ b/gn/src/gn/target.h
@@ -195,6 +195,9 @@ class Target : public Item {
bool testonly() const { return testonly_; }
void set_testonly(bool value) { testonly_ = value; }
+ std::vector<std::string>& rsp_types() { return rsp_types_; }
+ const std::vector<std::string>& rsp_types() const { return rsp_types_; }
+
OutputFile write_runtime_deps_output() const {
return write_runtime_deps_output_;
}
@@ -509,6 +512,7 @@ class Target : public Item {
SourceDir rebase_;
std::vector<std::string> data_keys_;
std::vector<std::string> walk_keys_;
+ std::vector<std::string> rsp_types_;
DISALLOW_COPY_AND_ASSIGN(Target);
};
diff --git a/gn/src/gn/target_generator.cc b/gn/src/gn/target_generator.cc
index 0ae9dafda81..1ff3b8304bb 100644
--- a/gn/src/gn/target_generator.cc
+++ b/gn/src/gn/target_generator.cc
@@ -58,6 +58,9 @@ void TargetGenerator::Run() {
if (!FillTestonly())
return;
+ if (!FillRspTypes())
+ return;
+
if (!FillAssertNoDeps())
return;
@@ -311,6 +314,27 @@ bool TargetGenerator::FillTestonly() {
return true;
}
+bool TargetGenerator::FillRspTypes() {
+ const Value* value = scope_->GetValue(variables::kRspTypes, true);
+ if (!value)
+ return true;
+ if (!value->VerifyTypeIs(Value::LIST, err_))
+ return false;
+
+ const std::vector<Value>& value_list = value->list_value();
+ std::vector<std::string>& rsp_types = target_->rsp_types();
+ rsp_types.reserve(value_list.size());
+
+ for (size_t i = 0; i < value_list.size(); i++) {
+ const Value& value = value_list[i];
+ if (!value.VerifyTypeIs(Value::STRING, err_))
+ return false;
+ const std::string str = value.string_value();
+ rsp_types.push_back(str);
+ }
+ return true;
+}
+
bool TargetGenerator::FillAssertNoDeps() {
const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
if (value) {
diff --git a/gn/src/gn/target_generator.h b/gn/src/gn/target_generator.h
index 20531969afe..524ade0cc3c 100644
--- a/gn/src/gn/target_generator.h
+++ b/gn/src/gn/target_generator.h
@@ -71,6 +71,7 @@ class TargetGenerator {
bool FillDependencies(); // Includes data dependencies.
bool FillMetadata();
bool FillTestonly();
+ bool FillRspTypes();
bool FillAssertNoDeps();
bool FillWriteRuntimeDeps();
diff --git a/gn/src/gn/variables.cc b/gn/src/gn/variables.cc
index d5c5e45859b..fc08f41e466 100644
--- a/gn/src/gn/variables.cc
+++ b/gn/src/gn/variables.cc
@@ -2074,6 +2074,30 @@ Example
}
)";
+const char kRspTypes[] = "rsp_types";
+const char kRspTypes_HelpShort[] =
+ "rsp_types: [string list] A list of rsp files to create wih linker "
+ "information for given target.";
+const char kRspTypes_Help[] =
+ "rsp_types: Declares a target that instead of liking dumps the information "
+ "to set of rsp files.\n"
+ "\n"
+ " Defaults to ["
+ "].\n"
+ "\n"
+ " When a target is marked \"rsp_types = [ \"objects\" , \"archives\" ... "
+ "]\" and is linkable,"
+ " the linking step is skipped. Instead linking infomation is dumped as a "
+ "set of responses file containing"
+ " selected types of information\n"
+ "\n"
+ "Example\n"
+ "\n"
+ " static_library(\"test_support\") {\n"
+ " rsp_types = \"libs\"\n"
+ " ...\n"
+ " }\n";
+
const char kVisibility[] = "visibility";
const char kVisibility_HelpShort[] =
"visibility: [label list] A list of labels that can depend on a target.";
diff --git a/gn/src/gn/variables.h b/gn/src/gn/variables.h
index f5794d1d691..71789abebbe 100644
--- a/gn/src/gn/variables.h
+++ b/gn/src/gn/variables.h
@@ -326,6 +326,10 @@ extern const char kTestonly[];
extern const char kTestonly_HelpShort[];
extern const char kTestonly_Help[];
+extern const char kRspTypes[];
+extern const char kRspTypes_HelpShort[];
+extern const char kRspTypes_Help[];
+
extern const char kVisibility[];
extern const char kVisibility_HelpShort[];
extern const char kVisibility_Help[];