]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Expand system-dependent -m{arch,cpu,tune}=native options master
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 24 Jul 2025 13:35:47 +0000 (15:35 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 24 Jul 2025 14:22:01 +0000 (16:22 +0200)
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
src/ccache/argprocessing.hpp
src/ccache/ccache.cpp
test/fake-compilers/clang-march-native.sh [new file with mode: 0755]
test/fake-compilers/gcc-march-native.sh [new file with mode: 0755]
test/run
test/suites/base.bash

index 31d58091c200e42460b6a89ab9f591d52c3edce3..d3ab568a5de4a9137fa8976e7c0702310276f77b 100644 (file)
@@ -139,6 +139,13 @@ public:
     m_extra_args_to_hash.push_back(std::forward<T>(args));
   }
 
+  template<typename T>
+  void
+  add_native_arg(T&& arg)
+  {
+    m_native_args.push_back(std::forward<T>(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]);
index 7eabf5a1a98f1d8e77bafb0f7c78e0304aff3958..bd1b1f846379e0122a47a68ccdde69cb598e903b 100644 (file)
@@ -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;
 };
index bf8e918545cfcd4a6974dc49f495ee5b6e0e9825..4f6ecb2c557a5227e9976919eec39ce73554775a 100644 (file)
@@ -52,6 +52,7 @@
 #include <ccache/util/direntry.hpp>
 #include <ccache/util/duration.hpp>
 #include <ccache/util/environment.hpp>
+#include <ccache/util/exec.hpp>
 #include <ccache/util/expected.hpp>
 #include <ccache/util/fd.hpp>
 #include <ccache/util/file.hpp>
@@ -1779,6 +1780,51 @@ hash_common_info(const Context& ctx, const util::Args& args, Hash& hash)
   return {};
 }
 
+static tl::expected<void, Failure>
+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<std::string_view> 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<std::string_view>,
                   std::optional<std::string_view>>
 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 (executable)
index 0000000..32d6a7b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+args=("$@")
+
+if [ "$1" = "-###" ]; then
+    cat <<EOF >&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 (executable)
index 0000000..5eee6a6
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+args=("$@")
+
+if [ "$1" = "-###" ]; then
+    cat <<EOF >&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
index 4b69ee11f3e8db2c5568cb6aed50a6c583f8970e..00601597791dd044a6ce2eb26ba7f367ca876449 100755 (executable)
--- 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
 
 # ---------------------------------------
index 2c9542807550ccd09d244dbcfee50f43e6ffea49..80f9c7f30674afc39a9d6d41bd57c1c244403f04 100644 (file)
@@ -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"