From: Joel Rosdahl Date: Thu, 30 Apr 2020 06:29:31 +0000 (+0200) Subject: Improve handling of profiling options X-Git-Tag: v4.0~517 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d0eb89de;p=thirdparty%2Fccache.git Improve handling of profiling options Handling of -fprofile-{generate,use}[=path] was implemented in PR #2 (2011). ccache has since then gained support for Clang, which is not GCC-compatible for -fprofile-{generate,use}[=path]. Furthermore, GCC 9 changed the semantics of -fprofile-{generate,use}=path, making it incompatible with ccache’s original implementation. One crucial problem with the implementation is that there is no error handling when the expected profiling data file cannot be found. This means that there will be false positives cache hits for Clang and GCC 9+. Fix this by: * Checking for different profiling data file locations to handle different compilers and versions. * Bailing out if no profiling data file can be found. Also: * Implemented support for Clang’s -fprofile-instr-{generate,use}[=path] options. * Implemented support for -fauto-profile[=path]. * Removed the conversion of absolute path to the profile directory. 91a2954e says that the directory is rewritten to increase the hit rate, but I don’t understand how that could be the case. * Added tests for the profiling options. Exception: -fauto-profile[=path], since that would require running the perf tool. Fixes #582. (cherry picked from commit c9fdcef576dd13a2ea2355bcd866b5c561cb1562) --- diff --git a/src/ArgsInfo.hpp b/src/ArgsInfo.hpp index 76a9a708a..9b85fbe46 100644 --- a/src/ArgsInfo.hpp +++ b/src/ArgsInfo.hpp @@ -79,8 +79,8 @@ struct ArgsInfo // Is the compiler being asked to output coverage data (.gcda) at runtime? bool profile_arcs = false; - // Name of the custom profile directory (default: object dirname). - std::string profile_dir; + // Name of the custom profile directory or file. + std::string profile_path; // Profile generation / usage information. bool profile_use = false; diff --git a/src/ccache.cpp b/src/ccache.cpp index a53f7a11f..30f93e003 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -1559,8 +1559,8 @@ hash_common_info(const Context& ctx, // Possibly hash the coverage data file path. if (ctx.args_info.generating_coverage && ctx.args_info.profile_arcs) { std::string dir; - if (!ctx.args_info.profile_dir.empty()) { - dir = ctx.args_info.profile_dir; + if (!ctx.args_info.profile_path.empty()) { + dir = ctx.args_info.profile_path; } else { dir = Util::real_path(std::string(Util::dir_name(ctx.args_info.output_obj))); @@ -1604,6 +1604,43 @@ hash_common_info(const Context& ctx, } } +static bool +hash_profile_data_file(const Context& ctx, struct hash* hash) +{ + const std::string& profile_path = ctx.args_info.profile_path; + string_view base_name = Util::remove_extension(ctx.args_info.output_obj); + std::string hashified_cwd = ctx.apparent_cwd; + std::replace(hashified_cwd.begin(), hashified_cwd.end(), '/', '#'); + + std::vector paths_to_try{ + // -fprofile-use[=dir]/-fbranch-probabilities (GCC <9) + fmt::format("{}/{}.gcda", profile_path, base_name), + // -fprofile-use[=dir]/-fbranch-probabilities (GCC >=9) + fmt::format("{}/{}#{}.gcda", profile_path, hashified_cwd, base_name), + // -fprofile(-instr)-use=file (Clang), -fauto-profile=file (GCC >=5) + profile_path, + // -fprofile(-instr)-use=dir (Clang) + fmt::format("{}/default.profdata", profile_path), + // -fauto-profile (GCC >=5) + "fbdata.afdo", // -fprofile-dir is not used + }; + + bool found = false; + for (const std::string& p : paths_to_try) { + cc_log("Checking for profile data file %s", p.c_str()); + auto st = Stat::stat(p); + if (st && !st.is_directory()) { + cc_log("Adding profile data %s to the hash", p.c_str()); + hash_delimiter(hash, "-fprofile-use"); + if (hash_file(hash, p.c_str())) { + found = true; + } + } + } + + return found; +} + // Update a hash sum with information specific to the direct and preprocessor // modes and calculate the result name. Returns the result name on success, // otherwise NULL. Caller frees. @@ -1784,33 +1821,29 @@ calculate_result_name(Context& ctx, hash_nvcc_host_compiler(ctx, hash, nullptr, nullptr); } - // For profile generation (-fprofile-arcs, -fprofile-generate): - // - hash profile directory + // For profile generation (-fprofile(-instr)-generate[=path]) + // - hash profile path // - // For profile usage (-fprofile-use): + // For profile usage (-fprofile(-instr)-use, -fbranch-probabilities): // - hash profile data // // -fbranch-probabilities and -fvpt usage is covered by // -fprofile-generate/-fprofile-use. // // The profile directory can be specified as an argument to - // -fprofile-generate=, -fprofile-use= or -fprofile-dir=. + // -fprofile(-instr)-generate=, -fprofile(-instr)-use= or -fprofile-dir=. + if (ctx.args_info.profile_generate) { + assert(!ctx.args_info.profile_path.empty()); cc_log("Adding profile directory %s to our hash", - ctx.args_info.profile_dir.c_str()); + ctx.args_info.profile_path.c_str()); hash_delimiter(hash, "-fprofile-dir"); - hash_string(hash, ctx.args_info.profile_dir); + hash_string(hash, ctx.args_info.profile_path); } - if (ctx.args_info.profile_use) { - // Calculate gcda name. - string_view base_name = Util::remove_extension(ctx.args_info.output_obj); - std::string gcda_name = - fmt::format("{}/{}.gcda", ctx.args_info.profile_dir, base_name); - cc_log("Adding profile data %s to our hash", gcda_name.c_str()); - // Add the gcda to our hash. - hash_delimiter(hash, "-fprofile-use"); - hash_file(hash, gcda_name.c_str()); + if (ctx.args_info.profile_use && !hash_profile_data_file(ctx, hash)) { + cc_log("No profile data file found"); + failed(STATS_NOINPUT); } // Adding -arch to hash since cpp output is affected. @@ -2077,6 +2110,64 @@ detect_pch(Context& ctx, const char* option, const char* arg, bool* found_pch) return true; } +static bool +process_profiling_option(Context& ctx, const std::string& arg) +{ + std::string new_profile_path; + bool new_profile_use = false; + + if (Util::starts_with(arg, "-fprofile-dir=")) { + new_profile_path = arg.substr(arg.find('=') + 1); + } else if (arg == "-fprofile-generate" || arg == "-fprofile-instr-generate") { + ctx.args_info.profile_generate = true; + if (ctx.guessed_compiler == GuessedCompiler::clang) { + new_profile_path = "."; + } else { + // GCC uses $PWD/$(basename $obj). + new_profile_path = ctx.apparent_cwd; + } + } else if (Util::starts_with(arg, "-fprofile-generate=") + || Util::starts_with(arg, "-fprofile-instr-generate=")) { + ctx.args_info.profile_generate = true; + new_profile_path = arg.substr(arg.find('=') + 1); + } else if (arg == "-fprofile-use" || arg == "-fprofile-instr-use" + || arg == "-fbranch-probabilities" || arg == "-fauto-profile") { + new_profile_use = true; + if (ctx.args_info.profile_path.empty()) { + new_profile_path = "."; + } + } else if (Util::starts_with(arg, "-fprofile-use=") + || Util::starts_with(arg, "-fprofile-instr-use=") + || Util::starts_with(arg, "-fauto-profile=")) { + new_profile_use = true; + new_profile_path = arg.substr(arg.find('=') + 1); + } else { + cc_log("Unknown profiling option: %s", arg.c_str()); + return false; + } + + if (new_profile_use) { + if (ctx.args_info.profile_use) { + cc_log("Multiple profiling options not supported"); + return false; + } + ctx.args_info.profile_use = true; + } + + if (!new_profile_path.empty()) { + ctx.args_info.profile_path = new_profile_path; + cc_log("Set profile directory to %s", ctx.args_info.profile_path.c_str()); + } + + if (ctx.args_info.profile_generate && ctx.args_info.profile_use) { + // Too hard to figure out what the compiler will do. + cc_log("Both generating and using profile info, giving up"); + return false; + } + + return true; +} + // Process the compiler options into options suitable for passing to the // preprocessor and the real compiler. preprocessor_args doesn't include -E; // this is added later. extra_args_to_hash are the arguments that are not @@ -2158,6 +2249,7 @@ process_args(Context& ctx, for (size_t i = 1; i < expanded_args.size(); i++) { size_t argc = expanded_args.size(); + const std::string& arg = expanded_args[i]; // The user knows best: just swallow the next arg. if (str_eq(argv[i], "--ccache-skip")) { @@ -2244,7 +2336,7 @@ process_args(Context& ctx, // -Xarch_* options are too hard. if (str_startswith(argv[i], "-Xarch_")) { - cc_log("Unsupported compiler option :%s", argv[i]); + cc_log("Unsupported compiler option: %s", argv[i]); return STATS_UNSUPPORTED_OPTION; } @@ -2497,8 +2589,13 @@ process_args(Context& ctx, args_add(common_args, argv[i]); continue; } - if (str_startswith(argv[i], "-fprofile-dir=")) { - args_info.profile_dir.assign(argv[i] + 14); + if (Util::starts_with(arg, "-fprofile-") + || Util::starts_with(arg, "-fauto-profile") + || arg == "-fbranch-probabilities") { + if (!process_profiling_option(ctx, argv[i])) { + // The failure is logged by process_profiling_option. + return STATS_UNSUPPORTED_OPTION; + } args_add(common_args, argv[i]); continue; } @@ -2609,53 +2706,6 @@ process_args(Context& ctx, continue; } - if (str_startswith(argv[i], "-fprofile-")) { - char* arg = x_strdup(argv[i]); - const char* arg_profile_dir = strchr(argv[i], '='); - if (arg_profile_dir) { - // Convert to absolute path. - std::string dir = Util::real_path(arg_profile_dir + 1); - - // We can get a better hit rate by using the real path here. - free(arg); - char* option = x_strndup(argv[i], arg_profile_dir - argv[i]); - arg = format("%s=%s", option, dir.c_str()); - cc_log("Rewriting %s to %s", argv[i], arg); - free(option); - } - - bool supported_profile_option = false; - if (str_startswith(argv[i], "-fprofile-generate") - || str_eq(argv[i], "-fprofile-arcs")) { - args_info.profile_generate = true; - supported_profile_option = true; - } else if (str_startswith(argv[i], "-fprofile-use") - || str_eq(argv[i], "-fbranch-probabilities")) { - args_info.profile_use = true; - supported_profile_option = true; - } else if (str_eq(argv[i], "-fprofile-dir")) { - supported_profile_option = true; - } - - if (supported_profile_option) { - args_add(common_args, arg); - free(arg); - - // If the profile directory has already been set, give up... Hard to - // know what the user means, and what the compiler will do. - if (arg_profile_dir && !args_info.profile_dir.empty()) { - cc_log("Profile directory already set; giving up"); - return STATS_UNSUPPORTED_OPTION; - } else if (arg_profile_dir) { - cc_log("Setting profile directory to %s", arg_profile_dir); - args_info.profile_dir = from_cstr(arg_profile_dir); - } - continue; - } - cc_log("Unknown profile option: %s", argv[i]); - free(arg); - } - if (str_eq(argv[i], "-fcolor-diagnostics") || str_eq(argv[i], "-fno-color-diagnostics") || str_eq(argv[i], "-fdiagnostics-color") @@ -2897,8 +2947,8 @@ process_args(Context& ctx, } } - if (args_info.profile_dir.empty()) { - args_info.profile_dir = ctx.apparent_cwd; + if (args_info.profile_path.empty()) { + args_info.profile_path = ctx.apparent_cwd; } if (explicit_language && str_eq(explicit_language, "none")) { diff --git a/test/run b/test/run index c7fcbed0d..7b356d7b2 100755 --- a/test/run +++ b/test/run @@ -363,6 +363,7 @@ case $compiler_version in ;; *clang*) COMPILER_TYPE_CLANG=true + CLANG_VERSION_SUFFIX=$(echo $COMPILER | sed -r 's/.*clang//') ;; *) echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2 @@ -425,6 +426,9 @@ multi_arch serialize_diagnostics sanitize_blacklist debug_prefix_map +profiling +profiling_gcc +profiling_clang split_dwarf masquerading hardlink diff --git a/test/suites/profiling.bash b/test/suites/profiling.bash new file mode 100644 index 000000000..553f90865 --- /dev/null +++ b/test/suites/profiling.bash @@ -0,0 +1,103 @@ +SUITE_profiling_PROBE() { + touch test.c + if ! $COMPILER -fprofile-generate -c test.c 2>/dev/null; then + echo "compiler does not support profiling" + fi + if $COMPILER_TYPE_CLANG && ! which llvm-profdata$CLANG_VERSION_SUFFIX >/dev/null 2>/dev/null; then + echo "llvm-profdata$CLANG_VERSION_SUFFIX tool not found" + fi +} + +SUITE_profiling_SETUP() { + echo 'int main(void) { return 0; }' >test.c + unset CCACHE_NODIRECT +} + +SUITE_profiling() { + # ------------------------------------------------------------------------- + TEST "-fprofile-use, missing file" + + $CCACHE_COMPILE -fprofile-use -c test.c 2>/dev/null + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 0 + expect_stat 'no input file' 1 + + # ------------------------------------------------------------------------- + TEST "-fbranch-probabilities, missing file" + + $CCACHE_COMPILE -fbranch-probabilities -c test.c 2>/dev/null + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 0 + expect_stat 'no input file' 1 + + # ------------------------------------------------------------------------- + TEST "-fprofile-use=file, missing file" + + $CCACHE_COMPILE -fprofile-use=data.gcda -c test.c 2>/dev/null + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 0 + expect_stat 'no input file' 1 + + # ------------------------------------------------------------------------- + TEST "-fprofile-use" + + $CCACHE_COMPILE -fprofile-generate -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-generate test.o -o test + + ./test + merge_profiling_data . + + $CCACHE_COMPILE -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + merge_profiling_data . + + $CCACHE_COMPILE -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-use=dir" + + mkdir data + + $CCACHE_COMPILE -fprofile-generate=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-generate=data test.o -o test + + ./test + merge_profiling_data data + + $CCACHE_COMPILE -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + merge_profiling_data data + + $CCACHE_COMPILE -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 +} + +merge_profiling_data() { + local dir=$1 + if $COMPILER_TYPE_CLANG; then + llvm-profdata$CLANG_VERSION_SUFFIX merge -output $dir/default.profdata $dir/*.profraw + fi +} diff --git a/test/suites/profiling_clang.bash b/test/suites/profiling_clang.bash new file mode 100644 index 000000000..4344f7d02 --- /dev/null +++ b/test/suites/profiling_clang.bash @@ -0,0 +1,98 @@ +SUITE_profiling_clang_PROBE() { + if ! $COMPILER_TYPE_CLANG; then + echo "compiler is not Clang" + fi + if ! which llvm-profdata$CLANG_VERSION_SUFFIX >/dev/null 2>/dev/null; then + echo "llvm-profdata$CLANG_VERSION_SUFFIX tool not found" + fi +} + +SUITE_profiling_clang_SETUP() { + echo 'int main(void) { return 0; }' >test.c + unset CCACHE_NODIRECT +} + +SUITE_profiling_clang() { + # ------------------------------------------------------------------------- + TEST "-fprofile-use=file" + + mkdir data + + $CCACHE_COMPILE -fprofile-generate=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-generate=data test.o -o test + + ./test + llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata data/default_*.profraw + + $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata data/default_*.profraw + + $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-instr-use" + + mkdir data + + $CCACHE_COMPILE -fprofile-instr-generate -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-instr-generate test.o -o test + + ./test + llvm-profdata$CLANG_VERSION_SUFFIX merge -output default.profdata default.profraw + + $CCACHE_COMPILE -fprofile-instr-use -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-instr-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + echo >>default.profdata # Dummy change to trigger modification + + $CCACHE_COMPILE -fprofile-instr-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-instr-use=file" + + $CCACHE_COMPILE -fprofile-instr-generate=foo.profraw -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-instr-generate=data=foo.profraw test.o -o test + + ./test + llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata foo.profraw + + $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + echo >>foo.profdata # Dummy change to trigger modification + + $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 +} diff --git a/test/suites/profiling_gcc.bash b/test/suites/profiling_gcc.bash new file mode 100644 index 000000000..fe61109ed --- /dev/null +++ b/test/suites/profiling_gcc.bash @@ -0,0 +1,118 @@ +SUITE_profiling_gcc_PROBE() { + if ! $COMPILER_TYPE_GCC; then + echo "compiler is not GCC" + fi +} + +SUITE_profiling_gcc_SETUP() { + echo 'int main(void) { return 0; }' >test.c + unset CCACHE_NODIRECT +} + +SUITE_profiling_gcc() { + # ------------------------------------------------------------------------- + TEST "-fbranch-probabilities" + + $CCACHE_COMPILE -fprofile-generate -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-generate test.o -o test + + ./test + + $CCACHE_COMPILE -fbranch-probabilities -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fbranch-probabilities -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + + $CCACHE_COMPILE -fbranch-probabilities -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-dir=dir + -fprofile-use" + + mkdir data + + $CCACHE_COMPILE -fprofile-dir=data -fprofile-generate -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-dir=data -fprofile-generate test.o -o test + + ./test + + $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + + $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-use + -fprofile-dir=dir" + + mkdir data + + $CCACHE_COMPILE -fprofile-generate -fprofile-dir=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-generate -fprofile-dir=data test.o -o test + + ./test + + $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + + $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 + + # ------------------------------------------------------------------------- + TEST "-fprofile-dir=path1 + -fprofile-use=path2" + + mkdir data + + $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-generate=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 1 + + $COMPILER -fprofile-dir=data2 -fprofile-generate=data test.o -o test + + ./test + + $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache miss' 2 + + $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 2 + + ./test + + $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache miss' 3 +} diff --git a/unittest/test_argument_processing.cpp b/unittest/test_argument_processing.cpp index 9a53c7494..4fc681920 100644 --- a/unittest/test_argument_processing.cpp +++ b/unittest/test_argument_processing.cpp @@ -509,56 +509,6 @@ TEST(MT_flag_with_immediate_argument_should_not_add_MQobj) CHECK_ARGS_EQ_FREE12(exp_cc, act_cc); } -TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path) -{ - Context ctx; - - Args orig = args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c"); - Args exp_cpp = args_init_from_string("gcc"); - Args exp_extra = args_init(0, NULL); - Args exp_cc = args_init_from_string("gcc"); - Args act_cpp; - Args act_extra; - Args act_cc; - - char* s; - - create_file("foo.c", ""); - mkdir("some", 0777); - mkdir("some/dir", 0777); - std::string path = Util::real_path("some/dir"); - s = format("-fprofile-generate=%s", path.c_str()); - args_add(exp_cpp, s); - args_add(exp_cc, s); - args_add(exp_cc, "-c"); - free(s); - - CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc)); - CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp); - CHECK_ARGS_EQ_FREE12(exp_extra, act_extra); - CHECK_ARGS_EQ_FREE12(exp_cc, act_cc); -} - -TEST(fprofile_flag_with_nonexistent_dir_should_not_be_rewritten) -{ - Context ctx; - - Args orig = args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c"); - Args exp_cpp = args_init_from_string("gcc -fprofile-generate=some/dir"); - Args exp_extra = args_init(0, NULL); - Args exp_cc = args_init_from_string("gcc -fprofile-generate=some/dir -c"); - Args act_cpp; - Args act_extra; - Args act_cc; - - create_file("foo.c", ""); - - CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc)); - CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp); - CHECK_ARGS_EQ_FREE12(exp_extra, act_extra); - CHECK_ARGS_EQ_FREE12(exp_cc, act_cc); -} - TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used) { Context ctx;