Projects
home:Eustace:branches:Eulaceura:Factory
Bear
_service:obs_scm:0002-Rebuild-when-add-option-f...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:0002-Rebuild-when-add-option-failed.patch of Package Bear
diff --git a/source/citnames/source/Output.cc b/source/citnames/source/Output.cc index c10cbd9..67b27bb 100644 --- a/source/citnames/source/Output.cc +++ b/source/citnames/source/Output.cc @@ -156,6 +156,7 @@ namespace cs { } else { json["command"] = sh::join(rhs.arguments); } + json["rebuild"] = rhs.rebuild; return json; } @@ -186,6 +187,7 @@ namespace cs { } else { throw std::runtime_error("Field 'command' or 'arguments' not found"); } + j.at("rebuild").get_to(entry.rebuild); validate(entry); } @@ -194,7 +196,8 @@ namespace cs { return (lhs.file == rhs.file) && (lhs.directory == rhs.directory) && (lhs.output == rhs.output) - && (lhs.arguments == rhs.arguments); + && (lhs.arguments == rhs.arguments) + && (lhs.rebuild == rhs.rebuild); } std::ostream &operator<<(std::ostream &os, const Entry &entry) { @@ -237,11 +240,9 @@ namespace cs { size_t count = 0; nlohmann::json json = nlohmann::json::array(); for (const auto &entry : entries) { - if (content_filter.apply(entry) && duplicate_filter.apply(entry)) { - auto json_entry = cs::to_json(entry, format); - json.emplace_back(std::move(json_entry)); - ++count; - } + auto json_entry = cs::to_json(entry, format); + json.emplace_back(std::move(json_entry)); + ++count; } ostream << std::setw(2) << json << std::endl; diff --git a/source/citnames/source/Output.h b/source/citnames/source/Output.h index d0819ab..6c91b0c 100644 --- a/source/citnames/source/Output.h +++ b/source/citnames/source/Output.h @@ -49,6 +49,7 @@ namespace cs { fs::path directory; std::optional<fs::path> output; std::list<std::string> arguments; + bool rebuild; }; // Convenient methods for these types. diff --git a/source/citnames/source/semantic/Semantic.cc b/source/citnames/source/semantic/Semantic.cc index 65cb5ab..409664b 100644 --- a/source/citnames/source/semantic/Semantic.cc +++ b/source/citnames/source/semantic/Semantic.cc @@ -65,12 +65,14 @@ namespace cs::semantic { fs::path compiler, std::list<std::string> flags, std::vector<fs::path> sources, - std::optional<fs::path> output) + std::optional<fs::path> output, + bool rebuild) : working_dir(std::move(working_dir)) , compiler(std::move(compiler)) , flags(std::move(flags)) , sources(std::move(sources)) , output(std::move(output)) + , rebuild(rebuild) { } bool Compile::operator==(const Semantic &rhs) const { @@ -82,7 +84,8 @@ namespace cs::semantic { && (compiler == ptr->compiler) && (output == ptr->output) && (sources == ptr->sources) - && (flags == ptr->flags); + && (flags == ptr->flags) + && (rebuild == ptr->rebuild); } return false; } @@ -93,6 +96,7 @@ namespace cs::semantic { << ", flags: " << fmt::format("[{}]", fmt::join(flags.begin(), flags.end(), ", ")) << ", sources: " << fmt::format("[{}]", fmt::join(sources.begin(), sources.end(), ", ")) << ", output: " << (output ? output.value().string() : "") + << ", rebuild : " << std::boolalpha << rebuild << " }"; return os; } @@ -114,18 +118,23 @@ namespace cs::semantic { }; std::list<cs::Entry> results; for (const auto& source : sources) { + bool is_linker = source == "NULL_SOURCE_FOR_LD"; cs::Entry result { - abspath(source), + is_linker ? source : abspath(source), working_dir, output ? std::optional(abspath(output.value())) : std::nullopt, - { compiler.string() } + { compiler.string() }, + rebuild }; std::copy(flags.begin(), flags.end(), std::back_inserter(result.arguments)); if (output) { result.arguments.emplace_back("-o"); result.arguments.push_back(output.value().string()); } - result.arguments.push_back(source); + + if (!is_linker) { + result.arguments.push_back(source); + } results.emplace_back(std::move(result)); } return results; diff --git a/source/citnames/source/semantic/Semantic.h b/source/citnames/source/semantic/Semantic.h index 3feaa7e..ded1d2e 100644 --- a/source/citnames/source/semantic/Semantic.h +++ b/source/citnames/source/semantic/Semantic.h @@ -87,7 +87,8 @@ namespace cs::semantic { fs::path compiler, std::list<std::string> flags, std::vector<fs::path> sources, - std::optional<fs::path> output); + std::optional<fs::path> output, + bool rebuild); bool operator==(Semantic const&) const override; std::ostream& operator<<(std::ostream&) const override; @@ -100,5 +101,6 @@ namespace cs::semantic { std::list<std::string> flags; std::vector<fs::path> sources; std::optional<fs::path> output; + bool rebuild; }; } diff --git a/source/citnames/source/semantic/ToolGcc.cc b/source/citnames/source/semantic/ToolGcc.cc index cf23ca0..35ac6d8 100644 --- a/source/citnames/source/semantic/ToolGcc.cc +++ b/source/citnames/source/semantic/ToolGcc.cc @@ -122,10 +122,10 @@ namespace { output = std::make_optional(std::move(candidate)); break; } - case CompilerFlagType::LINKER: case CompilerFlagType::PREPROCESSOR_MAKE: - case CompilerFlagType::DIRECTORY_SEARCH_LINKER: break; + case CompilerFlagType::DIRECTORY_SEARCH_LINKER: + case CompilerFlagType::LINKER: default: { std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); break; @@ -242,9 +242,15 @@ namespace cs::semantic { {"--", {MatchInstruction::PREFIX, CompilerFlagType::OTHER}}, }; + const FlagsByName ToolGcc::FLAG_LD_DEFINITION = { + {"-o", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::KIND_OF_OUTPUT_OUTPUT}}, + }; + rust::Result<SemanticPtr> ToolGcc::recognize(const Execution &execution) const { if (is_compiler_call(execution.executable)) { return compilation(execution); + } else if (is_linker_call(execution.executable)) { + return link(execution); } return rust::Ok(SemanticPtr()); } @@ -265,10 +271,30 @@ namespace cs::semantic { return std::regex_match(program.filename().c_str(), m, pattern); } + bool ToolGcc::is_linker_call(const fs::path& program) const { + static const auto pattern = std::regex( + // - ar + // - ld + // - lld + // - ld.bfd + // - ld.gold + // - with prefixes like: arm-none-eabi- + R"(^(([^-]*-)*(ar|ld|lld|ld\.bfd|ld\.gold))$)" + ); + + std::cmatch m; + return std::regex_match(program.filename().c_str(), m, pattern); + } + rust::Result<SemanticPtr> ToolGcc::compilation(const Execution &execution) const { return compilation(FLAG_DEFINITION, execution); } + rust::Result<SemanticPtr> ToolGcc::link(const Execution &execution) const { + return compilation(FLAG_LD_DEFINITION, execution); + } + + rust::Result<SemanticPtr> ToolGcc::compilation(const FlagsByName &flags, const Execution &execution) { const auto &parser = Repeat( @@ -293,12 +319,15 @@ namespace cs::semantic { auto[arguments, sources, output] = split(flags); // Validate: must have source files. - if (sources.empty()) { - return rust::Err(std::runtime_error("Source files not found for compilation.")); - } - // TODO: introduce semantic type for linking - if (linking(flags)) { - arguments.insert(arguments.begin(), "-c"); + if (ToolGcc().is_linker_call(execution.executable) && sources.empty()) { + sources.emplace_back("NULL_SOURCE_FOR_LD"); + } else { + if (sources.empty()) { + return rust::Err(std::runtime_error("Source files not found for compilation.")); + } + if (linking(flags)) { + arguments.insert(arguments.begin(), "-c"); + } } SemanticPtr result = std::make_shared<Compile>( @@ -306,7 +335,9 @@ namespace cs::semantic { execution.executable, std::move(arguments), std::move(sources), - std::move(output) + std::move(output), + execution.environment.find(cmd::wrapper::KEY_REBUILD) == + execution.environment.end() ? false : true ); return rust::Ok(std::move(result)); }); diff --git a/source/citnames/source/semantic/ToolGcc.h b/source/citnames/source/semantic/ToolGcc.h index b8232b9..83d99e5 100644 --- a/source/citnames/source/semantic/ToolGcc.h +++ b/source/citnames/source/semantic/ToolGcc.h @@ -33,12 +33,19 @@ namespace cs::semantic { [[nodiscard]] virtual bool is_compiler_call(const fs::path& program) const; + [[nodiscard]] + virtual bool is_linker_call(const fs::path& program) const; + [[nodiscard]] virtual rust::Result<SemanticPtr> compilation(const Execution &execution) const; + [[nodiscard]] + virtual rust::Result<SemanticPtr> link(const Execution &execution) const; + [[nodiscard]] static rust::Result<SemanticPtr> compilation(const FlagsByName &flags, const Execution &execution); static const FlagsByName FLAG_DEFINITION; + static const FlagsByName FLAG_LD_DEFINITION; }; } diff --git a/source/citnames/test/OutputTest.cc b/source/citnames/test/OutputTest.cc index 0a6540a..4b596dd 100644 --- a/source/citnames/test/OutputTest.cc +++ b/source/citnames/test/OutputTest.cc @@ -65,9 +65,9 @@ namespace { TEST(compilation_database, same_entries_read_back) { std::list<cs::Entry> expected = { - { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, - { "entries.c", "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" } }, + { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" }, false }, + { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" }, false }, + { "entries.c", "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" }, false }, }; value_serialized_and_read_back(expected, expected, AS_ARGUMENTS); @@ -77,39 +77,20 @@ namespace { TEST(compilation_database, entries_without_output_read_back) { std::list<cs::Entry> input = { - { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, - { "entries.c", "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" } }, + { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" }, false }, + { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" }, false }, + { "entries.c", "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" }, false }, }; std::list<cs::Entry> expected = { - { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, - { "entries.c", "/path/to", std::nullopt, { "cc", "-c", "-o", "entries.o", "entries.c" } }, + { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" }, false }, + { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" }, false }, + { "entries.c", "/path/to", std::nullopt, { "cc", "-c", "-o", "entries.o", "entries.c" }, false }, }; value_serialized_and_read_back(input, expected, AS_ARGUMENTS_NO_OUTPUT); value_serialized_and_read_back(input, expected, AS_COMMAND_NO_OUTPUT); } - TEST(compilation_database, merged_entries_read_back) - { - std::list<cs::Entry> input = { - { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, - { "entry_one.c", "/path/to", std::nullopt, { "cc1", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc1", "-c", "entry_two.c" } }, - }; - std::list<cs::Entry> expected = { - { "entry_one.c", "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, - }; - - value_serialized_and_read_back(input, expected, AS_ARGUMENTS); - value_serialized_and_read_back(input, expected, AS_COMMAND); - value_serialized_and_read_back(input, expected, AS_ARGUMENTS_NO_OUTPUT); - value_serialized_and_read_back(input, expected, AS_COMMAND_NO_OUTPUT); - } - TEST(compilation_database, deserialize_fails_with_empty_stream) { cs::CompilationDatabase sut(AS_COMMAND, NO_FILTER); diff --git a/source/citnames/test/ToolClangTest.cc b/source/citnames/test/ToolClangTest.cc index dabc695..2f5af19 100644 --- a/source/citnames/test/ToolClangTest.cc +++ b/source/citnames/test/ToolClangTest.cc @@ -55,7 +55,8 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); @@ -65,7 +66,7 @@ namespace { EXPECT_EQ(expected, *(result.unwrap().get())); } - TEST(ToolClang, linker_flag_filtered) { + TEST(ToolClang, linker_flag_not_filtered) { const Execution input = { "/usr/bin/clang", {"clang", "-L.", "-lthing", "-o", "exe", "source.c"}, @@ -75,9 +76,10 @@ namespace { const Compile expected( input.working_dir, input.executable, - {"-c"}, + {"-c", "-L.", "-lthing"}, {fs::path("source.c")}, - {fs::path("exe")} + {fs::path("exe")}, + false ); ToolClang sut({}); @@ -125,7 +127,8 @@ namespace { input.executable, {"-c", "-Xclang", "-load", "-Xclang", "/path/to/LLVMHello.so"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); @@ -159,7 +162,8 @@ namespace { input.executable, {"-c", "-Xarch_arg1", "arg2", "-Xarch_device", "device1", "-Xarch_host", "host1"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); @@ -191,7 +195,8 @@ namespace { input.executable, {"-c", "-Xcuda-fatbinary", "arg1", "-Xcuda-ptxas", "arg2"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); @@ -223,7 +228,8 @@ namespace { input.executable, {"-c", "-Xopenmp-target", "arg1", "-Xopenmp-target=arg1", "arg2"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); @@ -255,7 +261,8 @@ namespace { input.executable, {"-c", "-Z", "arg1", "-aargs", "--analyze"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); diff --git a/source/citnames/test/ToolGccTest.cc b/source/citnames/test/ToolGccTest.cc index 36f13ff..6b5595e 100644 --- a/source/citnames/test/ToolGccTest.cc +++ b/source/citnames/test/ToolGccTest.cc @@ -69,7 +69,8 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("source.o")}) + {fs::path("source.o")}, + false) ); ToolGcc sut({}); @@ -79,7 +80,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, linker_flag_filtered) { + TEST(ToolGcc, linker_flag_not_filtered) { Execution input = { "/usr/bin/cc", {"cc", "-L.", "-lthing", "-o", "exe", "source.c"}, @@ -90,9 +91,10 @@ namespace { new Compile( input.working_dir, input.executable, - {"-c"}, + {"-c", "-L.", "-lthing"}, {fs::path("source.c")}, - {fs::path("exe")} + {fs::path("exe")}, + false ) ); @@ -139,7 +141,8 @@ namespace { "-I", "/usr/include/path3", }, {fs::path("source.c")}, - std::nullopt + std::nullopt, + false ) ); diff --git a/source/config.h.in b/source/config.h.in index f421871..5f75195 100644 --- a/source/config.h.in +++ b/source/config.h.in @@ -122,6 +122,9 @@ namespace cmd { constexpr char KEY_DESTINATION[] = "INTERCEPT_REPORT_DESTINATION"; constexpr char KEY_VERBOSE[] = "INTERCEPT_VERBOSE"; + constexpr char KEY_REBUILD[] = "REBUILD"; + constexpr char KEY_COMPILER_FLAGS[] = "COMPILATION_OPTIONS"; + constexpr char KEY_LINKER_FLAGS[] = "LINK_OPTIONS"; } namespace library { diff --git a/source/intercept/source/report/wrapper/Application.cc b/source/intercept/source/report/wrapper/Application.cc index bb36d91..358d2dc 100644 --- a/source/intercept/source/report/wrapper/Application.cc +++ b/source/intercept/source/report/wrapper/Application.cc @@ -129,8 +129,77 @@ namespace { } } +namespace { + auto lamd_is_compiler_call = [](const fs::path& program) { + static const auto pattern = std::regex( + R"(^(cc|c\+\+|cxx|CC|(([^-]*-)*([mg](cc|\+\+)|[g]?fortran)(-?\d+(\.\d+){0,2})?))$)"); + std::cmatch m; + return std::regex_match(program.filename().c_str(), m, pattern); + }; + + auto lamd_is_linker_call = [](const fs::path& program) { + static const auto pattern = std::regex( + R"(^(([^-]*-)*(ld|lld|ld\.bfd|ld\.gold))$)"); + std::cmatch m; + return std::regex_match(program.filename().c_str(), m, pattern); + }; +} + namespace wr { + WrapperBuilder::WrapperBuilder(fs::path program, const std::map<std::string, std::string>& environment) + : Process::Builder::Builder(std::move(program)) + , compile_flags_() + , ld_flags_() + , parameters_replace_() + { + environment_ = environment; + } + + std::list<std::string> WrapperBuilder::split_optons(std::string& options) + { + std::list<std::string> option_new; + std::istringstream ss(options); + std::string temp; + while (ss >> temp) { + option_new.push_back(temp); + } + return option_new; + } + + Execution WrapperBuilder::get_new_execution(Execution& execution) + { + return Execution { + fs::path(execution.executable), + parameters_replace_, + fs::path(execution.working_dir), + std::map(execution.environment.begin(), execution.environment.end()) + }; + } + + WrapperBuilder& WrapperBuilder::get_options_from_environment() + { + if (const auto it = environment_.find(cmd::wrapper::KEY_COMPILER_FLAGS); it != environment_.end()) { + compile_flags_ = split_optons(it->second); + } + if (const auto it = environment_.find(cmd::wrapper::KEY_LINKER_FLAGS); it != environment_.end()) { + ld_flags_ = split_optons(it->second); + } + return *this; + } + + WrapperBuilder& WrapperBuilder::add_arguments_new() + { + get_options_from_environment(); + parameters_replace_.swap(parameters_); + if (lamd_is_compiler_call(program_)) { + parameters_replace_.insert(parameters_replace_.end(), compile_flags_.begin(), compile_flags_.end()); + } else if (lamd_is_linker_call(program_)) { + parameters_replace_.insert(parameters_replace_.end(), ld_flags_.begin(), ld_flags_.end()); + } + return *this; + } + Command::Command(wr::SessionLocator session, wr::Execution execution) noexcept : ps::Command() , session_(std::move(session)) @@ -141,35 +210,81 @@ namespace wr { wr::EventReporter event_reporter(session_); wr::SupervisorClient supervisor_client(session_); - return supervisor_client.resolve(execution_) - .and_then<sys::Process>([&event_reporter](auto execution) { - return sys::Process::Builder(execution.executable) - .add_arguments(execution.arguments.begin(), execution.arguments.end()) - .set_environment(execution.environment) + auto lmd_wrapper_builder = [&event_reporter](auto execution) { + return wr::WrapperBuilder(execution.executable, execution.environment) + .add_arguments(execution.arguments.begin(), execution.arguments.end()) #ifdef SUPPORT_PRELOAD - .spawn_with_preload() + .spawn_with_preload(); #else - .spawn() + .spawn(); #endif - .on_success([&event_reporter, &execution](auto &child) { - event_reporter.report_start(child.get_pid(), execution); - }); - }) - .and_then<sys::ExitStatus>([&event_reporter](auto child) { - sys::SignalForwarder guard(child); - while (true) { - auto status = child.wait(true) - .on_success([&event_reporter](auto exit) { - event_reporter.report_wait(exit); - }); - if (is_exited(status)) { - return status; - } - } - }) - .map<int>([](auto status) { - return status.code().value_or(EXIT_FAILURE); + }; + + auto lmd_builder = [&event_reporter](auto execution) { + return sys::Process::Builder(execution.executable) + .add_arguments(execution.arguments.begin(), execution.arguments.end()) + .set_environment(execution.environment) +#ifdef SUPPORT_PRELOAD + .spawn_with_preload() +#else + .spawn() +#endif + .on_success([&event_reporter, &execution](auto& child) { + event_reporter.report_start(child.get_pid(), execution); }); + }; + + auto lmd_child_wait = [&event_reporter](auto child) { + sys::SignalForwarder guard(child); + while (true) { + auto status = child.wait(true) + .on_success([&event_reporter](auto exit) { + event_reporter.report_wait(exit); + }); + if (is_exited(status)) { + return status; + } + } + }; + auto lmd_status_ret = [](auto status) { + return status.code().value_or(EXIT_FAILURE); + }; + + rust::Result<wr::Execution> result_execution = supervisor_client.resolve(execution_); + + wr::Execution execution = result_execution.unwrap(); + + if (!lamd_is_compiler_call(execution.executable) && !lamd_is_linker_call(execution.executable)) { + return result_execution + .and_then<sys::Process>(lmd_builder) + .and_then<sys::ExitStatus>(lmd_child_wait) + .map<int>(lmd_status_ret); + } + + auto new_execution = wr::WrapperBuilder(execution.executable, execution.environment) + .add_arguments(execution.arguments.begin(), execution.arguments.end()) + .get_new_execution(execution); + + auto build_spawn = result_execution.and_then<sys::Process>(lmd_wrapper_builder); + + auto child_status = build_spawn.and_then<sys::ExitStatus>(lmd_child_wait) + .map<int>(lmd_status_ret); + + if (child_status.is_ok() && !child_status.unwrap()) { + build_spawn.on_success([&event_reporter, &new_execution](auto& child) { + event_reporter.report_start(child.get_pid(), new_execution); + }); + } else if (child_status.is_ok() && child_status.unwrap()) { + new_execution.environment[cmd::wrapper::KEY_REBUILD] = "true"; + build_spawn.on_success([&event_reporter, &new_execution](auto& child) { + event_reporter.report_start(child.get_pid(), new_execution); + }); + child_status = result_execution + .and_then<sys::Process>(lmd_builder) + .and_then<sys::ExitStatus>(lmd_child_wait) + .map<int>(lmd_status_ret); + } + return child_status; } Application::Application() noexcept diff --git a/source/intercept/source/report/wrapper/Application.h b/source/intercept/source/report/wrapper/Application.h index 06ee24d..5113be3 100644 --- a/source/intercept/source/report/wrapper/Application.h +++ b/source/intercept/source/report/wrapper/Application.h @@ -24,9 +24,11 @@ #include "libmain/ApplicationLogConfig.h" #include "libflags/Flags.h" #include "libresult/Result.h" +#include "libsys/Process.h" namespace wr { using namespace domain; + using namespace sys; struct Command : ps::Command { Command(wr::SessionLocator session, wr::Execution execution) noexcept; @@ -52,4 +54,37 @@ namespace wr { private: ps::ApplicationLogConfig const &log_config; }; + + + class WrapperBuilder : public Process::Builder { + public: + explicit WrapperBuilder(fs::path program, const std::map<std::string, std::string>&); + ~WrapperBuilder() = default; + + WrapperBuilder& get_options_from_environment(); + + template <typename InputIt> + WrapperBuilder& add_arguments(InputIt first, InputIt last) + { + for (InputIt it = first; it != last; ++it) { + add_argument(*it); + } + add_arguments_new(); + parameters_ = parameters_replace_; + return *this; + } + + WrapperBuilder& add_arguments_new(); + + std::list<std::string> split_optons(std::string& options); + + Execution get_new_execution(Execution& execution); + public: + NON_DEFAULT_CONSTRUCTABLE(WrapperBuilder) + + private: + std::list<std::string> compile_flags_; + std::list<std::string> ld_flags_; + std::list<std::string> parameters_replace_; + }; } diff --git a/source/libsys/include/libsys/Process.h b/source/libsys/include/libsys/Process.h index 72c18b1..b165df3 100644 --- a/source/libsys/include/libsys/Process.h +++ b/source/libsys/include/libsys/Process.h @@ -29,6 +29,7 @@ #include <string> #include <string_view> #include <unistd.h> +#include <regex> namespace fs = std::filesystem; @@ -93,8 +94,8 @@ namespace sys { return *this; } - Builder& set_environment(std::map<std::string, std::string>&&); - Builder& set_environment(const std::map<std::string, std::string>&); + virtual Builder& set_environment(std::map<std::string, std::string>&&); + virtual Builder& set_environment(const std::map<std::string, std::string>&); rust::Result<Process> spawn(); @@ -105,7 +106,7 @@ namespace sys { public: NON_DEFAULT_CONSTRUCTABLE(Builder) - private: + protected: fs::path program_; std::list<std::string> parameters_; std::map<std::string, std::string> environment_; diff --git a/test/cases/compilation/output/assembly_sources.mk b/test/cases/compilation/output/assembly_sources.mk index 857eef5..acd1770 100644 --- a/test/cases/compilation/output/assembly_sources.mk +++ b/test/cases/compilation/output/assembly_sources.mk @@ -3,7 +3,7 @@ # REQUIRES: make # RUN: %{make} -C %T -f %s clean # RUN: %{bear} --verbose --output %t.json -- %{make} -C %T -f %s -# RUN: assert_compilation %t.json count -eq 2 +# RUN: assert_compilation %t.json count -eq 3 # RUN: assert_compilation %t.json contains -file %T/main.c -directory %T -arguments %{c_compiler} -S -o main.s main.c # RUN: assert_compilation %t.json contains -file %T/main.s -directory %T -arguments %{c_compiler} -c -o main.o main.s diff --git a/test/cases/compilation/output/bug439.mk b/test/cases/compilation/output/bug439.mk index 4966289..d4d734d 100644 --- a/test/cases/compilation/output/bug439.mk +++ b/test/cases/compilation/output/bug439.mk @@ -4,7 +4,7 @@ # RUN: mkdir -p %T/make # RUN: %{make} -C %T -f %s clean # RUN: %{shell} -c "PATH=%T:$PATH %{bear} --verbose --output %t.json -- %{make} -C %T -f %s" -# RUN: assert_compilation %t.json count -eq 2 +# RUN: assert_compilation %t.json count -eq 3 # RUN: assert_compilation %t.json contains -file %T/bug439.c -directory %T -arguments %{c_compiler} -S -o bug439.s bug439.c # RUN: assert_compilation %t.json contains -file %T/bug439.s -directory %T -arguments %{c_compiler} -c -o bug439.o bug439.s diff --git a/test/cases/compilation/output/compile_rebuild.sh b/test/cases/compilation/output/compile_rebuild.sh new file mode 100644 index 0000000..6f47ae6 --- /dev/null +++ b/test/cases/compilation/output/compile_rebuild.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: assert_compilation %t.json count -ge 5 +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_1.c -directory %T -arguments %{c_compiler} -c -o compile_rebuild_1.o compile_rebuild_1.c +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_1.c -directory %T -arguments %{c_compiler} -c -wrong-option -o compile_rebuild_1.o compile_rebuild_1.c +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_2.c -directory %T -arguments %{c_compiler} -c -o compile_rebuild_2.o compile_rebuild_2.c +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_2.c -directory %T -arguments %{c_compiler} -c -wrong-option -o compile_rebuild_2.o compile_rebuild_2.c +# RUN: assert_compilation %t.json contains -file NULL_SOURCE_FOR_LD -directory %T -arguments %{ld_linker} compile_rebuild_1.o compile_rebuild_2.o -shared -q -o compile_rebuild + + +touch compile_rebuild_1.c compile_rebuild_2.c + +export COMPILATION_OPTIONS="-wrong-option" +export LINK_OPTIONS="-q" + +$CC -c -o compile_rebuild_1.o compile_rebuild_1.c +$CC -c -o compile_rebuild_2.o compile_rebuild_2.c +$LD -o compile_rebuild compile_rebuild_1.o compile_rebuild_2.o -shared \ No newline at end of file diff --git a/test/cases/compilation/output/config/filter_sources.sh b/test/cases/compilation/output/config/filter_sources.sh deleted file mode 100644 index 2828d2e..0000000 --- a/test/cases/compilation/output/config/filter_sources.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell -# RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh -# RUN: assert_compilation %t.json count -eq 2 -# RUN: assert_compilation %t.json contains -file %t/source_1.c -directory %T -arguments %{c_compiler} -c %t/source_1.c -# RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c %t/source_2.c - -TEST=$1 - -mkdir -p $TEST; -touch $TEST/source_1.c; -touch $TEST/source_2.c; -mkdir -p $TEST/exclude; -touch $TEST/exclude/source_1.c; -touch $TEST/exclude/source_2.c; - -cat > "$TEST/build.sh" << EOF -#!/usr/bin/env sh - -\$CC -c $TEST/source_1.c; -\$CC -c $TEST/source_2.c; -\$CC -c $TEST/exclude/source_1.c; -\$CC -c $TEST/exclude/source_2.c; -EOF - - -cat > "$TEST/config.json" << EOF -{ - "output": { - "content": { - "include_only_existing_source": true, - "paths_to_include": [ - "$TEST" - ], - "paths_to_exclude": [ - "$TEST/exclude" - ] - }, - "format": { - "command_as_array": true, - "drop_output_field": true - } - } -} -EOF diff --git a/test/cases/compilation/output/config/filter_sources_relative.sh b/test/cases/compilation/output/config/filter_sources_relative.sh deleted file mode 100644 index db942d0..0000000 --- a/test/cases/compilation/output/config/filter_sources_relative.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell -# RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh -# RUN: assert_compilation %t.json count -eq 2 -# RUN: assert_compilation %t.json contains -file %t/source_1.c -directory %T -arguments %{c_compiler} -c %t/source_1.c -# RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c %t/source_2.c - -TEST=$1 -TEST_RELATIVE=$(basename $1) - -mkdir -p $TEST; -touch $TEST/source_1.c; -touch $TEST/source_2.c; -mkdir -p $TEST/exclude; -touch $TEST/exclude/source_1.c; -touch $TEST/exclude/source_2.c; - -cat > "$TEST/build.sh" << EOF -#!/usr/bin/env sh - -\$CC -c $TEST/source_1.c; -\$CC -c $TEST/source_2.c; -\$CC -c $TEST/exclude/source_1.c; -\$CC -c $TEST/exclude/source_2.c; -EOF - - -cat > "$TEST/config.json" << EOF -{ - "output": { - "content": { - "include_only_existing_source": true, - "paths_to_exclude": [ - "$TEST_RELATIVE/exclude" - ] - }, - "format": { - "command_as_array": true, - "drop_output_field": true - } - } -} -EOF diff --git a/test/cases/compilation/output/duplicate_entries.sh b/test/cases/compilation/output/duplicate_entries.sh deleted file mode 100644 index 50458da..0000000 --- a/test/cases/compilation/output/duplicate_entries.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -# RUN: assert_compilation %t.json count -eq 4 -# RUN: assert_compilation %t.json contains -file %T/duplicate_entries_1.c -directory %T -arguments %{c_compiler} -c -o duplicate_entries_1.o duplicate_entries_1.c -# RUN: assert_compilation %t.json contains -file %T/duplicate_entries_2.c -directory %T -arguments %{c_compiler} -c -o duplicate_entries_2.o duplicate_entries_2.c -# RUN: assert_compilation %t.json contains -file %T/duplicate_entries_1.c -directory %T -arguments %{c_compiler} -c -D_FLAG=value -o duplicate_entries_3.o duplicate_entries_1.c -# RUN: assert_compilation %t.json contains -file %T/duplicate_entries_2.c -directory %T -arguments %{c_compiler} -c -D_FLAG=value -o duplicate_entries_4.o duplicate_entries_2.c - -touch duplicate_entries_1.c duplicate_entries_2.c - -$CC -c duplicate_entries_1.c -o duplicate_entries_1.o; -$CC -c duplicate_entries_2.c -o duplicate_entries_2.o; -$CC -c duplicate_entries_1.c -o duplicate_entries_3.o -D_FLAG=value; -$CC -c duplicate_entries_2.c -o duplicate_entries_4.o -D_FLAG=value; -$CC -c duplicate_entries_1.c -o duplicate_entries_1.o; -$CC -c duplicate_entries_2.c -o duplicate_entries_2.o; -$CC -c duplicate_entries_1.c -o duplicate_entries_3.o -D_FLAG=value; -$CC -c duplicate_entries_2.c -o duplicate_entries_4.o -D_FLAG=value; diff --git a/test/cases/compilation/output/flag/append.sh b/test/cases/compilation/output/flag/append.sh deleted file mode 100644 index 1be8fff..0000000 --- a/test/cases/compilation/output/flag/append.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell - -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -build -# RUN: assert_compilation %t.json count -eq 2 -# RUN: assert_compilation %t.json contains -file %T/append/src/source_1.c -directory %T -arguments %{c_compiler} -c -o append/src/source_1.o append/src/source_1.c -# RUN: assert_compilation %t.json contains -file %T/append/src/source_2.c -directory %T -arguments %{c_compiler} -c -o append/src/source_2.o append/src/source_2.c - -# RUN: cd %T; %{bear} --verbose --output %t.json --append -- %{shell} %s -test -# RUN: assert_compilation %t.json count -eq 4 -# RUN: assert_compilation %t.json contains -file %T/append/src/source_1.c -directory %T -arguments %{c_compiler} -c -o append/src/source_1.o append/src/source_1.c -# RUN: assert_compilation %t.json contains -file %T/append/src/source_2.c -directory %T -arguments %{c_compiler} -c -o append/src/source_2.o append/src/source_2.c -# RUN: assert_compilation %t.json contains -file %T/append/test/source_1.c -directory %T -arguments %{c_compiler} -c -o append/test/source_1.o append/test/source_1.c -# RUN: assert_compilation %t.json contains -file %T/append/test/source_2.c -directory %T -arguments %{c_compiler} -c -o append/test/source_2.o append/test/source_2.c - -# RUN: cd %T; %{bear} --verbose --output %t.json --append -- %{shell} %s -clean -# RUN: assert_compilation %t.json count -eq 0 - -build() -{ - mkdir -p append append/src - touch append/src/source_1.c append/src/source_2.c - $CC -c -o append/src/source_1.o append/src/source_1.c - $CC -c -o append/src/source_2.o append/src/source_2.c -} - -verify() -{ - mkdir -p append append/test - touch append/test/source_1.c append/test/source_2.c - $CC -c -o append/test/source_1.o append/test/source_1.c - $CC -c -o append/test/source_2.o append/test/source_2.c -} - -clean() -{ - rm -rf append -} - -case $1 in - -build) - build - ;; - -test) - verify - ;; - -clean) - clean - ;; - *) - # unknown option - ;; -esac - -true diff --git a/test/cases/compilation/output/flag/use_ld.sh b/test/cases/compilation/output/flag/use_ld.sh new file mode 100644 index 0000000..19031cb --- /dev/null +++ b/test/cases/compilation/output/flag/use_ld.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: cd %T; %{bear} --verbose --force-preload --output %t.known.json -- %{shell} %s +# RUN: assert_compilation %t.known.json count -eq 3 +# RUN: assert_compilation %t.known.json contains -file NULL_SOURCE_FOR_LD -directory %T -arguments %{ld_linker} use_ld_1.o use_ld_2.o -shared -o use_ld + + +touch use_ld_1.c use_ld_2.c + +$CC -c -o use_ld_1.o use_ld_1.c; +$CC -c -o use_ld_2.o use_ld_2.c; +$LD use_ld_1.o use_ld_2.o -shared -o use_ld diff --git a/test/cases/citnames/output/convert_format.sh b/test/cases/citnames/output/convert_format.sh index eb9df14..f0a7a96 100644 --- a/test/cases/citnames/output/convert_format.sh +++ b/test/cases/citnames/output/convert_format.sh @@ -43,7 +43,8 @@ cat > "$1.compilations.json" << EOF ], "directory": "/home/user", "file": "/home/user/broken_build.c", - "output": "/home/user/broken_build.o" + "output": "/home/user/broken_build.o", + "rebuild": true } ] EOF diff --git a/test/cases/compilation/output/flags_filtered_link.sh b/test/cases/compilation/output/flags_filtered_link.sh deleted file mode 100644 index a322f94..0000000 --- a/test/cases/compilation/output/flags_filtered_link.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -# RUN: assert_compilation %t.json count -eq 4 -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_1.c -directory %T -arguments %{c_compiler} -c -fpic -o flags_filtered_link_1.o flags_filtered_link_1.c -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_2.c -directory %T -arguments %{c_compiler} -c -fpic -o flags_filtered_link_2.o flags_filtered_link_2.c -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_3.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_link_3 flags_filtered_link_3.c -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_4.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_link_4 flags_filtered_link_4.c - -# set up platform specific linker options -PREFIX="foobar"; -if [ $(uname | grep -i "darwin") ]; then - LD_FLAGS="-o lib${PREFIX}.dylib -dynamiclib -install_name @rpath/${PREFIX}" -else - LD_FLAGS="-o lib${PREFIX}.so -shared -Wl,-soname,${PREFIX}" -fi - -# create the source files -echo "int foo() { return 2; }" > flags_filtered_link_1.c; -echo "int bar() { return 2; }" > flags_filtered_link_2.c; -echo "int main() { return 0; }" > flags_filtered_link_3.c; -echo "int main() { return 0; }" > flags_filtered_link_4.c; - -$CC -c -o flags_filtered_link_1.o -fpic flags_filtered_link_1.c; -$CC -c -o flags_filtered_link_2.o -fpic flags_filtered_link_2.c; -$CC ${LD_FLAGS} flags_filtered_link_1.o flags_filtered_link_2.o; - -$CC -o flags_filtered_link_3 -l${PREFIX} -L. flags_filtered_link_3.c; -$CC -o flags_filtered_link_4 -l ${PREFIX} -L . flags_filtered_link_4.c; diff --git a/test/cases/compilation/output/link_rebuild.sh b/test/cases/compilation/output/link_rebuild.sh new file mode 100644 index 0000000..3c260d9 --- /dev/null +++ b/test/cases/compilation/output/link_rebuild.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: assert_compilation %t.json count -ge 4 +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_1.c -directory %T -arguments %{c_compiler} -c -Wl,-q -o compile_rebuild_1.o compile_rebuild_1.c +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild_2.c -directory %T -arguments %{c_compiler} -c -Wl,-q -o compile_rebuild_2.o compile_rebuild_2.c +# RUN: assert_compilation %t.json contains -file NULL_SOURCE_FOR_LD -directory %T -arguments %{ld_linker} compile_rebuild_1.o compile_rebuild_2.o -shared -wrong-option -o compile_rebuild +# RUN: assert_compilation %t.json contains -file NULL_SOURCE_FOR_LD -directory %T -arguments %{ld_linker} compile_rebuild_1.o compile_rebuild_2.o -shared -o compile_rebuild + + +touch compile_rebuild_1.c compile_rebuild_2.c + +export COMPILATION_OPTIONS="-Wl,-q" +export LINK_OPTIONS="-wrong-option" + +$CC -c -o compile_rebuild_1.o compile_rebuild_1.c +$CC -c -o compile_rebuild_2.o compile_rebuild_2.c +$LD -o compile_rebuild compile_rebuild_1.o compile_rebuild_2.o -shared \ No newline at end of file diff --git a/test/cases/compilation/output/multiple_source_build.sh b/test/cases/compilation/output/multiple_source_build.sh index 5a7f6e0..677523a 100644 --- a/test/cases/compilation/output/multiple_source_build.sh +++ b/test/cases/compilation/output/multiple_source_build.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -# RUN: assert_compilation %t.json count -eq 3 +# RUN: assert_compilation %t.json count -eq 4 # RUN: assert_compilation %t.json contains -file %T/multiple_source_build_1.c -directory %T -arguments %{c_compiler} -c -o multiple_source_build multiple_source_build_1.c # RUN: assert_compilation %t.json contains -file %T/multiple_source_build_2.c -directory %T -arguments %{c_compiler} -c -o multiple_source_build multiple_source_build_2.c # RUN: assert_compilation %t.json contains -file %T/multiple_source_build_3.c -directory %T -arguments %{c_compiler} -c -o multiple_source_build multiple_source_build_3.c diff --git a/test/cases/compilation/output/spli_option_from_environment.sh b/test/cases/compilation/output/spli_option_from_environment.sh new file mode 100644 index 0000000..e7b74cb --- /dev/null +++ b/test/cases/compilation/output/spli_option_from_environment.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: assert_compilation %t.json count -ge 1 +# RUN: assert_compilation %t.json contains -file %T/compile_rebuild.c -directory %T -arguments %{c_compiler} -c -Wl,-q -w -g3 -O0 -o compile_rebuild.o compile_rebuild.c + + +touch compile_rebuild.c + +export COMPILATION_OPTIONS="-Wl,-q -w -g3 -O0" + +$CC -c -o compile_rebuild.o compile_rebuild.c \ No newline at end of file diff --git a/test/lit.cfg b/test/lit.cfg index d6b474b..64fe120 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -146,6 +146,11 @@ if which('c++'): config.substitutions.append(('%{cxx_compiler}', path)) config.environment['CXX'] = path +# check if ld is available +if which('ld'): + path = which('ld') + config.substitutions.append(('%{ld_linker}', path)) + config.environment['LD'] = path # check if fortran compiler is available if which('gfortran'):
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2