From ac084ecdf307b4e17187f573a570410809ca5c49 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+MashaK5@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:38:59 +0300 Subject: [PATCH 1/7] Linking database (#2) * Add patch for linking database --- source/bear/source/Application.cc | 114 ++++++------ source/citnames/source/Citnames.cc | 169 ++++++++++++------ source/citnames/source/Citnames.h | 4 +- source/citnames/source/Configuration.h | 3 + source/citnames/source/Output.cc | 72 +++++--- source/citnames/source/Output.h | 1 + source/citnames/source/semantic/Build.cc | 4 +- source/citnames/source/semantic/Build.h | 2 +- source/citnames/source/semantic/Parsers.cc | 2 + source/citnames/source/semantic/Semantic.cc | 137 +++++++++++--- source/citnames/source/semantic/Semantic.h | 32 +++- source/citnames/source/semantic/Tool.h | 7 +- source/citnames/source/semantic/ToolAny.cc | 4 +- source/citnames/source/semantic/ToolAny.h | 2 +- source/citnames/source/semantic/ToolClang.cc | 17 +- source/citnames/source/semantic/ToolClang.h | 2 +- .../source/semantic/ToolExtendingWrapper.cc | 4 +- .../source/semantic/ToolExtendingWrapper.h | 2 +- source/citnames/source/semantic/ToolGcc.cc | 129 +++++++++++-- source/citnames/source/semantic/ToolGcc.h | 11 +- .../citnames/source/semantic/ToolWrapper.cc | 30 +++- source/citnames/source/semantic/ToolWrapper.h | 2 +- source/citnames/test/OutputTest.cc | 93 +++++----- source/citnames/test/ToolClangTest.cc | 37 ++-- source/citnames/test/ToolGccTest.cc | 20 ++- source/config.h.in | 7 +- .../exit_code/exit_code_for_success.sh | 2 +- test/cases/citnames/output/clang_plugin.sh | 2 +- test/cases/citnames/output/convert_format.sh | 3 +- .../output/relative_paths_converted.sh | 2 +- .../citnames/output/wrapper_flags_extended.sh | 2 +- .../exit_code/exit_code_for_fail.sh | 2 +- .../exit_code/exit_code_for_success.sh | 2 +- .../compilation/output/assembly_sources.mk | 2 +- test/cases/compilation/output/broken_build.sh | 2 +- test/cases/compilation/output/bug439.mk | 2 +- test/cases/compilation/output/compile_cuda.sh | 2 +- .../compilation/output/compile_fortran.sh | 2 +- .../output/config/filter_compilers.sh | 2 +- .../compilation/output/config/filter_flags.sh | 4 +- .../config/filter_flags_on_known_compiler.sh | 4 +- .../output/config/filter_sources.sh | 2 +- .../output/config/filter_sources_relative.sh | 2 +- .../output/define_with_escaped_quote.sh | 4 +- .../compilation/output/define_with_quote.sh | 4 +- .../compilation/output/duplicate_entries.sh | 2 +- .../compilation/output/empty_argument.sh | 2 +- test/cases/compilation/output/empty_env.sh | 2 +- .../compilation/output/existing_files_only.sh | 2 +- test/cases/compilation/output/flag/append.sh | 9 +- .../compilation/output/flag/field_output.sh | 2 +- test/cases/compilation/output/flag/use_cc.sh | 8 +- test/cases/compilation/output/flag/use_cxx.sh | 8 +- .../compilation/output/flags_filtered_link.sh | 6 +- .../output/flags_filtered_preproc.sh | 2 +- .../output/multiple_source_build.sh | 8 +- .../compilation/output/parallel_build.sh | 2 +- .../compilation/output/successful_build.sh | 2 +- test/cases/compilation/output/wrapper.sh | 4 +- .../intercept/preload/signal_outside_build.sh | 2 +- 60 files changed, 700 insertions(+), 315 deletions(-) diff --git a/source/bear/source/Application.cc b/source/bear/source/Application.cc index 0af55e87..4eedb219 100644 --- a/source/bear/source/Application.cc +++ b/source/bear/source/Application.cc @@ -69,26 +69,32 @@ namespace { rust::Result prepare_citnames(const flags::Arguments &arguments, const sys::env::Vars &environment, const fs::path &input) { auto program = arguments.as_string(cmd::bear::FLAG_BEAR); - auto output = arguments.as_string(cmd::citnames::FLAG_OUTPUT); + auto with_link = arguments.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); + auto output_compile = arguments.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE); + auto output_link = arguments.as_string(cmd::citnames::FLAG_OUTPUT_LINK); auto config = arguments.as_string(cmd::citnames::FLAG_CONFIG); auto append = arguments.as_bool(cmd::citnames::FLAG_APPEND).unwrap_or(false); auto verbose = arguments.as_bool(flags::VERBOSE).unwrap_or(false); - return rust::merge(program, output) - .map([&environment, &input, &config, &append, &verbose](auto tuple) { - const auto&[program, output] = tuple; + return rust::merge(program, output_compile, output_link) + .map([&environment, &input, &config, &append, &verbose, &with_link](auto tuple) { + const auto&[program, output_compile, output_link] = tuple; auto builder = sys::Process::Builder(program) .set_environment(environment) .add_argument(program) .add_argument("citnames") .add_argument(cmd::citnames::FLAG_INPUT).add_argument(input) - .add_argument(cmd::citnames::FLAG_OUTPUT).add_argument(output) + .add_argument(cmd::citnames::FLAG_OUTPUT_COMPILE).add_argument(output_compile) + .add_argument(cmd::citnames::FLAG_OUTPUT_LINK).add_argument(output_link) // can run the file checks, because we are on the host. .add_argument(cmd::citnames::FLAG_RUN_CHECKS); if (append) { builder.add_argument(cmd::citnames::FLAG_APPEND); } + if (with_link) { + builder.add_argument(cmd::citnames::FLAG_WITH_LINK); + } if (config.is_ok()) { builder.add_argument(cmd::citnames::FLAG_CONFIG).add_argument(config.unwrap()); } @@ -145,7 +151,7 @@ namespace bear { rust::Result Application::parse(int argc, const char **argv) const { - const flags::Parser intercept_parser("intercept", cmd::VERSION, { + const flags::Parser intercept_parser("intercept", cmd::VERSION, { {cmd::intercept::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, DEVELOPER_GROUP}}, @@ -153,59 +159,65 @@ namespace bear { {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} - }); - - const flags::Parser citnames_parser("citnames", cmd::VERSION, { - {cmd::citnames::FLAG_INPUT, {1, false, "path of the input file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, - {cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}}, - {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_APPEND, {0, false, "append to output, instead of overwrite it", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_RUN_CHECKS, {0, false, "can run checks on the current host", std::nullopt, std::nullopt}} - }); - - const flags::Parser parser("bear", cmd::VERSION, {intercept_parser, citnames_parser}, { - {cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}}, - {cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}}, - {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}}, - {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}}, - {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}}, - {cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} - }); - return parser.parse_or_exit(argc, const_cast(argv)); + }); + + const flags::Parser citnames_parser("citnames", cmd::VERSION, { + {cmd::citnames::FLAG_INPUT, {1, false, "path of the input file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, + {cmd::citnames::FLAG_WITH_LINK, {0, false, "whether to create a link base", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_OUTPUT_COMPILE, {1, false, "path of the result compile file", {cmd::citnames::DEFAULT_OUTPUT_COMPILE}, std::nullopt}}, + {cmd::citnames::FLAG_OUTPUT_LINK, {1, false, "path of the result link file", {cmd::citnames::DEFAULT_OUTPUT_LINK}, std::nullopt}}, + {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_APPEND, {0, false, "append to output, instead of overwrite it", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_RUN_CHECKS, {0, false, "can run checks on the current host", std::nullopt, std::nullopt}} + }); + + const flags::Parser parser("bear", cmd::VERSION, {intercept_parser, citnames_parser}, { + {cmd::citnames::FLAG_WITH_LINK, {0, false, "whether to create a link base", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_OUTPUT_COMPILE, {1, false, "path of the result compile file", {cmd::citnames::DEFAULT_OUTPUT_COMPILE}, std::nullopt}}, + {cmd::citnames::FLAG_OUTPUT_LINK, {1, false, "path of the result link file", {cmd::citnames::DEFAULT_OUTPUT_LINK}, std::nullopt}}, + {cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}}, + {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}}, + {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}}, + {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}}, + {cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} + }); + return parser.parse_or_exit(argc, const_cast(argv)); } rust::Result Application::command(const flags::Arguments &args, const char **envp) const { - if (args.as_string(flags::COMMAND).is_ok()) { - if (auto citnames = cs::Citnames(log_config_); citnames.matches(args)) { - return citnames.subcommand(args, envp); - } - if (auto intercept = ic::Intercept(log_config_); intercept.matches(args)) { - return intercept.subcommand(args, envp); + if (args.as_string(flags::COMMAND).is_ok()) { + if (auto citnames = cs::Citnames(log_config_); citnames.matches(args)) { + return citnames.subcommand(args, envp); + } + if (auto intercept = ic::Intercept(log_config_); intercept.matches(args)) { + return intercept.subcommand(args, envp); + } + + return rust::Err(std::runtime_error("Invalid subcommand")); } - return rust::Err(std::runtime_error("Invalid subcommand")); - } - - auto commands = args.as_string(cmd::citnames::FLAG_OUTPUT) - .map([](const auto &output) { - return fs::path(output).replace_extension(".events.json"); - }) - .unwrap_or(fs::path(cmd::citnames::DEFAULT_OUTPUT)); + // now only the name of the compile file is used + // to generate the name of the intermediate file (events) + auto commands = args.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE) + .map([](const auto &output) { + return fs::path(output).replace_extension(".events.json"); + }) + .unwrap_or(fs::path(cmd::intercept::DEFAULT_OUTPUT)); - auto environment = sys::env::from(const_cast(envp)); - auto intercept = prepare_intercept(args, environment, commands); - auto citnames = prepare_citnames(args, environment, commands); + auto environment = sys::env::from(const_cast(envp)); + auto intercept = prepare_intercept(args, environment, commands); + auto citnames = prepare_citnames(args, environment, commands); - return rust::merge(intercept, citnames) - .map([&commands](const auto &tuple) { - const auto&[intercept, citnames] = tuple; + return rust::merge(intercept, citnames) + .map([&commands](const auto &tuple) { + const auto&[intercept, citnames] = tuple; - return std::make_unique(intercept, citnames, commands); - }); + return std::make_unique(intercept, citnames, commands); + }); } } diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index 0eee05ed..19d62667 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -102,17 +102,20 @@ namespace { rust::Result into_arguments(const flags::Arguments &args) { auto input = args.as_string(cmd::citnames::FLAG_INPUT); - auto output = args.as_string(cmd::citnames::FLAG_OUTPUT); - auto append = args.as_bool(cmd::citnames::FLAG_APPEND) - .unwrap_or(false); + auto output_compile = args.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE); + auto output_link = args.as_string(cmd::citnames::FLAG_OUTPUT_LINK); + auto append = args.as_bool(cmd::citnames::FLAG_APPEND).unwrap_or(false); + auto with_link = args.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); - return rust::merge(input, output) - .map([&append](auto tuple) { - const auto&[input, output] = tuple; + return rust::merge(input, output_compile, output_link) + .map([&append, &with_link](auto tuple) { + const auto&[input, output_compile, output_link] = tuple; return cs::Arguments{ fs::path(input), - fs::path(output), + fs::path(output_compile), + fs::path(output_link), append, + with_link }; }) .and_then([](auto arguments) -> rust::Result { @@ -123,8 +126,11 @@ namespace { } return rust::Ok(cs::Arguments{ arguments.input, - arguments.output, - (arguments.append && is_exists(arguments.output)), + arguments.output_compile, + arguments.output_link, + (arguments.append && is_exists(arguments.output_compile) + && (!arguments.with_link || is_exists(arguments.output_link))), + arguments.with_link }); }); } @@ -143,6 +149,14 @@ namespace { return result; } + void customize_configuration(cs::Configuration& configuration, const flags::Arguments &args) { + auto with_link = args.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); + if (with_link) { + configuration.output.content.without_existence_check = true; + configuration.output.content.without_duplicate_filter = true; + } + } + rust::Result into_configuration(const flags::Arguments &args, const sys::env::Vars &environment) { auto config_arg = args.as_string(cmd::citnames::FLAG_CONFIG); @@ -170,63 +184,116 @@ namespace { update_compilers_to_recognize(config.compilation.compilers_to_recognize, env_compilers); return config; }) + .map([&args](auto config) { + customize_configuration(config, args); + return config; + }) .on_success([](const auto &config) { spdlog::debug("Configuration: {}", config); }); } - size_t transform(cs::semantic::Build &build, const db::EventsDatabaseReader::Ptr& events, std::list &output) { + size_t transform( + cs::semantic::Build &build, + const db::EventsDatabaseReader::Ptr& events, + std::list &output_compile, + std::list &output_link, + const bool with_link + ) { for (const auto &event : *events) { - const auto entries = build.recognize(event) - .map>([](const auto &semantic) -> std::list { - const auto candidate = dynamic_cast(semantic.get()); - return (candidate != nullptr) ? candidate->into_entries() : std::list(); - }) - .unwrap_or({}); - std::copy(entries.begin(), entries.end(), std::back_inserter(output)); + const auto get_entries = [](const auto &semantic) -> std::list { + const auto candidate = dynamic_cast(semantic.get()); + return (candidate != nullptr) ? candidate->into_entries() : std::list(); + }; + + const auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER) + .map>(get_entries).unwrap_or({}); + std::copy(entries_compile.begin(), entries_compile.end(), std::back_inserter(output_compile)); + + if (with_link) { + const auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER) + .map>(get_entries).unwrap_or({}); + std::copy(entries_link.begin(), entries_link.end(), std::back_inserter(output_link)); + } } - return output.size(); + return output_compile.size() + output_link.size(); + } + + rust::Result complete_entries_from_json( + cs::CompilationDatabase& output, + const fs::path& output_file, + std::list& entries, + size_t new_entries_counts, + bool append + ) { + // read back the current content and extend with the new elements. + if (append) { + return output.from_json(output_file, entries) + .template map([&new_entries_counts](auto old_entries_count) { + spdlog::debug("entries have read. [size: {}]", old_entries_count); + return new_entries_counts + old_entries_count; + }); + } + return rust::Result(rust::Ok(new_entries_counts)); + } + + rust::Result write_entries( + cs::CompilationDatabase& output, + const fs::path& output_file, + std::list& entries + ) { + // write the entries into the output file. + const fs::path temporary_output_file(output_file.string() + ".tmp"); + auto result = output.to_json(temporary_output_file, entries); + return not rename_file(temporary_output_file, output_file) + ? rust::Result(rust::Err(std::runtime_error(fmt::format("Failed to rename file: {}", output_file)))) + : result; } } namespace cs { rust::Result Command::execute() const { - cs::CompilationDatabase output(configuration_.output.format, configuration_.output.content); - std::list entries; + cs::CompilationDatabase output_compile(configuration_.output.format, configuration_.output.content); + cs::CompilationDatabase output_link(configuration_.output.format, configuration_.output.content); + std::list entries_compile; + std::list entries_link; - // get current compilations from the input. return db::EventsDatabaseReader::from(arguments_.input) - .map([this, &entries](const auto &commands) { - cs::semantic::Build build(configuration_.compilation); - return transform(build, commands, entries); - }) - .and_then([this, &output, &entries](auto new_entries_count) { - spdlog::debug("compilation entries created. [size: {}]", new_entries_count); - // read back the current content and extend with the new elements. - return (arguments_.append) - ? output.from_json(arguments_.output, entries) - .template map([&new_entries_count](auto old_entries_count) { - spdlog::debug("compilation entries have read. [size: {}]", old_entries_count); - return new_entries_count + old_entries_count; - }) - : rust::Result(rust::Ok(new_entries_count)); - }) - .and_then([this, &output, &entries](const size_t & size) { - // write the entries into the output file. - spdlog::debug("compilation entries to output. [size: {}]", size); - - const fs::path temporary_file(arguments_.output.string() + ".tmp"); - auto result = output.to_json(temporary_file, entries); - return rename_file(temporary_file, arguments_.output) - ? result - : rust::Err(std::runtime_error(fmt::format("Failed to rename file: {}", arguments_.output))); - }) - .map([](auto size) { - // just map to success exit code if it was successful. - spdlog::debug("compilation entries written. [size: {}]", size); - return EXIT_SUCCESS; - }); + .map([this, &entries_compile, &entries_link](const auto &commands) { + cs::semantic::Build build(configuration_.compilation); + return transform(build, commands, entries_compile, entries_link, arguments_.with_link); + }) + .and_then([this, &output_compile, &entries_compile](size_t new_entries_count) { + spdlog::debug("entries created. [size: {}]", new_entries_count); + return complete_entries_from_json(output_compile, arguments_.output_compile, + entries_compile, new_entries_count, arguments_.append); + }) + .and_then([this, &output_link, &entries_link](size_t new_entries_count) { + if (arguments_.with_link) { + return complete_entries_from_json(output_link, arguments_.output_link, + entries_link, new_entries_count, arguments_.append); + } + return rust::Result(rust::Ok(new_entries_count)); + }) + .and_then([this, &output_compile, &entries_compile](const auto entries_count_to_output) { + spdlog::debug("entries to output. [size: {}]", entries_count_to_output); + return write_entries(output_compile, arguments_.output_compile, entries_compile); + }) + .and_then([this, &output_link, &entries_link](const auto compile_entries_wrote) { + if (arguments_.with_link) { + const auto result_link = write_entries(output_link, arguments_.output_link, entries_link); + return (result_link.is_err()) + ? result_link + : rust::Ok(result_link.unwrap() + compile_entries_wrote); + } + return rust::Result(rust::Ok(compile_entries_wrote)); + }) + .map([](auto size) { + // just map to success exit code if it was successful. + spdlog::debug("entries written. [size: {}]", size); + return EXIT_SUCCESS; + }); } Command::Command(Arguments arguments, cs::Configuration configuration) noexcept diff --git a/source/citnames/source/Citnames.h b/source/citnames/source/Citnames.h index 6f28f376..53565658 100644 --- a/source/citnames/source/Citnames.h +++ b/source/citnames/source/Citnames.h @@ -36,8 +36,10 @@ namespace cs { struct Arguments { fs::path input; - fs::path output; + fs::path output_compile; + fs::path output_link; bool append; + bool with_link; }; struct Command : ps::Command { diff --git a/source/citnames/source/Configuration.h b/source/citnames/source/Configuration.h index d9c64a06..8934de32 100644 --- a/source/citnames/source/Configuration.h +++ b/source/citnames/source/Configuration.h @@ -58,6 +58,9 @@ namespace cs { std::string duplicate_filter_fields = DUPLICATE_FILE_OUTPUT; std::list paths_to_include = {}; std::list paths_to_exclude = {}; + + bool without_duplicate_filter = false; + bool without_existence_check = false; }; // Groups together the output related configurations. diff --git a/source/citnames/source/Output.cc b/source/citnames/source/Output.cc index ef87f8c1..5d028ec0 100644 --- a/source/citnames/source/Output.cc +++ b/source/citnames/source/Output.cc @@ -32,6 +32,28 @@ namespace { + void validate_files(const cs::Entry &entry) { + if (entry.file.empty() && (entry.files.empty())) { + throw std::runtime_error("Fields 'file' and 'files' have not values."); + } + if (std::any_of(entry.files.begin(), entry.files.end(), [](const auto& file) { return file.empty(); })) { + throw std::runtime_error("Field 'files' has empty paths."); + } + } + + void validate(const cs::Entry &entry) { + validate_files(entry); + if (entry.directory.empty()) { + throw std::runtime_error("Field 'directory' is empty string."); + } + if (entry.output.has_value() && entry.output.value().empty()) { + throw std::runtime_error("Field 'output' is empty string."); + } + if (entry.arguments.empty()) { + throw std::runtime_error("Field 'arguments' is empty list."); + } + } + struct Filter { virtual ~Filter() noexcept = default; virtual bool apply(const cs::Entry &) = 0; @@ -43,11 +65,21 @@ namespace { { } bool apply(const cs::Entry &entry) override { - const auto &file = entry.file; - return exists(file) && to_include(file) && !to_exclude(file); + validate_files(entry); + if (not entry.file.empty()) { + return check(entry.file); + } + if (not entry.files.empty()) { + return std::all_of(entry.files.begin(), entry.files.end(), [&](const auto &file){ return check(file); }); + } + return false; } private: + [[nodiscard]] inline bool check(const fs::path &file) const { + return (config.without_existence_check || exists(file)) && to_include(file) && !to_exclude(file); + } + [[nodiscard]] inline bool exists(const fs::path &file) const { const auto &to_check = config.include_only_existing_source; return (!to_check) || (to_check && does_exist(file)); @@ -104,12 +136,10 @@ namespace { std::unordered_set hashes; }; - struct FileDuplicateFilter : public DuplicateFilter { private: size_t hash(const cs::Entry &entry) const override { auto string_hasher = std::hash{}; - return string_hasher(entry.file); } }; @@ -120,11 +150,9 @@ namespace { auto string_hasher = std::hash{}; auto hash = string_hasher(entry.file); - if (entry.output) { hash = hash_combine(hash, string_hasher(*entry.output)); } - return hash; } }; @@ -135,15 +163,12 @@ namespace { auto string_hasher = std::hash{}; auto hash = string_hasher(entry.file); - if (entry.output) { hash = hash_combine(hash, string_hasher(*entry.output)); } - for (const auto& arg : entry.arguments) { hash = hash_combine(hash, string_hasher(arg)); } - return hash; } }; @@ -163,30 +188,16 @@ namespace { // If the parameter is invalid use the default filter return std::make_unique(); } - } namespace cs { - void validate(const Entry &entry) { - if (entry.file.empty()) { - throw std::runtime_error("Field 'file' is empty string."); - } - if (entry.directory.empty()) { - throw std::runtime_error("Field 'directory' is empty string."); - } - if (entry.output.has_value() && entry.output.value().empty()) { - throw std::runtime_error("Field 'output' is empty string."); - } - if (entry.arguments.empty()) { - throw std::runtime_error("Field 'arguments' is empty list."); - } - } - nlohmann::json to_json(const Entry &rhs, const Format &format) { nlohmann::json json; + validate_files(rhs); json["file"] = rhs.file; + json["files"] = rhs.files; json["directory"] = rhs.directory; if (!format.drop_output_field && rhs.output.has_value()) { json["output"] = rhs.output.value(); @@ -202,12 +213,19 @@ namespace cs { void from_json(const nlohmann::json &j, Entry &entry) { j.at("file").get_to(entry.file); + + std::list files; + j.at("files").get_to(files); + entry.files.swap(files); + j.at("directory").get_to(entry.directory); + if (j.contains("output")) { std::string output; j.at("output").get_to(output); entry.output.emplace(output); } + if (j.contains("arguments")) { std::list arguments; j.at("arguments").get_to(arguments); @@ -232,6 +250,7 @@ namespace cs { bool operator==(const Entry &lhs, const Entry &rhs) { return (lhs.file == rhs.file) + && (lhs.files == rhs.files) && (lhs.directory == rhs.directory) && (lhs.output == rhs.output) && (lhs.arguments == rhs.arguments); @@ -278,7 +297,8 @@ 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)) { + const auto filter = content_filter.apply(entry) && (content.without_duplicate_filter || duplicate_filter->apply(entry)); + if (filter) { auto json_entry = cs::to_json(entry, format); json.emplace_back(std::move(json_entry)); ++count; diff --git a/source/citnames/source/Output.h b/source/citnames/source/Output.h index d73076ea..10f0a07f 100644 --- a/source/citnames/source/Output.h +++ b/source/citnames/source/Output.h @@ -46,6 +46,7 @@ namespace cs { // really a database with keys. struct Entry { fs::path file; + std::list files; fs::path directory; std::optional output; std::list arguments; diff --git a/source/citnames/source/semantic/Build.cc b/source/citnames/source/semantic/Build.cc index 170e6b6d..aa105ea7 100644 --- a/source/citnames/source/semantic/Build.cc +++ b/source/citnames/source/semantic/Build.cc @@ -62,14 +62,14 @@ namespace cs::semantic { { } [[nodiscard]] - rust::Result Build::recognize(const rpc::Event &event) const { + rust::Result Build::recognize(const rpc::Event &event, const BuildTarget target) const { if (event.has_started()) { auto execution = domain::from(event.started().execution()); auto pid = event.started().pid(); spdlog::debug("[pid: {}] execution: {}", pid, execution); - auto result = tools_->recognize(execution); + auto result = tools_->recognize(execution, target); if (Tool::recognized_ok(result)) { spdlog::debug("[pid: {}] recognized.", pid); } else if (Tool::recognized_with_error(result)) { diff --git a/source/citnames/source/semantic/Build.h b/source/citnames/source/semantic/Build.h index 458d9428..e170cbf2 100644 --- a/source/citnames/source/semantic/Build.h +++ b/source/citnames/source/semantic/Build.h @@ -36,7 +36,7 @@ namespace cs::semantic { explicit Build(Compilation cfg) noexcept; [[nodiscard]] - rust::Result recognize(const rpc::Event &event) const; + rust::Result recognize(const rpc::Event &event, const BuildTarget target) const; NON_DEFAULT_CONSTRUCTABLE(Build) NON_COPYABLE_NOR_MOVABLE(Build) diff --git a/source/citnames/source/semantic/Parsers.cc b/source/citnames/source/semantic/Parsers.cc index 50425a85..229771b5 100644 --- a/source/citnames/source/semantic/Parsers.cc +++ b/source/citnames/source/semantic/Parsers.cc @@ -21,6 +21,8 @@ #include +#include + namespace { std::string_view take_extension(const std::string_view &file) { diff --git a/source/citnames/source/semantic/Semantic.cc b/source/citnames/source/semantic/Semantic.cc index e956ecf4..909514f4 100644 --- a/source/citnames/source/semantic/Semantic.cc +++ b/source/citnames/source/semantic/Semantic.cc @@ -21,6 +21,41 @@ #include +namespace { + fs::path abspath(const fs::path &path, const fs::path &working_dir) { + auto candidate = (path.is_absolute()) ? path : working_dir / path; + // Create canonical path without checking of file existence. + fs::path result; + for (const auto& part : candidate) { + if (part == ".") + continue; + if (part == "..") + result = result.parent_path(); + else + result = result / part; + } + return result; + } + + std::list abspath(const std::list &files, const fs::path &working_dir) { + std::list files_with_abspath; + for (const auto& file : files) { + files_with_abspath.push_back(abspath(file, working_dir)); + } + return files_with_abspath; + } + + std::list get_object_files(const std::list& files) + { + std::list object_files; + for (const auto& file : files) { + object_files.emplace_back(file.string() + ".o"); + } + + return object_files; + } +} + namespace fmt { template <> @@ -64,13 +99,15 @@ namespace cs::semantic { Compile::Compile(fs::path working_dir, fs::path compiler, std::list flags, - std::vector sources, - std::optional output) + std::list sources, + std::optional output, + bool with_linking) : working_dir(std::move(working_dir)) , compiler(std::move(compiler)) , flags(std::move(flags)) , sources(std::move(sources)) , output(std::move(output)) + , with_linking(with_linking) { } bool Compile::operator==(const Semantic &rhs) const { @@ -82,7 +119,8 @@ namespace cs::semantic { && (compiler == ptr->compiler) && (output == ptr->output) && (sources == ptr->sources) - && (flags == ptr->flags); + && (flags == ptr->flags) + && (with_linking == ptr->with_linking); } return false; } @@ -93,41 +131,98 @@ 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() : "") + << ", with_linking: " << with_linking << " }"; return os; } std::list Compile::into_entries() const { - const auto abspath = [this](const fs::path &path) -> fs::path { - auto candidate = (path.is_absolute()) ? path : working_dir / path; - // Create canonical path without checking of file existence. - fs::path result; - for (const auto& part : candidate) { - if (part == ".") - continue; - if (part == "..") - result = result.parent_path(); - else - result = result / part; - } - return result; - }; std::list results; for (const auto& source : sources) { + const fs::path real_output = (output && !with_linking) + ? output.value() + : fs::path(source.string() + ".o"); + cs::Entry result { - abspath(source), + abspath(source, working_dir), + std::list(), working_dir, - output ? std::optional(abspath(output.value())) : std::nullopt, + abspath(real_output, working_dir), { compiler.string() } }; + 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(real_output); } result.arguments.push_back(source); + results.emplace_back(std::move(result)); } return results; } -} \ No newline at end of file + + Link::Link(fs::path working_dir, + fs::path compiler, + std::list flags, + std::list object_files, + std::optional output, + bool with_compilation) + : working_dir(std::move(working_dir)) + , compiler(std::move(compiler)) + , flags(std::move(flags)) + , object_files(std::move(object_files)) + , output(std::move(output)) + , with_compilation(with_compilation) + { } + + bool Link::operator==(const Semantic &rhs) const { + if (this == &rhs) + return true; + + if (const auto *const ptr = dynamic_cast(&rhs); ptr != nullptr) { + return (working_dir == ptr->working_dir) + && (compiler == ptr->compiler) + && (output == ptr->output) + && (object_files == ptr->object_files) + && (flags == ptr->flags) + && (with_compilation == ptr->with_compilation); + } + return false; + } + + std::ostream &Link::operator<<(std::ostream &os) const { + os << "Link { working_dir: " << working_dir + << ", compiler: " << compiler + << ", flags: " << fmt::format("[{}]", fmt::join(flags.begin(), flags.end(), ", ")) + << ", files: " << fmt::format("[{}]", fmt::join(object_files.begin(), object_files.end(), ", ")) + << ", output: " << (output ? output.value().string() : "") + << ", with compilation: " << with_compilation + << " }"; + return os; + } + + std::list Link::into_entries() const { + const auto real_object_files = (with_compilation) + ? get_object_files(object_files) + : object_files; + + cs::Entry result { + fs::path(), + abspath(real_object_files, working_dir), + working_dir, + output ? std::optional(abspath(output.value(), working_dir)) : std::nullopt, + { compiler.string() } + }; + + 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()); + } + std::copy(real_object_files.begin(), real_object_files.end(), std::back_inserter(result.arguments)); + + return std::list{result}; + } +} diff --git a/source/citnames/source/semantic/Semantic.h b/source/citnames/source/semantic/Semantic.h index 00844971..73d4e28f 100644 --- a/source/citnames/source/semantic/Semantic.h +++ b/source/citnames/source/semantic/Semantic.h @@ -86,8 +86,9 @@ namespace cs::semantic { Compile(fs::path working_dir, fs::path compiler, std::list flags, - std::vector sources, - std::optional output); + std::list sources, + std::optional output, + bool with_linking); bool operator==(Semantic const&) const override; std::ostream& operator<<(std::ostream&) const override; @@ -98,7 +99,32 @@ namespace cs::semantic { fs::path working_dir; fs::path compiler; std::list flags; - std::vector sources; + std::list sources; std::optional output; + bool with_linking; + }; + + // Then, perhaps, it is better to change to inheritance from Semantic, + // because into_entries() returns only one Entry. + struct Link : public CompilerCall { + Link(fs::path working_dir, + fs::path compiler, + std::list flags, + std::list sources, + std::optional output, + bool with_compilation); + + bool operator==(Semantic const&) const override; + std::ostream& operator<<(std::ostream&) const override; + + [[nodiscard]] std::list into_entries() const override; + + public: + fs::path working_dir; + fs::path compiler; + std::list flags; + std::list object_files; + std::optional output; + bool with_compilation; }; } diff --git a/source/citnames/source/semantic/Tool.h b/source/citnames/source/semantic/Tool.h index fcc61c73..f6d2ed52 100644 --- a/source/citnames/source/semantic/Tool.h +++ b/source/citnames/source/semantic/Tool.h @@ -26,6 +26,11 @@ namespace cs::semantic { + enum class BuildTarget { + COMPILER, + LINKER + }; + // Represents a program, which can recognize the intent of the execution // and return the semantic of that. It can be a compiler or any other // program participating in a build process. @@ -34,7 +39,7 @@ namespace cs::semantic { // Returns the semantic of a command execution. [[nodiscard]] - virtual rust::Result recognize(const Execution &) const = 0; + virtual rust::Result recognize(const Execution &, const BuildTarget target) const = 0; // Helper methods to evaluate the recognize method result. static bool recognized_ok(const rust::Result &result) noexcept; diff --git a/source/citnames/source/semantic/ToolAny.cc b/source/citnames/source/semantic/ToolAny.cc index 7c742cec..fc49f73e 100644 --- a/source/citnames/source/semantic/ToolAny.cc +++ b/source/citnames/source/semantic/ToolAny.cc @@ -28,14 +28,14 @@ namespace cs::semantic { , to_exclude_(to_exclude) { } - rust::Result ToolAny::recognize(const domain::Execution &execution) const { + rust::Result ToolAny::recognize(const domain::Execution &execution, const BuildTarget target) const { // do different things if the execution is matching one of the nominated compilers. if (to_exclude_.end() != std::find(to_exclude_.begin(), to_exclude_.end(), execution.executable)) { return rust::Err(std::runtime_error("The tool is on the exclude list from configuration.")); } else { // check if any tool can recognize the execution. for (const auto &tool : tools_) { - auto result = tool->recognize(execution); + auto result = tool->recognize(execution, target); // return if it recognized in any way. if (Tool::recognized_ok(result) || Tool::recognized_with_error(result)) { return result; diff --git a/source/citnames/source/semantic/ToolAny.h b/source/citnames/source/semantic/ToolAny.h index d1c2fe2f..cc868473 100644 --- a/source/citnames/source/semantic/ToolAny.h +++ b/source/citnames/source/semantic/ToolAny.h @@ -31,7 +31,7 @@ namespace cs::semantic { ToolAny(ToolPtrs &&tools, std::list &&to_exclude) noexcept; [[nodiscard]] - rust::Result recognize(const Execution &execution) const override; + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; private: ToolPtrs tools_; diff --git a/source/citnames/source/semantic/ToolClang.cc b/source/citnames/source/semantic/ToolClang.cc index 193d8ba7..7821d437 100644 --- a/source/citnames/source/semantic/ToolClang.cc +++ b/source/citnames/source/semantic/ToolClang.cc @@ -184,9 +184,20 @@ namespace cs::semantic { : flag_definition(clang_flags(ToolGcc::FLAG_DEFINITION)) { } - rust::Result ToolClang::recognize(const Execution &execution) const { - if (is_compiler_call(execution.executable)) { - return ToolGcc::compilation(ToolClang::flag_definition, execution); + rust::Result ToolClang::recognize(const Execution &execution, const BuildTarget target) const { + switch (target) { + case BuildTarget::COMPILER: { + if (is_compiler_call(execution.executable)) { + return ToolGcc::compilation(ToolClang::flag_definition, execution); + } + break; + } + case BuildTarget::LINKER: { + if (is_linker_call(execution.executable)){ + return ToolGcc::linking(ToolClang::flag_definition, execution); + } + break; + } } return rust::Ok(SemanticPtr()); } diff --git a/source/citnames/source/semantic/ToolClang.h b/source/citnames/source/semantic/ToolClang.h index 8a362f63..933a49f5 100644 --- a/source/citnames/source/semantic/ToolClang.h +++ b/source/citnames/source/semantic/ToolClang.h @@ -28,7 +28,7 @@ namespace cs::semantic { ToolClang() noexcept; [[nodiscard]] - rust::Result recognize(const Execution &execution) const override; + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; protected: [[nodiscard]] diff --git a/source/citnames/source/semantic/ToolExtendingWrapper.cc b/source/citnames/source/semantic/ToolExtendingWrapper.cc index 293137c4..3d3b7e57 100644 --- a/source/citnames/source/semantic/ToolExtendingWrapper.cc +++ b/source/citnames/source/semantic/ToolExtendingWrapper.cc @@ -31,8 +31,8 @@ namespace cs::semantic { return compilers_to_recognize_.executable == program; } - rust::Result ToolExtendingWrapper::recognize(const Execution &execution) const { - return ToolGcc::recognize(execution) + rust::Result ToolExtendingWrapper::recognize(const Execution &execution, const BuildTarget target) const { + return ToolGcc::recognize(execution, target) .map([this](auto semantic) { if (auto* ptr = dynamic_cast(semantic.get()); ptr != nullptr) { // remove flags which were asked to be removed. diff --git a/source/citnames/source/semantic/ToolExtendingWrapper.h b/source/citnames/source/semantic/ToolExtendingWrapper.h index c764202b..5720bc0f 100644 --- a/source/citnames/source/semantic/ToolExtendingWrapper.h +++ b/source/citnames/source/semantic/ToolExtendingWrapper.h @@ -31,7 +31,7 @@ namespace cs::semantic { bool is_compiler_call(const fs::path& program) const override; [[nodiscard]] - rust::Result recognize(const Execution &execution) const override; + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; private: CompilerWrapper compilers_to_recognize_; diff --git a/source/citnames/source/semantic/ToolGcc.cc b/source/citnames/source/semantic/ToolGcc.cc index e5109fd4..76490e99 100644 --- a/source/citnames/source/semantic/ToolGcc.cc +++ b/source/citnames/source/semantic/ToolGcc.cc @@ -94,7 +94,14 @@ namespace { }); } - bool linking(const CompilerFlags& flags) + bool is_linker(const CompilerFlags& flags) + { + return std::any_of(flags.begin(), flags.end(), [](const auto& flag) { + return (flag.type == CompilerFlagType::LINKER_OBJECT_FILE); + }); + } + + bool has_linker(const CompilerFlags& flags) { return std::none_of(flags.begin(), flags.end(), [](auto flag) { return (flag.type == CompilerFlagType::KIND_OF_OUTPUT_NO_LINKING); @@ -103,12 +110,14 @@ namespace { std::tuple< Arguments, - std::vector, - std::optional + std::list, + std::optional, + std::list > split(const CompilerFlags &flags) { Arguments arguments; - std::vector sources; + std::list sources; std::optional output; + std::list object_files; for (const auto &flag : flags) { switch (flag.type) { @@ -122,6 +131,11 @@ namespace { output = std::make_optional(std::move(candidate)); break; } + case CompilerFlagType::LINKER_OBJECT_FILE: { + auto candidate = fs::path(flag.arguments.front()); + object_files.emplace_back(std::move(candidate)); + break; + } case CompilerFlagType::LINKER: case CompilerFlagType::PREPROCESSOR_MAKE: case CompilerFlagType::DIRECTORY_SEARCH_LINKER: @@ -132,7 +146,7 @@ namespace { } } } - return std::make_tuple(arguments, sources, output); + return std::make_tuple(arguments, sources, output, object_files); } } @@ -242,9 +256,20 @@ namespace cs::semantic { {"--", {MatchInstruction::PREFIX, CompilerFlagType::OTHER}}, }; - rust::Result ToolGcc::recognize(const Execution &execution) const { - if (is_compiler_call(execution.executable)) { - return compilation(execution); + rust::Result ToolGcc::recognize(const Execution &execution, const BuildTarget target) const { + switch (target) { + case BuildTarget::COMPILER: { + if (is_compiler_call(execution.executable)) { + return compilation(execution); + } + break; + } + case BuildTarget::LINKER: { + if (is_linker_call(execution.executable)) { + return linking(execution); + } + break; + } } return rust::Ok(SemanticPtr()); } @@ -265,6 +290,12 @@ 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(R"((ld|lld|gold|ar)*)"); + std::cmatch m; + return is_compiler_call(program) || std::regex_match(program.filename().c_str(), m, pattern); + } + rust::Result ToolGcc::compilation(const Execution &execution) const { return compilation(FLAG_DEFINITION, execution); } @@ -291,24 +322,92 @@ namespace cs::semantic { return rust::Ok(std::move(result)); } - auto[arguments, sources, output] = split(flags); - // Validate: must have source files. + auto[arguments, sources, output, object_files] = split(flags); if (sources.empty()) { return rust::Err(std::runtime_error("Source files not found for compilation.")); } - // TODO: introduce semantic type for linking - if (linking(flags)) { + if (not object_files.empty()) { + return rust::Err(std::runtime_error("Linker object files found for compilation.")); + } + + bool with_linking; + if (has_linker(flags)) { + with_linking = true; arguments.insert(arguments.begin(), "-c"); } + else { + with_linking = false; + } SemanticPtr result = std::make_shared( + execution.working_dir, + execution.executable, + std::move(arguments), + std::move(sources), + std::move(output), + with_linking + ); + return rust::Ok(std::move(result)); + }); + } + + rust::Result ToolGcc::linking(const Execution &execution) const { + return linking(FLAG_DEFINITION, execution); + } + + rust::Result ToolGcc::linking(const FlagsByName &flags, const Execution &execution) { + const auto &parser = + Repeat( + OneOf( + FlagParser(flags), + SourceMatcher(), + EverythingElseFlagMatcher() + ) + ); + + const Arguments &input_arguments = create_argument_list(execution); + return parse(parser, input_arguments) + .and_then([&execution](auto flags) -> rust::Result { + if (is_compiler_query(flags)) { + SemanticPtr result = std::make_shared(); + return rust::Ok(std::move(result)); + } + if (is_prerpocessor(flags)) { + SemanticPtr result = std::make_shared(); + return rust::Ok(std::move(result)); + } + + auto[arguments, sources, output, object_files] = split(flags); + + if (is_linker(flags)) { + if (not sources.empty()) { + return rust::Err(std::runtime_error("Source files found for linking.")); + } + + SemanticPtr result = std::make_shared( + execution.working_dir, + execution.executable, + std::move(arguments), + std::move(object_files), + std::move(output), + false + ); + return rust::Ok(std::move(result)); + } + + if (has_linker(flags)) { + SemanticPtr result = std::make_shared( execution.working_dir, execution.executable, std::move(arguments), std::move(sources), - std::move(output) - ); - return rust::Ok(std::move(result)); + std::move(output), + true + ); + return rust::Ok(std::move(result)); + } + + return rust::Ok(SemanticPtr()); }); } } diff --git a/source/citnames/source/semantic/ToolGcc.h b/source/citnames/source/semantic/ToolGcc.h index 80223fb3..d162efe1 100644 --- a/source/citnames/source/semantic/ToolGcc.h +++ b/source/citnames/source/semantic/ToolGcc.h @@ -27,18 +27,27 @@ namespace cs::semantic { struct ToolGcc : public Tool { [[nodiscard]] - rust::Result recognize(const Execution &execution) const override; + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; protected: [[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 compilation(const Execution &execution) const; [[nodiscard]] static rust::Result compilation(const FlagsByName &flags, const Execution &execution); + [[nodiscard]] + virtual rust::Result linking(const Execution &execution) const; + + [[nodiscard]] + static rust::Result linking(const FlagsByName &flags, const Execution &execution); + static const FlagsByName FLAG_DEFINITION; }; } diff --git a/source/citnames/source/semantic/ToolWrapper.cc b/source/citnames/source/semantic/ToolWrapper.cc index 78e70b85..92638cf2 100644 --- a/source/citnames/source/semantic/ToolWrapper.cc +++ b/source/citnames/source/semantic/ToolWrapper.cc @@ -40,16 +40,34 @@ namespace { namespace cs::semantic { - rust::Result ToolWrapper::recognize(const Execution &execution) const { - if (is_ccache_call(execution.executable)) { - return is_ccache_query(execution.arguments) + rust::Result ToolWrapper::recognize(const Execution &execution, const BuildTarget target) const { + switch (target) { + case BuildTarget::COMPILER: { + if (is_ccache_call(execution.executable)) { + return is_ccache_query(execution.arguments) ? rust::Ok(std::make_shared()) : compilation(remove_wrapper(execution)); - } - if (is_distcc_call(execution.executable)) { - return is_distcc_query(execution.arguments) + } + if (is_distcc_call(execution.executable)) { + return is_distcc_query(execution.arguments) ? rust::Ok(std::make_shared()) : compilation(remove_wrapper(execution)); + } + break; + } + case BuildTarget::LINKER: { + if (is_ccache_call(execution.executable)) { + return is_ccache_query(execution.arguments) + ? rust::Ok(std::make_shared()) + : linking(remove_wrapper(execution)); + } + if (is_distcc_call(execution.executable)) { + return is_distcc_query(execution.arguments) + ? rust::Ok(std::make_shared()) + : linking(remove_wrapper(execution)); + } + break; + } } return rust::Ok(SemanticPtr()); } diff --git a/source/citnames/source/semantic/ToolWrapper.h b/source/citnames/source/semantic/ToolWrapper.h index 2ea006cf..920150ff 100644 --- a/source/citnames/source/semantic/ToolWrapper.h +++ b/source/citnames/source/semantic/ToolWrapper.h @@ -32,7 +32,7 @@ namespace cs::semantic { struct ToolWrapper : public ToolGcc { [[nodiscard]] - rust::Result recognize(const Execution &execution) const override; + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; // visible for testing public: diff --git a/source/citnames/test/OutputTest.cc b/source/citnames/test/OutputTest.cc index 3e5f1dd5..52a2015c 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 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" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, + { { "entries.c" }, std::list(), "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" } }, }; value_serialized_and_read_back(expected, expected, AS_ARGUMENTS); @@ -77,14 +77,14 @@ namespace { TEST(compilation_database, entries_without_output_read_back) { std::list 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" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, + { { "entries.c" }, std::list(), "/path/to", { "entries.o" }, { "cc", "-c", "-o", "entries.o", "entries.c" } }, }; std::list 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" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, + { { "entries.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "-o", "entries.o", "entries.c" } }, }; value_serialized_and_read_back(input, expected, AS_ARGUMENTS_NO_OUTPUT); @@ -94,14 +94,14 @@ namespace { TEST(compilation_database, merged_entries_read_back) { std::list 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" } }, + { { "entry_one.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", std::nullopt, { "cc1", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc1", "-c", "entry_two.c" } }, }; std::list 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" } }, + { { "entry_one.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", std::nullopt, { "cc", "-c", "entry_two.c" } }, }; value_serialized_and_read_back(input, expected, AS_ARGUMENTS); @@ -113,14 +113,14 @@ namespace { TEST(compilation_database, duplicate_entries_file_read_back) { std::list input = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_one.c", "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, - { "entry_two.c", "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, }; std::list expected = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, }; cs::Content content; @@ -131,18 +131,18 @@ namespace { TEST(compilation_database, duplicate_entries_file_output_read_back) { std::list input = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_one.c", "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, - { "entry_two.c", "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, - { "entry_one.c", "/path/to/changed", { "entry_one.o" }, { "cc1", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to/changed", { "entry_two.o" }, { "cc1", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to/changed", { "entry_one.o" }, { "cc1", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to/changed", { "entry_two.o" }, { "cc1", "-c", "entry_two.c" } }, }; std::list expected = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_one.c", "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, - { "entry_two.c", "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_one.c" }, std::list(), "/path/to/changed", { "entry_one2.o" }, { "cc1", "-c", "-o", "entry_one2.o", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to/changed", { "entry_two2.o" }, { "cc1", "-c", "-o", "entry_two2.o", "entry_two.c" } }, }; cs::Content content; @@ -153,31 +153,30 @@ namespace { TEST(compilation_database, duplicate_entries_all_read_back) { std::list input = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_three.c", "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, + { { "entry_one.c"}, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_three.c" }, std::list(), "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, // Filename changed - { "entry_one.changed.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_one.changed.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, // Output changed - { "entry_two.c", "/path/to", { "entry_two_changed.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two_changed.o" }, { "cc", "-c", "entry_two.c" } }, // Flags changed - { "entry_three.c", "/path/to", { "entry_three.o" }, { "cc", "-DCHANGED", "-c", "entry_three.c" } }, + { { "entry_three.c" }, std::list(), "/path/to", { "entry_three.o" }, { "cc", "-DCHANGED", "-c", "entry_three.c" } }, - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_three.c", "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_three.c" }, std::list(), "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, }; std::list expected = { - { "entry_one.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_three.c", "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, - { "entry_one.changed.c", "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, - { "entry_two.c", "/path/to", { "entry_two_changed.o" }, { "cc", "-c", "entry_two.c" } }, - { "entry_three.c", "/path/to", { "entry_three.o" }, { "cc", "-DCHANGED", "-c", "entry_three.c" } }, - + { { "entry_one.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_three.c" }, std::list(), "/path/to", { "entry_three.o" }, { "cc", "-c", "entry_three.c" } }, + { { "entry_one.changed.c" }, std::list(), "/path/to", { "entry_one.o" }, { "cc", "-c", "entry_one.c" } }, + { { "entry_two.c" }, std::list(), "/path/to", { "entry_two_changed.o" }, { "cc", "-c", "entry_two.c" } }, + { { "entry_three.c" }, std::list(), "/path/to", { "entry_three.o" }, { "cc", "-DCHANGED", "-c", "entry_three.c" } }, }; cs::Content content; diff --git a/source/citnames/test/ToolClangTest.cc b/source/citnames/test/ToolClangTest.cc index f79cb2b4..b286e174 100644 --- a/source/citnames/test/ToolClangTest.cc +++ b/source/citnames/test/ToolClangTest.cc @@ -55,12 +55,13 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -77,12 +78,13 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("exe")} + {fs::path("exe")}, + true ); ToolClang sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -98,7 +100,7 @@ namespace { ToolClang sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -125,12 +127,13 @@ 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({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -159,12 +162,13 @@ 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({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -191,12 +195,13 @@ 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({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -223,12 +228,13 @@ 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({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } @@ -255,12 +261,13 @@ namespace { input.executable, {"-c", "-Z", "arg1", "-aargs", "--analyze"}, {fs::path("source.c")}, - {fs::path("source.o")} + {fs::path("source.o")}, + false ); ToolClang sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_EQ(expected, *(result.unwrap().get())); } diff --git a/source/citnames/test/ToolGccTest.cc b/source/citnames/test/ToolGccTest.cc index 1f74ea8d..e25efd1a 100644 --- a/source/citnames/test/ToolGccTest.cc +++ b/source/citnames/test/ToolGccTest.cc @@ -53,7 +53,7 @@ namespace { ToolGcc sut; - EXPECT_TRUE(Tool::not_recognized(sut.recognize(input))); + EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::COMPILER))); } TEST(ToolGcc, simple) { @@ -69,12 +69,14 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("source.o")}) + {fs::path("source.o")}, + false + ) ); ToolGcc sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } @@ -92,13 +94,14 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, - {fs::path("exe")} + {fs::path("exe")}, + true ) ); ToolGcc sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } @@ -114,7 +117,7 @@ namespace { ToolGcc sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(result.is_ok()); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } @@ -139,13 +142,14 @@ namespace { "-I", "/usr/include/path3", }, {fs::path("source.c")}, - std::nullopt + std::nullopt, + false ) ); ToolGcc sut({}); - auto result = sut.recognize(input); + auto result = sut.recognize(input, BuildTarget::COMPILER); EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } diff --git a/source/config.h.in b/source/config.h.in index dbc5a5c2..158e4cd4 100644 --- a/source/config.h.in +++ b/source/config.h.in @@ -86,12 +86,15 @@ namespace cmd { namespace citnames { constexpr char FLAG_INPUT[] = "--input"; - constexpr char FLAG_OUTPUT[] = "--output"; + constexpr char FLAG_OUTPUT_COMPILE[] = "--output-compile"; + constexpr char FLAG_WITH_LINK[] = "--with-link"; + constexpr char FLAG_OUTPUT_LINK[] = "--output-link"; constexpr char FLAG_APPEND[] = "--append"; constexpr char FLAG_RUN_CHECKS[] = "--run-checks"; constexpr char FLAG_CONFIG[] = "--config"; - constexpr char DEFAULT_OUTPUT[] = "compile_commands.json"; + constexpr char DEFAULT_OUTPUT_COMPILE[] = "compile_commands.json"; + constexpr char DEFAULT_OUTPUT_LINK[] = "link_commands.json"; } namespace intercept { diff --git a/test/cases/citnames/exit_code/exit_code_for_success.sh b/test/cases/citnames/exit_code/exit_code_for_success.sh index 47710677..937efd68 100644 --- a/test/cases/citnames/exit_code/exit_code_for_success.sh +++ b/test/cases/citnames/exit_code/exit_code_for_success.sh @@ -2,7 +2,7 @@ # UNSUPPORTED: true # RUN: cd %T; %{shell} %s %t.commands.json -# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json # RUN: assert_compilation %t.compilations.json count -eq 0 cat > $1 << EOF diff --git a/test/cases/citnames/output/clang_plugin.sh b/test/cases/citnames/output/clang_plugin.sh index b1f36cf0..db9c7602 100644 --- a/test/cases/citnames/output/clang_plugin.sh +++ b/test/cases/citnames/output/clang_plugin.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/clang -c -Xclang -load -Xclang /path/to/LLVMHello.so -o broken_build.o broken_build.c diff --git a/test/cases/citnames/output/convert_format.sh b/test/cases/citnames/output/convert_format.sh index eb9df147..1d7e82c8 100644 --- a/test/cases/citnames/output/convert_format.sh +++ b/test/cases/citnames/output/convert_format.sh @@ -3,7 +3,7 @@ # RUN: cd %T; %{shell} %s %t # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/gcc -c -o broken_build.o broken_build.c -# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json --append +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json --append # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/gcc -c -o broken_build.o broken_build.c @@ -43,6 +43,7 @@ cat > "$1.compilations.json" << EOF ], "directory": "/home/user", "file": "/home/user/broken_build.c", + "files": [], "output": "/home/user/broken_build.o" } ] diff --git a/test/cases/citnames/output/relative_paths_converted.sh b/test/cases/citnames/output/relative_paths_converted.sh index 80dcb099..3a4427cf 100644 --- a/test/cases/citnames/output/relative_paths_converted.sh +++ b/test/cases/citnames/output/relative_paths_converted.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user/build -arguments /usr/bin/wrapper -c -o broken_build.o ../broken_build.c diff --git a/test/cases/citnames/output/wrapper_flags_extended.sh b/test/cases/citnames/output/wrapper_flags_extended.sh index ab8b0086..6db6804a 100644 --- a/test/cases/citnames/output/wrapper_flags_extended.sh +++ b/test/cases/citnames/output/wrapper_flags_extended.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/wrapper -c -Dwrapper -o broken_build.o broken_build.c diff --git a/test/cases/compilation/exit_code/exit_code_for_fail.sh b/test/cases/compilation/exit_code/exit_code_for_fail.sh index 4ae7ceb7..c86be67b 100644 --- a/test/cases/compilation/exit_code/exit_code_for_fail.sh +++ b/test/cases/compilation/exit_code/exit_code_for_fail.sh @@ -1,4 +1,4 @@ #!/usr/bin/env sh # XFAIL: * -# RUN: %{bear} --verbose --output %t.json -- %{false} +# RUN: %{bear} --verbose --output-compile %t.json -- %{false} diff --git a/test/cases/compilation/exit_code/exit_code_for_success.sh b/test/cases/compilation/exit_code/exit_code_for_success.sh index 049fd9f7..9f686f94 100644 --- a/test/cases/compilation/exit_code/exit_code_for_success.sh +++ b/test/cases/compilation/exit_code/exit_code_for_success.sh @@ -1,3 +1,3 @@ #!/usr/bin/env sh -# RUN: %{bear} --verbose --output %t.json -- %{true} +# RUN: %{bear} --verbose --output-compile %t.json -- %{true} diff --git a/test/cases/compilation/output/assembly_sources.mk b/test/cases/compilation/output/assembly_sources.mk index 857eef52..8bf6e428 100644 --- a/test/cases/compilation/output/assembly_sources.mk +++ b/test/cases/compilation/output/assembly_sources.mk @@ -2,7 +2,7 @@ # REQUIRES: make # RUN: %{make} -C %T -f %s clean -# RUN: %{bear} --verbose --output %t.json -- %{make} -C %T -f %s +# RUN: %{bear} --verbose --output-compile %t.json -- %{make} -C %T -f %s # RUN: assert_compilation %t.json count -eq 2 # 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/broken_build.sh b/test/cases/compilation/output/broken_build.sh index d871d77f..5ca555e2 100644 --- a/test/cases/compilation/output/broken_build.sh +++ b/test/cases/compilation/output/broken_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -ge 1 # RUN: assert_compilation %t.json contains -file %T/broken_build.c -directory %T -arguments %{c_compiler} -c -o broken_build.o broken_build.c diff --git a/test/cases/compilation/output/bug439.mk b/test/cases/compilation/output/bug439.mk index 49662893..c367b08c 100644 --- a/test/cases/compilation/output/bug439.mk +++ b/test/cases/compilation/output/bug439.mk @@ -3,7 +3,7 @@ # REQUIRES: make, shell # 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: %{shell} -c "PATH=%T:$PATH %{bear} --verbose --output-compile %t.json -- %{make} -C %T -f %s" # RUN: assert_compilation %t.json count -eq 2 # 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_cuda.sh b/test/cases/compilation/output/compile_cuda.sh index 41b8b374..7390f977 100644 --- a/test/cases/compilation/output/compile_cuda.sh +++ b/test/cases/compilation/output/compile_cuda.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell, cuda -# RUN: cd %T; env CC=%{cuda} %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; env CC=%{cuda} %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/successful_build_1.cu -directory %T # RUN: assert_compilation %t.json contains -file %T/successful_build_2.cu -directory %T diff --git a/test/cases/compilation/output/compile_fortran.sh b/test/cases/compilation/output/compile_fortran.sh index 15dc6c2a..7b4411ae 100644 --- a/test/cases/compilation/output/compile_fortran.sh +++ b/test/cases/compilation/output/compile_fortran.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell, fortran -# RUN: cd %T; env FC=%{fortran} %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; env FC=%{fortran} %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/compile_fortran.f95 -directory %T -arguments %{fortran} -c -o compile_fortran.o compile_fortran.f95 diff --git a/test/cases/compilation/output/config/filter_compilers.sh b/test/cases/compilation/output/config/filter_compilers.sh index 77f12f3c..31a55e34 100644 --- a/test/cases/compilation/output/config/filter_compilers.sh +++ b/test/cases/compilation/output/config/filter_compilers.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output-compile %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 diff --git a/test/cases/compilation/output/config/filter_flags.sh b/test/cases/compilation/output/config/filter_flags.sh index 015abc0e..46151f12 100644 --- a/test/cases/compilation/output/config/filter_flags.sh +++ b/test/cases/compilation/output/config/filter_flags.sh @@ -2,12 +2,12 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output-compile %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 %t/wrapper -c -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %t/wrapper -c -Werror -I. %t/source_2.c -# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output %t.json --config %t/config.json --force-wrapper -- %{shell} %t/build.sh +# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output-compile %t.json --config %t/config.json --force-wrapper -- %{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 %t/wrapper -c -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %t/wrapper -c -Werror -I. %t/source_2.c diff --git a/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh b/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh index f71f8eda..6138135e 100644 --- a/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh +++ b/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh @@ -2,12 +2,12 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output-compile %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 -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -Werror -I. %t/source_2.c -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json --force-wrapper -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json --force-wrapper -- %{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 -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -Werror -I. %t/source_2.c diff --git a/test/cases/compilation/output/config/filter_sources.sh b/test/cases/compilation/output/config/filter_sources.sh index 2828d2e5..fff1ae08 100644 --- a/test/cases/compilation/output/config/filter_sources.sh +++ b/test/cases/compilation/output/config/filter_sources.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output-compile %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 diff --git a/test/cases/compilation/output/config/filter_sources_relative.sh b/test/cases/compilation/output/config/filter_sources_relative.sh index db942d0a..bef648d4 100644 --- a/test/cases/compilation/output/config/filter_sources_relative.sh +++ b/test/cases/compilation/output/config/filter_sources_relative.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output-compile %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 diff --git a/test/cases/compilation/output/define_with_escaped_quote.sh b/test/cases/compilation/output/define_with_escaped_quote.sh index cbdb6ed3..89cad511 100644 --- a/test/cases/compilation/output/define_with_escaped_quote.sh +++ b/test/cases/compilation/output/define_with_escaped_quote.sh @@ -1,9 +1,9 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -ge 1 -# RUN: assert_compilation %t.json contains -file %T/define_with_escaped_quote.c -directory %T -arguments %{c_compiler} -c '-DMESSAGE="Hello World\n"' -o define_with_escaped_quote define_with_escaped_quote.c +# RUN: assert_compilation %t.json contains -file %T/define_with_escaped_quote.c -directory %T -arguments %{c_compiler} -c '-DMESSAGE="Hello World\n"' -o define_with_escaped_quote.c.o define_with_escaped_quote.c cat > define_with_escaped_quote.c < diff --git a/test/cases/compilation/output/define_with_quote.sh b/test/cases/compilation/output/define_with_quote.sh index f96db242..a481ef7f 100644 --- a/test/cases/compilation/output/define_with_quote.sh +++ b/test/cases/compilation/output/define_with_quote.sh @@ -1,9 +1,9 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -ge 1 -# RUN: assert_compilation %t.json contains -file %T/define_with_quote.c -directory %T -arguments %{cxx_compiler} -c -DEXPORT="extern \"C\"" -o define_with_quote define_with_quote.c +# RUN: assert_compilation %t.json contains -file %T/define_with_quote.c -directory %T -arguments %{cxx_compiler} -c -DEXPORT="extern \"C\"" -o define_with_quote.c.o define_with_quote.c cat > define_with_quote.c < diff --git a/test/cases/compilation/output/duplicate_entries.sh b/test/cases/compilation/output/duplicate_entries.sh index 50458da8..e108ebaa 100644 --- a/test/cases/compilation/output/duplicate_entries.sh +++ b/test/cases/compilation/output/duplicate_entries.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %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 diff --git a/test/cases/compilation/output/empty_argument.sh b/test/cases/compilation/output/empty_argument.sh index 6b8841d4..cb63b987 100644 --- a/test/cases/compilation/output/empty_argument.sh +++ b/test/cases/compilation/output/empty_argument.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 0 touch empty_argument_1.c empty_argument_2.c diff --git a/test/cases/compilation/output/empty_env.sh b/test/cases/compilation/output/empty_env.sh index 415f4078..dd1f37dc 100644 --- a/test/cases/compilation/output/empty_env.sh +++ b/test/cases/compilation/output/empty_env.sh @@ -2,7 +2,7 @@ # REQUIRES: preload, shell # RUN: %{shell} %s %t -# RUN: cd %T; /usr/bin/env - %{bear} --verbose --output %t.json -- %{shell} %t/build.sh +# RUN: cd %T; /usr/bin/env - %{bear} --verbose --output-compile %t.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 -o %t/source_1.o %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -o %t/source_2.o %t/source_2.c diff --git a/test/cases/compilation/output/existing_files_only.sh b/test/cases/compilation/output/existing_files_only.sh index 9129a78d..b4bd0a00 100644 --- a/test/cases/compilation/output/existing_files_only.sh +++ b/test/cases/compilation/output/existing_files_only.sh @@ -2,7 +2,7 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -build +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s -build # RUN: assert_compilation %t.json count -ge 2 # RUN: assert_compilation %t.json contains -file %T/exists/src/source_1.c -directory %T -arguments %{c_compiler} -c -o exists/src/source_1.o exists/src/source_1.c # RUN: assert_compilation %t.json contains -file %T/exists/src/source_2.c -directory %T -arguments %{c_compiler} -c -o exists/src/source_2.o exists/src/source_2.c diff --git a/test/cases/compilation/output/flag/append.sh b/test/cases/compilation/output/flag/append.sh index 1be8fff1..95baba0f 100644 --- a/test/cases/compilation/output/flag/append.sh +++ b/test/cases/compilation/output/flag/append.sh @@ -2,20 +2,21 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -build +# RUN: cd %T; %{bear} --verbose --output-compile %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: cd %T; %{bear} --verbose --output-compile %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 +# don't work after disable check for file existence +# cd %T; %{bear} --verbose --output-compile %t.json --append -- %{shell} %s -clean +# assert_compilation %t.json count -eq 0 build() { diff --git a/test/cases/compilation/output/flag/field_output.sh b/test/cases/compilation/output/flag/field_output.sh index 1bab2133..1192b349 100644 --- a/test/cases/compilation/output/flag/field_output.sh +++ b/test/cases/compilation/output/flag/field_output.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/field_output_1.c -output %T/field_output_1.o -directory %T -arguments %{c_compiler} -c -o field_output_1.o field_output_1.c # RUN: assert_compilation %t.json contains -file %T/field_output_2.c -output %T/field_output_2.o -directory %T -arguments %{c_compiler} -c -o field_output_2.o field_output_2.c diff --git a/test/cases/compilation/output/flag/use_cc.sh b/test/cases/compilation/output/flag/use_cc.sh index 5c9575a1..2160d067 100644 --- a/test/cases/compilation/output/flag/use_cc.sh +++ b/test/cases/compilation/output/flag/use_cc.sh @@ -2,22 +2,22 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --force-preload --output %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-preload --output-compile %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cc_1.c -directory %T -arguments %{c_compiler} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.known.json contains -file %T/use_cc_2.c -directory %T -arguments %{c_compiler} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-preload --output %t.all.json -- %{shell} %s +# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-preload --output-compile %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cc_1.c -directory %T -arguments %{true} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.all.json contains -file %T/use_cc_2.c -directory %T -arguments %{true} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; %{bear} --verbose --force-wrapper --output %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-wrapper --output-compile %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cc_1.c -directory %T -arguments %{c_compiler} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.known.json contains -file %T/use_cc_2.c -directory %T -arguments %{c_compiler} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-wrapper --output %t.all.json -- %{shell} %s +# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-wrapper --output-compile %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cc_1.c -directory %T -arguments %{true} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.all.json contains -file %T/use_cc_2.c -directory %T -arguments %{true} -c -o use_cc_2.o use_cc_2.c diff --git a/test/cases/compilation/output/flag/use_cxx.sh b/test/cases/compilation/output/flag/use_cxx.sh index 0bd1b8d9..488297ea 100644 --- a/test/cases/compilation/output/flag/use_cxx.sh +++ b/test/cases/compilation/output/flag/use_cxx.sh @@ -2,22 +2,22 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --force-preload --output %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-preload --output-compile %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-preload --output %t.all.json -- %{shell} %s +# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-preload --output-compile %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{true} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{true} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; %{bear} --verbose --force-wrapper --output %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-wrapper --output-compile %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-wrapper --output %t.all.json -- %{shell} %s +# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-wrapper --output-compile %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{true} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{true} -c -o use_cxx_2.o use_cxx_2.cc diff --git a/test/cases/compilation/output/flags_filtered_link.sh b/test/cases/compilation/output/flags_filtered_link.sh index a322f94f..9b0739fd 100644 --- a/test/cases/compilation/output/flags_filtered_link.sh +++ b/test/cases/compilation/output/flags_filtered_link.sh @@ -1,12 +1,12 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %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 +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_3.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_link_3.c.o 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.c.o flags_filtered_link_4.c # set up platform specific linker options PREFIX="foobar"; diff --git a/test/cases/compilation/output/flags_filtered_preproc.sh b/test/cases/compilation/output/flags_filtered_preproc.sh index fb4e29fc..2eb0407f 100644 --- a/test/cases/compilation/output/flags_filtered_preproc.sh +++ b/test/cases/compilation/output/flags_filtered_preproc.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_1.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_preproc_1.o flags_filtered_preproc_1.c # RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_2.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_preproc_2.o flags_filtered_preproc_2.c diff --git a/test/cases/compilation/output/multiple_source_build.sh b/test/cases/compilation/output/multiple_source_build.sh index 5a7f6e04..c999941c 100644 --- a/test/cases/compilation/output/multiple_source_build.sh +++ b/test/cases/compilation/output/multiple_source_build.sh @@ -1,11 +1,11 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 3 -# 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 +# RUN: assert_compilation %t.json contains -file %T/multiple_source_build_1.c -directory %T -arguments %{c_compiler} -c -o multiple_source_build_1.c.o 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_2.c.o 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_3.c.o multiple_source_build_3.c echo "int foo() { return 1; }" > multiple_source_build_1.c echo "int bar() { return 1; }" > multiple_source_build_2.c diff --git a/test/cases/compilation/output/parallel_build.sh b/test/cases/compilation/output/parallel_build.sh index a501822f..ed9f2f36 100644 --- a/test/cases/compilation/output/parallel_build.sh +++ b/test/cases/compilation/output/parallel_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 4 # RUN: assert_compilation %t.json contains -file %T/parallel_build_1.c -directory %T -arguments %{c_compiler} -c -o parallel_build_1.o parallel_build_1.c # RUN: assert_compilation %t.json contains -file %T/parallel_build_2.c -directory %T -arguments %{c_compiler} -c -o parallel_build_2.o parallel_build_2.c diff --git a/test/cases/compilation/output/successful_build.sh b/test/cases/compilation/output/successful_build.sh index 391b3e41..abd5fc83 100644 --- a/test/cases/compilation/output/successful_build.sh +++ b/test/cases/compilation/output/successful_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 4 # RUN: assert_compilation %t.json contains -file %T/successful_build_1.c -directory %T -arguments %{c_compiler} -c -o successful_build_1.o successful_build_1.c # RUN: assert_compilation %t.json contains -file %T/successful_build_2.c -directory %T -arguments %{c_compiler} -c -o successful_build_2.o successful_build_2.c diff --git a/test/cases/compilation/output/wrapper.sh b/test/cases/compilation/output/wrapper.sh index 9f2454ed..78ba76dc 100644 --- a/test/cases/compilation/output/wrapper.sh +++ b/test/cases/compilation/output/wrapper.sh @@ -1,12 +1,12 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/wrapper_1.c -directory %T -arguments %{c_compiler} -c -o wrapper_1.o wrapper_1.c # RUN: assert_compilation %t.json contains -file %T/wrapper_2.c -directory %T -arguments %{c_compiler} -c -o wrapper_2.o wrapper_2.c -# RUN: cd %T; %{bear} --verbose --output %t.json --force-wrapper -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output-compile %t.json --force-wrapper -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/wrapper_1.c -directory %T -arguments %{c_compiler} -c -o wrapper_1.o wrapper_1.c # RUN: assert_compilation %t.json contains -file %T/wrapper_2.c -directory %T -arguments %{c_compiler} -c -o wrapper_2.o wrapper_2.c diff --git a/test/cases/intercept/preload/signal_outside_build.sh b/test/cases/intercept/preload/signal_outside_build.sh index 7c6dbf3c..81d948d5 100644 --- a/test/cases/intercept/preload/signal_outside_build.sh +++ b/test/cases/intercept/preload/signal_outside_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: preload, shell, dynamic-shell -# RUN: %{shell} -c "%{intercept} --verbose --output %t.json -- %{shell} %s --sleep %{sleep} --true %{true} & %{sleep} 1; kill -15 %1; wait;" +# RUN: %{shell} -c "%{intercept} --output %t.json -- %{shell} %s --sleep %{sleep} --true %{true} & %{sleep} 1; kill -15 %1; wait;" # RUN: assert_intercepted %t.json count -eq 3 # RUN: assert_intercepted %t.json contains -program %{true} # RUN: assert_intercepted %t.json contains -program %{sleep} -arguments %{sleep} 5 From 559b2da4d675a4c1e2856f6a4d410f70b1cc0fa0 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+MashaK5@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:52:04 +0300 Subject: [PATCH 2/7] Save all arguments (#3) * Fix arguments formation for Entry, fix unit tests * Change saving arguments and fix tests * Add functional tests for linking --- source/bear/man/bear.1.md | 26 +- source/citnames/man/bear-citnames.1.md | 29 +- source/citnames/source/Citnames.cc | 40 ++- source/citnames/source/semantic/Parsers.cc | 47 +++- source/citnames/source/semantic/Parsers.h | 20 +- source/citnames/source/semantic/Semantic.cc | 46 ++- source/citnames/source/semantic/Semantic.h | 10 +- source/citnames/source/semantic/ToolClang.cc | 1 + source/citnames/source/semantic/ToolGcc.cc | 153 +++++----- source/citnames/test/ParserTest.cc | 52 +++- source/citnames/test/ToolClangTest.cc | 9 +- source/citnames/test/ToolGccTest.cc | 264 +++++++++++++++++- test/bin/assert_compilation | 15 +- .../output/define_with_escaped_quote.sh | 2 +- .../compilation/output/define_with_quote.sh | 2 +- test/cases/compilation/output/flag/append.sh | 5 +- .../compilation/output/flags_filtered_link.sh | 4 +- .../output/flags_filtered_preproc.sh | 4 +- .../compilation/output/linking/append.sh | 64 +++++ .../output/linking/compile_link_one_file.sh | 12 + .../output/linking/compile_link_some_files.sh | 14 + .../not_append_without_link_database.sh | 20 ++ .../output/linking/without_link_flag.sh | 11 + .../compilation/output/with_other_files.sh | 10 + 24 files changed, 702 insertions(+), 158 deletions(-) create mode 100644 test/cases/compilation/output/linking/append.sh create mode 100644 test/cases/compilation/output/linking/compile_link_one_file.sh create mode 100644 test/cases/compilation/output/linking/compile_link_some_files.sh create mode 100644 test/cases/compilation/output/linking/not_append_without_link_database.sh create mode 100644 test/cases/compilation/output/linking/without_link_flag.sh create mode 100644 test/cases/compilation/output/with_other_files.sh diff --git a/source/bear/man/bear.1.md b/source/bear/man/bear.1.md index f455d195..1d945f6a 100644 --- a/source/bear/man/bear.1.md +++ b/source/bear/man/bear.1.md @@ -4,7 +4,7 @@ # NAME -Bear - a tool to generate compilation database for Clang tooling. +Bear - a tool to generate compilation and linking databases for Clang tooling. # SYNOPSIS @@ -21,7 +21,7 @@ compilation with different programs. Bear executes the original build command and intercept the command executions issued by the build tool. From the log of command executions it tries to identify the compiler calls and creates the final -compilation database. +compilation and linking databases. # OPTIONS @@ -34,9 +34,17 @@ compilation database. \--verbose : Enable verbose logging. -\--output *file* -: Specify output file. (Default file name provided.) The output is - a JSON compilation database. +\--with-link +: Use if you want to generate a linking database. + +\--output-compile *file* +: Specify output compile file. (Default file name provided.) The output is + currently a JSON compilation database. + +\--output-link *file* +: Specify output link file. (Default file name provided.) The output is + currently a JSON linking database. + Used only if --with-link is used, ignored otherwise. \--append : Use previously generated output file and append the new entries to it. @@ -44,6 +52,8 @@ compilation database. compilation database up to date. File deletion and addition are both considered. But build process change (compiler flags change) might cause duplicate entries. + When used with --with-link, requires the existence of both database files. + Otherwise, overwrites existing data. \--config *file* : Specify a configuration file. The configuration file captures how @@ -75,14 +85,16 @@ version of Bear generates entries where: `file` : has absolute path. +`files` +: has absolute paths. + `output` : has absolute path. `arguments` : used instead of `command` to avoid shell escaping problems. (Configuration can force to emit the `command` field.) The compiler as the first argument - has absolute path. Some non compilation related flags are filtered out from - the final output. + has absolute path. Saves all flags. # CONFIG FILE diff --git a/source/citnames/man/bear-citnames.1.md b/source/citnames/man/bear-citnames.1.md index 2a5aeaa7..dceaaaf0 100644 --- a/source/citnames/man/bear-citnames.1.md +++ b/source/citnames/man/bear-citnames.1.md @@ -19,8 +19,8 @@ execution is just a thing to achieve your goal. This program takes the command which was executed, and try to find out what the intent was to run that command. It deduces the semantic of the command. -This is useful to generate a compilation database. Citnames get a -list of commands, and it creates a JSON compilation database. (This +This is useful to generate a compilation and linking databases. Citnames get a +list of commands, and it creates a JSON compilation and linking databases. (This is currently the only output of the tool.) # OPTIONS @@ -39,16 +39,26 @@ is currently the only output of the tool.) command execution list, with some extra information. The syntax is detailed in a separate section. -\--output *file* -: Specify output file. (Default file name provided.) The output is +\--with-link +: Use if you want to generate a linking database. + +\--output-compile *file* +: Specify output compile file. (Default file name provided.) The output is currently a JSON compilation database. +\--output-link *file* +: Specify output link file. (Default file name provided.) The output is + currently a JSON linking database. + Used only if --with-link is used, ignored otherwise. + \--append : Use previously generated output file and append the new entries to it. This way you can run continuously during work, and it keeps the compilation database up to date. File deletion and addition are both considered. But build process change (compiler flags change) might cause duplicate entries. + When used with --with-link, requires the existence of both database files. + Otherwise, overwrites existing data. \--run-checks : Allow the program to verify file location checks on the current machine @@ -79,11 +89,15 @@ of a build. Read more about the syntax of the file in the `bear-intercept(1)` man page. -# OUTPUT FILE +# OUTPUT COMPILE FILE -Currently, the only output format is the JSON compilation database. +Currently, the output format is the JSON compilation database. Read more about the syntax of that in the `bear(1)` man page. +# OUTPUT LINK FILE + +JSON linking database. + # CONFIG FILE The config file influences the command recognition (by the section "compilation") @@ -145,6 +159,9 @@ the command line argument overrides the config file values. The `--run-checks` flag overrides this config value. The `duplicate_filter_fields` select the method how duplicate entries are detected in the output. The possible values for this field are: `all`, `file` and `file_output`. + `without_duplicate_filter` is intended to disable the filtering of duplicate entries when generating a database. + `without_existence_check` is intended to disable existence check for sources/object files when generating a database. + In this version `without_duplicate_filter=true` and `without_existence_check=true`, only when used `--with-link`. `output.format` : The `command_as_array` controls which command field is emitted in the output. diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index 19d62667..8a289d3d 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -27,6 +27,7 @@ #include "libsys/Path.h" #include +#include #ifdef HAVE_FMT_STD_H #include @@ -193,14 +194,33 @@ namespace { }); } - size_t transform( + rust::Result transform( cs::semantic::Build &build, const db::EventsDatabaseReader::Ptr& events, std::list &output_compile, std::list &output_link, const bool with_link ) { - for (const auto &event : *events) { + std::set all_ppid; + std::set writed_command_pids; + + for (const rpc::Event &event : *events) { + const size_t pid = event.started().pid(); + const size_t ppid = event.started().ppid(); + if (pid == 0 && ppid == 0) { + continue; + } + + if (all_ppid.find(pid) != all_ppid.end()) { + return rust::Err(std::runtime_error("Processes in events database are not sorted!")); + } + all_ppid.insert(ppid); + + if (writed_command_pids.find(ppid) != writed_command_pids.end()) { + writed_command_pids.insert(pid); + continue; + } + const auto get_entries = [](const auto &semantic) -> std::list { const auto candidate = dynamic_cast(semantic.get()); return (candidate != nullptr) ? candidate->into_entries() : std::list(); @@ -208,15 +228,21 @@ namespace { const auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER) .map>(get_entries).unwrap_or({}); - std::copy(entries_compile.begin(), entries_compile.end(), std::back_inserter(output_compile)); + if (!entries_compile.empty()) { + writed_command_pids.insert(pid); + std::copy(entries_compile.begin(), entries_compile.end(), std::back_inserter(output_compile)); + } if (with_link) { const auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER) .map>(get_entries).unwrap_or({}); - std::copy(entries_link.begin(), entries_link.end(), std::back_inserter(output_link)); + if (!entries_link.empty()) { + writed_command_pids.insert(pid); + std::copy(entries_link.begin(), entries_link.end(), std::back_inserter(output_link)); + } } } - return output_compile.size() + output_link.size(); + return rust::Ok(output_compile.size() + output_link.size()); } rust::Result complete_entries_from_json( @@ -234,7 +260,7 @@ namespace { return new_entries_counts + old_entries_count; }); } - return rust::Result(rust::Ok(new_entries_counts)); + return rust::Ok(new_entries_counts); } rust::Result write_entries( @@ -260,7 +286,7 @@ namespace cs { std::list entries_link; return db::EventsDatabaseReader::from(arguments_.input) - .map([this, &entries_compile, &entries_link](const auto &commands) { + .and_then([this, &entries_compile, &entries_link](const auto &commands) { cs::semantic::Build build(configuration_.compilation); return transform(build, commands, entries_compile, entries_link, arguments_.with_link); }) diff --git a/source/citnames/source/semantic/Parsers.cc b/source/citnames/source/semantic/Parsers.cc index 229771b5..6ff73794 100644 --- a/source/citnames/source/semantic/Parsers.cc +++ b/source/citnames/source/semantic/Parsers.cc @@ -301,6 +301,51 @@ namespace cs::semantic { return rust::Err(input); } + rust::Result, ArgumentsView> ObjectFileMatcher::parse(const ArgumentsView &input) { + if (input.empty()) { + return rust::Err(input); + } + const auto &candidate = input.front(); + const auto &extension = take_extension(candidate); + if (".o" == extension) { + const auto &[arguments, remainder] = input.take(1); + if (arguments.empty()) { + return rust::Err(input); + } + auto flag = CompilerFlag { arguments, CompilerFlagType::OBJECT_FILE }; + return rust::Ok(std::make_pair(flag, remainder)); + } + return rust::Err(input); + } + + rust::Result, ArgumentsView> LibraryMatcher::parse(const ArgumentsView &input) { + static const std::set extensions = { + // unix + ".so", ".a", ".la", + // macos + ".dylib", + // windows + ".dll", ".DLL", ".ocx", ".OCX", ".lib", ".LIB", + // amigaOS + ".library" + }; + + if (input.empty()) { + return rust::Err(input); + } + const auto &candidate = input.front(); + const auto &extension = take_extension(candidate); + if (extensions.find(extension) != extensions.end() || candidate.find(".so.") != std::string::npos) { + const auto &[arguments, remainder] = input.take(1); + if (arguments.empty()) { + return rust::Err(input); + } + auto flag = CompilerFlag { arguments, CompilerFlagType::LIBRARY }; + return rust::Ok(std::make_pair(flag, remainder)); + } + return rust::Err(input); + } + rust::Result, ArgumentsView> EverythingElseFlagMatcher::parse(const ArgumentsView &input) { if (input.empty()) { return rust::Err(input); @@ -310,7 +355,7 @@ namespace cs::semantic { if (arguments.empty()) { return rust::Err(input); } - auto flag = CompilerFlag { arguments, CompilerFlagType::LINKER_OBJECT_FILE }; + auto flag = CompilerFlag { arguments, CompilerFlagType::UNKNOWN }; return rust::Ok(std::make_pair(flag, remainder)); } return rust::Err(input); diff --git a/source/citnames/source/semantic/Parsers.h b/source/citnames/source/semantic/Parsers.h index 62e1e92e..ae20352c 100644 --- a/source/citnames/source/semantic/Parsers.h +++ b/source/citnames/source/semantic/Parsers.h @@ -102,16 +102,20 @@ namespace cs::semantic { KIND_OF_OUTPUT, KIND_OF_OUTPUT_NO_LINKING, KIND_OF_OUTPUT_INFO, - KIND_OF_OUTPUT_OUTPUT, PREPROCESSOR, PREPROCESSOR_MAKE, LINKER, - LINKER_OBJECT_FILE, DIRECTORY_SEARCH, DIRECTORY_SEARCH_LINKER, - SOURCE, OTHER, STATIC_ANALYZER, + UNKNOWN, + + SOURCE, + OBJECT_FILE, + LIBRARY, + + KIND_OF_OUTPUT_OUTPUT, }; struct CompilerFlag { @@ -177,6 +181,16 @@ namespace cs::semantic { static rust::Result, ArgumentsView> parse(const ArgumentsView &input); }; + struct ObjectFileMatcher { + [[nodiscard]] + static rust::Result, ArgumentsView> parse(const ArgumentsView &input); + }; + + struct LibraryMatcher { + [[nodiscard]] + static rust::Result, ArgumentsView> parse(const ArgumentsView &input); + }; + // A parser combinator, which recognize a single compiler flag without any conditions. struct EverythingElseFlagMatcher { [[nodiscard]] diff --git a/source/citnames/source/semantic/Semantic.cc b/source/citnames/source/semantic/Semantic.cc index 909514f4..2f217c2a 100644 --- a/source/citnames/source/semantic/Semantic.cc +++ b/source/citnames/source/semantic/Semantic.cc @@ -44,16 +44,6 @@ namespace { } return files_with_abspath; } - - std::list get_object_files(const std::list& files) - { - std::list object_files; - for (const auto& file : files) { - object_files.emplace_back(file.string() + ".o"); - } - - return object_files; - } } namespace fmt { @@ -100,12 +90,14 @@ namespace cs::semantic { fs::path compiler, std::list flags, std::list sources, + std::list dependencies, std::optional output, bool with_linking) : working_dir(std::move(working_dir)) , compiler(std::move(compiler)) , flags(std::move(flags)) , sources(std::move(sources)) + , dependencies(std::move(dependencies)) , output(std::move(output)) , with_linking(with_linking) { } @@ -117,9 +109,10 @@ namespace cs::semantic { if (const auto *const ptr = dynamic_cast(&rhs); ptr != nullptr) { return (working_dir == ptr->working_dir) && (compiler == ptr->compiler) - && (output == ptr->output) - && (sources == ptr->sources) && (flags == ptr->flags) + && (sources == ptr->sources) + && (dependencies == ptr->dependencies) + && (output == ptr->output) && (with_linking == ptr->with_linking); } return false; @@ -130,6 +123,7 @@ namespace cs::semantic { << ", compiler: " << compiler << ", flags: " << fmt::format("[{}]", fmt::join(flags.begin(), flags.end(), ", ")) << ", sources: " << fmt::format("[{}]", fmt::join(sources.begin(), sources.end(), ", ")) + << ", dependencies: " << fmt::format("[{}]", fmt::join(dependencies.begin(), dependencies.end(), ", ")) << ", output: " << (output ? output.value().string() : "") << ", with_linking: " << with_linking << " }"; @@ -137,6 +131,7 @@ namespace cs::semantic { } std::list Compile::into_entries() const { + const auto dependencies_abspath = abspath(dependencies, working_dir); std::list results; for (const auto& source : sources) { const fs::path real_output = (output && !with_linking) @@ -145,12 +140,13 @@ namespace cs::semantic { cs::Entry result { abspath(source, working_dir), - std::list(), + dependencies_abspath, working_dir, abspath(real_output, working_dir), { compiler.string() } }; + // flags contains everything except output and sources std::copy(flags.begin(), flags.end(), std::back_inserter(result.arguments)); if (output) { result.arguments.emplace_back("-o"); @@ -166,15 +162,13 @@ namespace cs::semantic { Link::Link(fs::path working_dir, fs::path compiler, std::list flags, - std::list object_files, - std::optional output, - bool with_compilation) + std::list files, + std::optional output) : working_dir(std::move(working_dir)) , compiler(std::move(compiler)) , flags(std::move(flags)) - , object_files(std::move(object_files)) + , files(std::move(files)) , output(std::move(output)) - , with_compilation(with_compilation) { } bool Link::operator==(const Semantic &rhs) const { @@ -184,10 +178,9 @@ namespace cs::semantic { if (const auto *const ptr = dynamic_cast(&rhs); ptr != nullptr) { return (working_dir == ptr->working_dir) && (compiler == ptr->compiler) - && (output == ptr->output) - && (object_files == ptr->object_files) && (flags == ptr->flags) - && (with_compilation == ptr->with_compilation); + && (files == ptr->files) + && (output == ptr->output); } return false; } @@ -196,32 +189,27 @@ namespace cs::semantic { os << "Link { working_dir: " << working_dir << ", compiler: " << compiler << ", flags: " << fmt::format("[{}]", fmt::join(flags.begin(), flags.end(), ", ")) - << ", files: " << fmt::format("[{}]", fmt::join(object_files.begin(), object_files.end(), ", ")) + << ", files: " << fmt::format("[{}]", fmt::join(files.begin(), files.end(), ", ")) << ", output: " << (output ? output.value().string() : "") - << ", with compilation: " << with_compilation << " }"; return os; } std::list Link::into_entries() const { - const auto real_object_files = (with_compilation) - ? get_object_files(object_files) - : object_files; - cs::Entry result { fs::path(), - abspath(real_object_files, working_dir), + abspath(files, working_dir), working_dir, output ? std::optional(abspath(output.value(), working_dir)) : std::nullopt, { compiler.string() } }; + // flags contains everything except output 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()); } - std::copy(real_object_files.begin(), real_object_files.end(), std::back_inserter(result.arguments)); return std::list{result}; } diff --git a/source/citnames/source/semantic/Semantic.h b/source/citnames/source/semantic/Semantic.h index 73d4e28f..63778d2a 100644 --- a/source/citnames/source/semantic/Semantic.h +++ b/source/citnames/source/semantic/Semantic.h @@ -87,6 +87,7 @@ namespace cs::semantic { fs::path compiler, std::list flags, std::list sources, + std::list dependencies, std::optional output, bool with_linking); @@ -100,6 +101,7 @@ namespace cs::semantic { fs::path compiler; std::list flags; std::list sources; + std::list dependencies; std::optional output; bool with_linking; }; @@ -110,9 +112,8 @@ namespace cs::semantic { Link(fs::path working_dir, fs::path compiler, std::list flags, - std::list sources, - std::optional output, - bool with_compilation); + std::list files, + std::optional output); bool operator==(Semantic const&) const override; std::ostream& operator<<(std::ostream&) const override; @@ -123,8 +124,7 @@ namespace cs::semantic { fs::path working_dir; fs::path compiler; std::list flags; - std::list object_files; + std::list files; std::optional output; - bool with_compilation; }; } diff --git a/source/citnames/source/semantic/ToolClang.cc b/source/citnames/source/semantic/ToolClang.cc index 7821d437..d066ffa0 100644 --- a/source/citnames/source/semantic/ToolClang.cc +++ b/source/citnames/source/semantic/ToolClang.cc @@ -169,6 +169,7 @@ namespace { {"-Xassembler", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}}, {"-Xclang", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}}, {"-Xpreprocessor", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}}, + {"-main-file-name", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}}, }; FlagsByName clang_flags(const FlagsByName &base) { diff --git a/source/citnames/source/semantic/ToolGcc.cc b/source/citnames/source/semantic/ToolGcc.cc index 76490e99..40d37e48 100644 --- a/source/citnames/source/semantic/ToolGcc.cc +++ b/source/citnames/source/semantic/ToolGcc.cc @@ -94,13 +94,6 @@ namespace { }); } - bool is_linker(const CompilerFlags& flags) - { - return std::any_of(flags.begin(), flags.end(), [](const auto& flag) { - return (flag.type == CompilerFlagType::LINKER_OBJECT_FILE); - }); - } - bool has_linker(const CompilerFlags& flags) { return std::none_of(flags.begin(), flags.end(), [](auto flag) { @@ -111,42 +104,78 @@ namespace { std::tuple< Arguments, std::list, - std::optional, - std::list - > split(const CompilerFlags &flags) { + std::list, + std::optional + > split_compile(const CompilerFlags &flags) { Arguments arguments; std::list sources; + std::list dependencies; std::optional output; - std::list object_files; for (const auto &flag : flags) { switch (flag.type) { + case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: { + auto candidate = fs::path(flag.arguments.back()); + output = std::make_optional(std::move(candidate)); + continue; + } case CompilerFlagType::SOURCE: { auto candidate = fs::path(flag.arguments.front()); sources.emplace_back(std::move(candidate)); + continue; + } + case CompilerFlagType::LIBRARY: + case CompilerFlagType::OBJECT_FILE: { + auto candidate = fs::path(flag.arguments.front()); + dependencies.emplace_back(candidate); break; } + default: { + break; + } + } + std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); + } + return std::make_tuple(arguments, sources, dependencies, output); + } + + std::tuple< + Arguments, + std::list, + std::optional, + size_t + > split_link_with_updating_sources(const CompilerFlags &flags) { + Arguments arguments; + std::list files; + std::optional output; + size_t sources_count = 0; + + for (const auto &flag : flags) { + switch (flag.type) { case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: { auto candidate = fs::path(flag.arguments.back()); output = std::make_optional(std::move(candidate)); - break; + continue; } - case CompilerFlagType::LINKER_OBJECT_FILE: { - auto candidate = fs::path(flag.arguments.front()); - object_files.emplace_back(std::move(candidate)); + case CompilerFlagType::SOURCE: { + sources_count++; + const auto source_after_compilation = flag.arguments.front() + ".o"; + arguments.push_back(source_after_compilation); + files.emplace_back(source_after_compilation); break; } - case CompilerFlagType::LINKER: - case CompilerFlagType::PREPROCESSOR_MAKE: - case CompilerFlagType::DIRECTORY_SEARCH_LINKER: + case CompilerFlagType::LIBRARY: + case CompilerFlagType::OBJECT_FILE: { + arguments.push_back(flag.arguments.front()); + files.emplace_back(flag.arguments.front()); break; + } default: { std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); - break; } } } - return std::make_tuple(arguments, sources, output, object_files); + return std::make_tuple(arguments, files, output, sources_count); } } @@ -291,7 +320,7 @@ namespace cs::semantic { } bool ToolGcc::is_linker_call(const fs::path& program) const { - static const auto pattern = std::regex(R"((ld|lld|gold|ar)*)"); + static const auto pattern = std::regex(R"(^(ld|lld|gold|ar)\S*$)"); std::cmatch m; return is_compiler_call(program) || std::regex_match(program.filename().c_str(), m, pattern); } @@ -300,18 +329,21 @@ namespace cs::semantic { return compilation(FLAG_DEFINITION, execution); } - rust::Result ToolGcc::compilation(const FlagsByName &flags, const Execution &execution) { - const auto &parser = - Repeat( - OneOf( - FlagParser(flags), - SourceMatcher(), - EverythingElseFlagMatcher() - ) - ); + auto get_parser(const FlagsByName &flags) { + return Repeat( + OneOf( + FlagParser(flags), + SourceMatcher(), + ObjectFileMatcher(), + LibraryMatcher(), + EverythingElseFlagMatcher() + ) + ); + } + rust::Result ToolGcc::compilation(const FlagsByName &flags, const Execution &execution) { const Arguments &input_arguments = create_argument_list(execution); - return parse(parser, input_arguments) + return parse(get_parser(flags), input_arguments) .and_then([&execution](auto flags) -> rust::Result { if (is_compiler_query(flags)) { SemanticPtr result = std::make_shared(); @@ -322,13 +354,11 @@ namespace cs::semantic { return rust::Ok(std::move(result)); } - auto[arguments, sources, output, object_files] = split(flags); + // arguments contains everything except output and sources + auto[arguments, sources, dependencies, output] = split_compile(flags); if (sources.empty()) { return rust::Err(std::runtime_error("Source files not found for compilation.")); } - if (not object_files.empty()) { - return rust::Err(std::runtime_error("Linker object files found for compilation.")); - } bool with_linking; if (has_linker(flags)) { @@ -344,6 +374,7 @@ namespace cs::semantic { execution.executable, std::move(arguments), std::move(sources), + std::move(dependencies), std::move(output), with_linking ); @@ -356,17 +387,8 @@ namespace cs::semantic { } rust::Result ToolGcc::linking(const FlagsByName &flags, const Execution &execution) { - const auto &parser = - Repeat( - OneOf( - FlagParser(flags), - SourceMatcher(), - EverythingElseFlagMatcher() - ) - ); - const Arguments &input_arguments = create_argument_list(execution); - return parse(parser, input_arguments) + return parse(get_parser(flags), input_arguments) .and_then([&execution](auto flags) -> rust::Result { if (is_compiler_query(flags)) { SemanticPtr result = std::make_shared(); @@ -377,37 +399,20 @@ namespace cs::semantic { return rust::Ok(std::move(result)); } - auto[arguments, sources, output, object_files] = split(flags); - - if (is_linker(flags)) { - if (not sources.empty()) { - return rust::Err(std::runtime_error("Source files found for linking.")); - } - - SemanticPtr result = std::make_shared( - execution.working_dir, - execution.executable, - std::move(arguments), - std::move(object_files), - std::move(output), - false - ); - return rust::Ok(std::move(result)); - } - - if (has_linker(flags)) { - SemanticPtr result = std::make_shared( - execution.working_dir, - execution.executable, - std::move(arguments), - std::move(sources), - std::move(output), - true - ); - return rust::Ok(std::move(result)); + // arguments contains everything except output + auto[arguments, files, output, sources_count] = split_link_with_updating_sources(flags); + if (sources_count != 0 && !has_linker(flags)) { + return rust::Err(std::runtime_error("Without linking.")); } - return rust::Ok(SemanticPtr()); + SemanticPtr result = std::make_shared( + execution.working_dir, + execution.executable, + std::move(arguments), + std::move(files), + std::move(output) + ); + return rust::Ok(std::move(result)); }); } } diff --git a/source/citnames/test/ParserTest.cc b/source/citnames/test/ParserTest.cc index dd6b85a3..b5f6cebb 100644 --- a/source/citnames/test/ParserTest.cc +++ b/source/citnames/test/ParserTest.cc @@ -56,10 +56,10 @@ namespace { const auto flags = parse(sut, input); EXPECT_TRUE(flags.is_ok()); const CompilerFlags expected = { - CompilerFlag{slice(input, 1), CompilerFlagType::LINKER_OBJECT_FILE}, - CompilerFlag{slice(input, 2), CompilerFlagType::LINKER_OBJECT_FILE}, - CompilerFlag{slice(input, 3), CompilerFlagType::LINKER_OBJECT_FILE}, - CompilerFlag{slice(input, 4), CompilerFlagType::LINKER_OBJECT_FILE}, + CompilerFlag{slice(input, 1), CompilerFlagType::UNKNOWN}, + CompilerFlag{slice(input, 2), CompilerFlagType::UNKNOWN}, + CompilerFlag{slice(input, 3), CompilerFlagType::UNKNOWN}, + CompilerFlag{slice(input, 4), CompilerFlagType::UNKNOWN}, }; EXPECT_EQ(expected, flags.unwrap()); } @@ -91,6 +91,50 @@ namespace { } } + TEST(Parser, ObjectFileMatcher) { + const auto sut = Repeat(ObjectFileMatcher()); + + const Arguments input = {"compiler", "source1.o", "source2.o"}; + const auto flags = parse(sut, input); + EXPECT_TRUE(flags.is_ok()); + const CompilerFlags expected = { + CompilerFlag{slice(input, 1), CompilerFlagType::OBJECT_FILE}, + CompilerFlag{slice(input, 2), CompilerFlagType::OBJECT_FILE}, + }; + EXPECT_EQ(expected, flags.unwrap()); + } + + TEST(Parser, LibraryMatcher) { + const auto sut = Repeat(LibraryMatcher()); + + const Arguments input = { + "compiler", + "lib.a", + "lib.so", + "lib.la", + "lib.dylib", + "lib.library", + "lib.DLL", + "lib.lib", + "lib.ocx", + "lib.so.2.13.9746.adhfj.9" + }; + const auto flags = parse(sut, input); + EXPECT_TRUE(flags.is_ok()); + const CompilerFlags expected = { + CompilerFlag{slice(input, 1), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 2), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 3), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 4), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 5), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 6), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 7), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 8), CompilerFlagType::LIBRARY}, + CompilerFlag{slice(input, 9), CompilerFlagType::LIBRARY}, + }; + EXPECT_EQ(expected, flags.unwrap()); + } + TEST(Parser, parse_flags_with_separate_options) { const FlagsByName flags_by_name = { {"-a", {MatchInstruction::EXACTLY, CompilerFlagType::OTHER}}, diff --git a/source/citnames/test/ToolClangTest.cc b/source/citnames/test/ToolClangTest.cc index b286e174..af0bf1d6 100644 --- a/source/citnames/test/ToolClangTest.cc +++ b/source/citnames/test/ToolClangTest.cc @@ -55,6 +55,7 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); @@ -76,8 +77,9 @@ namespace { const Compile expected( input.working_dir, input.executable, - {"-c"}, + {"-c", "-L.", "-lthing"}, {fs::path("source.c")}, + {}, {fs::path("exe")}, true ); @@ -127,6 +129,7 @@ namespace { input.executable, {"-c", "-Xclang", "-load", "-Xclang", "/path/to/LLVMHello.so"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); @@ -162,6 +165,7 @@ namespace { input.executable, {"-c", "-Xarch_arg1", "arg2", "-Xarch_device", "device1", "-Xarch_host", "host1"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); @@ -195,6 +199,7 @@ namespace { input.executable, {"-c", "-Xcuda-fatbinary", "arg1", "-Xcuda-ptxas", "arg2"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); @@ -228,6 +233,7 @@ namespace { input.executable, {"-c", "-Xopenmp-target", "arg1", "-Xopenmp-target=arg1", "arg2"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); @@ -261,6 +267,7 @@ namespace { input.executable, {"-c", "-Z", "arg1", "-aargs", "--analyze"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ); diff --git a/source/citnames/test/ToolGccTest.cc b/source/citnames/test/ToolGccTest.cc index e25efd1a..1aeacf0f 100644 --- a/source/citnames/test/ToolGccTest.cc +++ b/source/citnames/test/ToolGccTest.cc @@ -48,7 +48,7 @@ namespace { EXPECT_TRUE(sut.is_compiler_call("fortran")); } - TEST(ToolGcc, fails_on_empty) { + TEST(ToolGcc, compilation_fails_on_empty) { Execution input = {}; ToolGcc sut; @@ -56,7 +56,19 @@ namespace { EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::COMPILER))); } - TEST(ToolGcc, simple) { + TEST(ToolGcc, compilation_check_compilation_without_compilation) { + Execution input = { + "/usr/bin/cc", + {"cc", "-L.", "source_1.o", "lib.a", "source_2.o", "-la"}, + "/home/user/project", + {}, + }; + + ToolGcc sut({}); + EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::COMPILER))); + } + + TEST(ToolGcc, compilation_simple) { Execution input = { "/usr/bin/cc", {"cc", "-c", "-o", "source.o", "source.c"}, @@ -69,6 +81,7 @@ namespace { input.executable, {"-c"}, {fs::path("source.c")}, + {}, {fs::path("source.o")}, false ) @@ -81,10 +94,10 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, linker_flag_filtered) { + TEST(ToolGcc, compilation_output_filtered) { Execution input = { "/usr/bin/cc", - {"cc", "-L.", "-lthing", "-o", "exe", "source.c"}, + {"cc", "source.c", "-L.", "-lthing", "-o", "exe"}, "/home/user/project", {}, }; @@ -92,8 +105,9 @@ namespace { new Compile( input.working_dir, input.executable, - {"-c"}, + {"-c", "-L.", "-lthing"}, {fs::path("source.c")}, + {}, {fs::path("exe")}, true ) @@ -106,7 +120,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, pass_on_help) { + TEST(ToolGcc, compilation_pass_on_help) { Execution input = { "/usr/bin/gcc", {"gcc", "--version"}, @@ -122,7 +136,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, simple_with_C_PATH) { + TEST(ToolGcc, compilation_simple_with_C_PATH) { Execution input = { "/usr/bin/cc", {"cc", "-c", "source.c"}, @@ -142,6 +156,7 @@ namespace { "-I", "/usr/include/path3", }, {fs::path("source.c")}, + {}, std::nullopt, false ) @@ -153,4 +168,239 @@ namespace { EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } + + TEST(ToolGcc, compilation_with_linking_one_file) { + Execution input = { + "/usr/bin/cc", + {"cc", "-o", "source", "source.c"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Compile( + input.working_dir, + input.executable, + {"-c"}, + {fs::path("source.c")}, + {}, + {fs::path("source")}, + true + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::COMPILER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGcc, compilation_with_linking_with_obj) { + Execution input = { + "/usr/bin/cc", + {"cc", "source_1.c", "-o", "source", "source_2.c", "obj.o"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Compile( + input.working_dir, + input.executable, + {"-c", "obj.o"}, + {"source_1.c", "source_2.c"}, + {"obj.o"}, + {fs::path("source")}, + true + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::COMPILER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGcc, compilation_with_obj_and_libs) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "lib.library", "source_1.c", "lib.so.2", "-o", "source", "source_2.c", "obj.o", "lib.dll"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Compile( + input.working_dir, + input.executable, + {"-c", "lib.library", "lib.so.2", "obj.o", "lib.dll"}, + {"source_1.c", "source_2.c"}, + {"lib.library", "lib.so.2", "obj.o", "lib.dll"}, + {fs::path("source")}, + false + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::COMPILER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGcc, compilation_with_unknown_files) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "lib.library", "lib", "aaaaa", "source_1.c", "lib.so", "-o", "source", "source_2.c", "obj.o", "lib.dll"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Compile( + input.working_dir, + input.executable, + {"-c", "lib.library", "lib", "aaaaa", "lib.so", "obj.o", "lib.dll"}, + {"source_1.c", "source_2.c"}, + {"lib.library", "lib.so", "obj.o", "lib.dll"}, + {fs::path("source")}, + false + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::COMPILER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + +//--------------------------------------------------------------------------------------------------------- + + TEST(ToolGcc, is_linker_call) { + struct Expose : public ToolGcc { + using ToolGcc::is_linker_call; + }; + Expose sut; + + EXPECT_TRUE(sut.is_linker_call("cc")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/cc")); + EXPECT_TRUE(sut.is_linker_call("gcc")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc")); + EXPECT_TRUE(sut.is_linker_call("c++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/c++")); + EXPECT_TRUE(sut.is_linker_call("g++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/g++")); + EXPECT_TRUE(sut.is_linker_call("arm-none-eabi-g++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/arm-none-eabi-g++")); + EXPECT_TRUE(sut.is_linker_call("gcc-6")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc-6")); + EXPECT_TRUE(sut.is_linker_call("gfortran")); + EXPECT_TRUE(sut.is_linker_call("fortran")); + EXPECT_TRUE(sut.is_linker_call("ld")); + EXPECT_TRUE(sut.is_linker_call("lld")); + EXPECT_TRUE(sut.is_linker_call("ar")); + } + + TEST(ToolGcc, linking_fails_on_empty) { + Execution input = {}; + + ToolGcc sut; + + EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGcc, without_linking_simple) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "-o", "source.o", "source.c"}, + "/home/user/project", + {}, + }; + + ToolGcc sut; + EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGcc, without_linking_with_object_files) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "x.o", "x2.o", "-o", "source.o", "source.c"}, + "/home/user/project", + {}, + }; + + ToolGcc sut; + EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGcc, linking_with_compilation_one_file) { + Execution input = { + "/usr/bin/cc", + {"cc", "-o", "source", "source.c"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"source.c.o"}, + {fs::path("source.c.o")}, + {fs::path("source")} + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGcc, linking_with_compilation) { + Execution input = { + "/usr/bin/cc", + {"cc", "source_1.c", "-o", "source", "lib.o", "-la", "source_2.c"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"source_1.c.o", "lib.o", "-la", "source_2.c.o"}, + {"source_1.c.o", "lib.o", "source_2.c.o"}, + {fs::path("source")} + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGcc, linking) { + Execution input = { + "/usr/bin/cc", + {"cc", "-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, + {"source_1.o", "lib.DLL", "source_2.o"}, + std::nullopt + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } } diff --git a/test/bin/assert_compilation b/test/bin/assert_compilation index 4a2f4440..ae253b43 100755 --- a/test/bin/assert_compilation +++ b/test/bin/assert_compilation @@ -22,6 +22,7 @@ def main(): count_parser.add_argument('-le', dest='le', type=int) entry_parser = subparsers.add_parser('contains') entry_parser.add_argument('-file') + entry_parser.add_argument('-files', nargs='*') entry_parser.add_argument('-output') entry_parser.add_argument('-directory') entry_parser.add_argument('-arguments', nargs=argparse.REMAINDER) @@ -65,6 +66,7 @@ def filter_from(args): p1 = True if args.file is None else entry['file'] == args.file p2 = True if args.output is None else entry['output'] == args.output p3 = True if args.directory is None else entry['directory'] == args.directory + if args.arguments is not None: if 'arguments' in entry: p4 = entry['arguments'] == args.arguments @@ -72,17 +74,20 @@ def filter_from(args): p4 = shlex.split(entry['command']) == args.arguments else: p4 = True - return p1 and p2 and p3 and p4 + + p5 = True if args.files is None else entry['files'] == args.files + return p1 and p2 and p3 and p4 and p5 return test def to_string(args): p1 = '' if args.file is None else '-file {}'.format(args.file) - p2 = '' if args.output is None else '-output {}'.format(args.output) - p3 = '' if args.directory is None else '-directory {}'.format(args.directory) - p4 = '' if args.arguments is None else ' '.join(['-arguments'] + args.arguments) - return ' '.join([p1, p2, p3, p4]) + p2 = '' if args.files is None else ' '.join(['-files'] + args.files) + p3 = '' if args.output is None else '-output {}'.format(args.output) + p4 = '' if args.directory is None else '-directory {}'.format(args.directory) + p5 = '' if args.arguments is None else ' '.join(['-arguments'] + args.arguments) + return ' '.join([p1, p2, p3, p4, p5]) if __name__ == "__main__": diff --git a/test/cases/compilation/output/define_with_escaped_quote.sh b/test/cases/compilation/output/define_with_escaped_quote.sh index 89cad511..5a67cebf 100644 --- a/test/cases/compilation/output/define_with_escaped_quote.sh +++ b/test/cases/compilation/output/define_with_escaped_quote.sh @@ -14,4 +14,4 @@ int main() { } EOF -$CC '-DMESSAGE="Hello World\n"' -o define_with_escaped_quote define_with_escaped_quote.c; +$CC '-DMESSAGE="Hello World\n"' define_with_escaped_quote.c -o define_with_escaped_quote; diff --git a/test/cases/compilation/output/define_with_quote.sh b/test/cases/compilation/output/define_with_quote.sh index a481ef7f..976c2f28 100644 --- a/test/cases/compilation/output/define_with_quote.sh +++ b/test/cases/compilation/output/define_with_quote.sh @@ -17,4 +17,4 @@ int main() { } EOF -$CXX -DEXPORT="extern \"C\"" -o define_with_quote define_with_quote.c; +$CXX define_with_quote.c -DEXPORT="extern \"C\"" -o define_with_quote; diff --git a/test/cases/compilation/output/flag/append.sh b/test/cases/compilation/output/flag/append.sh index 95baba0f..f67e46c5 100644 --- a/test/cases/compilation/output/flag/append.sh +++ b/test/cases/compilation/output/flag/append.sh @@ -14,9 +14,8 @@ # 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 -# don't work after disable check for file existence -# cd %T; %{bear} --verbose --output-compile %t.json --append -- %{shell} %s -clean -# assert_compilation %t.json count -eq 0 +# RUN: cd %T; %{bear} --verbose --output-compile %t.json --append -- %{shell} %s -clean +# RUN: assert_compilation %t.json count -eq 0 build() { diff --git a/test/cases/compilation/output/flags_filtered_link.sh b/test/cases/compilation/output/flags_filtered_link.sh index 9b0739fd..a9484a9e 100644 --- a/test/cases/compilation/output/flags_filtered_link.sh +++ b/test/cases/compilation/output/flags_filtered_link.sh @@ -5,8 +5,8 @@ # 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.c.o 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.c.o flags_filtered_link_4.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_3.c -directory %T -arguments %{c_compiler} -c -lfoobar -L. -o flags_filtered_link_3.c.o flags_filtered_link_3.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_4.c -directory %T -arguments %{c_compiler} -c -l foobar -L . -o flags_filtered_link_4.c.o flags_filtered_link_4.c # set up platform specific linker options PREFIX="foobar"; diff --git a/test/cases/compilation/output/flags_filtered_preproc.sh b/test/cases/compilation/output/flags_filtered_preproc.sh index 2eb0407f..0f919738 100644 --- a/test/cases/compilation/output/flags_filtered_preproc.sh +++ b/test/cases/compilation/output/flags_filtered_preproc.sh @@ -3,8 +3,8 @@ # REQUIRES: shell # RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_1.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_preproc_1.o flags_filtered_preproc_1.c -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_2.c -directory %T -arguments %{c_compiler} -c -o flags_filtered_preproc_2.o flags_filtered_preproc_2.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_1.c -directory %T -arguments %{c_compiler} -c -MD -MF flags_filtered_preproc_1.d -o flags_filtered_preproc_1.o flags_filtered_preproc_1.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_2.c -directory %T -arguments %{c_compiler} -c -MMD -MF flags_filtered_preproc_2.d -o flags_filtered_preproc_2.o flags_filtered_preproc_2.c touch flags_filtered_preproc_1.c flags_filtered_preproc_2.c diff --git a/test/cases/compilation/output/linking/append.sh b/test/cases/compilation/output/linking/append.sh new file mode 100644 index 00000000..5d5bc035 --- /dev/null +++ b/test/cases/compilation/output/linking/append.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.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: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/append/src/source_1.o %T/append/src/source_2.o -directory %T -arguments %{c_compiler} append/src/source_1.o append/src/source_2.o -o src + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.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: assert_compilation %t_link.json count -eq 2 +# RUN: assert_compilation %t_link.json contains -files %T/append/src/source_1.o %T/append/src/source_2.o -directory %T -arguments %{c_compiler} append/src/source_1.o append/src/source_2.o -o src +# RUN: assert_compilation %t_link.json contains -files %T/append/test/source_1.o %T/append/test/source_2.o -directory %T -arguments %{c_compiler} append/test/source_1.o append/test/source_2.o -o test + +# RUN: cd %T; %{bear} --verbose --output-compile %t.json --append -- %{shell} %s -clean +# RUN: assert_compilation %t.json count -eq 0 +# RUN: assert_compilation %t_link.json count -eq 2 + +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 + $CC -o src append/src/source_1.o append/src/source_2.o +} + +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 + $CC -o test append/test/source_1.o append/test/source_2.o +} + +clean() +{ + rm -rf append +} + +case $1 in + -build) + build + ;; + -test) + verify + ;; + -clean) + clean + ;; + *) + # unknown option + ;; +esac + +true diff --git a/test/cases/compilation/output/linking/compile_link_one_file.sh b/test/cases/compilation/output/linking/compile_link_one_file.sh new file mode 100644 index 00000000..d9478d10 --- /dev/null +++ b/test/cases/compilation/output/linking/compile_link_one_file.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/compile_link_one_file.c -directory %T -arguments %{c_compiler} -c -o compile_link_one_file.c.o compile_link_one_file.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/compile_link_one_file.c.o -directory %T -arguments %{c_compiler} compile_link_one_file.c.o -o compile_link_one_file + +echo "int main() { return 0; }" > compile_link_one_file.c + +$CC compile_link_one_file.c -o compile_link_one_file diff --git a/test/cases/compilation/output/linking/compile_link_some_files.sh b/test/cases/compilation/output/linking/compile_link_some_files.sh new file mode 100644 index 00000000..7a1e45ae --- /dev/null +++ b/test/cases/compilation/output/linking/compile_link_some_files.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 2 +# RUN: assert_compilation %t.json contains -file %T/compile_link_some_files_1.c -directory %T -arguments %{c_compiler} -c -o compile_link_some_files_1.c.o compile_link_some_files_1.c +# RUN: assert_compilation %t.json contains -file %T/compile_link_some_files_2.c -directory %T -arguments %{c_compiler} -c -o compile_link_some_files_2.c.o compile_link_some_files_2.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/compile_link_some_files_1.c.o %T/compile_link_some_files_2.c.o -directory %T -arguments %{c_compiler} compile_link_some_files_1.c.o compile_link_some_files_2.c.o -o compile_link_some_files + +echo "int foo() { return 1; }" > compile_link_some_files_1.c +echo "int main() { return 0; }" > compile_link_some_files_2.c + +$CC compile_link_some_files_1.c -o compile_link_some_files compile_link_some_files_2.c diff --git a/test/cases/compilation/output/linking/not_append_without_link_database.sh b/test/cases/compilation/output/linking/not_append_without_link_database.sh new file mode 100644 index 00000000..08a21490 --- /dev/null +++ b/test/cases/compilation/output/linking/not_append_without_link_database.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: rm -f %t.json %t_link.json +# RUN: echo "[{\"arguments\": [\"gcc\", \"-c\"]}]" > %t.json + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json --append -- %{shell} %s +# 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 -o source_1.o source_1.c +# RUN: assert_compilation %t.json contains -file %T/source_2.c -directory %T -arguments %{c_compiler} -c -o source_2.o source_2.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/source_1.o %T/source_2.o -directory %T -arguments %{c_compiler} source_1.o source_2.o + +echo "int foo() { return 1; }" > source_1.c +echo "int main() { return 0; }" > source_2.c + +$CC -c -o source_1.o source_1.c +$CC -c -o source_2.o source_2.c +$CC source_1.o source_2.o diff --git a/test/cases/compilation/output/linking/without_link_flag.sh b/test/cases/compilation/output/linking/without_link_flag.sh new file mode 100644 index 00000000..b0460b6c --- /dev/null +++ b/test/cases/compilation/output/linking/without_link_flag.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/without_link_flag.c -directory %T -arguments %{c_compiler} -c -o without_link_flag.c.o without_link_flag.c + + +echo "int main() { return 0; }" > without_link_flag.c + +$CC -o without_link_flag without_link_flag.c diff --git a/test/cases/compilation/output/with_other_files.sh b/test/cases/compilation/output/with_other_files.sh new file mode 100644 index 00000000..b4f366ed --- /dev/null +++ b/test/cases/compilation/output/with_other_files.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# REQUIRES: shell +# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/with_other_files.c -files %T/lib.o -directory %T -arguments %{c_compiler} -c lib.o -o with_other_files.o with_other_files.c + +touch with_other_files.c lib.o + +$CC -c lib.o with_other_files.c -o with_other_files.o; From 8ba199ecc5734ee918be98d5668445173fde5210 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+MashaK5@users.noreply.github.com> Date: Mon, 15 May 2023 22:11:58 +0300 Subject: [PATCH 3/7] After testing: fix case with ar, content filter, debug message (#7) * Add files count for linking checking * Fix files validation and content filter checking * Fix processing case with ar * Fix test name * Update unit test --- source/citnames/CMakeLists.txt | 2 + source/citnames/source/Output.cc | 15 +- source/citnames/source/semantic/Build.cc | 2 + source/citnames/source/semantic/Semantic.cc | 3 +- source/citnames/source/semantic/ToolAr.cc | 143 ++++++++++++++++++ source/citnames/source/semantic/ToolAr.h | 42 ++++++ source/citnames/source/semantic/ToolGcc.cc | 40 ++++-- source/citnames/test/ToolArTest.cc | 152 ++++++++++++++++++++ source/citnames/test/ToolGccTest.cc | 2 +- 9 files changed, 380 insertions(+), 21 deletions(-) create mode 100644 source/citnames/source/semantic/ToolAr.cc create mode 100644 source/citnames/source/semantic/ToolAr.h create mode 100644 source/citnames/test/ToolArTest.cc diff --git a/source/citnames/CMakeLists.txt b/source/citnames/CMakeLists.txt index 18c42133..65c1ffeb 100644 --- a/source/citnames/CMakeLists.txt +++ b/source/citnames/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources(citnames_a source/semantic/ToolGcc.cc source/semantic/ToolWrapper.cc source/semantic/ToolExtendingWrapper.cc + source/semantic/ToolAr.cc INTERFACE $ ) @@ -67,6 +68,7 @@ if (ENABLE_UNIT_TESTS) test/ToolClangTest.cc test/ToolGccTest.cc test/ToolWrapperTest.cc + test/ToolArTest.cc ) target_link_libraries(citnames_unit_test citnames_a) diff --git a/source/citnames/source/Output.cc b/source/citnames/source/Output.cc index 5d028ec0..a5c63be9 100644 --- a/source/citnames/source/Output.cc +++ b/source/citnames/source/Output.cc @@ -33,9 +33,6 @@ namespace { void validate_files(const cs::Entry &entry) { - if (entry.file.empty() && (entry.files.empty())) { - throw std::runtime_error("Fields 'file' and 'files' have not values."); - } if (std::any_of(entry.files.begin(), entry.files.end(), [](const auto& file) { return file.empty(); })) { throw std::runtime_error("Field 'files' has empty paths."); } @@ -66,13 +63,19 @@ namespace { bool apply(const cs::Entry &entry) override { validate_files(entry); + + bool checking_result = true; if (not entry.file.empty()) { - return check(entry.file); + checking_result = checking_result && check(entry.file); } if (not entry.files.empty()) { - return std::all_of(entry.files.begin(), entry.files.end(), [&](const auto &file){ return check(file); }); + checking_result = checking_result && std::all_of( + entry.files.begin(), + entry.files.end(), + [&](const auto &file){ return check(file); } + ); } - return false; + return checking_result; } private: diff --git a/source/citnames/source/semantic/Build.cc b/source/citnames/source/semantic/Build.cc index aa105ea7..0487aadd 100644 --- a/source/citnames/source/semantic/Build.cc +++ b/source/citnames/source/semantic/Build.cc @@ -24,6 +24,7 @@ #include "ToolCuda.h" #include "ToolWrapper.h" #include "ToolExtendingWrapper.h" +#include "ToolAr.h" #include "Convert.h" #include @@ -44,6 +45,7 @@ namespace { std::make_shared(), std::make_shared(), std::make_shared(), + std::make_shared(), }; for (auto && compiler : cfg.compilers_to_recognize) { tools.emplace_front(std::make_shared(std::move(compiler))); diff --git a/source/citnames/source/semantic/Semantic.cc b/source/citnames/source/semantic/Semantic.cc index 2f217c2a..5505d169 100644 --- a/source/citnames/source/semantic/Semantic.cc +++ b/source/citnames/source/semantic/Semantic.cc @@ -18,6 +18,7 @@ */ #include "semantic/Semantic.h" +#include "ToolAr.h" #include @@ -206,7 +207,7 @@ namespace cs::semantic { // flags contains everything except output std::copy(flags.begin(), flags.end(), std::back_inserter(result.arguments)); - if (output) { + if (output && !ToolAr::is_linker_call(compiler.string())) { result.arguments.emplace_back("-o"); result.arguments.push_back(output.value().string()); } diff --git a/source/citnames/source/semantic/ToolAr.cc b/source/citnames/source/semantic/ToolAr.cc new file mode 100644 index 00000000..ecd5f231 --- /dev/null +++ b/source/citnames/source/semantic/ToolAr.cc @@ -0,0 +1,143 @@ +/* Copyright (C) 2012-2023 by László Nagy + This file is part of Bear. + + Bear is a tool to generate compilation database for clang tooling. + + Bear is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bear is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "ToolAr.h" +#include "Parsers.h" + +#include +#include +#include + +using namespace cs::semantic; + +namespace { + + bool is_compiler_query(const CompilerFlags& flags) + { + // no flag is a no compilation + if (flags.empty()) { + return true; + } + // otherwise check if this was a version query of a help + return std::any_of(flags.begin(), flags.end(), [](const auto& flag) { + return (flag.type == CompilerFlagType::KIND_OF_OUTPUT_INFO); + }); + } + + std::tuple< + Arguments, + std::list, + std::optional + > split(const CompilerFlags &flags) { + Arguments arguments; + std::list files; + std::optional output; + + for (const auto &flag : flags) { + switch (flag.type) { + case CompilerFlagType::LIBRARY: { + if (!output.has_value()) { + output = std::make_optional(flag.arguments.front()); + break; + } + [[fallthrough]]; + } + case CompilerFlagType::SOURCE: + case CompilerFlagType::OBJECT_FILE: { + files.emplace_back(flag.arguments.front()); + break; + } + default: { + break; + } + } + std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); + } + return std::make_tuple(arguments, files, output); + } + + auto get_parser(const FlagsByName &flags) { + return Repeat( + OneOf( + FlagParser(flags), + SourceMatcher(), + ObjectFileMatcher(), + LibraryMatcher(), + EverythingElseFlagMatcher() + ) + ); + } +} + +namespace cs::semantic { + + const FlagsByName ToolAr::FLAG_DEFINITION = { + {"--help", {MatchInstruction::PREFIX, CompilerFlagType::KIND_OF_OUTPUT_INFO}}, + {"--version", {MatchInstruction::EXACTLY, CompilerFlagType::KIND_OF_OUTPUT_INFO}}, + {"-X32_64", {MatchInstruction::EXACTLY, CompilerFlagType::OTHER}}, + {"--plugin", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ_OR_SEP, CompilerFlagType::OTHER}}, + {"--target", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ_OR_SEP, CompilerFlagType::OTHER}}, + {"--output", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ_OR_SEP, CompilerFlagType::OTHER}}, + {"--record-libdeps", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ_OR_SEP, CompilerFlagType::OTHER}}, + {"--thin", {MatchInstruction::EXACTLY, CompilerFlagType::OTHER}}, + }; + + rust::Result ToolAr::recognize(const Execution &execution, const BuildTarget target) const { + switch (target) { + case BuildTarget::LINKER: { + if (is_linker_call(execution.executable)) { + return linking(FLAG_DEFINITION, execution); + } + break; + } + case BuildTarget::COMPILER: { + break; + } + } + return rust::Ok(SemanticPtr()); + } + + bool ToolAr::is_linker_call(const fs::path& program) { + static const auto pattern = std::regex(R"(^(ar)\S*$)"); + std::cmatch m; + return std::regex_match(program.filename().c_str(), m, pattern); + } + + rust::Result ToolAr::linking(const FlagsByName &flags, const Execution &execution) { + return parse(get_parser(flags), execution.arguments) + .and_then([&execution](auto flags) -> rust::Result { + if (is_compiler_query(flags)) { + SemanticPtr result = std::make_shared(); + return rust::Ok(std::move(result)); + } + + // arguments contains everything + auto[arguments, files, output] = split(flags); + + SemanticPtr result = std::make_shared( + execution.working_dir, + execution.executable, + std::move(arguments), + std::move(files), + std::move(output) + ); + return rust::Ok(std::move(result)); + }); + } +} diff --git a/source/citnames/source/semantic/ToolAr.h b/source/citnames/source/semantic/ToolAr.h new file mode 100644 index 00000000..07ca61be --- /dev/null +++ b/source/citnames/source/semantic/ToolAr.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2012-2023 by László Nagy + This file is part of Bear. + + Bear is a tool to generate compilation database for clang tooling. + + Bear is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bear is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#pragma once + +#include "Tool.h" +#include "Parsers.h" + +namespace cs::semantic { + + struct ToolAr : public Tool { + + [[nodiscard]] + rust::Result recognize(const Execution &execution, const BuildTarget target) const override; + + [[nodiscard]] + static bool is_linker_call(const fs::path& program); + + protected: + + [[nodiscard]] + static rust::Result linking(const FlagsByName &flags, const Execution &execution); + + static const FlagsByName FLAG_DEFINITION; + }; +} diff --git a/source/citnames/source/semantic/ToolGcc.cc b/source/citnames/source/semantic/ToolGcc.cc index 40d37e48..1a08ecac 100644 --- a/source/citnames/source/semantic/ToolGcc.cc +++ b/source/citnames/source/semantic/ToolGcc.cc @@ -27,6 +27,9 @@ #include #include #include +#include + +#include using namespace cs::semantic; @@ -177,6 +180,18 @@ namespace { } return std::make_tuple(arguments, files, output, sources_count); } + + auto get_parser(const FlagsByName &flags) { + return Repeat( + OneOf( + FlagParser(flags), + SourceMatcher(), + ObjectFileMatcher(), + LibraryMatcher(), + EverythingElseFlagMatcher() + ) + ); + } } namespace cs::semantic { @@ -320,7 +335,7 @@ namespace cs::semantic { } bool ToolGcc::is_linker_call(const fs::path& program) const { - static const auto pattern = std::regex(R"(^(ld|lld|gold|ar)\S*$)"); + static const auto pattern = std::regex(R"(^(ld|lld)\S*$)"); std::cmatch m; return is_compiler_call(program) || std::regex_match(program.filename().c_str(), m, pattern); } @@ -329,18 +344,6 @@ namespace cs::semantic { return compilation(FLAG_DEFINITION, execution); } - auto get_parser(const FlagsByName &flags) { - return Repeat( - OneOf( - FlagParser(flags), - SourceMatcher(), - ObjectFileMatcher(), - LibraryMatcher(), - EverythingElseFlagMatcher() - ) - ); - } - rust::Result ToolGcc::compilation(const FlagsByName &flags, const Execution &execution) { const Arguments &input_arguments = create_argument_list(execution); return parse(get_parser(flags), input_arguments) @@ -404,6 +407,17 @@ namespace cs::semantic { if (sources_count != 0 && !has_linker(flags)) { return rust::Err(std::runtime_error("Without linking.")); } + if (files.empty()) { + spdlog::debug("Files not found for linking in command: {}", std::accumulate( + std::next(arguments.begin()), + arguments.end(), + arguments.front(), + [](std::string res, std::string flag) { + return std::move(res) + " " + std::move(flag); + } + )); + return rust::Err(std::runtime_error("Files not found for linking.")); + } SemanticPtr result = std::make_shared( execution.working_dir, diff --git a/source/citnames/test/ToolArTest.cc b/source/citnames/test/ToolArTest.cc new file mode 100644 index 00000000..03e97117 --- /dev/null +++ b/source/citnames/test/ToolArTest.cc @@ -0,0 +1,152 @@ +/* Copyright (C) 2012-2023 by László Nagy + This file is part of Bear. + + Bear is a tool to generate compilation database for clang tooling. + + Bear is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bear is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "gtest/gtest.h" + +#include "semantic/Tool.h" +#include "semantic/ToolAr.h" + +using namespace cs::semantic; + +namespace { + + TEST(ToolAr, is_ar_call) { + struct Expose : public ToolAr { + using ToolAr::is_linker_call; + }; + Expose sut; + + EXPECT_TRUE(sut.is_linker_call("ar")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/ar")); + EXPECT_FALSE(sut.is_linker_call("gcc")); + EXPECT_FALSE(sut.is_linker_call("/usr/bin/gcc")); + } + + TEST(ToolAr, target_compiler) { + Execution input = { + "/usr/bin/ar", + {"ar", "qc", "libmy.a"}, + "/home/user/project", + {}, + }; + + ToolAr sut; + + EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::COMPILER))); + } + + TEST(ToolAr, fails_on_empty) { + Execution input = {}; + + ToolAr sut; + + EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolAr, pass_on_help) { + Execution input = { + "/usr/bin/ar", + {"ar", "--version"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr(new QueryCompiler()); + + ToolAr sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(result.is_ok()); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolAr, simple_without_files) { + Execution input = { + "/usr/bin/ar", + {"ar", "qc", "libmy.a"}, + "/home/user/project", + {}, + }; + + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"qc", "libmy.a"}, + {}, + {fs::path("libmy.a")} + ) + ); + + ToolAr sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolAr, simple_with_files) { + Execution input = { + "/usr/bin/ar", + {"ar", "qc", "libmy.a", "x.o", "lmy.a", "x.cpp"}, + "/home/user/project", + {}, + }; + + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"qc", "libmy.a", "x.o", "lmy.a", "x.cpp"}, + {"x.o", "lmy.a", "x.cpp"}, + {fs::path("libmy.a")} + ) + ); + + ToolAr sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolAr, with_flags) { + Execution input = { + "/usr/bin/ar", + {"ar", "qc", "--plugin", "l.a", "--output=/usr/my/", "libmy.a", "x.o"}, + "/home/user/project", + {}, + }; + + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"qc", "--plugin", "l.a", "--output=/usr/my/", "libmy.a", "x.o"}, + {"x.o"}, + {fs::path("libmy.a")} + ) + ); + + ToolAr sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } +} diff --git a/source/citnames/test/ToolGccTest.cc b/source/citnames/test/ToolGccTest.cc index 1aeacf0f..a69f7889 100644 --- a/source/citnames/test/ToolGccTest.cc +++ b/source/citnames/test/ToolGccTest.cc @@ -297,7 +297,7 @@ namespace { EXPECT_TRUE(sut.is_linker_call("fortran")); EXPECT_TRUE(sut.is_linker_call("ld")); EXPECT_TRUE(sut.is_linker_call("lld")); - EXPECT_TRUE(sut.is_linker_call("ar")); + EXPECT_FALSE(sut.is_linker_call("ar")); } TEST(ToolGcc, linking_fails_on_empty) { From b590597056820ad655689bb0887186cdb631edd4 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+mamaria-k@users.noreply.github.com> Date: Wed, 31 May 2023 23:12:42 +0300 Subject: [PATCH 4/7] Add processing of linking flags -l -Wl -L (#8) * Add processing of linking flags -l -Wl -L * Separate -static flag from -static-s * Supplement testing system, add processing libs for compilation database --- source/citnames/CMakeLists.txt | 3 +- source/citnames/source/semantic/Parsers.h | 6 +- source/citnames/source/semantic/ToolGcc.cc | 180 ++++++++++++++++-- .../{ToolGccTest.cc => ToolGccCompileTest.cc} | 153 ++------------- source/citnames/test/ToolGccLinkTest.cc | 159 ++++++++++++++++ test/bin/assert_compilation | 10 +- .../compilation/output/flags_filtered_link.sh | 8 +- .../compilation/output/linking/flag_wl.sh | 23 +++ .../output/linking/some_dir_for_libs.sh | 22 +++ .../compilation/output/linking/some_libs.sh | 26 +++ .../output/linking/with_static_lib.sh | 17 ++ test/lit.cfg | 10 + 12 files changed, 452 insertions(+), 165 deletions(-) rename source/citnames/test/{ToolGccTest.cc => ToolGccCompileTest.cc} (63%) create mode 100644 source/citnames/test/ToolGccLinkTest.cc create mode 100644 test/cases/compilation/output/linking/flag_wl.sh create mode 100644 test/cases/compilation/output/linking/some_dir_for_libs.sh create mode 100644 test/cases/compilation/output/linking/some_libs.sh create mode 100644 test/cases/compilation/output/linking/with_static_lib.sh diff --git a/source/citnames/CMakeLists.txt b/source/citnames/CMakeLists.txt index 65c1ffeb..8118d332 100644 --- a/source/citnames/CMakeLists.txt +++ b/source/citnames/CMakeLists.txt @@ -66,7 +66,8 @@ if (ENABLE_UNIT_TESTS) test/OutputTest.cc test/ParserTest.cc test/ToolClangTest.cc - test/ToolGccTest.cc + test/ToolGccCompileTest.cc + test/ToolGccLinkTest.cc test/ToolWrapperTest.cc test/ToolArTest.cc ) diff --git a/source/citnames/source/semantic/Parsers.h b/source/citnames/source/semantic/Parsers.h index ae20352c..5e686934 100644 --- a/source/citnames/source/semantic/Parsers.h +++ b/source/citnames/source/semantic/Parsers.h @@ -106,7 +106,6 @@ namespace cs::semantic { PREPROCESSOR_MAKE, LINKER, DIRECTORY_SEARCH, - DIRECTORY_SEARCH_LINKER, OTHER, STATIC_ANALYZER, UNKNOWN, @@ -116,6 +115,11 @@ namespace cs::semantic { LIBRARY, KIND_OF_OUTPUT_OUTPUT, + + DIRECTORY_SEARCH_LIBRARY, + LINKER_LIBRARY_FLAG, + LINKER_LIBRARY_STATIC, + LINKER_OPTIONS_FLAG, }; struct CompilerFlag { diff --git a/source/citnames/source/semantic/ToolGcc.cc b/source/citnames/source/semantic/ToolGcc.cc index 1a08ecac..7bdcfdf6 100644 --- a/source/citnames/source/semantic/ToolGcc.cc +++ b/source/citnames/source/semantic/ToolGcc.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -35,6 +36,12 @@ using namespace cs::semantic; namespace { + enum class LibraryPriorityType { + FIRSTLY_SHARED, + ONLY_STATIC, + ONLY_STATIC_FIXED + }; + // https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html Arguments flags_from_environment(const std::map &environment) { Arguments flags; @@ -71,6 +78,19 @@ namespace { return input_arguments; } + std::vector get_library_directories(const Execution &execution) { + std::vector library_directories; + if (const auto it = execution.environment.find("LIBRARY_PATH"); it != execution.environment.end()) + { + for (const auto &path : sys::path::split(it->second)) { + auto directory = (path.empty()) ? "." : path.string(); + library_directories.emplace_back(directory); + } + } + + return library_directories; + } + bool is_compiler_query(const CompilerFlags& flags) { // no flag is a no compilation @@ -104,17 +124,117 @@ namespace { }); } + std::string directory_path_from_flag(const CompilerFlag& flag) { + assert(flag.type == CompilerFlagType::DIRECTORY_SEARCH_LIBRARY); + + if (flag.arguments.front() == "-L") { + return flag.arguments.back(); + } + return flag.arguments.front().substr(2); + } + + std::string library_name_from_flag(const CompilerFlag& flag) { + assert(flag.type == CompilerFlagType::LINKER_LIBRARY_FLAG); + + if (flag.arguments.front() == "-l") { + return flag.arguments.back(); + } + return flag.arguments.front().substr(2); + } + + std::optional find_library( + const std::string& libname, + const std::vector& library_directories, + const std::vector& added_library_directories, + const LibraryPriorityType type + ) { + static const std::vector shared_extensions = { + ".so", ".dylib", ".dll", ".DLL", ".ocx", ".OCX", ".lib", ".LIB", ".library" + }; + static const std::vector static_extensions = { + ".a", ".lib", ".LIB" + }; + + const std::string libname_with_prefix = "lib" + libname; + + const auto find_lib = [&libname_with_prefix]( + const std::vector& dirs, + const std::vector& extensions + ) -> std::optional { + for (const auto& dir : dirs) { + for (const auto& extension: extensions) { + fs::path libname_full = dir; + libname_full /= libname_with_prefix + extension; + + if (fs::exists(libname_full)) { + return std::make_optional(libname_full); + } + } + } + return std::nullopt; + }; + + if (type == LibraryPriorityType::FIRSTLY_SHARED) { + if (const auto lib = find_lib(added_library_directories, shared_extensions); lib.has_value()) { + return lib; + } + if (const auto lib = find_lib(library_directories, shared_extensions); lib.has_value()) { + return lib; + } + } + + if (const auto lib = find_lib(added_library_directories, static_extensions); lib.has_value()) { + return lib; + } + if (const auto lib = find_lib(library_directories, static_extensions); lib.has_value()) { + return lib; + } + + return std::nullopt; + } + + inline bool contains_static_flag(const CompilerFlags &flags) { + return std::any_of(flags.begin(), flags.end(), [](const auto& flag) { + return flag.type == CompilerFlagType::LINKER_LIBRARY_STATIC; + }); + } + + void processing_linker_options_flag(const CompilerFlag& flag, LibraryPriorityType& type) { + const auto& options = flag.arguments.front(); + size_t option_start = 0; + + while (option_start < options.size()) { + size_t option_end = options.find(',', option_start); + if (option_end == std::string::npos) { + option_end = options.size(); + } + const auto option = options.substr(option_start, option_end - option_start); + if (type != LibraryPriorityType::ONLY_STATIC_FIXED && option == "-Bdynamic") { + type = LibraryPriorityType::FIRSTLY_SHARED; + } + if (type != LibraryPriorityType::ONLY_STATIC_FIXED && option == "-Bstatic") { + type = LibraryPriorityType::ONLY_STATIC; + } + option_start = option_end + 1; + } + } + std::tuple< Arguments, std::list, std::list, std::optional - > split_compile(const CompilerFlags &flags) { + > split_compile(const CompilerFlags &flags, const std::vector& library_directories) { Arguments arguments; std::list sources; std::list dependencies; std::optional output; + std::vector added_library_directories; + LibraryPriorityType type = (contains_static_flag(flags)) + ? LibraryPriorityType::ONLY_STATIC_FIXED + : LibraryPriorityType::FIRSTLY_SHARED; + for (const auto &flag : flags) { switch (flag.type) { case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: { @@ -133,6 +253,21 @@ namespace { dependencies.emplace_back(candidate); break; } + case CompilerFlagType::LINKER_OPTIONS_FLAG: { + processing_linker_options_flag(flag, type); + break; + } + case CompilerFlagType::DIRECTORY_SEARCH_LIBRARY: { + added_library_directories.push_back(directory_path_from_flag(flag)); + break; + } + case CompilerFlagType::LINKER_LIBRARY_FLAG: { + const auto library = find_library(library_name_from_flag(flag), library_directories, added_library_directories, type); + if (library.has_value()) { + dependencies.push_back(library.value()); + } + break; + } default: { break; } @@ -147,12 +282,17 @@ namespace { std::list, std::optional, size_t - > split_link_with_updating_sources(const CompilerFlags &flags) { + > split_link_with_updating_sources(const CompilerFlags &flags, const std::vector& library_directories) { Arguments arguments; std::list files; std::optional output; size_t sources_count = 0; + std::vector added_library_directories; + LibraryPriorityType type = (contains_static_flag(flags)) + ? LibraryPriorityType::ONLY_STATIC_FIXED + : LibraryPriorityType::FIRSTLY_SHARED; + for (const auto &flag : flags) { switch (flag.type) { case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: { @@ -163,20 +303,35 @@ namespace { case CompilerFlagType::SOURCE: { sources_count++; const auto source_after_compilation = flag.arguments.front() + ".o"; - arguments.push_back(source_after_compilation); files.emplace_back(source_after_compilation); - break; + arguments.push_back(source_after_compilation); + continue; } case CompilerFlagType::LIBRARY: case CompilerFlagType::OBJECT_FILE: { - arguments.push_back(flag.arguments.front()); files.emplace_back(flag.arguments.front()); break; } + case CompilerFlagType::LINKER_OPTIONS_FLAG: { + processing_linker_options_flag(flag, type); + break; + } + case CompilerFlagType::DIRECTORY_SEARCH_LIBRARY: { + added_library_directories.push_back(directory_path_from_flag(flag)); + break; + } + case CompilerFlagType::LINKER_LIBRARY_FLAG: { + const auto library = find_library(library_name_from_flag(flag), library_directories, added_library_directories, type); + if (library.has_value()) { + files.push_back(library.value()); + } + break; + } default: { - std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); + break; } } + std::copy(flag.arguments.begin(), flag.arguments.end(), std::back_inserter(arguments)); } return std::make_tuple(arguments, files, output, sources_count); } @@ -252,12 +407,12 @@ namespace cs::semantic { {"-iwithprefixbefore", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}}, {"-isysroot", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}}, {"-imultilib", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}}, - {"-L", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH_LINKER}}, + {"-L", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH_LIBRARY}}, {"-B", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH}}, {"--sysroot", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::DIRECTORY_SEARCH}}, {"-flinker-output", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::LINKER}}, {"-fuse-ld", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::LINKER}}, - {"-l", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::LINKER}}, + {"-l", {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::LINKER_LIBRARY_FLAG}}, {"-nostartfiles", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, {"-nodefaultlibs", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, {"-nolibc", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, @@ -271,11 +426,12 @@ namespace cs::semantic { {"-rdynamic", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, {"-s", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, {"-symbolic", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}}, - {"-static", {MatchInstruction::PREFIX, CompilerFlagType::LINKER}}, + {"-static", {MatchInstruction::EXACTLY, CompilerFlagType::LINKER_LIBRARY_STATIC}}, + {"-static-", {MatchInstruction::PREFIX, CompilerFlagType::LINKER}}, {"-shared", {MatchInstruction::PREFIX, CompilerFlagType::LINKER}}, {"-T", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}}, {"-Xlinker", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}}, - {"-Wl,", {MatchInstruction::PREFIX, CompilerFlagType::LINKER}}, + {"-Wl,", {MatchInstruction::PREFIX, CompilerFlagType::LINKER_OPTIONS_FLAG}}, {"-u", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}}, {"-z", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}}, {"-Xassembler", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}}, @@ -358,7 +514,7 @@ namespace cs::semantic { } // arguments contains everything except output and sources - auto[arguments, sources, dependencies, output] = split_compile(flags); + auto[arguments, sources, dependencies, output] = split_compile(flags, get_library_directories(execution)); if (sources.empty()) { return rust::Err(std::runtime_error("Source files not found for compilation.")); } @@ -403,7 +559,7 @@ namespace cs::semantic { } // arguments contains everything except output - auto[arguments, files, output, sources_count] = split_link_with_updating_sources(flags); + auto[arguments, files, output, sources_count] = split_link_with_updating_sources(flags, get_library_directories(execution)); if (sources_count != 0 && !has_linker(flags)) { return rust::Err(std::runtime_error("Without linking.")); } diff --git a/source/citnames/test/ToolGccTest.cc b/source/citnames/test/ToolGccCompileTest.cc similarity index 63% rename from source/citnames/test/ToolGccTest.cc rename to source/citnames/test/ToolGccCompileTest.cc index a69f7889..f819c993 100644 --- a/source/citnames/test/ToolGccTest.cc +++ b/source/citnames/test/ToolGccCompileTest.cc @@ -26,7 +26,7 @@ using namespace cs::semantic; namespace { - TEST(ToolGcc, is_compiler_call) { + TEST(ToolGccCompile, is_compiler_call) { struct Expose : public ToolGcc { using ToolGcc::is_compiler_call; }; @@ -48,7 +48,7 @@ namespace { EXPECT_TRUE(sut.is_compiler_call("fortran")); } - TEST(ToolGcc, compilation_fails_on_empty) { + TEST(ToolGccCompile, fails_on_empty) { Execution input = {}; ToolGcc sut; @@ -56,7 +56,7 @@ namespace { EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::COMPILER))); } - TEST(ToolGcc, compilation_check_compilation_without_compilation) { + TEST(ToolGccCompile, without_compilation) { Execution input = { "/usr/bin/cc", {"cc", "-L.", "source_1.o", "lib.a", "source_2.o", "-la"}, @@ -68,7 +68,7 @@ namespace { EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::COMPILER))); } - TEST(ToolGcc, compilation_simple) { + TEST(ToolGccCompile, simple) { Execution input = { "/usr/bin/cc", {"cc", "-c", "-o", "source.o", "source.c"}, @@ -94,7 +94,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_output_filtered) { + TEST(ToolGccCompile, output_filtered) { Execution input = { "/usr/bin/cc", {"cc", "source.c", "-L.", "-lthing", "-o", "exe"}, @@ -120,7 +120,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_pass_on_help) { + TEST(ToolGccCompile, pass_on_help) { Execution input = { "/usr/bin/gcc", {"gcc", "--version"}, @@ -136,7 +136,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_simple_with_C_PATH) { + TEST(ToolGccCompile, simple_with_C_PATH) { Execution input = { "/usr/bin/cc", {"cc", "-c", "source.c"}, @@ -169,7 +169,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_with_linking_one_file) { + TEST(ToolGccCompile, with_linking_one_file) { Execution input = { "/usr/bin/cc", {"cc", "-o", "source", "source.c"}, @@ -195,7 +195,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_with_linking_with_obj) { + TEST(ToolGccCompile, with_linking_with_obj) { Execution input = { "/usr/bin/cc", {"cc", "source_1.c", "-o", "source", "source_2.c", "obj.o"}, @@ -221,7 +221,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_with_obj_and_libs) { + TEST(ToolGccCompile, with_obj_and_libs) { Execution input = { "/usr/bin/cc", {"cc", "-c", "lib.library", "source_1.c", "lib.so.2", "-o", "source", "source_2.c", "obj.o", "lib.dll"}, @@ -247,7 +247,7 @@ namespace { EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - TEST(ToolGcc, compilation_with_unknown_files) { + TEST(ToolGccCompile, with_unknown_files) { Execution input = { "/usr/bin/cc", {"cc", "-c", "lib.library", "lib", "aaaaa", "source_1.c", "lib.so", "-o", "source", "source_2.c", "obj.o", "lib.dll"}, @@ -272,135 +272,4 @@ namespace { EXPECT_TRUE(Tool::recognized_ok(result)); EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); } - -//--------------------------------------------------------------------------------------------------------- - - TEST(ToolGcc, is_linker_call) { - struct Expose : public ToolGcc { - using ToolGcc::is_linker_call; - }; - Expose sut; - - EXPECT_TRUE(sut.is_linker_call("cc")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/cc")); - EXPECT_TRUE(sut.is_linker_call("gcc")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc")); - EXPECT_TRUE(sut.is_linker_call("c++")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/c++")); - EXPECT_TRUE(sut.is_linker_call("g++")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/g++")); - EXPECT_TRUE(sut.is_linker_call("arm-none-eabi-g++")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/arm-none-eabi-g++")); - EXPECT_TRUE(sut.is_linker_call("gcc-6")); - EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc-6")); - EXPECT_TRUE(sut.is_linker_call("gfortran")); - EXPECT_TRUE(sut.is_linker_call("fortran")); - EXPECT_TRUE(sut.is_linker_call("ld")); - EXPECT_TRUE(sut.is_linker_call("lld")); - EXPECT_FALSE(sut.is_linker_call("ar")); - } - - TEST(ToolGcc, linking_fails_on_empty) { - Execution input = {}; - - ToolGcc sut; - - EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::LINKER))); - } - - TEST(ToolGcc, without_linking_simple) { - Execution input = { - "/usr/bin/cc", - {"cc", "-c", "-o", "source.o", "source.c"}, - "/home/user/project", - {}, - }; - - ToolGcc sut; - EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); - } - - TEST(ToolGcc, without_linking_with_object_files) { - Execution input = { - "/usr/bin/cc", - {"cc", "-c", "x.o", "x2.o", "-o", "source.o", "source.c"}, - "/home/user/project", - {}, - }; - - ToolGcc sut; - EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); - } - - TEST(ToolGcc, linking_with_compilation_one_file) { - Execution input = { - "/usr/bin/cc", - {"cc", "-o", "source", "source.c"}, - "/home/user/project", - {}, - }; - SemanticPtr expected = SemanticPtr( - new Link( - input.working_dir, - input.executable, - {"source.c.o"}, - {fs::path("source.c.o")}, - {fs::path("source")} - ) - ); - - ToolGcc sut({}); - - auto result = sut.recognize(input, BuildTarget::LINKER); - EXPECT_TRUE(Tool::recognized_ok(result)); - EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); - } - - TEST(ToolGcc, linking_with_compilation) { - Execution input = { - "/usr/bin/cc", - {"cc", "source_1.c", "-o", "source", "lib.o", "-la", "source_2.c"}, - "/home/user/project", - {}, - }; - SemanticPtr expected = SemanticPtr( - new Link( - input.working_dir, - input.executable, - {"source_1.c.o", "lib.o", "-la", "source_2.c.o"}, - {"source_1.c.o", "lib.o", "source_2.c.o"}, - {fs::path("source")} - ) - ); - - ToolGcc sut({}); - - auto result = sut.recognize(input, BuildTarget::LINKER); - EXPECT_TRUE(Tool::recognized_ok(result)); - EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); - } - - TEST(ToolGcc, linking) { - Execution input = { - "/usr/bin/cc", - {"cc", "-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, - "/home/user/project", - {}, - }; - SemanticPtr expected = SemanticPtr( - new Link( - input.working_dir, - input.executable, - {"-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, - {"source_1.o", "lib.DLL", "source_2.o"}, - std::nullopt - ) - ); - - ToolGcc sut({}); - - auto result = sut.recognize(input, BuildTarget::LINKER); - EXPECT_TRUE(Tool::recognized_ok(result)); - EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); - } } diff --git a/source/citnames/test/ToolGccLinkTest.cc b/source/citnames/test/ToolGccLinkTest.cc new file mode 100644 index 00000000..f49bc920 --- /dev/null +++ b/source/citnames/test/ToolGccLinkTest.cc @@ -0,0 +1,159 @@ +/* Copyright (C) 2012-2023 by László Nagy + This file is part of Bear. + + Bear is a tool to generate compilation database for clang tooling. + + Bear is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bear is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "gtest/gtest.h" + +#include "semantic/Tool.h" +#include "semantic/ToolGcc.h" + +using namespace cs::semantic; + +namespace { + + TEST(ToolGccLink, is_linker_call) { + struct Expose : public ToolGcc { + using ToolGcc::is_linker_call; + }; + Expose sut; + + EXPECT_TRUE(sut.is_linker_call("cc")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/cc")); + EXPECT_TRUE(sut.is_linker_call("gcc")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc")); + EXPECT_TRUE(sut.is_linker_call("c++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/c++")); + EXPECT_TRUE(sut.is_linker_call("g++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/g++")); + EXPECT_TRUE(sut.is_linker_call("arm-none-eabi-g++")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/arm-none-eabi-g++")); + EXPECT_TRUE(sut.is_linker_call("gcc-6")); + EXPECT_TRUE(sut.is_linker_call("/usr/bin/gcc-6")); + EXPECT_TRUE(sut.is_linker_call("gfortran")); + EXPECT_TRUE(sut.is_linker_call("fortran")); + EXPECT_TRUE(sut.is_linker_call("ld")); + EXPECT_TRUE(sut.is_linker_call("lld")); + EXPECT_FALSE(sut.is_linker_call("ar")); + } + + TEST(ToolGccLink, fails_on_empty) { + Execution input = {}; + + ToolGcc sut; + + EXPECT_TRUE(Tool::not_recognized(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGccLink, without_linking) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "-o", "source.o", "source.c"}, + "/home/user/project", + {}, + }; + + ToolGcc sut; + EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGccLink, without_linking_with_object_files) { + Execution input = { + "/usr/bin/cc", + {"cc", "-c", "x.o", "x2.o", "-o", "source.o", "source.c"}, + "/home/user/project", + {}, + }; + + ToolGcc sut; + EXPECT_TRUE(Tool::recognized_with_error(sut.recognize(input, BuildTarget::LINKER))); + } + + TEST(ToolGccLink, with_compilation_one_file) { + Execution input = { + "/usr/bin/cc", + {"cc", "-o", "source", "source.c"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"source.c.o"}, + {fs::path("source.c.o")}, + {fs::path("source")} + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGccLink, with_compilation) { + // lib a does not exist + Execution input = { + "/usr/bin/cc", + {"cc", "source_1.c", "-o", "source", "lib.o", "-la", "source_2.c"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"source_1.c.o", "lib.o", "-la", "source_2.c.o"}, + {"source_1.c.o", "lib.o", "source_2.c.o"}, + {fs::path("source")} + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } + + TEST(ToolGccLink, big) { + // lib a does not exist + Execution input = { + "/usr/bin/cc", + {"cc", "-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, + "/home/user/project", + {}, + }; + SemanticPtr expected = SemanticPtr( + new Link( + input.working_dir, + input.executable, + {"-L.", "source_1.o", "uncorrect_lib", "lib.DLL", "source_2.o", "-la"}, + {"source_1.o", "lib.DLL", "source_2.o"}, + std::nullopt + ) + ); + + ToolGcc sut({}); + + auto result = sut.recognize(input, BuildTarget::LINKER); + EXPECT_TRUE(Tool::recognized_ok(result)); + EXPECT_PRED2([](auto lhs, auto rhs) { return lhs->operator==(*rhs); }, expected, result.unwrap()); + } +} diff --git a/test/bin/assert_compilation b/test/bin/assert_compilation index ae253b43..7a0b2101 100755 --- a/test/bin/assert_compilation +++ b/test/bin/assert_compilation @@ -82,11 +82,11 @@ def filter_from(args): def to_string(args): - p1 = '' if args.file is None else '-file {}'.format(args.file) - p2 = '' if args.files is None else ' '.join(['-files'] + args.files) - p3 = '' if args.output is None else '-output {}'.format(args.output) - p4 = '' if args.directory is None else '-directory {}'.format(args.directory) - p5 = '' if args.arguments is None else ' '.join(['-arguments'] + args.arguments) + p1 = '' if args.file is None else '\n-file {}'.format(args.file) + p2 = '' if args.files is None else ' '.join(['\n-files'] + args.files) + p3 = '' if args.output is None else '\n-output {}'.format(args.output) + p4 = '' if args.directory is None else '\n-directory {}'.format(args.directory) + p5 = '' if args.arguments is None else ' '.join(['\n-arguments'] + args.arguments) return ' '.join([p1, p2, p3, p4, p5]) diff --git a/test/cases/compilation/output/flags_filtered_link.sh b/test/cases/compilation/output/flags_filtered_link.sh index a9484a9e..5652810f 100644 --- a/test/cases/compilation/output/flags_filtered_link.sh +++ b/test/cases/compilation/output/flags_filtered_link.sh @@ -5,8 +5,8 @@ # 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 -lfoobar -L. -o flags_filtered_link_3.c.o flags_filtered_link_3.c -# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_4.c -directory %T -arguments %{c_compiler} -c -l foobar -L . -o flags_filtered_link_4.c.o flags_filtered_link_4.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_3.c -files %T/libfoobar.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L. -lfoobar -o flags_filtered_link_3.c.o flags_filtered_link_3.c +# RUN: assert_compilation %t.json contains -file %T/flags_filtered_link_4.c -files %T/libfoobar.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L . -l foobar -o flags_filtered_link_4.c.o flags_filtered_link_4.c # set up platform specific linker options PREFIX="foobar"; @@ -26,5 +26,5 @@ $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; +$CC -o flags_filtered_link_3 -L. -l${PREFIX} flags_filtered_link_3.c; +$CC -o flags_filtered_link_4 -L . -l ${PREFIX} flags_filtered_link_4.c; diff --git a/test/cases/compilation/output/linking/flag_wl.sh b/test/cases/compilation/output/linking/flag_wl.sh new file mode 100644 index 00000000..936a1aa7 --- /dev/null +++ b/test/cases/compilation/output/linking/flag_wl.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh + +# UNSUPPORTED: is_darwin + +# RUN: touch %T/libflag_wl_1.%{dynamic_lib_extension} +# RUN: ar -q -c %T/libflag_wl_2.a +# RUN: touch %T/libflag_wl_2.%{dynamic_lib_extension} + +# RUN: mkdir -p %T/other +# RUN: ar -q -c %T/other/libflag_wl_3.a +# RUN: ar -q -c %T/other/libflag_wl_1.a +# RUN: touch %T/other/libflag_wl_3.%{dynamic_lib_extension} +# RUN: touch %T/other/libflag_wl_1.%{dynamic_lib_extension} + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/flag_wl.c -files %T/other/libflag_wl_3.a %T/other/libflag_wl_1.a %T/other/libflag_wl_1.%{dynamic_lib_extension} %T/libflag_wl_2.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 -o flag_wl.c.o flag_wl.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/flag_wl.c.o %T/other/libflag_wl_3.a %T/other/libflag_wl_1.a %T/other/libflag_wl_1.%{dynamic_lib_extension} %T/libflag_wl_2.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} flag_wl.c.o -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 -o flag_wl + +echo "int main() { return 0; }" > flag_wl.c + +$CC -o flag_wl flag_wl.c -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 diff --git a/test/cases/compilation/output/linking/some_dir_for_libs.sh b/test/cases/compilation/output/linking/some_dir_for_libs.sh new file mode 100644 index 00000000..e86e4fa4 --- /dev/null +++ b/test/cases/compilation/output/linking/some_dir_for_libs.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: printf "int foo() { return 1; }" > %T/libsome_dir_for_libs.c +# RUN: gcc -c %T/libsome_dir_for_libs.c -o %T/libsome_dir_for_libs.o +# RUN: ar -q -c %T/libsome_dir_for_libs.a %T/libsome_dir_for_libs.o + +# RUN: mkdir -p %T/other +# RUN: printf "int foo() { return 1; }" > %T/other/libsome_dir_for_libs.c +# RUN: gcc -c %T/other/libsome_dir_for_libs.c -o %T/other/libsome_dir_for_libs.o +# RUN: ar -q -c %T/other/libsome_dir_for_libs.a %T/other/libsome_dir_for_libs.o + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/some_dir_for_libs.c -files %T/other/libsome_dir_for_libs.a -directory %T -arguments %{c_compiler} -c -L ./other -L. -lsome_dir_for_libs -o some_dir_for_libs.c.o some_dir_for_libs.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/other/libsome_dir_for_libs.a %T/some_dir_for_libs.c.o -directory %T -arguments %{c_compiler} -L ./other -L. -lsome_dir_for_libs some_dir_for_libs.c.o -o some_dir_for_libs + +echo "int main() { return 0; }" > some_dir_for_libs.c + +$CC -o some_dir_for_libs -L ./other -L. -lsome_dir_for_libs some_dir_for_libs.c diff --git a/test/cases/compilation/output/linking/some_libs.sh b/test/cases/compilation/output/linking/some_libs.sh new file mode 100644 index 00000000..bea0f4e0 --- /dev/null +++ b/test/cases/compilation/output/linking/some_libs.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: printf "int foo() { return 1; }" > %T/libsome_libs.c +# RUN: gcc -c %T/libsome_libs.c -o %T/libsome_libs.o +# RUN: ar -q -c %T/libsome_libs.a %T/libsome_libs.o + +# RUN: echo "int bar() { return 2; }" > %T/libsome_libs_1.c +# RUN: gcc -c -o %T/libsome_libs_1.o -fpic %T/libsome_libs_1.c +# RUN: gcc %{some_libs_flags} %T/libsome_libs_1.o + +# RUN: mkdir -p %T/other +# RUN: printf "int foo() { return 1; }" > %T/other/libsome_libs.c +# RUN: gcc -c %T/other/libsome_libs.c -o %T/other/libsome_libs.o +# RUN: ar -q -c %T/other/libsome_libs.a %T/other/libsome_libs.o + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/some_libs.c -files %T/libsome_libs.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L ./other -L. -lsome_libs -o some_libs.c.o some_libs.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/libsome_libs.%{dynamic_lib_extension} %T/some_libs.c.o -directory %T -arguments %{c_compiler} -L ./other -L. -lsome_libs some_libs.c.o -o some_libs + +echo "int main() { return 0; }" > some_libs.c + +$CC -o some_libs -L ./other -L. -lsome_libs some_libs.c diff --git a/test/cases/compilation/output/linking/with_static_lib.sh b/test/cases/compilation/output/linking/with_static_lib.sh new file mode 100644 index 00000000..49a1f109 --- /dev/null +++ b/test/cases/compilation/output/linking/with_static_lib.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env sh + +# REQUIRES: shell + +# RUN: printf "int foo() { return 1; }" > %T/libwith_static_lib.c +# RUN: gcc -c %T/libwith_static_lib.c -o %T/libwith_static_lib.o +# RUN: ar -q -c %T/libwith_static_lib.a %T/libwith_static_lib.o + +# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: assert_compilation %t.json count -eq 1 +# RUN: assert_compilation %t.json contains -file %T/with_static_lib.c -files %T/libwith_static_lib.a -directory %T -arguments %{c_compiler} -c -L. -lwith_static_lib -o with_static_lib.c.o with_static_lib.c +# RUN: assert_compilation %t_link.json count -eq 1 +# RUN: assert_compilation %t_link.json contains -files %T/libwith_static_lib.a %T/with_static_lib.c.o -directory %T -arguments %{c_compiler} -L. -lwith_static_lib with_static_lib.c.o -o with_static_lib + +echo "int main() { return 0; }" > with_static_lib.c + +$CC -o with_static_lib -L. -lwith_static_lib with_static_lib.c diff --git a/test/lit.cfg b/test/lit.cfg index 118c979a..d3846934 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -86,6 +86,16 @@ citnames_cmd = '{} citnames'.format( config.substitutions.append(('%{citnames}', citnames_cmd)) +if sys.platform in ['darwin']: + config.available_features.add('is_darwin') + config.substitutions.append(('%{dynamic_lib_extension}', 'dylib')) + config.substitutions.append(('%{some_libs_flags}', '-o %T/libsome_libs.dylib -dynamiclib -install_name @rpath/some_libs')) + +if not (sys.platform in ['darwin']): + config.substitutions.append(('%{dynamic_lib_extension}', 'so')) + config.substitutions.append(('%{some_libs_flags}', '-o %T/libsome_libs.so -shared -Wl,-soname,some_libs')) + + # check if a shell is available shell_path = None if which('sh'): From 19968957d6633308ca525a07c53f739189c78549 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+mamaria-k@users.noreply.github.com> Date: Fri, 9 Jun 2023 19:15:54 +0300 Subject: [PATCH 5/7] Fix case with unsorted events (#9) * Fix case with unsorted events --- source/citnames/source/Citnames.cc | 101 +++++++++++++----- test/cases/citnames/output/unsorted_events.sh | 20 ++++ 2 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 test/cases/citnames/output/unsorted_events.sh diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index 8a289d3d..c7587fc9 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -28,6 +28,7 @@ #include #include +#include #ifdef HAVE_FMT_STD_H #include @@ -44,6 +45,11 @@ template <> struct fmt::formatter : ostream_formatter {}; namespace { + struct EventEntries { + std::list compile; + std::list link; + }; + std::list to_abspath(const std::list &paths, const fs::path &root) { std::list results; for (const auto &path : paths) { @@ -194,15 +200,49 @@ namespace { }); } - rust::Result transform( - cs::semantic::Build &build, + bool transform_event( + const cs::semantic::Build &build, + const rpc::Event &event, + std::map &pid_entries, + const bool with_link + ) { + const auto get_entries = [](const auto &semantic) -> std::list { + const auto candidate = dynamic_cast(semantic.get()); + return (candidate != nullptr) ? candidate->into_entries() : std::list(); + }; + + const size_t pid = event.started().pid(); + bool is_written = false; + + auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER).map>(get_entries).unwrap_or({}); + if (!entries_compile.empty()) { + is_written = true; + std::move(entries_compile.begin(), entries_compile.end(), std::back_inserter(pid_entries[pid].compile)); + } + if (with_link) { + auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER).map>(get_entries).unwrap_or({}); + if (!entries_link.empty()) { + is_written = true; + std::move(entries_link.begin(), entries_link.end(), std::back_inserter(pid_entries[pid].link)); + } + } + + return is_written; + } + + size_t transform( + const cs::semantic::Build &build, const db::EventsDatabaseReader::Ptr& events, std::list &output_compile, std::list &output_link, const bool with_link ) { - std::set all_ppid; - std::set writed_command_pids; + std::set writed_event_pids; + std::map> pid_children; + std::set pids_without_parent; + std::set pids_with_parent; + + std::map pid_entries; for (const rpc::Event &event : *events) { const size_t pid = event.started().pid(); @@ -211,38 +251,43 @@ namespace { continue; } - if (all_ppid.find(pid) != all_ppid.end()) { - return rust::Err(std::runtime_error("Processes in events database are not sorted!")); + pid_children[ppid].insert(pid); + pids_without_parent.erase(pid); + pids_with_parent.insert(pid); + if (pids_with_parent.find(ppid) == pids_with_parent.end()) { + pids_without_parent.insert(ppid); } - all_ppid.insert(ppid); - if (writed_command_pids.find(ppid) != writed_command_pids.end()) { - writed_command_pids.insert(pid); - continue; + if (writed_event_pids.find(ppid) != writed_event_pids.end()) { + writed_event_pids.insert(pid); + } + else if (transform_event(build, event, pid_entries, with_link)) { + writed_event_pids.insert(pid); } + } - const auto get_entries = [](const auto &semantic) -> std::list { - const auto candidate = dynamic_cast(semantic.get()); - return (candidate != nullptr) ? candidate->into_entries() : std::list(); - }; + for (const auto &p : pids_without_parent) { + std::vector pids; + std::copy(pid_children[p].rbegin(), pid_children[p].rend(), std::back_inserter(pids)); - const auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER) - .map>(get_entries).unwrap_or({}); - if (!entries_compile.empty()) { - writed_command_pids.insert(pid); - std::copy(entries_compile.begin(), entries_compile.end(), std::back_inserter(output_compile)); - } + while (!pids.empty()) { + const auto cur_pid = pids.back(); + pids.pop_back(); - if (with_link) { - const auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER) - .map>(get_entries).unwrap_or({}); - if (!entries_link.empty()) { - writed_command_pids.insert(pid); - std::copy(entries_link.begin(), entries_link.end(), std::back_inserter(output_link)); + auto entries_iter = pid_entries.find(cur_pid); + // tree before meaningful event + if (entries_iter == pid_entries.end()) { + std::copy(pid_children[cur_pid].rbegin(), pid_children[cur_pid].rend(), std::back_inserter(pids)); + } + // meaningful event, children should not be written + else { + std::move(entries_iter->second.compile.begin(), entries_iter->second.compile.end(), std::back_inserter(output_compile)); + std::move(entries_iter->second.link.begin(), entries_iter->second.link.end(), std::back_inserter(output_link)); } } } - return rust::Ok(output_compile.size() + output_link.size()); + + return output_compile.size() + output_link.size(); } rust::Result complete_entries_from_json( @@ -286,7 +331,7 @@ namespace cs { std::list entries_link; return db::EventsDatabaseReader::from(arguments_.input) - .and_then([this, &entries_compile, &entries_link](const auto &commands) { + .map([this, &entries_compile, &entries_link](const auto &commands) { cs::semantic::Build build(configuration_.compilation); return transform(build, commands, entries_compile, entries_link, arguments_.with_link); }) diff --git a/test/cases/citnames/output/unsorted_events.sh b/test/cases/citnames/output/unsorted_events.sh new file mode 100644 index 00000000..6c41fd15 --- /dev/null +++ b/test/cases/citnames/output/unsorted_events.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# RUN: cd %T; %{shell} %s %t +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json +# RUN: assert_compilation %t.compilations.json count -eq 1 + +cat << EOF > "$1.commands.json" +{"rid":"5208588700335725496","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.573991Z"} +{"rid":"5982815742339840829","started":{"execution":{"executable":"/usr/lib/gcc/x86_64-linux-gnu/11/collect2","arguments":["/usr/lib/gcc/x86_64-linux-gnu/11/collect2"],"working_dir":"example/build","environment":{}},"pid":13896,"ppid":13868},"timestamp":"2023-05-26T11:42:25.580038Z"} +{"rid":"16827070368060185859","started":{"execution":{"executable":"/usr/bin/ld","arguments":["/usr/bin/ld"],"working_dir":"example/build","environment":{}},"pid":13904,"ppid":13896},"timestamp":"2023-05-26T11:42:25.585572Z"} +{"rid":"16827070368060185859","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.638394Z"} +{"rid":"5982815742339840829","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.639796Z"} +{"rid":"11620369640675796770","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.641203Z"} +{"rid":"3208622825367537157","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.642386Z"} +{"rid":"3208622825367537157","started":{"execution":{"executable":"/usr/bin/make","arguments":["make","-f","../Makefile"],"working_dir":"example/build","environment":{}},"pid":13860,"ppid":13847},"timestamp":"2023-05-26T11:42:25.322304Z"} +{"rid":"11620369640675796770","started":{"execution":{"executable":"/usr/bin/g++","arguments":["g++","../main.cpp"],"working_dir":"example/build","environment":{}},"pid":13868,"ppid":13860},"timestamp":"2023-05-26T11:42:25.332432Z"} +{"rid":"1195915605071429231","started":{"execution":{"executable":"/usr/lib/gcc/x86_64-linux-gnu/11/cc1plus","arguments":["/usr/lib/gcc/x86_64-linux-gnu/11/cc1plus"],"working_dir":"example/build","environment":{}},"pid":13876,"ppid":13868},"timestamp":"2023-05-26T11:42:25.345192Z"} +{"rid":"1195915605071429231","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.563234Z"} +{"rid":"5208588700335725496","started":{"execution":{"executable":"/usr/bin/as","arguments":["as"],"working_dir":"example/build","environment":{}},"pid":13888,"ppid":13868},"timestamp":"2023-05-26T11:42:25.568801Z"} +EOF \ No newline at end of file From a190fa1a323df84679404f23543a4fc040443b91 Mon Sep 17 00:00:00 2001 From: Maria Date: Thu, 29 Jun 2023 17:07:51 +0300 Subject: [PATCH 6/7] Return original flags and add setting up the creation of a linking database to the configuration file --- source/bear/man/bear.1.md | 16 +-- source/bear/source/Application.cc | 116 ++++++++---------- source/citnames/man/bear-citnames.1.md | 36 +++--- source/citnames/source/Citnames.cc | 72 ++++++----- source/citnames/source/Citnames.h | 4 +- source/citnames/source/Configuration.cc | 41 ++++++- source/citnames/source/Configuration.h | 7 ++ source/config.h.in | 6 +- .../exit_code/exit_code_for_success.sh | 2 +- test/cases/citnames/output/clang_plugin.sh | 2 +- test/cases/citnames/output/convert_format.sh | 2 +- .../citnames/output/linking_with_filename.sh | 16 +++ .../output/linking_without_filename.sh | 15 +++ .../output/relative_paths_converted.sh | 2 +- test/cases/citnames/output/unsorted_events.sh | 2 +- .../citnames/output/wrapper_flags_extended.sh | 2 +- .../exit_code/exit_code_for_fail.sh | 2 +- .../exit_code/exit_code_for_success.sh | 2 +- .../compilation/output/assembly_sources.mk | 2 +- test/cases/compilation/output/broken_build.sh | 2 +- test/cases/compilation/output/bug439.mk | 2 +- test/cases/compilation/output/compile_cuda.sh | 2 +- .../compilation/output/compile_fortran.sh | 2 +- .../output/config/filter_compilers.sh | 2 +- .../compilation/output/config/filter_flags.sh | 4 +- .../config/filter_flags_on_known_compiler.sh | 4 +- .../output/config/filter_sources.sh | 2 +- .../output/config/filter_sources_relative.sh | 2 +- .../output/define_with_escaped_quote.sh | 2 +- .../compilation/output/define_with_quote.sh | 2 +- .../compilation/output/duplicate_entries.sh | 2 +- .../compilation/output/empty_argument.sh | 2 +- test/cases/compilation/output/empty_env.sh | 2 +- .../compilation/output/existing_files_only.sh | 2 +- test/cases/compilation/output/flag/append.sh | 6 +- .../compilation/output/flag/field_output.sh | 2 +- test/cases/compilation/output/flag/use_cc.sh | 8 +- test/cases/compilation/output/flag/use_cxx.sh | 8 +- .../compilation/output/flags_filtered_link.sh | 2 +- .../output/flags_filtered_preproc.sh | 2 +- .../compilation/output/linking/append.sh | 16 ++- .../output/linking/compile_link_one_file.sh | 10 +- .../output/linking/compile_link_some_files.sh | 10 +- .../compilation/output/linking/flag_wl.sh | 10 +- .../not_append_without_link_database.sh | 10 +- .../output/linking/some_dir_for_libs.sh | 10 +- .../compilation/output/linking/some_libs.sh | 10 +- .../output/linking/with_static_lib.sh | 10 +- .../output/linking/without_link_flag.sh | 11 -- .../output/multiple_source_build.sh | 2 +- .../compilation/output/parallel_build.sh | 2 +- .../compilation/output/successful_build.sh | 2 +- .../compilation/output/with_other_files.sh | 2 +- test/cases/compilation/output/wrapper.sh | 4 +- 54 files changed, 308 insertions(+), 210 deletions(-) create mode 100644 test/cases/citnames/output/linking_with_filename.sh create mode 100644 test/cases/citnames/output/linking_without_filename.sh delete mode 100644 test/cases/compilation/output/linking/without_link_flag.sh diff --git a/source/bear/man/bear.1.md b/source/bear/man/bear.1.md index 1d945f6a..22c3a49f 100644 --- a/source/bear/man/bear.1.md +++ b/source/bear/man/bear.1.md @@ -34,17 +34,9 @@ compilation and linking databases. \--verbose : Enable verbose logging. -\--with-link -: Use if you want to generate a linking database. - -\--output-compile *file* -: Specify output compile file. (Default file name provided.) The output is - currently a JSON compilation database. - -\--output-link *file* -: Specify output link file. (Default file name provided.) The output is - currently a JSON linking database. - Used only if --with-link is used, ignored otherwise. +\--output *file* +: Specify output file. (Default file name provided.) The output is + a JSON compilation database. \--append : Use previously generated output file and append the new entries to it. @@ -52,7 +44,7 @@ compilation and linking databases. compilation database up to date. File deletion and addition are both considered. But build process change (compiler flags change) might cause duplicate entries. - When used with --with-link, requires the existence of both database files. + When creating a database using linking, both database files are required. Otherwise, overwrites existing data. \--config *file* diff --git a/source/bear/source/Application.cc b/source/bear/source/Application.cc index 4eedb219..7db1755f 100644 --- a/source/bear/source/Application.cc +++ b/source/bear/source/Application.cc @@ -69,32 +69,26 @@ namespace { rust::Result prepare_citnames(const flags::Arguments &arguments, const sys::env::Vars &environment, const fs::path &input) { auto program = arguments.as_string(cmd::bear::FLAG_BEAR); - auto with_link = arguments.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); - auto output_compile = arguments.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE); - auto output_link = arguments.as_string(cmd::citnames::FLAG_OUTPUT_LINK); + auto output = arguments.as_string(cmd::citnames::FLAG_OUTPUT); auto config = arguments.as_string(cmd::citnames::FLAG_CONFIG); auto append = arguments.as_bool(cmd::citnames::FLAG_APPEND).unwrap_or(false); auto verbose = arguments.as_bool(flags::VERBOSE).unwrap_or(false); - return rust::merge(program, output_compile, output_link) - .map([&environment, &input, &config, &append, &verbose, &with_link](auto tuple) { - const auto&[program, output_compile, output_link] = tuple; + return rust::merge(program, output) + .map([&environment, &input, &config, &append, &verbose](auto tuple) { + const auto&[program, output] = tuple; auto builder = sys::Process::Builder(program) .set_environment(environment) .add_argument(program) .add_argument("citnames") .add_argument(cmd::citnames::FLAG_INPUT).add_argument(input) - .add_argument(cmd::citnames::FLAG_OUTPUT_COMPILE).add_argument(output_compile) - .add_argument(cmd::citnames::FLAG_OUTPUT_LINK).add_argument(output_link) + .add_argument(cmd::citnames::FLAG_OUTPUT).add_argument(output) // can run the file checks, because we are on the host. .add_argument(cmd::citnames::FLAG_RUN_CHECKS); if (append) { builder.add_argument(cmd::citnames::FLAG_APPEND); } - if (with_link) { - builder.add_argument(cmd::citnames::FLAG_WITH_LINK); - } if (config.is_ok()) { builder.add_argument(cmd::citnames::FLAG_CONFIG).add_argument(config.unwrap()); } @@ -151,7 +145,7 @@ namespace bear { rust::Result Application::parse(int argc, const char **argv) const { - const flags::Parser intercept_parser("intercept", cmd::VERSION, { + const flags::Parser intercept_parser("intercept", cmd::VERSION, { {cmd::intercept::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, DEVELOPER_GROUP}}, @@ -159,65 +153,59 @@ namespace bear { {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} - }); - - const flags::Parser citnames_parser("citnames", cmd::VERSION, { - {cmd::citnames::FLAG_INPUT, {1, false, "path of the input file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, - {cmd::citnames::FLAG_WITH_LINK, {0, false, "whether to create a link base", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_OUTPUT_COMPILE, {1, false, "path of the result compile file", {cmd::citnames::DEFAULT_OUTPUT_COMPILE}, std::nullopt}}, - {cmd::citnames::FLAG_OUTPUT_LINK, {1, false, "path of the result link file", {cmd::citnames::DEFAULT_OUTPUT_LINK}, std::nullopt}}, - {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_APPEND, {0, false, "append to output, instead of overwrite it", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_RUN_CHECKS, {0, false, "can run checks on the current host", std::nullopt, std::nullopt}} - }); - - const flags::Parser parser("bear", cmd::VERSION, {intercept_parser, citnames_parser}, { - {cmd::citnames::FLAG_WITH_LINK, {0, false, "whether to create a link base", std::nullopt, std::nullopt}}, - {cmd::citnames::FLAG_OUTPUT_COMPILE, {1, false, "path of the result compile file", {cmd::citnames::DEFAULT_OUTPUT_COMPILE}, std::nullopt}}, - {cmd::citnames::FLAG_OUTPUT_LINK, {1, false, "path of the result link file", {cmd::citnames::DEFAULT_OUTPUT_LINK}, std::nullopt}}, - {cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}}, - {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}}, - {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}}, - {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}}, - {cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, - {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} - }); - return parser.parse_or_exit(argc, const_cast(argv)); + }); + + const flags::Parser citnames_parser("citnames", cmd::VERSION, { + {cmd::citnames::FLAG_INPUT, {1, false, "path of the input file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}}, + {cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}}, + {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_APPEND, {0, false, "append to output, instead of overwrite it", std::nullopt, std::nullopt}}, + {cmd::citnames::FLAG_RUN_CHECKS, {0, false, "can run checks on the current host", std::nullopt, std::nullopt}} + }); + + const flags::Parser parser("bear", cmd::VERSION, {intercept_parser, citnames_parser}, { + {cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}}, + {cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}}, + {cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}}, + {cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}}, + {cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}}, + {cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}}, + {cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}} + }); + return parser.parse_or_exit(argc, const_cast(argv)); } rust::Result Application::command(const flags::Arguments &args, const char **envp) const { - if (args.as_string(flags::COMMAND).is_ok()) { - if (auto citnames = cs::Citnames(log_config_); citnames.matches(args)) { - return citnames.subcommand(args, envp); - } - if (auto intercept = ic::Intercept(log_config_); intercept.matches(args)) { - return intercept.subcommand(args, envp); - } - - return rust::Err(std::runtime_error("Invalid subcommand")); + if (args.as_string(flags::COMMAND).is_ok()) { + if (auto citnames = cs::Citnames(log_config_); citnames.matches(args)) { + return citnames.subcommand(args, envp); + } + if (auto intercept = ic::Intercept(log_config_); intercept.matches(args)) { + return intercept.subcommand(args, envp); } - // now only the name of the compile file is used - // to generate the name of the intermediate file (events) - auto commands = args.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE) - .map([](const auto &output) { - return fs::path(output).replace_extension(".events.json"); - }) - .unwrap_or(fs::path(cmd::intercept::DEFAULT_OUTPUT)); + return rust::Err(std::runtime_error("Invalid subcommand")); + } - auto environment = sys::env::from(const_cast(envp)); - auto intercept = prepare_intercept(args, environment, commands); - auto citnames = prepare_citnames(args, environment, commands); + auto commands = args.as_string(cmd::citnames::FLAG_OUTPUT) + .map([](const auto &output) { + return fs::path(output).replace_extension(".events.json"); + }) + .unwrap_or(fs::path(cmd::intercept::DEFAULT_OUTPUT)); - return rust::merge(intercept, citnames) - .map([&commands](const auto &tuple) { - const auto&[intercept, citnames] = tuple; + auto environment = sys::env::from(const_cast(envp)); + auto intercept = prepare_intercept(args, environment, commands); + auto citnames = prepare_citnames(args, environment, commands); - return std::make_unique(intercept, citnames, commands); - }); + return rust::merge(intercept, citnames) + .map([&commands](const auto &tuple) { + const auto&[intercept, citnames] = tuple; + + return std::make_unique(intercept, citnames, commands); + }); } -} +} \ No newline at end of file diff --git a/source/citnames/man/bear-citnames.1.md b/source/citnames/man/bear-citnames.1.md index dceaaaf0..e1ea3cdc 100644 --- a/source/citnames/man/bear-citnames.1.md +++ b/source/citnames/man/bear-citnames.1.md @@ -39,25 +39,17 @@ is currently the only output of the tool.) command execution list, with some extra information. The syntax is detailed in a separate section. -\--with-link -: Use if you want to generate a linking database. - -\--output-compile *file* -: Specify output compile file. (Default file name provided.) The output is +\--output *file* +: Specify output file. (Default file name provided.) The output is currently a JSON compilation database. -\--output-link *file* -: Specify output link file. (Default file name provided.) The output is - currently a JSON linking database. - Used only if --with-link is used, ignored otherwise. - \--append : Use previously generated output file and append the new entries to it. This way you can run continuously during work, and it keeps the compilation database up to date. File deletion and addition are both considered. But build process change (compiler flags change) might cause duplicate entries. - When used with --with-link, requires the existence of both database files. + When creating a database using linking, both database files are required. Otherwise, overwrites existing data. \--run-checks @@ -89,19 +81,16 @@ of a build. Read more about the syntax of the file in the `bear-intercept(1)` man page. -# OUTPUT COMPILE FILE +# OUTPUT FILE -Currently, the output format is the JSON compilation database. +Currently, the only output format is the JSON compilation database. Read more about the syntax of that in the `bear(1)` man page. -# OUTPUT LINK FILE - -JSON linking database. - # CONFIG FILE -The config file influences the command recognition (by the section "compilation") -and the output format (by the section "output"). +The config file influences the command recognition (by the section "compilation"), +the output format (by the section "output") and the setting for creating a linking database +(by the section "linking"). The config file is optional. The program will use default values, which can be dumped with the `--verbose` flags. @@ -132,6 +121,9 @@ the command line argument overrides the config file values. "command_as_array": true, "drop_output_field": false } + }, + "linking": { + "filename": "link.json" } } ``` @@ -161,13 +153,17 @@ the command line argument overrides the config file values. values for this field are: `all`, `file` and `file_output`. `without_duplicate_filter` is intended to disable the filtering of duplicate entries when generating a database. `without_existence_check` is intended to disable existence check for sources/object files when generating a database. - In this version `without_duplicate_filter=true` and `without_existence_check=true`, only when used `--with-link`. + In this version `without_duplicate_filter=true` and `without_existence_check=true`, only when used ``. `output.format` : The `command_as_array` controls which command field is emitted in the output. True produces `arguments`, false produces `command` field. The `drop_output_field` will disable the `output` field from the output. +`linking` +: Specifies the creation of a linking database. Can contain optional field `filename`, + which contains the name of the file that will be used to create the database. + # SEE ALSO `bear(1)`, `bear-intercept(1)` diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index c7587fc9..95e5cc1d 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -109,20 +109,17 @@ namespace { rust::Result into_arguments(const flags::Arguments &args) { auto input = args.as_string(cmd::citnames::FLAG_INPUT); - auto output_compile = args.as_string(cmd::citnames::FLAG_OUTPUT_COMPILE); - auto output_link = args.as_string(cmd::citnames::FLAG_OUTPUT_LINK); - auto append = args.as_bool(cmd::citnames::FLAG_APPEND).unwrap_or(false); - auto with_link = args.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); - - return rust::merge(input, output_compile, output_link) - .map([&append, &with_link](auto tuple) { - const auto&[input, output_compile, output_link] = tuple; + auto output = args.as_string(cmd::citnames::FLAG_OUTPUT); + auto append = args.as_bool(cmd::citnames::FLAG_APPEND) + .unwrap_or(false); + + return rust::merge(input, output) + .map([&append](auto tuple) { + const auto&[input, output] = tuple; return cs::Arguments{ fs::path(input), - fs::path(output_compile), - fs::path(output_link), - append, - with_link + fs::path(output), + append }; }) .and_then([](auto arguments) -> rust::Result { @@ -133,11 +130,10 @@ namespace { } return rust::Ok(cs::Arguments{ arguments.input, - arguments.output_compile, - arguments.output_link, - (arguments.append && is_exists(arguments.output_compile) - && (!arguments.with_link || is_exists(arguments.output_link))), - arguments.with_link + arguments.output, + arguments.append && is_exists(arguments.output) +// (arguments.append && is_exists(arguments.output) +// && (!arguments.with_link || is_exists(arguments.output_link))) }); }); } @@ -156,9 +152,8 @@ namespace { return result; } - void customize_configuration(cs::Configuration& configuration, const flags::Arguments &args) { - auto with_link = args.as_bool(cmd::citnames::FLAG_WITH_LINK).unwrap_or(false); - if (with_link) { + void customize_configuration(cs::Configuration& configuration) { + if (configuration.linking.has_value()) { configuration.output.content.without_existence_check = true; configuration.output.content.without_duplicate_filter = true; } @@ -191,8 +186,8 @@ namespace { update_compilers_to_recognize(config.compilation.compilers_to_recognize, env_compilers); return config; }) - .map([&args](auto config) { - customize_configuration(config, args); + .map([](auto config) { + customize_configuration(config); return config; }) .on_success([](const auto &config) { @@ -291,7 +286,7 @@ namespace { } rust::Result complete_entries_from_json( - cs::CompilationDatabase& output, + cs::CompilationDatabase& output, const fs::path& output_file, std::list& entries, size_t new_entries_counts, @@ -330,30 +325,33 @@ namespace cs { std::list entries_compile; std::list entries_link; + const bool with_link = configuration_.linking.has_value(); + const bool append = arguments_.append && (!with_link || is_exists(configuration_.linking.value().filename)); + return db::EventsDatabaseReader::from(arguments_.input) - .map([this, &entries_compile, &entries_link](const auto &commands) { + .map([this, &entries_compile, &entries_link, with_link](const auto &commands) { cs::semantic::Build build(configuration_.compilation); - return transform(build, commands, entries_compile, entries_link, arguments_.with_link); + return transform(build, commands, entries_compile, entries_link, with_link); }) - .and_then([this, &output_compile, &entries_compile](size_t new_entries_count) { + .and_then([this, &output_compile, &entries_compile, append](size_t new_entries_count) { spdlog::debug("entries created. [size: {}]", new_entries_count); - return complete_entries_from_json(output_compile, arguments_.output_compile, - entries_compile, new_entries_count, arguments_.append); + return complete_entries_from_json(output_compile, arguments_.output, + entries_compile, new_entries_count, append); }) - .and_then([this, &output_link, &entries_link](size_t new_entries_count) { - if (arguments_.with_link) { - return complete_entries_from_json(output_link, arguments_.output_link, - entries_link, new_entries_count, arguments_.append); + .and_then([this, &output_link, &entries_link, with_link, append](size_t new_entries_count) { + if (with_link) { + return complete_entries_from_json(output_link, configuration_.linking.value().filename, + entries_link, new_entries_count, append); } return rust::Result(rust::Ok(new_entries_count)); }) .and_then([this, &output_compile, &entries_compile](const auto entries_count_to_output) { spdlog::debug("entries to output. [size: {}]", entries_count_to_output); - return write_entries(output_compile, arguments_.output_compile, entries_compile); + return write_entries(output_compile, arguments_.output, entries_compile); }) - .and_then([this, &output_link, &entries_link](const auto compile_entries_wrote) { - if (arguments_.with_link) { - const auto result_link = write_entries(output_link, arguments_.output_link, entries_link); + .and_then([this, &output_link, &entries_link, with_link](const auto compile_entries_wrote) { + if (with_link) { + const auto result_link = write_entries(output_link, configuration_.linking.value().filename, entries_link); return (result_link.is_err()) ? result_link : rust::Ok(result_link.unwrap() + compile_entries_wrote); @@ -380,8 +378,8 @@ namespace cs { rust::Result Citnames::command(const flags::Arguments &args, const char **envp) const { auto environment = sys::env::from(const_cast(envp)); - auto arguments = into_arguments(args); auto configuration = into_configuration(args, environment); + auto arguments = into_arguments(args); return rust::merge(arguments, configuration) .map([](auto tuples) { diff --git a/source/citnames/source/Citnames.h b/source/citnames/source/Citnames.h index 53565658..6f28f376 100644 --- a/source/citnames/source/Citnames.h +++ b/source/citnames/source/Citnames.h @@ -36,10 +36,8 @@ namespace cs { struct Arguments { fs::path input; - fs::path output_compile; - fs::path output_link; + fs::path output; bool append; - bool with_link; }; struct Command : ps::Command { diff --git a/source/citnames/source/Configuration.cc b/source/citnames/source/Configuration.cc index 2d898d76..513ab74c 100644 --- a/source/citnames/source/Configuration.cc +++ b/source/citnames/source/Configuration.cc @@ -17,6 +17,7 @@ along with this program. If not, see . */ +#include "config.h" #include "Configuration.h" #include @@ -119,6 +120,19 @@ namespace cs { } } + void from_json(const nlohmann::json &j, Linking &rhs) { + if (j.contains("filename")) { + j.at("filename").get_to(rhs.filename); + } + else { + rhs.filename = cmd::citnames::DEFAULT_OUTPUT_LINK; + } + } + + void to_json(nlohmann::json &j, const Linking &rhs) { + j["filename"] = rhs.filename; + } + void from_json(const nlohmann::json &j, Configuration &rhs) { if (j.contains("output")) { j.at("output").get_to(rhs.output); @@ -126,13 +140,27 @@ namespace cs { if (j.contains("compilation")) { j.at("compilation").get_to(rhs.compilation); } + if (j.contains("linking")) { + Linking linking; + j.at("linking").get_to(linking); + rhs.linking.emplace(linking); + } } void to_json(nlohmann::json &j, const Configuration &rhs) { - j = nlohmann::json{ + if (rhs.linking.has_value()) { + j = nlohmann::json{ {"output", rhs.output}, {"compilation", rhs.compilation}, - }; + {"linking", rhs.linking.value()}, + }; + } + else { + j = nlohmann::json{ + {"output", rhs.output}, + {"compilation", rhs.compilation}, + }; + } } std::ostream &operator<<(std::ostream &os, const Format &value) @@ -180,6 +208,15 @@ namespace cs { return os; } + std::ostream &operator<<(std::ostream &os, const Linking &value) + { + nlohmann::json payload; + to_json(payload, value); + os << payload; + + return os; + } + std::ostream &operator<<(std::ostream &os, const Configuration &value) { nlohmann::json payload; diff --git a/source/citnames/source/Configuration.h b/source/citnames/source/Configuration.h index 8934de32..8f65b5b9 100644 --- a/source/citnames/source/Configuration.h +++ b/source/citnames/source/Configuration.h @@ -86,10 +86,16 @@ namespace cs { std::list compilers_to_exclude; }; + // Represents the configuration related creating a linking database. + struct Linking { + std::string filename; + }; + // Represents the application configuration. struct Configuration { Output output; Compilation compilation; + std::optional linking; }; // Convenient methods for these types. @@ -98,6 +104,7 @@ namespace cs { std::ostream& operator<<(std::ostream&, const Output&); std::ostream& operator<<(std::ostream&, const CompilerWrapper&); std::ostream& operator<<(std::ostream&, const Compilation&); + std::ostream& operator<<(std::ostream&, const Linking&); std::ostream& operator<<(std::ostream&, const Configuration&); // Utility class to persists configuration in JSON. diff --git a/source/config.h.in b/source/config.h.in index 158e4cd4..f924e695 100644 --- a/source/config.h.in +++ b/source/config.h.in @@ -86,14 +86,12 @@ namespace cmd { namespace citnames { constexpr char FLAG_INPUT[] = "--input"; - constexpr char FLAG_OUTPUT_COMPILE[] = "--output-compile"; - constexpr char FLAG_WITH_LINK[] = "--with-link"; - constexpr char FLAG_OUTPUT_LINK[] = "--output-link"; + constexpr char FLAG_OUTPUT[] = "--output"; constexpr char FLAG_APPEND[] = "--append"; constexpr char FLAG_RUN_CHECKS[] = "--run-checks"; constexpr char FLAG_CONFIG[] = "--config"; - constexpr char DEFAULT_OUTPUT_COMPILE[] = "compile_commands.json"; + constexpr char DEFAULT_OUTPUT[] = "compile_commands.json"; constexpr char DEFAULT_OUTPUT_LINK[] = "link_commands.json"; } diff --git a/test/cases/citnames/exit_code/exit_code_for_success.sh b/test/cases/citnames/exit_code/exit_code_for_success.sh index 937efd68..47710677 100644 --- a/test/cases/citnames/exit_code/exit_code_for_success.sh +++ b/test/cases/citnames/exit_code/exit_code_for_success.sh @@ -2,7 +2,7 @@ # UNSUPPORTED: true # RUN: cd %T; %{shell} %s %t.commands.json -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json # RUN: assert_compilation %t.compilations.json count -eq 0 cat > $1 << EOF diff --git a/test/cases/citnames/output/clang_plugin.sh b/test/cases/citnames/output/clang_plugin.sh index db9c7602..b1f36cf0 100644 --- a/test/cases/citnames/output/clang_plugin.sh +++ b/test/cases/citnames/output/clang_plugin.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/clang -c -Xclang -load -Xclang /path/to/LLVMHello.so -o broken_build.o broken_build.c diff --git a/test/cases/citnames/output/convert_format.sh b/test/cases/citnames/output/convert_format.sh index 1d7e82c8..8c2e2a48 100644 --- a/test/cases/citnames/output/convert_format.sh +++ b/test/cases/citnames/output/convert_format.sh @@ -3,7 +3,7 @@ # RUN: cd %T; %{shell} %s %t # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/gcc -c -o broken_build.o broken_build.c -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json --append +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json --append # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/gcc -c -o broken_build.o broken_build.c diff --git a/test/cases/citnames/output/linking_with_filename.sh b/test/cases/citnames/output/linking_with_filename.sh new file mode 100644 index 00000000..c78f5f16 --- /dev/null +++ b/test/cases/citnames/output/linking_with_filename.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# RUN: cd %T; %{shell} %s %t +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json --append +# RUN: assert_compilation lll.json count -eq 0 + +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "lll.json" + } +} +EOF + +cat > "$1.commands.json" << EOF +EOF diff --git a/test/cases/citnames/output/linking_without_filename.sh b/test/cases/citnames/output/linking_without_filename.sh new file mode 100644 index 00000000..b6af0b4f --- /dev/null +++ b/test/cases/citnames/output/linking_without_filename.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# RUN: cd %T; %{shell} %s %t +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json --append +# RUN: assert_compilation link_commands.json count -eq 0 + +cat > "$1.config.json" << EOF +{ + "linking": { + } +} +EOF + +cat > "$1.commands.json" << EOF +EOF diff --git a/test/cases/citnames/output/relative_paths_converted.sh b/test/cases/citnames/output/relative_paths_converted.sh index 3a4427cf..80dcb099 100644 --- a/test/cases/citnames/output/relative_paths_converted.sh +++ b/test/cases/citnames/output/relative_paths_converted.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user/build -arguments /usr/bin/wrapper -c -o broken_build.o ../broken_build.c diff --git a/test/cases/citnames/output/unsorted_events.sh b/test/cases/citnames/output/unsorted_events.sh index 6c41fd15..9c96c441 100644 --- a/test/cases/citnames/output/unsorted_events.sh +++ b/test/cases/citnames/output/unsorted_events.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json # RUN: assert_compilation %t.compilations.json count -eq 1 cat << EOF > "$1.commands.json" diff --git a/test/cases/citnames/output/wrapper_flags_extended.sh b/test/cases/citnames/output/wrapper_flags_extended.sh index 6db6804a..ab8b0086 100644 --- a/test/cases/citnames/output/wrapper_flags_extended.sh +++ b/test/cases/citnames/output/wrapper_flags_extended.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # RUN: cd %T; %{shell} %s %t -# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json --config %t.config.json +# RUN: %{citnames} --verbose --input %t.commands.json --output %t.compilations.json --config %t.config.json # RUN: assert_compilation %t.compilations.json count -eq 1 # RUN: assert_compilation %t.compilations.json contains -file /home/user/broken_build.c -directory /home/user -arguments /usr/bin/wrapper -c -Dwrapper -o broken_build.o broken_build.c diff --git a/test/cases/compilation/exit_code/exit_code_for_fail.sh b/test/cases/compilation/exit_code/exit_code_for_fail.sh index c86be67b..4ae7ceb7 100644 --- a/test/cases/compilation/exit_code/exit_code_for_fail.sh +++ b/test/cases/compilation/exit_code/exit_code_for_fail.sh @@ -1,4 +1,4 @@ #!/usr/bin/env sh # XFAIL: * -# RUN: %{bear} --verbose --output-compile %t.json -- %{false} +# RUN: %{bear} --verbose --output %t.json -- %{false} diff --git a/test/cases/compilation/exit_code/exit_code_for_success.sh b/test/cases/compilation/exit_code/exit_code_for_success.sh index 9f686f94..049fd9f7 100644 --- a/test/cases/compilation/exit_code/exit_code_for_success.sh +++ b/test/cases/compilation/exit_code/exit_code_for_success.sh @@ -1,3 +1,3 @@ #!/usr/bin/env sh -# RUN: %{bear} --verbose --output-compile %t.json -- %{true} +# RUN: %{bear} --verbose --output %t.json -- %{true} diff --git a/test/cases/compilation/output/assembly_sources.mk b/test/cases/compilation/output/assembly_sources.mk index 8bf6e428..857eef52 100644 --- a/test/cases/compilation/output/assembly_sources.mk +++ b/test/cases/compilation/output/assembly_sources.mk @@ -2,7 +2,7 @@ # REQUIRES: make # RUN: %{make} -C %T -f %s clean -# RUN: %{bear} --verbose --output-compile %t.json -- %{make} -C %T -f %s +# RUN: %{bear} --verbose --output %t.json -- %{make} -C %T -f %s # RUN: assert_compilation %t.json count -eq 2 # 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/broken_build.sh b/test/cases/compilation/output/broken_build.sh index 5ca555e2..d871d77f 100644 --- a/test/cases/compilation/output/broken_build.sh +++ b/test/cases/compilation/output/broken_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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/broken_build.c -directory %T -arguments %{c_compiler} -c -o broken_build.o broken_build.c diff --git a/test/cases/compilation/output/bug439.mk b/test/cases/compilation/output/bug439.mk index c367b08c..49662893 100644 --- a/test/cases/compilation/output/bug439.mk +++ b/test/cases/compilation/output/bug439.mk @@ -3,7 +3,7 @@ # REQUIRES: make, shell # RUN: mkdir -p %T/make # RUN: %{make} -C %T -f %s clean -# RUN: %{shell} -c "PATH=%T:$PATH %{bear} --verbose --output-compile %t.json -- %{make} -C %T -f %s" +# 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 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_cuda.sh b/test/cases/compilation/output/compile_cuda.sh index 7390f977..41b8b374 100644 --- a/test/cases/compilation/output/compile_cuda.sh +++ b/test/cases/compilation/output/compile_cuda.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell, cuda -# RUN: cd %T; env CC=%{cuda} %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; env CC=%{cuda} %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/successful_build_1.cu -directory %T # RUN: assert_compilation %t.json contains -file %T/successful_build_2.cu -directory %T diff --git a/test/cases/compilation/output/compile_fortran.sh b/test/cases/compilation/output/compile_fortran.sh index 7b4411ae..15dc6c2a 100644 --- a/test/cases/compilation/output/compile_fortran.sh +++ b/test/cases/compilation/output/compile_fortran.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell, fortran -# RUN: cd %T; env FC=%{fortran} %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; env FC=%{fortran} %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/compile_fortran.f95 -directory %T -arguments %{fortran} -c -o compile_fortran.o compile_fortran.f95 diff --git a/test/cases/compilation/output/config/filter_compilers.sh b/test/cases/compilation/output/config/filter_compilers.sh index 31a55e34..77f12f3c 100644 --- a/test/cases/compilation/output/config/filter_compilers.sh +++ b/test/cases/compilation/output/config/filter_compilers.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json -- %{shell} %t/build.sh +# 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 diff --git a/test/cases/compilation/output/config/filter_flags.sh b/test/cases/compilation/output/config/filter_flags.sh index 46151f12..015abc0e 100644 --- a/test/cases/compilation/output/config/filter_flags.sh +++ b/test/cases/compilation/output/config/filter_flags.sh @@ -2,12 +2,12 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output-compile %t.json --config %t/config.json -- %{shell} %t/build.sh +# RUN: cd %T; env CC=%t/wrapper %{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 %t/wrapper -c -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %t/wrapper -c -Werror -I. %t/source_2.c -# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output-compile %t.json --config %t/config.json --force-wrapper -- %{shell} %t/build.sh +# RUN: cd %T; env CC=%t/wrapper %{bear} --verbose --output %t.json --config %t/config.json --force-wrapper -- %{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 %t/wrapper -c -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %t/wrapper -c -Werror -I. %t/source_2.c diff --git a/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh b/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh index 6138135e..f71f8eda 100644 --- a/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh +++ b/test/cases/compilation/output/config/filter_flags_on_known_compiler.sh @@ -2,12 +2,12 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json -- %{shell} %t/build.sh +# 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 -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -Werror -I. %t/source_2.c -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json --force-wrapper -- %{shell} %t/build.sh +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t/config.json --force-wrapper -- %{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 -I. %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -Werror -I. %t/source_2.c diff --git a/test/cases/compilation/output/config/filter_sources.sh b/test/cases/compilation/output/config/filter_sources.sh index fff1ae08..2828d2e5 100644 --- a/test/cases/compilation/output/config/filter_sources.sh +++ b/test/cases/compilation/output/config/filter_sources.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json -- %{shell} %t/build.sh +# 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 diff --git a/test/cases/compilation/output/config/filter_sources_relative.sh b/test/cases/compilation/output/config/filter_sources_relative.sh index bef648d4..db942d0a 100644 --- a/test/cases/compilation/output/config/filter_sources_relative.sh +++ b/test/cases/compilation/output/config/filter_sources_relative.sh @@ -2,7 +2,7 @@ # REQUIRES: shell # RUN: %{shell} %s %t -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --config %t/config.json -- %{shell} %t/build.sh +# 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 diff --git a/test/cases/compilation/output/define_with_escaped_quote.sh b/test/cases/compilation/output/define_with_escaped_quote.sh index 5a67cebf..70f2053d 100644 --- a/test/cases/compilation/output/define_with_escaped_quote.sh +++ b/test/cases/compilation/output/define_with_escaped_quote.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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/define_with_escaped_quote.c -directory %T -arguments %{c_compiler} -c '-DMESSAGE="Hello World\n"' -o define_with_escaped_quote.c.o define_with_escaped_quote.c diff --git a/test/cases/compilation/output/define_with_quote.sh b/test/cases/compilation/output/define_with_quote.sh index 976c2f28..2fde1203 100644 --- a/test/cases/compilation/output/define_with_quote.sh +++ b/test/cases/compilation/output/define_with_quote.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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/define_with_quote.c -directory %T -arguments %{cxx_compiler} -c -DEXPORT="extern \"C\"" -o define_with_quote.c.o define_with_quote.c diff --git a/test/cases/compilation/output/duplicate_entries.sh b/test/cases/compilation/output/duplicate_entries.sh index e108ebaa..50458da8 100644 --- a/test/cases/compilation/output/duplicate_entries.sh +++ b/test/cases/compilation/output/duplicate_entries.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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 diff --git a/test/cases/compilation/output/empty_argument.sh b/test/cases/compilation/output/empty_argument.sh index cb63b987..6b8841d4 100644 --- a/test/cases/compilation/output/empty_argument.sh +++ b/test/cases/compilation/output/empty_argument.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 0 touch empty_argument_1.c empty_argument_2.c diff --git a/test/cases/compilation/output/empty_env.sh b/test/cases/compilation/output/empty_env.sh index dd1f37dc..415f4078 100644 --- a/test/cases/compilation/output/empty_env.sh +++ b/test/cases/compilation/output/empty_env.sh @@ -2,7 +2,7 @@ # REQUIRES: preload, shell # RUN: %{shell} %s %t -# RUN: cd %T; /usr/bin/env - %{bear} --verbose --output-compile %t.json -- %{shell} %t/build.sh +# RUN: cd %T; /usr/bin/env - %{bear} --verbose --output %t.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 -o %t/source_1.o %t/source_1.c # RUN: assert_compilation %t.json contains -file %t/source_2.c -directory %T -arguments %{c_compiler} -c -o %t/source_2.o %t/source_2.c diff --git a/test/cases/compilation/output/existing_files_only.sh b/test/cases/compilation/output/existing_files_only.sh index b4bd0a00..9129a78d 100644 --- a/test/cases/compilation/output/existing_files_only.sh +++ b/test/cases/compilation/output/existing_files_only.sh @@ -2,7 +2,7 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s -build +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s -build # RUN: assert_compilation %t.json count -ge 2 # RUN: assert_compilation %t.json contains -file %T/exists/src/source_1.c -directory %T -arguments %{c_compiler} -c -o exists/src/source_1.o exists/src/source_1.c # RUN: assert_compilation %t.json contains -file %T/exists/src/source_2.c -directory %T -arguments %{c_compiler} -c -o exists/src/source_2.o exists/src/source_2.c diff --git a/test/cases/compilation/output/flag/append.sh b/test/cases/compilation/output/flag/append.sh index f67e46c5..1be8fff1 100644 --- a/test/cases/compilation/output/flag/append.sh +++ b/test/cases/compilation/output/flag/append.sh @@ -2,19 +2,19 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s -build +# 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-compile %t.json --append -- %{shell} %s -test +# 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-compile %t.json --append -- %{shell} %s -clean +# RUN: cd %T; %{bear} --verbose --output %t.json --append -- %{shell} %s -clean # RUN: assert_compilation %t.json count -eq 0 build() diff --git a/test/cases/compilation/output/flag/field_output.sh b/test/cases/compilation/output/flag/field_output.sh index 1192b349..1bab2133 100644 --- a/test/cases/compilation/output/flag/field_output.sh +++ b/test/cases/compilation/output/flag/field_output.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/field_output_1.c -output %T/field_output_1.o -directory %T -arguments %{c_compiler} -c -o field_output_1.o field_output_1.c # RUN: assert_compilation %t.json contains -file %T/field_output_2.c -output %T/field_output_2.o -directory %T -arguments %{c_compiler} -c -o field_output_2.o field_output_2.c diff --git a/test/cases/compilation/output/flag/use_cc.sh b/test/cases/compilation/output/flag/use_cc.sh index 2160d067..5c9575a1 100644 --- a/test/cases/compilation/output/flag/use_cc.sh +++ b/test/cases/compilation/output/flag/use_cc.sh @@ -2,22 +2,22 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --force-preload --output-compile %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-preload --output %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cc_1.c -directory %T -arguments %{c_compiler} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.known.json contains -file %T/use_cc_2.c -directory %T -arguments %{c_compiler} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-preload --output-compile %t.all.json -- %{shell} %s +# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-preload --output %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cc_1.c -directory %T -arguments %{true} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.all.json contains -file %T/use_cc_2.c -directory %T -arguments %{true} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; %{bear} --verbose --force-wrapper --output-compile %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-wrapper --output %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cc_1.c -directory %T -arguments %{c_compiler} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.known.json contains -file %T/use_cc_2.c -directory %T -arguments %{c_compiler} -c -o use_cc_2.o use_cc_2.c -# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-wrapper --output-compile %t.all.json -- %{shell} %s +# RUN: cd %T; env CC=%{true} %{bear} --verbose --force-wrapper --output %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cc_1.c -directory %T -arguments %{true} -c -o use_cc_1.o use_cc_1.c # RUN: assert_compilation %t.all.json contains -file %T/use_cc_2.c -directory %T -arguments %{true} -c -o use_cc_2.o use_cc_2.c diff --git a/test/cases/compilation/output/flag/use_cxx.sh b/test/cases/compilation/output/flag/use_cxx.sh index 488297ea..0bd1b8d9 100644 --- a/test/cases/compilation/output/flag/use_cxx.sh +++ b/test/cases/compilation/output/flag/use_cxx.sh @@ -2,22 +2,22 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --force-preload --output-compile %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-preload --output %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-preload --output-compile %t.all.json -- %{shell} %s +# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-preload --output %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{true} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{true} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; %{bear} --verbose --force-wrapper --output-compile %t.known.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --force-wrapper --output %t.known.json -- %{shell} %s # RUN: assert_compilation %t.known.json count -eq 2 # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.known.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{cxx_compiler} -c -o use_cxx_2.o use_cxx_2.cc -# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-wrapper --output-compile %t.all.json -- %{shell} %s +# RUN: cd %T; env CXX=%{true} %{bear} --verbose --force-wrapper --output %t.all.json -- %{shell} %s # RUN: assert_compilation %t.all.json count -eq 2 # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_1.cc -directory %T -arguments %{true} -c -o use_cxx_1.o use_cxx_1.cc # RUN: assert_compilation %t.all.json contains -file %T/use_cxx_2.cc -directory %T -arguments %{true} -c -o use_cxx_2.o use_cxx_2.cc diff --git a/test/cases/compilation/output/flags_filtered_link.sh b/test/cases/compilation/output/flags_filtered_link.sh index 5652810f..00ca2c03 100644 --- a/test/cases/compilation/output/flags_filtered_link.sh +++ b/test/cases/compilation/output/flags_filtered_link.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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 diff --git a/test/cases/compilation/output/flags_filtered_preproc.sh b/test/cases/compilation/output/flags_filtered_preproc.sh index 0f919738..749b82fc 100644 --- a/test/cases/compilation/output/flags_filtered_preproc.sh +++ b/test/cases/compilation/output/flags_filtered_preproc.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_1.c -directory %T -arguments %{c_compiler} -c -MD -MF flags_filtered_preproc_1.d -o flags_filtered_preproc_1.o flags_filtered_preproc_1.c # RUN: assert_compilation %t.json contains -file %T/flags_filtered_preproc_2.c -directory %T -arguments %{c_compiler} -c -MMD -MF flags_filtered_preproc_2.d -o flags_filtered_preproc_2.o flags_filtered_preproc_2.c diff --git a/test/cases/compilation/output/linking/append.sh b/test/cases/compilation/output/linking/append.sh index 5d5bc035..40ecb89f 100644 --- a/test/cases/compilation/output/linking/append.sh +++ b/test/cases/compilation/output/linking/append.sh @@ -2,14 +2,14 @@ # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s -build +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t -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: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/append/src/source_1.o %T/append/src/source_2.o -directory %T -arguments %{c_compiler} append/src/source_1.o append/src/source_2.o -o src -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json --append -- %{shell} %s -test +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json --append -- %{shell} %s %t -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 @@ -19,10 +19,18 @@ # RUN: assert_compilation %t_link.json contains -files %T/append/src/source_1.o %T/append/src/source_2.o -directory %T -arguments %{c_compiler} append/src/source_1.o append/src/source_2.o -o src # RUN: assert_compilation %t_link.json contains -files %T/append/test/source_1.o %T/append/test/source_2.o -directory %T -arguments %{c_compiler} append/test/source_1.o append/test/source_2.o -o test -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --append -- %{shell} %s -clean +# RUN: cd %T; %{bear} --verbose --output %t.json --append -- %{shell} %s %t -clean # RUN: assert_compilation %t.json count -eq 0 # RUN: assert_compilation %t_link.json count -eq 2 +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + build() { mkdir -p append append/src @@ -46,7 +54,7 @@ clean() rm -rf append } -case $1 in +case $2 in -build) build ;; diff --git a/test/cases/compilation/output/linking/compile_link_one_file.sh b/test/cases/compilation/output/linking/compile_link_one_file.sh index d9478d10..71628076 100644 --- a/test/cases/compilation/output/linking/compile_link_one_file.sh +++ b/test/cases/compilation/output/linking/compile_link_one_file.sh @@ -1,12 +1,20 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/compile_link_one_file.c -directory %T -arguments %{c_compiler} -c -o compile_link_one_file.c.o compile_link_one_file.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/compile_link_one_file.c.o -directory %T -arguments %{c_compiler} compile_link_one_file.c.o -o compile_link_one_file +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int main() { return 0; }" > compile_link_one_file.c $CC compile_link_one_file.c -o compile_link_one_file diff --git a/test/cases/compilation/output/linking/compile_link_some_files.sh b/test/cases/compilation/output/linking/compile_link_some_files.sh index 7a1e45ae..b15ad2a8 100644 --- a/test/cases/compilation/output/linking/compile_link_some_files.sh +++ b/test/cases/compilation/output/linking/compile_link_some_files.sh @@ -1,13 +1,21 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/compile_link_some_files_1.c -directory %T -arguments %{c_compiler} -c -o compile_link_some_files_1.c.o compile_link_some_files_1.c # RUN: assert_compilation %t.json contains -file %T/compile_link_some_files_2.c -directory %T -arguments %{c_compiler} -c -o compile_link_some_files_2.c.o compile_link_some_files_2.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/compile_link_some_files_1.c.o %T/compile_link_some_files_2.c.o -directory %T -arguments %{c_compiler} compile_link_some_files_1.c.o compile_link_some_files_2.c.o -o compile_link_some_files +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int foo() { return 1; }" > compile_link_some_files_1.c echo "int main() { return 0; }" > compile_link_some_files_2.c diff --git a/test/cases/compilation/output/linking/flag_wl.sh b/test/cases/compilation/output/linking/flag_wl.sh index 936a1aa7..7fdb7847 100644 --- a/test/cases/compilation/output/linking/flag_wl.sh +++ b/test/cases/compilation/output/linking/flag_wl.sh @@ -12,12 +12,20 @@ # RUN: touch %T/other/libflag_wl_3.%{dynamic_lib_extension} # RUN: touch %T/other/libflag_wl_1.%{dynamic_lib_extension} -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/flag_wl.c -files %T/other/libflag_wl_3.a %T/other/libflag_wl_1.a %T/other/libflag_wl_1.%{dynamic_lib_extension} %T/libflag_wl_2.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 -o flag_wl.c.o flag_wl.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/flag_wl.c.o %T/other/libflag_wl_3.a %T/other/libflag_wl_1.a %T/other/libflag_wl_1.%{dynamic_lib_extension} %T/libflag_wl_2.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} flag_wl.c.o -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 -o flag_wl +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int main() { return 0; }" > flag_wl.c $CC -o flag_wl flag_wl.c -L ./other/ -Wl,-Bdynamic,-Bstatic -lflag_wl_3 -lflag_wl_1 -L. -Wl,-Bdynamic -lflag_wl_1 -lflag_wl_2 diff --git a/test/cases/compilation/output/linking/not_append_without_link_database.sh b/test/cases/compilation/output/linking/not_append_without_link_database.sh index 08a21490..b8377593 100644 --- a/test/cases/compilation/output/linking/not_append_without_link_database.sh +++ b/test/cases/compilation/output/linking/not_append_without_link_database.sh @@ -5,13 +5,21 @@ # RUN: rm -f %t.json %t_link.json # RUN: echo "[{\"arguments\": [\"gcc\", \"-c\"]}]" > %t.json -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json --append -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json --append -- %{shell} %s %t # 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 -o source_1.o source_1.c # RUN: assert_compilation %t.json contains -file %T/source_2.c -directory %T -arguments %{c_compiler} -c -o source_2.o source_2.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/source_1.o %T/source_2.o -directory %T -arguments %{c_compiler} source_1.o source_2.o +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int foo() { return 1; }" > source_1.c echo "int main() { return 0; }" > source_2.c diff --git a/test/cases/compilation/output/linking/some_dir_for_libs.sh b/test/cases/compilation/output/linking/some_dir_for_libs.sh index e86e4fa4..9de5ff60 100644 --- a/test/cases/compilation/output/linking/some_dir_for_libs.sh +++ b/test/cases/compilation/output/linking/some_dir_for_libs.sh @@ -11,12 +11,20 @@ # RUN: gcc -c %T/other/libsome_dir_for_libs.c -o %T/other/libsome_dir_for_libs.o # RUN: ar -q -c %T/other/libsome_dir_for_libs.a %T/other/libsome_dir_for_libs.o -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/some_dir_for_libs.c -files %T/other/libsome_dir_for_libs.a -directory %T -arguments %{c_compiler} -c -L ./other -L. -lsome_dir_for_libs -o some_dir_for_libs.c.o some_dir_for_libs.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/other/libsome_dir_for_libs.a %T/some_dir_for_libs.c.o -directory %T -arguments %{c_compiler} -L ./other -L. -lsome_dir_for_libs some_dir_for_libs.c.o -o some_dir_for_libs +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int main() { return 0; }" > some_dir_for_libs.c $CC -o some_dir_for_libs -L ./other -L. -lsome_dir_for_libs some_dir_for_libs.c diff --git a/test/cases/compilation/output/linking/some_libs.sh b/test/cases/compilation/output/linking/some_libs.sh index bea0f4e0..03000666 100644 --- a/test/cases/compilation/output/linking/some_libs.sh +++ b/test/cases/compilation/output/linking/some_libs.sh @@ -15,12 +15,20 @@ # RUN: gcc -c %T/other/libsome_libs.c -o %T/other/libsome_libs.o # RUN: ar -q -c %T/other/libsome_libs.a %T/other/libsome_libs.o -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/some_libs.c -files %T/libsome_libs.%{dynamic_lib_extension} -directory %T -arguments %{c_compiler} -c -L ./other -L. -lsome_libs -o some_libs.c.o some_libs.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/libsome_libs.%{dynamic_lib_extension} %T/some_libs.c.o -directory %T -arguments %{c_compiler} -L ./other -L. -lsome_libs some_libs.c.o -o some_libs +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int main() { return 0; }" > some_libs.c $CC -o some_libs -L ./other -L. -lsome_libs some_libs.c diff --git a/test/cases/compilation/output/linking/with_static_lib.sh b/test/cases/compilation/output/linking/with_static_lib.sh index 49a1f109..0099727d 100644 --- a/test/cases/compilation/output/linking/with_static_lib.sh +++ b/test/cases/compilation/output/linking/with_static_lib.sh @@ -6,12 +6,20 @@ # RUN: gcc -c %T/libwith_static_lib.c -o %T/libwith_static_lib.o # RUN: ar -q -c %T/libwith_static_lib.a %T/libwith_static_lib.o -# RUN: cd %T; %{bear} --verbose --with-link --output-compile %t.json --output-link %t_link.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --config %t.config.json -- %{shell} %s %t # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/with_static_lib.c -files %T/libwith_static_lib.a -directory %T -arguments %{c_compiler} -c -L. -lwith_static_lib -o with_static_lib.c.o with_static_lib.c # RUN: assert_compilation %t_link.json count -eq 1 # RUN: assert_compilation %t_link.json contains -files %T/libwith_static_lib.a %T/with_static_lib.c.o -directory %T -arguments %{c_compiler} -L. -lwith_static_lib with_static_lib.c.o -o with_static_lib +cat > "$1.config.json" << EOF +{ + "linking": { + "filename": "$1_link.json" + } +} +EOF + echo "int main() { return 0; }" > with_static_lib.c $CC -o with_static_lib -L. -lwith_static_lib with_static_lib.c diff --git a/test/cases/compilation/output/linking/without_link_flag.sh b/test/cases/compilation/output/linking/without_link_flag.sh deleted file mode 100644 index b0460b6c..00000000 --- a/test/cases/compilation/output/linking/without_link_flag.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env sh - -# REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --output-link %t_link.json -- %{shell} %s -# RUN: assert_compilation %t.json count -eq 1 -# RUN: assert_compilation %t.json contains -file %T/without_link_flag.c -directory %T -arguments %{c_compiler} -c -o without_link_flag.c.o without_link_flag.c - - -echo "int main() { return 0; }" > without_link_flag.c - -$CC -o without_link_flag without_link_flag.c diff --git a/test/cases/compilation/output/multiple_source_build.sh b/test/cases/compilation/output/multiple_source_build.sh index c999941c..6fdd2f53 100644 --- a/test/cases/compilation/output/multiple_source_build.sh +++ b/test/cases/compilation/output/multiple_source_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 3 # RUN: assert_compilation %t.json contains -file %T/multiple_source_build_1.c -directory %T -arguments %{c_compiler} -c -o multiple_source_build_1.c.o 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_2.c.o multiple_source_build_2.c diff --git a/test/cases/compilation/output/parallel_build.sh b/test/cases/compilation/output/parallel_build.sh index ed9f2f36..a501822f 100644 --- a/test/cases/compilation/output/parallel_build.sh +++ b/test/cases/compilation/output/parallel_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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/parallel_build_1.c -directory %T -arguments %{c_compiler} -c -o parallel_build_1.o parallel_build_1.c # RUN: assert_compilation %t.json contains -file %T/parallel_build_2.c -directory %T -arguments %{c_compiler} -c -o parallel_build_2.o parallel_build_2.c diff --git a/test/cases/compilation/output/successful_build.sh b/test/cases/compilation/output/successful_build.sh index abd5fc83..391b3e41 100644 --- a/test/cases/compilation/output/successful_build.sh +++ b/test/cases/compilation/output/successful_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# 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/successful_build_1.c -directory %T -arguments %{c_compiler} -c -o successful_build_1.o successful_build_1.c # RUN: assert_compilation %t.json contains -file %T/successful_build_2.c -directory %T -arguments %{c_compiler} -c -o successful_build_2.o successful_build_2.c diff --git a/test/cases/compilation/output/with_other_files.sh b/test/cases/compilation/output/with_other_files.sh index b4f366ed..da54682d 100644 --- a/test/cases/compilation/output/with_other_files.sh +++ b/test/cases/compilation/output/with_other_files.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 1 # RUN: assert_compilation %t.json contains -file %T/with_other_files.c -files %T/lib.o -directory %T -arguments %{c_compiler} -c lib.o -o with_other_files.o with_other_files.c diff --git a/test/cases/compilation/output/wrapper.sh b/test/cases/compilation/output/wrapper.sh index 78ba76dc..9f2454ed 100644 --- a/test/cases/compilation/output/wrapper.sh +++ b/test/cases/compilation/output/wrapper.sh @@ -1,12 +1,12 @@ #!/usr/bin/env sh # REQUIRES: shell -# RUN: cd %T; %{bear} --verbose --output-compile %t.json -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/wrapper_1.c -directory %T -arguments %{c_compiler} -c -o wrapper_1.o wrapper_1.c # RUN: assert_compilation %t.json contains -file %T/wrapper_2.c -directory %T -arguments %{c_compiler} -c -o wrapper_2.o wrapper_2.c -# RUN: cd %T; %{bear} --verbose --output-compile %t.json --force-wrapper -- %{shell} %s +# RUN: cd %T; %{bear} --verbose --output %t.json --force-wrapper -- %{shell} %s # RUN: assert_compilation %t.json count -eq 2 # RUN: assert_compilation %t.json contains -file %T/wrapper_1.c -directory %T -arguments %{c_compiler} -c -o wrapper_1.o wrapper_1.c # RUN: assert_compilation %t.json contains -file %T/wrapper_2.c -directory %T -arguments %{c_compiler} -c -o wrapper_2.o wrapper_2.c From fae579c9b572a81a30f00bd87991673c61e1b1c8 Mon Sep 17 00:00:00 2001 From: Maria Date: Thu, 29 Jun 2023 17:16:16 +0300 Subject: [PATCH 7/7] Small fix --- source/bear/source/Application.cc | 2 +- source/citnames/source/Citnames.cc | 6 ++---- test/cases/intercept/preload/signal_outside_build.sh | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/source/bear/source/Application.cc b/source/bear/source/Application.cc index 7db1755f..b2850860 100644 --- a/source/bear/source/Application.cc +++ b/source/bear/source/Application.cc @@ -208,4 +208,4 @@ namespace bear { return std::make_unique(intercept, citnames, commands); }); } -} \ No newline at end of file +} diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index 95e5cc1d..5c2bbd39 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -119,7 +119,7 @@ namespace { return cs::Arguments{ fs::path(input), fs::path(output), - append + append, }; }) .and_then([](auto arguments) -> rust::Result { @@ -131,9 +131,7 @@ namespace { return rust::Ok(cs::Arguments{ arguments.input, arguments.output, - arguments.append && is_exists(arguments.output) -// (arguments.append && is_exists(arguments.output) -// && (!arguments.with_link || is_exists(arguments.output_link))) + arguments.append && is_exists(arguments.output), }); }); } diff --git a/test/cases/intercept/preload/signal_outside_build.sh b/test/cases/intercept/preload/signal_outside_build.sh index 81d948d5..7c6dbf3c 100644 --- a/test/cases/intercept/preload/signal_outside_build.sh +++ b/test/cases/intercept/preload/signal_outside_build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # REQUIRES: preload, shell, dynamic-shell -# RUN: %{shell} -c "%{intercept} --output %t.json -- %{shell} %s --sleep %{sleep} --true %{true} & %{sleep} 1; kill -15 %1; wait;" +# RUN: %{shell} -c "%{intercept} --verbose --output %t.json -- %{shell} %s --sleep %{sleep} --true %{true} & %{sleep} 1; kill -15 %1; wait;" # RUN: assert_intercepted %t.json count -eq 3 # RUN: assert_intercepted %t.json contains -program %{true} # RUN: assert_intercepted %t.json contains -program %{sleep} -arguments %{sleep} 5