diff options
author | Michal Klocek <michal.klocek@qt.io> | 2017-01-09 13:28:49 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-04 10:20:59 +0200 |
commit | dc8b97a4affb646a8ee508d404f684a1e97c2eea (patch) | |
tree | 2b218f0aa870ce2493c822b43873a4b971938cef | |
parent | 5e25b04f055676df117338de22f5bf00601b57a1 (diff) | |
download | qtwebengine-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-x | gn/build/gen.py | 2 | ||||
-rw-r--r-- | gn/src/gn/escape.cc | 47 | ||||
-rw-r--r-- | gn/src/gn/escape.h | 3 | ||||
-rw-r--r-- | gn/src/gn/ninja_action_target_writer.cc | 2 | ||||
-rw-r--r-- | gn/src/gn/ninja_binary_target_writer.cc | 18 | ||||
-rw-r--r-- | gn/src/gn/ninja_binary_target_writer.h | 2 | ||||
-rw-r--r-- | gn/src/gn/ninja_c_binary_target_writer.cc | 17 | ||||
-rw-r--r-- | gn/src/gn/ninja_target_writer.cc | 1 | ||||
-rw-r--r-- | gn/src/gn/rsp_target_writer.cc | 253 | ||||
-rw-r--r-- | gn/src/gn/rsp_target_writer.h | 67 | ||||
-rw-r--r-- | gn/src/gn/rsp_target_writer_unittest.cc | 170 | ||||
-rw-r--r-- | gn/src/gn/target.cc | 6 | ||||
-rw-r--r-- | gn/src/gn/target.h | 4 | ||||
-rw-r--r-- | gn/src/gn/target_generator.cc | 24 | ||||
-rw-r--r-- | gn/src/gn/target_generator.h | 1 | ||||
-rw-r--r-- | gn/src/gn/variables.cc | 24 | ||||
-rw-r--r-- | gn/src/gn/variables.h | 4 |
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[]; |