From 29d24c81f42341f8cb725da3dbca7f7357ecbb40 Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Thu, 24 Jul 2025 15:35:47 +0200 Subject: [PATCH] fix: Expand system-dependent -m{arch,cpu,tune}=native options The -march=native, -mcpu=native and -mtune=native options have different effects depending on which system the compiler is run. Fix this by asking the compiler which cc1 options the -m*=native options expand to and including them in the input hash. Fixes #824. --- src/ccache/argprocessing.cpp | 17 ++++++++ src/ccache/argprocessing.hpp | 3 ++ src/ccache/ccache.cpp | 47 +++++++++++++++++++++++ test/fake-compilers/clang-march-native.sh | 17 ++++++++ test/fake-compilers/gcc-march-native.sh | 18 +++++++++ test/run | 5 ++- test/suites/base.bash | 38 ++++++++++++++++++ 7 files changed, 143 insertions(+), 2 deletions(-) create mode 100755 test/fake-compilers/clang-march-native.sh create mode 100755 test/fake-compilers/gcc-march-native.sh diff --git a/src/ccache/argprocessing.cpp b/src/ccache/argprocessing.cpp index 31d58091..d3ab568a 100644 --- a/src/ccache/argprocessing.cpp +++ b/src/ccache/argprocessing.cpp @@ -139,6 +139,13 @@ public: m_extra_args_to_hash.push_back(std::forward(args)); } + template + void + add_native_arg(T&& arg) + { + m_native_args.push_back(std::forward(arg)); + } + ProcessArgsResult to_result() { @@ -146,6 +153,7 @@ public: m_preprocessor_args, m_compiler_args, m_extra_args_to_hash, + m_native_args, hash_actual_cwd, }; } @@ -154,6 +162,7 @@ private: util::Args m_preprocessor_args; util::Args m_compiler_args; util::Args m_extra_args_to_hash; + util::Args m_native_args; }; bool @@ -1139,6 +1148,14 @@ process_option_arg(const Context& ctx, "Found -frecord-gcc-switches, hashing original command line unmodified"); } + // -march=native, -mcpu=native and -mtune=native make the compiler optimize + // differently depending on platform. + if (arg == "-march=native" || arg == "-mcpu=native" + || arg == "-mtune=native") { + LOG("Detected system dependent argument: {}", args[i]); + state.add_native_arg(args[i]); + } + // MSVC -u is something else than GCC -u, handle it specially. if (arg == "-u" && ctx.config.is_compiler_group_msvc()) { state.add_common_arg(args[i]); diff --git a/src/ccache/argprocessing.hpp b/src/ccache/argprocessing.hpp index 7eabf5a1..bd1b1f84 100644 --- a/src/ccache/argprocessing.hpp +++ b/src/ccache/argprocessing.hpp @@ -42,6 +42,9 @@ struct ProcessArgsResult // Arguments not sent to the preprocessor but added to the input hash anyway. util::Args extra_args_to_hash; + // -m*=native arguments to let the preprocessor expand. + util::Args native_args; + // Whether to include the actual CWD in the input hash. bool hash_actual_cwd = false; }; diff --git a/src/ccache/ccache.cpp b/src/ccache/ccache.cpp index bf8e9185..4f6ecb2c 100644 --- a/src/ccache/ccache.cpp +++ b/src/ccache/ccache.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -1779,6 +1780,51 @@ hash_common_info(const Context& ctx, const util::Args& args, Hash& hash) return {}; } +static tl::expected +hash_native_args(Context& ctx, const util::Args& native_args, Hash& hash) +{ + if (native_args.empty()) { + return {}; + } + + LOG("Querying compiler about {}", native_args.to_string()); + + util::Args args{ctx.orig_args[0], "-###", "-E", "-"}; + args.push_back(native_args); + auto output = util::exec_to_string(args); + if (!output) { + LOG("Failed to query compiler about {}: {}", + native_args.to_string(), + output.error()); + return tl::unexpected(Statistic::internal_error); + } + + std::string_view search_string = + ctx.config.is_compiler_group_clang() + ? "\"-cc1\"" // "/usr/lib/llvm-18/bin/clang" "-cc1" "-triple" ... + : "/cc1 -E"; // /usr/libexec/gcc/x86_64-linux-gnu/13/cc1 -E -quiet ... + std::optional line_to_hash; + for (const auto line : util::Tokenizer(*output, "\n")) { + if (line.find(search_string) != std::string_view::npos) { + line_to_hash = line; + break; + } + } + if (!line_to_hash) { + LOG("Did not find line to hash for {}", native_args.to_string()); + return tl::unexpected(Statistic::internal_error); + } + + hash.hash_delimiter(native_args.to_string()); + + // We could potentially work out exactly which options -m*=native expand to + // and hash only those, but to keep things simple we include the full line + // where cc1 was found for now. + hash.hash(*line_to_hash); + + return {}; +} + static std::tuple, std::optional> get_option_and_value(std::string_view option, const util::Args& args, size_t& i) @@ -2787,6 +2833,7 @@ do_cache_compilation(Context& ctx) TRY( hash_common_info(ctx, process_args_result->preprocessor_args, common_hash)); + TRY(hash_native_args(ctx, process_args_result->native_args, common_hash)); if (process_args_result->hash_actual_cwd) { common_hash.hash_delimiter("actual_cwd"); diff --git a/test/fake-compilers/clang-march-native.sh b/test/fake-compilers/clang-march-native.sh new file mode 100755 index 00000000..32d6a7b5 --- /dev/null +++ b/test/fake-compilers/clang-march-native.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +args=("$@") + +if [ "$1" = "-###" ]; then + cat <&2 +... +InstalledDir: /usr/bin + (in-process) + "/example/bin/clang" "-cc1" $CC1_ARGS +EOF + echo "bin/cc1" +elif [ "$1" = "-E" ]; then + echo preprocessed >"${args[$#-2]}" +else + echo compiled >"${args[$#-2]}" +fi diff --git a/test/fake-compilers/gcc-march-native.sh b/test/fake-compilers/gcc-march-native.sh new file mode 100755 index 00000000..5eee6a67 --- /dev/null +++ b/test/fake-compilers/gcc-march-native.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +args=("$@") + +if [ "$1" = "-###" ]; then + cat <&2 +Using built-in specs. +... +COLLECT_GCC_OPTIONS='-E' ... + /example/cc1 -E -quiet $CC1_ARGS +COMPILER_PATH=/example +EOF + echo "bin/cc1" +elif [ "$1" = "-E" ]; then + echo preprocessed >"${args[$#-2]}" +else + echo compiled >"${args[$#-2]}" +fi diff --git a/test/run b/test/run index 4b69ee11..00601597 100755 --- a/test/run +++ b/test/run @@ -630,10 +630,11 @@ fi # --------------------------------------- -all_suites="$(sed -En 's/^addtest\((.*)\)$/\1/p' $(dirname $0)/CMakeLists.txt)" +export TEST_BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +all_suites="$(sed -En 's/^addtest\((.*)\)$/\1/p' $(dirname $0)/CMakeLists.txt)" for suite in $all_suites; do - . $(dirname $0)/suites/$suite.bash + . "$TEST_BASE_DIR"/suites/$suite.bash done # --------------------------------------- diff --git a/test/suites/base.bash b/test/suites/base.bash index 2c954280..80f9c7f3 100644 --- a/test/suites/base.bash +++ b/test/suites/base.bash @@ -1632,6 +1632,44 @@ EOF expect_stat cache_miss 1 fi + # ------------------------------------------------------------------------- + TEST "-march=native, GCC" + + CC1_ARGS=one $CCACHE "$TEST_BASE_DIR/fake-compilers/gcc-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 0 + expect_stat cache_miss 1 + + CC1_ARGS=one $CCACHE "$TEST_BASE_DIR/fake-compilers/gcc-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 1 + expect_stat cache_miss 1 + + CC1_ARGS=two $CCACHE "$TEST_BASE_DIR/fake-compilers/gcc-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 1 + expect_stat cache_miss 2 + + CC1_ARGS=two $CCACHE "$TEST_BASE_DIR/fake-compilers/gcc-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 2 + expect_stat cache_miss 2 + + # ------------------------------------------------------------------------- + TEST "-march=native, Clang" + + CC1_ARGS=one $CCACHE "$TEST_BASE_DIR/fake-compilers/clang-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 0 + expect_stat cache_miss 1 + + CC1_ARGS=one $CCACHE "$TEST_BASE_DIR/fake-compilers/clang-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 1 + expect_stat cache_miss 1 + + CC1_ARGS=two $CCACHE "$TEST_BASE_DIR/fake-compilers/clang-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 1 + expect_stat cache_miss 2 + + CC1_ARGS=two $CCACHE "$TEST_BASE_DIR/fake-compilers/clang-march-native.sh" -march=native -c test1.c + expect_stat preprocessed_cache_hit 2 + expect_stat cache_miss 2 + # ------------------------------------------------------------------------- TEST "Handling of compiler-only arguments" -- 2.47.2