Bear/0002-Rebuild-when-add-option-failed.patch

1139 lines
46 KiB
Diff
Raw Permalink Normal View History

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'):