diff options
author | Joel Rosdahl <joel@rosdahl.net> | 2023-02-17 08:26:08 +0100 |
---|---|---|
committer | Joel Rosdahl <joel@rosdahl.net> | 2023-02-20 08:02:33 +0100 |
commit | e1a53fd0e67fb2d4ad7619e22550545fab27c620 (patch) | |
tree | a6faefad3976abd79fe939d80fd94423748ee362 | |
parent | 86bfec0d10ac8967fd8a2703837f9f6e25d51bc3 (diff) | |
download | ccache-e1a53fd0e67fb2d4ad7619e22550545fab27c620.tar.gz |
feat: Add support for setting per-compilation config on command line
Closes #1035.
-rw-r--r-- | doc/MANUAL.adoc | 24 | ||||
-rw-r--r-- | src/Config.cpp | 44 | ||||
-rw-r--r-- | src/Config.hpp | 10 | ||||
-rw-r--r-- | src/Context.cpp | 9 | ||||
-rw-r--r-- | src/Context.hpp | 5 | ||||
-rw-r--r-- | src/ccache.cpp | 129 | ||||
-rw-r--r-- | src/ccache.hpp | 18 | ||||
-rw-r--r-- | src/core/mainoptions.cpp | 14 | ||||
-rw-r--r-- | test/suites/config.bash | 12 | ||||
-rw-r--r-- | unittest/test_ccache.cpp | 156 |
10 files changed, 260 insertions, 161 deletions
diff --git a/doc/MANUAL.adoc b/doc/MANUAL.adoc index e22685ec..4645267b 100644 --- a/doc/MANUAL.adoc +++ b/doc/MANUAL.adoc @@ -9,9 +9,14 @@ ccache - a fast C/C++ compiler cache == Synopsis [verse] -*ccache* [_options_] -*ccache* _compiler_ [_compiler options_] -_compiler_ [_compiler options_] (ccache masquerading as the compiler) +*ccache* [_ccache options_] +*ccache* [_KEY_=_VALUE_ ...] _compiler_ [_compiler options_] +_compiler_ [_compiler options_] + +The first form takes options described in <<Command line options>> below. The +second form invokes the compiler, optionally using <<Configuration,configuration +options>> as _KEY_=_VALUE_ arguments. In the third form, ccache is masquerading +as the compiler as described in <<Run modes>>. == Description @@ -310,11 +315,16 @@ system-level configuration file and secondly a cache-specific configuration file. The priorities of configuration options are as follows (where 1 is highest): -1. Environment variables. -2. The cache-specific configuration file (see below). -3. The system (read-only) configuration file `<sysconfdir>/ccache.conf` +1. Command line settings in _KEY_=_VALUE_ form. Example: ++ +------------------------------------------------------------------------------- +ccache debug=true compiler_check="%compiler% --version" gcc -c example.c +------------------------------------------------------------------------------- +2. Environment variables. +3. The cache-specific configuration file (see below). +4. The system (read-only) configuration file `<sysconfdir>/ccache.conf` (typically `/etc/ccache.conf` or `/usr/local/etc/ccache.conf`). -4. Compile-time defaults. +5. Compile-time defaults. As a special case, if the environment variable `CCACHE_CONFIGPATH` is set it specifies the configuration file, and the system configuration file won't be diff --git a/src/Config.cpp b/src/Config.cpp index a12180a8..a28d5647 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2022 Joel Rosdahl and other contributors +// Copyright (C) 2019-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -439,6 +439,24 @@ parse_config_file(const std::string& path, return true; } +std::unordered_map<std::string, std::string> +create_cmdline_settings_map(const std::vector<std::string>& settings) +{ + std::unordered_map<std::string, std::string> result; + for (const auto& setting : settings) { + DEBUG_ASSERT(setting.find('=') != std::string::npos); + std::string key; + std::string value; + std::string error_message; + bool ok = parse_line(setting, &key, &value, &error_message); + ASSERT(ok); + if (!key.empty()) { + result.insert_or_assign(std::move(key), std::move(value)); + } + } + return result; +} + } // namespace #ifndef _WIN32 @@ -489,8 +507,11 @@ compiler_type_to_string(CompilerType compiler_type) } void -Config::read() +Config::read(const std::vector<std::string>& cmdline_config_settings) { + auto cmdline_settings_map = + create_cmdline_settings_map(cmdline_config_settings); + const std::string home_dir = Util::get_home_directory(); const std::string legacy_ccache_dir = Util::make_path(home_dir, ".ccache"); const bool legacy_ccache_dir_exists = @@ -525,8 +546,12 @@ Config::read() MTR_END("config", "conf_read_system"); const char* const env_ccache_dir = getenv("CCACHE_DIR"); + auto cmdline_cache_dir = cmdline_settings_map.find("cache_dir"); + std::string config_dir; - if (env_ccache_dir && *env_ccache_dir) { + if (cmdline_cache_dir != cmdline_settings_map.end()) { + config_dir = cmdline_cache_dir->second; + } else if (env_ccache_dir && *env_ccache_dir) { config_dir = env_ccache_dir; } else if (!cache_dir().empty() && !env_ccache_dir) { config_dir = cache_dir(); @@ -572,6 +597,8 @@ Config::read() // (cache_dir is set above if CCACHE_DIR is set.) MTR_END("config", "conf_update_from_environment"); + update_from_map(cmdline_settings_map); + if (cache_dir().empty()) { if (legacy_ccache_dir_exists) { set_cache_dir(legacy_ccache_dir); @@ -594,7 +621,8 @@ Config::read() // else: cache_dir was set explicitly via environment or via system config. // We have now determined config.cache_dir and populated the rest of config in - // prio order (1. environment, 2. cache-specific config, 3. system config). + // prio order (1. command line, 2. environment, 3. cache-specific config, 4. + // system config). } const std::string& @@ -633,6 +661,14 @@ Config::update_from_file(const std::string& path) } void +Config::update_from_map(const std::unordered_map<std::string, std::string>& map) +{ + for (const auto& [key, value] : map) { + set_item(key, value, std::nullopt, false, "command line"); + } +} + +void Config::update_from_environment() { for (char** env = environ; *env; ++env) { diff --git a/src/Config.hpp b/src/Config.hpp index b1d2e101..43c6a7fc 100644 --- a/src/Config.hpp +++ b/src/Config.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2022 Joel Rosdahl and other contributors +// Copyright (C) 2019-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -30,6 +30,7 @@ #include <optional> #include <string> #include <unordered_map> +#include <vector> enum class CompilerType { auto_guess, @@ -49,7 +50,7 @@ class Config : NonCopyable public: Config() = default; - void read(); + void read(const std::vector<std::string>& cmdline_config_settings = {}); bool absolute_paths_in_stderr() const; const std::string& base_dir() const; @@ -139,6 +140,11 @@ public: // invalid configuration values. bool update_from_file(const std::string& path); + // Set config values from a map with key-value pairs. + // + // Throws Error on invalid configuration values. + void update_from_map(const std::unordered_map<std::string, std::string>& map); + // Set config values from environment variables. // // Throws Error on invalid configuration values. diff --git a/src/Context.cpp b/src/Context.cpp index c46d3684..0a45d9e6 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Joel Rosdahl and other contributors +// Copyright (C) 2020-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -49,11 +49,12 @@ Context::Context() } void -Context::initialize() +Context::initialize(Args&& compiler_and_args, + const std::vector<std::string>& cmdline_config_settings) { - config.read(); + orig_args = std::move(compiler_and_args); + config.read(cmdline_config_settings); Logging::init(config); - ignore_header_paths = util::split_path_list(config.ignore_headers_in_manifest()); set_ignore_options(Util::split_into_strings(config.ignore_options(), " ")); diff --git a/src/Context.hpp b/src/Context.hpp index 883c02f4..3eee4e5e 100644 --- a/src/Context.hpp +++ b/src/Context.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Joel Rosdahl and other contributors +// Copyright (C) 2020-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -51,7 +51,8 @@ public: // Read configuration, initialize logging, etc. Typically not called from unit // tests. - void initialize(); + void initialize(Args&& compiler_and_args, + const std::vector<std::string>& cmdline_config_settings); ArgsInfo args_info; Config config; diff --git a/src/ccache.cpp b/src/ccache.cpp index ff5315c1..d867dd1e 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -72,6 +72,7 @@ #include <algorithm> #include <cmath> +#include <cstring> #include <limits> #include <memory> #include <unordered_map> @@ -2109,25 +2110,18 @@ from_cache(Context& ctx, FromCacheCallMode mode, const Digest& result_key) // PATH to find an executable of the same name that isn't ourselves. void find_compiler(Context& ctx, - const FindExecutableFunction& find_executable_function) + const FindExecutableFunction& find_executable_function, + bool masquerading_as_compiler) { - // gcc --> 0 - // ccache gcc --> 1 - // ccache ccache gcc --> 2 - size_t compiler_pos = 0; - while (compiler_pos < ctx.orig_args.size() - && Util::is_ccache_executable(ctx.orig_args[compiler_pos])) { - ++compiler_pos; - } - // Support user override of the compiler. const std::string compiler = !ctx.config.compiler().empty() ? ctx.config.compiler() // In case ccache is masquerading as the compiler, use only base_name so // the real compiler can be determined. - : (compiler_pos == 0 ? std::string(Util::base_name(ctx.orig_args[0])) - : ctx.orig_args[compiler_pos]); + : (masquerading_as_compiler + ? std::string(Util::base_name(ctx.orig_args[0])) + : ctx.orig_args[0]); const std::string resolved_compiler = util::is_full_path(compiler) @@ -2142,17 +2136,12 @@ find_compiler(Context& ctx, throw core::Fatal("Recursive invocation of ccache"); } - ctx.orig_args.pop_front(compiler_pos); ctx.orig_args[0] = resolved_compiler; } -// Initialize ccache. Must be called once before anything else is run. static void -initialize(Context& ctx, int argc, const char* const* argv) +initialize(Context& ctx, const char* const* argv, bool masquerading_as_compiler) { - ctx.orig_args = Args::from_argv(argc, argv); - ctx.storage.initialize(); - LOG("=== CCACHE {} STARTED =========================================", CCACHE_VERSION); @@ -2166,6 +2155,42 @@ initialize(Context& ctx, int argc, const char* const* argv) LOG_RAW("Error: tracing is not enabled!"); #endif } + + if (!ctx.config.log_file().empty() || ctx.config.debug()) { + ctx.config.visit_items([&ctx](const std::string& key, + const std::string& value, + const std::string& origin) { + const auto& log_value = + key == "remote_storage" + ? ctx.storage.get_remote_storage_config_for_logging() + : value; + BULK_LOG("Config: ({}) {} = {}", origin, key, log_value); + }); + } + + LOG("Command line: {}", Util::format_argv_for_logging(argv)); + LOG("Hostname: {}", Util::get_hostname()); + LOG("Working directory: {}", ctx.actual_cwd); + if (ctx.apparent_cwd != ctx.actual_cwd) { + LOG("Apparent working directory: {}", ctx.apparent_cwd); + } + + ctx.storage.initialize(); + + MTR_BEGIN("main", "find_compiler"); + find_compiler(ctx, &find_executable, masquerading_as_compiler); + MTR_END("main", "find_compiler"); + + // Guess compiler after logging the config value in order to be able to + // display "compiler_type = auto" before overwriting the value with the + // guess. + if (ctx.config.compiler_type() == CompilerType::auto_guess) { + ctx.config.set_compiler_type(guess_compiler(ctx.orig_args[0])); + } + DEBUG_ASSERT(ctx.config.compiler_type() != CompilerType::auto_guess); + + LOG("Compiler: {}", ctx.orig_args[0]); + LOG("Compiler type: {}", compiler_type_to_string(ctx.config.compiler_type())); } // Make a copy of stderr that will not be cached, so things like distcc can @@ -2187,7 +2212,7 @@ set_up_uncached_err() static int cache_compilation(int argc, const char* const* argv); static nonstd::expected<core::StatisticsCounters, Failure> -do_cache_compilation(Context& ctx, const char* const* argv); +do_cache_compilation(Context& ctx); static void log_result_to_debug_log(Context& ctx) @@ -2247,6 +2272,23 @@ finalize_at_exit(Context& ctx) } } +ArgvParts +split_argv(int argc, const char* const* argv) +{ + ArgvParts argv_parts; + int i = 0; + while (i < argc && Util::is_ccache_executable(argv[i])) { + argv_parts.masquerading_as_compiler = false; + ++i; + } + while (i < argc && std::strchr(argv[i], '=')) { + argv_parts.config_settings.emplace_back(argv[i]); + ++i; + } + argv_parts.compiler_and_args = Args::from_argv(argc - i, argv + i); + return argv_parts; +} + // The entry point when invoked to cache a compilation. static int cache_compilation(int argc, const char* const* argv) @@ -2258,15 +2300,21 @@ cache_compilation(int argc, const char* const* argv) std::optional<uint32_t> original_umask; std::string saved_temp_dir; + auto argv_parts = split_argv(argc, argv); + if (argv_parts.compiler_and_args.empty()) { + throw core::Fatal("no compiler given, see \"ccache --help\""); + } + { Context ctx; - ctx.initialize(); + ctx.initialize(std::move(argv_parts.compiler_and_args), + argv_parts.config_settings); SignalHandler signal_handler(ctx); Finalizer finalizer([&ctx] { finalize_at_exit(ctx); }); - initialize(ctx, argc, argv); + initialize(ctx, argv, argv_parts.masquerading_as_compiler); - const auto result = do_cache_compilation(ctx, argv); + const auto result = do_cache_compilation(ctx); ctx.storage.local.increment_statistics(result ? *result : result.error().counters()); const auto& counters = ctx.storage.local.get_statistics_updates(); @@ -2324,43 +2372,8 @@ cache_compilation(int argc, const char* const* argv) } static nonstd::expected<core::StatisticsCounters, Failure> -do_cache_compilation(Context& ctx, const char* const* argv) +do_cache_compilation(Context& ctx) { - if (!ctx.config.log_file().empty() || ctx.config.debug()) { - ctx.config.visit_items([&ctx](const std::string& key, - const std::string& value, - const std::string& origin) { - const auto& log_value = - key == "remote_storage" - ? ctx.storage.get_remote_storage_config_for_logging() - : value; - BULK_LOG("Config: ({}) {} = {}", origin, key, log_value); - }); - } - - LOG("Command line: {}", Util::format_argv_for_logging(argv)); - LOG("Hostname: {}", Util::get_hostname()); - LOG("Working directory: {}", ctx.actual_cwd); - if (ctx.apparent_cwd != ctx.actual_cwd) { - LOG("Apparent working directory: {}", ctx.apparent_cwd); - } - - // Note: do_cache_compilation must not return or use ctx.orig_args before - // find_compiler is executed. - MTR_BEGIN("main", "find_compiler"); - find_compiler(ctx, &find_executable); - MTR_END("main", "find_compiler"); - - // Guess compiler after logging the config value in order to be able to - // display "compiler_type = auto" before overwriting the value with the - // guess. - if (ctx.config.compiler_type() == CompilerType::auto_guess) { - ctx.config.set_compiler_type(guess_compiler(ctx.orig_args[0])); - } - DEBUG_ASSERT(ctx.config.compiler_type() != CompilerType::auto_guess); - - LOG("Compiler type: {}", compiler_type_to_string(ctx.config.compiler_type())); - if (ctx.config.disable()) { LOG_RAW("ccache is disabled"); return nonstd::make_unexpected(Statistic::none); diff --git a/src/ccache.hpp b/src/ccache.hpp index 510563a4..a3d0be77 100644 --- a/src/ccache.hpp +++ b/src/ccache.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2002-2007 Andrew Tridgell -// Copyright (C) 2009-2022 Joel Rosdahl and other contributors +// Copyright (C) 2009-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -19,11 +19,13 @@ #pragma once -#include "Config.hpp" +#include <Args.hpp> +#include <Config.hpp> #include <functional> #include <string> #include <string_view> +#include <vector> class Context; @@ -37,6 +39,16 @@ using FindExecutableFunction = int ccache_main(int argc, const char* const* argv); // Tested by unit tests. +struct ArgvParts +{ + bool masquerading_as_compiler = true; + std::vector<std::string> config_settings; + Args compiler_and_args; +}; + +ArgvParts split_argv(int argc, const char* const* argv); + void find_compiler(Context& ctx, - const FindExecutableFunction& find_executable_function); + const FindExecutableFunction& find_executable_function, + bool masquerading_as_compiler); CompilerType guess_compiler(std::string_view path); diff --git a/src/core/mainoptions.cpp b/src/core/mainoptions.cpp index 32a89b4e..e8b46437 100644 --- a/src/core/mainoptions.cpp +++ b/src/core/mainoptions.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Joel Rosdahl and other contributors +// Copyright (C) 2021-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -88,9 +88,13 @@ version. constexpr const char USAGE_TEXT[] = R"(Usage: - {0} [options] - {0} compiler [compiler options] - compiler [compiler options] (ccache masquerading as the compiler) + {0} [ccache options] + {0} [KEY=VALUE ...] compiler [compiler options] + compiler [compiler options] + + The first form takes options described below. The second form invokes the + compiler, optionally using configuration options from KEY=VALUE arguments. + In the third form, ccache is masquerading as the compiler. Common options: -c, --cleanup delete old files and recalculate size counters @@ -115,7 +119,7 @@ Common options: --recompress-threads THREADS use up to THREADS threads when recompressing the cache; default: number of CPUs - -o, --set-config KEY=VAL set configuration option KEY to value VAL + -o, --set-config KEY=VALUE set configuration option KEY to value VALUE -x, --show-compression show compression statistics -p, --show-config show current configuration options in human-readable format diff --git a/test/suites/config.bash b/test/suites/config.bash index 97da52c7..7a21f4bb 100644 --- a/test/suites/config.bash +++ b/test/suites/config.bash @@ -8,4 +8,16 @@ SUITE_config() { $CCACHE --show-config >config.txt expect_contains config.txt "(environment) max_size = 40" + + # ------------------------------------------------------------------------- + TEST "Command line origin" + + export CCACHE_DEBUG="1" + export CCACHE_MAXSIZE="40" + + touch test.c + $CCACHE debug=true "max_size = 40" $COMPILER -c test.c + + expect_contains test.o.*.ccache-log "(command line) debug = true" + expect_contains test.o.*.ccache-log "(command line) max_size = 40" } diff --git a/unittest/test_ccache.cpp b/unittest/test_ccache.cpp index 30f3bdd7..61671f84 100644 --- a/unittest/test_ccache.cpp +++ b/unittest/test_ccache.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Joel Rosdahl and other contributors +// Copyright (C) 2020-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -38,7 +38,8 @@ TEST_SUITE_BEGIN("ccache"); // Wraps find_compiler in a test friendly interface. static std::string -helper(const char* args, +helper(bool masquerading_as_compiler, + const char* args, const char* config_compiler, const char* find_executable_return_string = nullptr) { @@ -51,10 +52,60 @@ helper(const char* args, Context ctx; ctx.config.set_compiler(config_compiler); ctx.orig_args = Args::from_string(args); - find_compiler(ctx, find_executable_stub); + find_compiler(ctx, find_executable_stub, masquerading_as_compiler); return ctx.orig_args.to_string(); } +TEST_CASE("split_argv") +{ + ArgvParts argv_parts; + + SUBCASE("empty") + { + argv_parts = split_argv(0, nullptr); + CHECK(argv_parts.masquerading_as_compiler); + CHECK(argv_parts.config_settings.empty()); + CHECK(argv_parts.compiler_and_args.empty()); + } + + SUBCASE("ccache") + { + const char* const argv[] = {"ccache"}; + argv_parts = split_argv(std::size(argv), argv); + CHECK(!argv_parts.masquerading_as_compiler); + CHECK(argv_parts.config_settings.empty()); + CHECK(argv_parts.compiler_and_args.empty()); + } + + SUBCASE("normal compilation") + { + const char* const argv[] = {"ccache", "gcc", "-c", "test.c"}; + argv_parts = split_argv(std::size(argv), argv); + CHECK(!argv_parts.masquerading_as_compiler); + CHECK(argv_parts.config_settings.empty()); + CHECK(argv_parts.compiler_and_args == Args::from_string("gcc -c test.c")); + } + + SUBCASE("only config options") + { + const char* const argv[] = {"ccache", "foo=bar"}; + argv_parts = split_argv(std::size(argv), argv); + CHECK(!argv_parts.masquerading_as_compiler); + CHECK(argv_parts.config_settings == std::vector<std::string>{"foo=bar"}); + CHECK(argv_parts.compiler_and_args.empty()); + } + + SUBCASE("compilation with config options") + { + const char* const argv[] = {"ccache", "a=b", "c = d", "/usr/bin/gcc"}; + argv_parts = split_argv(std::size(argv), argv); + CHECK(!argv_parts.masquerading_as_compiler); + CHECK(argv_parts.config_settings + == std::vector<std::string>{"a=b", "c = d"}); + CHECK(argv_parts.compiler_and_args == Args::from_string("/usr/bin/gcc")); + } +} + TEST_CASE("find_compiler") { SUBCASE("no config") @@ -62,60 +113,27 @@ TEST_CASE("find_compiler") // In case the first parameter is gcc it must be a link to ccache, so // find_compiler should call find_executable to locate the next best "gcc" // and return that value. - CHECK(helper("gcc", "") == "resolved_gcc"); - CHECK(helper("relative/gcc", "") == "resolved_gcc"); - CHECK(helper("/absolute/gcc", "") == "resolved_gcc"); + CHECK(helper(true, "gcc", "") == "resolved_gcc"); + CHECK(helper(true, "relative/gcc", "") == "resolved_gcc"); + CHECK(helper(true, "/absolute/gcc", "") == "resolved_gcc"); // In case the first parameter is ccache, resolve the second parameter to // the real compiler unless it's a relative or absolute path. - CHECK(helper("ccache gcc", "") == "resolved_gcc"); - CHECK(helper("ccache rel/gcc", "") == "rel/gcc"); - CHECK(helper("ccache /abs/gcc", "") == "/abs/gcc"); - - CHECK(helper("rel/ccache gcc", "") == "resolved_gcc"); - CHECK(helper("rel/ccache rel/gcc", "") == "rel/gcc"); - CHECK(helper("rel/ccache /abs/gcc", "") == "/abs/gcc"); - - CHECK(helper("/abs/ccache gcc", "") == "resolved_gcc"); - CHECK(helper("/abs/ccache rel/gcc", "") == "rel/gcc"); - CHECK(helper("/abs/ccache /abs/gcc", "") == "/abs/gcc"); + CHECK(helper(false, "gcc", "") == "resolved_gcc"); + CHECK(helper(false, "rel/gcc", "") == "rel/gcc"); + CHECK(helper(false, "/abs/gcc", "") == "/abs/gcc"); // If gcc points back to ccache throw, unless either ccache or gcc is a // relative or absolute path. - CHECK_THROWS(helper("ccache gcc", "", "ccache")); - CHECK(helper("ccache rel/gcc", "", "ccache") == "rel/gcc"); - CHECK(helper("ccache /abs/gcc", "", "ccache") == "/abs/gcc"); - - CHECK_THROWS(helper("rel/ccache gcc", "", "ccache")); - CHECK(helper("rel/ccache rel/gcc", "", "ccache") == "rel/gcc"); - CHECK(helper("rel/ccache /a/gcc", "", "ccache") == "/a/gcc"); - - CHECK_THROWS(helper("/abs/ccache gcc", "", "ccache")); - CHECK(helper("/abs/ccache rel/gcc", "", "ccache") == "rel/gcc"); - CHECK(helper("/abs/ccache /a/gcc", "", "ccache") == "/a/gcc"); + CHECK_THROWS(helper(false, "gcc", "", "ccache")); + CHECK(helper(false, "rel/gcc", "", "ccache") == "rel/gcc"); + CHECK(helper(false, "/abs/gcc", "", "ccache") == "/abs/gcc"); // If compiler is not found then throw, unless the compiler has a relative // or absolute path. - CHECK_THROWS(helper("ccache gcc", "", "")); - CHECK(helper("ccache rel/gcc", "", "") == "rel/gcc"); - CHECK(helper("ccache /abs/gcc", "", "") == "/abs/gcc"); - - CHECK_THROWS(helper("rel/ccache gcc", "", "")); - CHECK(helper("rel/ccache rel/gcc", "", "") == "rel/gcc"); - CHECK(helper("rel/ccache /abs/gcc", "", "") == "/abs/gcc"); - - CHECK_THROWS(helper("/abs/ccache gcc", "", "")); - CHECK(helper("/abs/ccache rel/gcc", "", "") == "rel/gcc"); - CHECK(helper("/abs/ccache /abs/gcc", "", "") == "/abs/gcc"); - } - - SUBCASE("double ccache") - { - // E.g. due to some suboptimal setup, scripts etc. Source: - // https://github.com/ccache/ccache/issues/686 - CHECK(helper("ccache gcc", "") == "resolved_gcc"); - CHECK(helper("ccache ccache gcc", "") == "resolved_gcc"); - CHECK(helper("ccache ccache-1.2.3 ccache gcc", "") == "resolved_gcc"); + CHECK_THROWS(helper(false, "gcc", "", "")); + CHECK(helper(false, "rel/gcc", "", "") == "rel/gcc"); + CHECK(helper(false, "/abs/gcc", "", "") == "/abs/gcc"); } SUBCASE("config") @@ -123,37 +141,23 @@ TEST_CASE("find_compiler") // In case the first parameter is gcc it must be a link to ccache so use // config value instead. Don't resolve config if it's a relative or absolute // path. - CHECK(helper("gcc", "config") == "resolved_config"); - CHECK(helper("gcc", "rel/config") == "rel/config"); - CHECK(helper("gcc", "/abs/config") == "/abs/config"); - CHECK(helper("rel/gcc", "config") == "resolved_config"); - CHECK(helper("rel/gcc", "rel/config") == "rel/config"); - CHECK(helper("rel/gcc", "/abs/config") == "/abs/config"); - CHECK(helper("/abs/gcc", "config") == "resolved_config"); - CHECK(helper("/abs/gcc", "rel/config") == "rel/config"); - CHECK(helper("/abs/gcc", "/abs/config") == "/abs/config"); + CHECK(helper(true, "gcc", "config") == "resolved_config"); + CHECK(helper(true, "gcc", "rel/config") == "rel/config"); + CHECK(helper(true, "gcc", "/abs/config") == "/abs/config"); + CHECK(helper(true, "rel/gcc", "config") == "resolved_config"); + CHECK(helper(true, "rel/gcc", "rel/config") == "rel/config"); + CHECK(helper(true, "rel/gcc", "/abs/config") == "/abs/config"); + CHECK(helper(true, "/abs/gcc", "config") == "resolved_config"); + CHECK(helper(true, "/abs/gcc", "rel/config") == "rel/config"); + CHECK(helper(true, "/abs/gcc", "/abs/config") == "/abs/config"); // In case the first parameter is ccache, use the configuration value. Don't // resolve configuration value if it's a relative or absolute path. - CHECK(helper("ccache gcc", "config") == "resolved_config"); - CHECK(helper("ccache gcc", "rel/config") == "rel/config"); - CHECK(helper("ccache gcc", "/abs/config") == "/abs/config"); - CHECK(helper("ccache rel/gcc", "config") == "resolved_config"); - CHECK(helper("ccache /abs/gcc", "config") == "resolved_config"); - - // Same as above with relative path to ccache. - CHECK(helper("r/ccache gcc", "conf") == "resolved_conf"); - CHECK(helper("r/ccache gcc", "rel/conf") == "rel/conf"); - CHECK(helper("r/ccache gcc", "/abs/conf") == "/abs/conf"); - CHECK(helper("r/ccache rel/gcc", "conf") == "resolved_conf"); - CHECK(helper("r/ccache /abs/gcc", "conf") == "resolved_conf"); - - // Same as above with absolute path to ccache. - CHECK(helper("/a/ccache gcc", "conf") == "resolved_conf"); - CHECK(helper("/a/ccache gcc", "rel/conf") == "rel/conf"); - CHECK(helper("/a/ccache gcc", "/a/conf") == "/a/conf"); - CHECK(helper("/a/ccache rel/gcc", "conf") == "resolved_conf"); - CHECK(helper("/a/ccache /abs/gcc", "conf") == "resolved_conf"); + CHECK(helper(false, "gcc", "config") == "resolved_config"); + CHECK(helper(false, "gcc", "rel/config") == "rel/config"); + CHECK(helper(false, "gcc", "/abs/config") == "/abs/config"); + CHECK(helper(false, "rel/gcc", "config") == "resolved_config"); + CHECK(helper(false, "/abs/gcc", "config") == "resolved_config"); } } |