]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Detect errors in fmt::format format strings at compile time
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 22 Oct 2020 17:30:41 +0000 (19:30 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Fri, 23 Oct 2020 13:32:26 +0000 (15:32 +0200)
See also 4413d842e23c6fa52ec411951a4ab442f42227de.

22 files changed:
src/Config.cpp
src/Hash.cpp
src/InodeCache.cpp
src/Lockfile.cpp
src/MiniTrace.cpp
src/Result.cpp
src/ResultExtractor.cpp
src/Statistics.cpp
src/Util.cpp
src/argprocessing.cpp
src/ccache.cpp
src/compress.cpp
src/execute.cpp
src/fmtmacros.hpp
src/hashutil.cpp
unittest/TestUtil.cpp
unittest/main.cpp
unittest/test_Config.cpp
unittest/test_Statistics.cpp
unittest/test_Util.cpp
unittest/test_argprocessing.cpp
unittest/test_ccache.cpp

index c7168e06da8898823533c3fa0005e11d88faed63..36c7608df4dad6c7087b49f29899ff7321addb22 100644 (file)
@@ -24,6 +24,7 @@
 #include "assertions.hpp"
 #include "ccache.hpp"
 #include "exceptions.hpp"
+#include "fmtmacros.hpp"
 
 #include "third_party/fmt/core.h"
 
@@ -317,7 +318,7 @@ format_umask(uint32_t umask)
   if (umask == std::numeric_limits<uint32_t>::max()) {
     return {};
   } else {
-    return fmt::format("{:03o}", umask);
+    return FMT("{:03o}", umask);
   }
 }
 
@@ -490,7 +491,7 @@ Config::get_string_value(const std::string& key) const
     return format_bool(m_compression);
 
   case ConfigItem::compression_level:
-    return fmt::format("{}", m_compression_level);
+    return FMT("{}", m_compression_level);
 
   case ConfigItem::cpp_extension:
     return m_cpp_extension;
@@ -532,13 +533,13 @@ Config::get_string_value(const std::string& key) const
     return format_bool(m_keep_comments_cpp);
 
   case ConfigItem::limit_multiple:
-    return fmt::format("{:.1f}", m_limit_multiple);
+    return FMT("{:.1f}", m_limit_multiple);
 
   case ConfigItem::log_file:
     return m_log_file;
 
   case ConfigItem::max_files:
-    return fmt::format("{}", m_max_files);
+    return FMT("{}", m_max_files);
 
   case ConfigItem::max_size:
     return format_cache_size(m_max_size);
@@ -615,17 +616,17 @@ Config::set_value_in_file(const std::string& path,
                              const std::string& c_key,
                              const std::string& /*c_value*/) {
                            if (c_key == key) {
-                             output.write(fmt::format("{} = {}\n", key, value));
+                             output.write(FMT("{} = {}\n", key, value));
                              found = true;
                            } else {
-                             output.write(fmt::format("{}\n", c_line));
+                             output.write(FMT("{}\n", c_line));
                            }
                          })) {
     throw Error("failed to open {}: {}", path, strerror(errno));
   }
 
   if (!found) {
-    output.write(fmt::format("{} = {}\n", key, value));
+    output.write(FMT("{} = {}\n", key, value));
   }
 
   output.commit();
@@ -834,7 +835,7 @@ std::string
 Config::default_temporary_dir(const std::string& cache_dir)
 {
 #ifdef HAVE_GETEUID
-  std::string user_tmp_dir = fmt::format("/run/user/{}", geteuid());
+  std::string user_tmp_dir = FMT("/run/user/{}", geteuid());
   if (Stat::stat(user_tmp_dir).is_directory()) {
     return user_tmp_dir + "/ccache-tmp";
   }
index 3db2b54c3d29ad14046631a7c9b800a366510ff3..ccc6f7bb31a7cf665ddd42a0987aafc38fa5986e 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "Fd.hpp"
 #include "Logging.hpp"
+#include "fmtmacros.hpp"
 
 using nonstd::string_view;
 
@@ -97,7 +98,7 @@ Hash&
 Hash::hash(int64_t x)
 {
   hash_buffer(string_view(reinterpret_cast<const char*>(&x), sizeof(x)));
-  add_debug_text(fmt::format("{}\n", x));
+  add_debug_text(FMT("{}\n", x));
   return *this;
 }
 
index a0f6f76c5ff76f90cd55d4d92e538cb1145501fa..5c77f08bdda0bb24099b94b02416b36221283ad2 100644 (file)
@@ -26,6 +26,7 @@
 #include "Stat.hpp"
 #include "TemporaryFile.hpp"
 #include "Util.hpp"
+#include "fmtmacros.hpp"
 
 #include <atomic>
 #include <libgen.h>
@@ -464,7 +465,7 @@ InodeCache::drop()
 std::string
 InodeCache::get_file()
 {
-  return fmt::format("{}/inode-cache.v{}", m_config.temporary_dir(), k_version);
+  return FMT("{}/inode-cache.v{}", m_config.temporary_dir(), k_version);
 }
 
 int64_t
index e37c8dc71937d675d4b21c79e798069bf4058ac8..715ffa4f8d829709c5377b1e5677dcf75ba3f8d1 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "Logging.hpp"
 #include "Util.hpp"
+#include "fmtmacros.hpp"
 
 #ifdef _WIN32
 #  include "Win32Util.hpp"
@@ -49,7 +50,7 @@ do_acquire_posix(const std::string& lockfile, uint32_t staleness_limit)
   const auto content_prefix = ss.str();
 
   while (true) {
-    auto my_content = fmt::format("{}:{}", content_prefix, time(nullptr));
+    auto my_content = FMT("{}:{}", content_prefix, time(nullptr));
 
     if (symlink(my_content.c_str(), lockfile.c_str()) == 0) {
       // We got the lock.
index 788d316061b9dbb7bfaaddaaca02cfa264e195d5..bf17397b92d5f04066a74bea56257c84a3cf1deb 100644 (file)
@@ -24,6 +24,7 @@
 #  include "MiniTrace.hpp"
 #  include "TemporaryFile.hpp"
 #  include "Util.hpp"
+#  include "fmtmacros.hpp"
 
 #  ifdef HAVE_SYS_TIME_H
 #    include <sys/time.h>
@@ -70,7 +71,7 @@ MiniTrace::MiniTrace(const ArgsInfo& args_info)
   m_tmp_trace_file = tmp_file.path;
 
   mtr_init(m_tmp_trace_file.c_str());
-  MTR_INSTANT_C("", "", "time", fmt::format("{:f}", time_seconds()).c_str());
+  MTR_INSTANT_C("", "", "time", FMT("{:f}", time_seconds()).c_str());
   MTR_META_PROCESS_NAME("ccache");
   MTR_START("program", "ccache", m_trace_id);
 }
index 09d704c0bc90dfa001fc19a71b2ab6fbb425282a..ef8ac747e692e93d900abc286663edc870d8ef56 100644 (file)
@@ -30,6 +30,7 @@
 #include "Statistics.hpp"
 #include "Util.hpp"
 #include "exceptions.hpp"
+#include "fmtmacros.hpp"
 
 #include <algorithm>
 
@@ -106,7 +107,7 @@ get_raw_file_path(string_view result_path, uint32_t entry_number)
 {
   const auto prefix = result_path.substr(
     0, result_path.length() - Result::k_file_suffix.length());
-  return fmt::format("{}{}W", prefix, entry_number);
+  return FMT("{}{}W", prefix, entry_number);
 }
 
 bool
@@ -183,7 +184,7 @@ gcno_file_in_mangled_form(const Context& ctx)
   const std::string abs_output_obj =
     Util::is_absolute_path(output_obj)
       ? output_obj
-      : fmt::format("{}/{}", ctx.apparent_cwd, output_obj);
+      : FMT("{}/{}", ctx.apparent_cwd, output_obj);
   std::string hashified_obj = abs_output_obj;
   std::replace(hashified_obj.begin(), hashified_obj.end(), '/', '#');
   return Util::change_extension(hashified_obj, ".gcno");
index 10b8189c82b5c84442d783cce827d660233ecb30..e18ae516018132adba68b9a212596e8c0dac3cc3 100644 (file)
@@ -19,6 +19,7 @@
 #include "ResultExtractor.hpp"
 
 #include "Util.hpp"
+#include "fmtmacros.hpp"
 
 ResultExtractor::ResultExtractor(const std::string& directory)
   : m_directory(directory)
@@ -38,13 +39,13 @@ ResultExtractor::on_entry_start(uint32_t /*entry_number*/,
 {
   std::string suffix = Result::file_type_to_string(file_type);
   if (suffix == Result::k_unknown_file_type) {
-    suffix = fmt::format(".type_{}", file_type);
+    suffix = FMT(".type_{}", file_type);
   } else if (suffix[0] == '<') {
     suffix[0] = '.';
     suffix.resize(suffix.length() - 1);
   }
 
-  m_dest_path = fmt::format("{}/ccache-result{}", m_directory, suffix);
+  m_dest_path = FMT("{}/ccache-result{}", m_directory, suffix);
 
   if (!raw_file) {
     m_dest_fd = Fd(
index b8dccf873b8ed80acaee1a4b20333681a2cdf2a9..08ad8928c9af7b834029b07451a928416d577de6 100644 (file)
@@ -24,6 +24,7 @@
 #include "Logging.hpp"
 #include "Util.hpp"
 #include "exceptions.hpp"
+#include "fmtmacros.hpp"
 
 const unsigned FLAG_NOZERO = 1; // don't zero with the -z option
 const unsigned FLAG_ALWAYS = 2; // always show, even if zero
@@ -39,7 +40,7 @@ using FormatFunction = std::string (*)(uint64_t value);
 static std::string
 format_size(uint64_t size)
 {
-  return fmt::format("{:>11}", Util::format_human_readable_size(size));
+  return FMT("{:>11}", Util::format_human_readable_size(size));
 }
 
 static std::string
@@ -80,9 +81,9 @@ for_each_level_1_and_2_stats_file(
   const std::function<void(const std::string& path)> function)
 {
   for (size_t level_1 = 0; level_1 <= 0xF; ++level_1) {
-    function(fmt::format("{}/{:x}/stats", cache_dir, level_1));
+    function(FMT("{}/{:x}/stats", cache_dir, level_1));
     for (size_t level_2 = 0; level_2 <= 0xF; ++level_2) {
-      function(fmt::format("{}/{:x}/{:x}/stats", cache_dir, level_1, level_2));
+      function(FMT("{}/{:x}/{:x}/stats", cache_dir, level_1, level_2));
     }
   }
 }
@@ -229,7 +230,7 @@ update(const std::string& path,
 
   AtomicFile file(path, AtomicFile::Mode::text);
   for (size_t i = 0; i < counters.size(); ++i) {
-    file.write(fmt::format("{}\n", counters.get_raw(i)));
+    file.write(FMT("{}\n", counters.get_raw(i)));
   }
   try {
     file.commit();
@@ -280,10 +281,9 @@ format_human_readable(const Config& config)
   std::tie(counters, last_updated) = collect_counters(config);
   std::string result;
 
-  result += fmt::format("{:36}{}\n", "cache directory", config.cache_dir());
-  result +=
-    fmt::format("{:36}{}\n", "primary config", config.primary_config_path());
-  result += fmt::format(
+  result += FMT("{:36}{}\n", "cache directory", config.cache_dir());
+  result += FMT("{:36}{}\n", "primary config", config.primary_config_path());
+  result += FMT(
     "{:36}{}\n", "secondary config (readonly)", config.secondary_config_path());
   if (last_updated > 0) {
     const auto tm = Util::localtime(last_updated);
@@ -291,7 +291,7 @@ format_human_readable(const Config& config)
     if (tm) {
       strftime(timestamp, sizeof(timestamp), "%c", &*tm);
     }
-    result += fmt::format("{:36}{}\n", "stats updated", timestamp);
+    result += FMT("{:36}{}\n", "stats updated", timestamp);
   }
 
   // ...and display them.
@@ -309,23 +309,23 @@ format_human_readable(const Config& config)
     const std::string value =
       k_statistics_fields[i].format
         ? k_statistics_fields[i].format(counters.get(statistic))
-        : fmt::format("{:8}", counters.get(statistic));
+        : FMT("{:8}", counters.get(statistic));
     if (!value.empty()) {
-      result += fmt::format("{:32}{}\n", k_statistics_fields[i].message, value);
+      result += FMT("{:32}{}\n", k_statistics_fields[i].message, value);
     }
 
     if (statistic == Statistic::cache_miss) {
       double percent = hit_rate(counters);
-      result += fmt::format("{:34}{:6.2f} %\n", "cache hit rate", percent);
+      result += FMT("{:34}{:6.2f} %\n", "cache hit rate", percent);
     }
   }
 
   if (config.max_files() != 0) {
-    result += fmt::format("{:32}{:8}\n", "max files", config.max_files());
+    result += FMT("{:32}{:8}\n", "max files", config.max_files());
   }
   if (config.max_size() != 0) {
-    result += fmt::format(
-      "{:32}{}\n", "max cache size", format_size(config.max_size()));
+    result +=
+      FMT("{:32}{}\n", "max cache size", format_size(config.max_size()));
   }
 
   return result;
@@ -339,13 +339,13 @@ format_machine_readable(const Config& config)
   std::tie(counters, last_updated) = collect_counters(config);
   std::string result;
 
-  result += fmt::format("stats_updated_timestamp\t{}\n", last_updated);
+  result += FMT("stats_updated_timestamp\t{}\n", last_updated);
 
   for (size_t i = 0; k_statistics_fields[i].message; i++) {
     if (!(k_statistics_fields[i].flags & FLAG_NEVER)) {
-      result += fmt::format("{}\t{}\n",
-                            k_statistics_fields[i].id,
-                            counters.get(k_statistics_fields[i].statistic));
+      result += FMT("{}\t{}\n",
+                    k_statistics_fields[i].id,
+                    counters.get(k_statistics_fields[i].statistic));
     }
   }
 
index cd2966643e4863d8a5678542f6004d6f837b8d15..bac6b7d123c2803e937cc614fe7e5c94c0cc1342 100644 (file)
@@ -24,6 +24,7 @@
 #include "FormatNonstdStringView.hpp"
 #include "Logging.hpp"
 #include "TemporaryFile.hpp"
+#include "fmtmacros.hpp"
 
 extern "C" {
 #include "third_party/base32hex.h"
@@ -503,7 +504,7 @@ for_each_level_1_subdir(const std::string& cache_dir,
   for (int i = 0; i <= 0xF; i++) {
     double progress = 1.0 * i / 16;
     progress_receiver(progress);
-    std::string subdir_path = fmt::format("{}/{:x}", cache_dir, i);
+    std::string subdir_path = FMT("{}/{:x}", cache_dir, i);
     visitor(subdir_path, [&](double inner_progress) {
       progress_receiver(progress + inner_progress / 16);
     });
@@ -553,11 +554,11 @@ std::string
 format_human_readable_size(uint64_t size)
 {
   if (size >= 1000 * 1000 * 1000) {
-    return fmt::format("{:.1f} GB", size / ((double)(1000 * 1000 * 1000)));
+    return FMT("{:.1f} GB", size / ((double)(1000 * 1000 * 1000)));
   } else if (size >= 1000 * 1000) {
-    return fmt::format("{:.1f} MB", size / ((double)(1000 * 1000)));
+    return FMT("{:.1f} MB", size / ((double)(1000 * 1000)));
   } else {
-    return fmt::format("{:.1f} kB", size / 1000.0);
+    return FMT("{:.1f} kB", size / 1000.0);
   }
 }
 
@@ -565,11 +566,11 @@ std::string
 format_parsable_size_with_suffix(uint64_t size)
 {
   if (size >= 1000 * 1000 * 1000) {
-    return fmt::format("{:.1f}G", size / ((double)(1000 * 1000 * 1000)));
+    return FMT("{:.1f}G", size / ((double)(1000 * 1000 * 1000)));
   } else if (size >= 1000 * 1000) {
-    return fmt::format("{:.1f}M", size / ((double)(1000 * 1000)));
+    return FMT("{:.1f}M", size / ((double)(1000 * 1000)));
   } else {
-    return fmt::format("{}", size);
+    return FMT("{}", size);
   }
 }
 
@@ -844,7 +845,7 @@ make_relative_path(const Context& ctx, string_view path)
   if (path.length() >= 3 && path[0] == '/') {
     if (isalpha(path[1]) && path[2] == '/') {
       // Transform /c/path... to c:/path...
-      winpath = fmt::format("{}:/{}", path[1], path.substr(3));
+      winpath = FMT("{}:/{}", path[1], path.substr(3));
       path = winpath;
     } else if (path[2] == ':') {
       // Transform /c:/path to c:/path
@@ -1249,8 +1250,7 @@ same_program_name(nonstd::string_view program_name,
 #ifdef _WIN32
   std::string lowercase_program_name = Util::to_lowercase(program_name);
   return lowercase_program_name == canonical_program_name
-         || lowercase_program_name
-              == fmt::format("{}.exe", canonical_program_name);
+         || lowercase_program_name == FMT("{}.exe", canonical_program_name);
 #else
   return program_name == canonical_program_name;
 #endif
index ccb7d8e8687412cfdbaf68fa94b52042a3f73398..fc61655bc0c460dd47322d76bc7e09639a8ef74c 100644 (file)
@@ -23,6 +23,7 @@
 #include "Logging.hpp"
 #include "assertions.hpp"
 #include "compopt.hpp"
+#include "fmtmacros.hpp"
 #include "language.hpp"
 
 #include <cassert>
@@ -534,7 +535,7 @@ process_arg(Context& ctx,
       auto arg_opt = string_view(args[i]).substr(0, 3);
       auto option = string_view(args[i]).substr(3);
       auto relpath = Util::make_relative_path(ctx, option);
-      state.dep_args.push_back(fmt::format("{}{}", arg_opt, relpath));
+      state.dep_args.push_back(FMT("{}{}", arg_opt, relpath));
     }
     return nullopt;
   }
@@ -902,8 +903,7 @@ handle_dependency_environment_variables(Context& ctx,
     string_view abspath_obj = dependencies[1];
     std::string relpath_obj = Util::make_relative_path(ctx, abspath_obj);
     // Ensure that the compiler gets a relative path.
-    std::string relpath_both =
-      fmt::format("{} {}", args_info.output_dep, relpath_obj);
+    std::string relpath_both = FMT("{} {}", args_info.output_dep, relpath_obj);
     if (using_sunpro_dependencies) {
       Util::setenv("SUNPRO_DEPENDENCIES", relpath_both);
     } else {
index a57dd8a8e826fa9599f039de52296fc4cbdce57f..2eef578374ec1d48882e5686515c4fb9b95fc61e 100644 (file)
@@ -240,7 +240,7 @@ init_hash_debug(Context& ctx,
     return;
   }
 
-  std::string path = fmt::format("{}.ccache-input-{}", obj_path, type);
+  std::string path = FMT("{}.ccache-input-{}", obj_path, type);
   File debug_binary_file(path, "wb");
   if (debug_binary_file) {
     hash.enable_debug(section_name, debug_binary_file.get(), debug_text_file);
@@ -361,7 +361,7 @@ do_remember_include_file(Context& ctx,
     if (ctx.config.pch_external_checksum()) {
       // hash pch.sum instead of pch when it exists
       // to prevent hashing a very large .pch file every time
-      std::string pch_sum_path = fmt::format("{}.sum", path);
+      std::string pch_sum_path = FMT("{}.sum", path);
       if (Stat::stat(pch_sum_path, Stat::OnError::log)) {
         path = std::move(pch_sum_path);
         using_pch_sum = true;
@@ -787,7 +787,7 @@ look_up_cache_file(const std::string& cache_dir,
                    const Digest& name,
                    nonstd::string_view suffix)
 {
-  const auto name_string = fmt::format("{}{}", name.to_string(), suffix);
+  const auto name_string = FMT("{}{}", name.to_string(), suffix);
 
   for (uint8_t level = k_min_cache_levels; level <= k_max_cache_levels;
        ++level) {
@@ -853,9 +853,9 @@ create_cachedir_tag(const Context& ctx)
     "# For information about cache directory tags, see:\n"
     "#\thttp://www.brynosaurus.com/cachedir/\n";
 
-  const std::string path = fmt::format("{}/{}/CACHEDIR.TAG",
-                                       ctx.config.cache_dir(),
-                                       ctx.result_name()->to_string()[0]);
+  const std::string path = FMT("{}/{}/CACHEDIR.TAG",
+                               ctx.config.cache_dir(),
+                               ctx.result_name()->to_string()[0]);
   const auto stat = Stat::stat(path);
   if (stat) {
     return;
@@ -955,13 +955,11 @@ to_cache(Context& ctx,
   LOG_RAW("Running real compiler");
   MTR_BEGIN("execute", "compiler");
 
-  TemporaryFile tmp_stdout(
-    fmt::format("{}/tmp.stdout", ctx.config.temporary_dir()));
+  TemporaryFile tmp_stdout(FMT("{}/tmp.stdout", ctx.config.temporary_dir()));
   ctx.register_pending_tmp_file(tmp_stdout.path);
   std::string tmp_stdout_path = tmp_stdout.path;
 
-  TemporaryFile tmp_stderr(
-    fmt::format("{}/tmp.stderr", ctx.config.temporary_dir()));
+  TemporaryFile tmp_stderr(FMT("{}/tmp.stderr", ctx.config.temporary_dir()));
   ctx.register_pending_tmp_file(tmp_stderr.path);
   std::string tmp_stderr_path = tmp_stderr.path;
 
@@ -1127,12 +1125,12 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash)
     // Run cpp on the input file to obtain the .i.
 
     TemporaryFile tmp_stdout(
-      fmt::format("{}/tmp.cpp_stdout", ctx.config.temporary_dir()));
+      FMT("{}/tmp.cpp_stdout", ctx.config.temporary_dir()));
     stdout_path = tmp_stdout.path;
     ctx.register_pending_tmp_file(stdout_path);
 
     TemporaryFile tmp_stderr(
-      fmt::format("{}/tmp.cpp_stderr", ctx.config.temporary_dir()));
+      FMT("{}/tmp.cpp_stderr", ctx.config.temporary_dir()));
     stderr_path = tmp_stderr.path;
     ctx.register_pending_tmp_file(stderr_path);
 
@@ -1180,8 +1178,7 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash)
   } else {
     // i_tmpfile needs the proper cpp_extension for the compiler to do its
     // thing correctly
-    ctx.i_tmpfile =
-      fmt::format("{}.{}", stdout_path, ctx.config.cpp_extension());
+    ctx.i_tmpfile = FMT("{}.{}", stdout_path, ctx.config.cpp_extension());
     Util::rename(stdout_path, ctx.i_tmpfile);
     ctx.register_pending_tmp_file(ctx.i_tmpfile);
   }
@@ -1261,7 +1258,7 @@ hash_nvcc_host_compiler(const Context& ctx,
 #endif
     for (const char* compiler : compilers) {
       if (!ccbin.empty()) {
-        std::string path = fmt::format("{}/{}", ccbin, compiler);
+        std::string path = FMT("{}/{}", ccbin, compiler);
         auto st = Stat::stat(path);
         if (st) {
           hash_compiler(ctx, hash, st, path, false);
@@ -1395,7 +1392,7 @@ hash_common_info(const Context& ctx,
     }
     string_view stem =
       Util::remove_extension(Util::base_name(ctx.args_info.output_obj));
-    std::string gcda_path = fmt::format("{}/{}.gcda", dir, stem);
+    std::string gcda_path = FMT("{}/{}.gcda", dir, stem);
     LOG("Hashing coverage path {}", gcda_path);
     hash.hash_delimiter("gcda");
     hash.hash(gcda_path);
@@ -1441,13 +1438,13 @@ hash_profile_data_file(const Context& ctx, Hash& hash)
 
   std::vector<std::string> paths_to_try{
     // -fprofile-use[=dir]/-fbranch-probabilities (GCC <9)
-    fmt::format("{}/{}.gcda", profile_path, base_name),
+    FMT("{}/{}.gcda", profile_path, base_name),
     // -fprofile-use[=dir]/-fbranch-probabilities (GCC >=9)
-    fmt::format("{}/{}#{}.gcda", profile_path, hashified_cwd, base_name),
+    FMT("{}/{}#{}.gcda", profile_path, hashified_cwd, base_name),
     // -fprofile(-instr|-sample)-use=file (Clang), -fauto-profile=file (GCC >=5)
     profile_path,
     // -fprofile(-instr|-sample)-use=dir (Clang)
-    fmt::format("{}/default.profdata", profile_path),
+    FMT("{}/default.profdata", profile_path),
     // -fauto-profile (GCC >=5)
     "fbdata.afdo", // -fprofile-dir is not used
   };
@@ -1927,9 +1924,9 @@ set_up_config(Config& config)
     // Only used for ccache tests:
     const char* const env_ccache_configpath2 = getenv("CCACHE_CONFIGPATH2");
 
-    config.set_secondary_config_path(
-      env_ccache_configpath2 ? env_ccache_configpath2
-                             : fmt::format("{}/ccache.conf", SYSCONFDIR));
+    config.set_secondary_config_path(env_ccache_configpath2
+                                       ? env_ccache_configpath2
+                                       : FMT("{}/ccache.conf", SYSCONFDIR));
     MTR_BEGIN("config", "conf_read_secondary");
     // A missing config file in SYSCONFDIR is OK so don't check return value.
     config.update_from_file(config.secondary_config_path());
@@ -1944,7 +1941,7 @@ set_up_config(Config& config)
     } else if (legacy_ccache_dir_exists) {
       primary_config_dir = legacy_ccache_dir;
     } else if (env_xdg_config_home) {
-      primary_config_dir = fmt::format("{}/ccache", env_xdg_config_home);
+      primary_config_dir = FMT("{}/ccache", env_xdg_config_home);
     } else {
       primary_config_dir = default_config_dir(home_dir);
     }
@@ -1969,7 +1966,7 @@ set_up_config(Config& config)
     if (legacy_ccache_dir_exists) {
       config.set_cache_dir(legacy_ccache_dir);
     } else if (env_xdg_cache_home) {
-      config.set_cache_dir(fmt::format("{}/ccache", env_xdg_cache_home));
+      config.set_cache_dir(FMT("{}/ccache", env_xdg_cache_home));
     } else {
       config.set_cache_dir(default_cache_dir(home_dir));
     }
@@ -2032,7 +2029,7 @@ set_up_uncached_err()
     throw Failure(Statistic::internal_error);
   }
 
-  Util::setenv("UNCACHED_ERR_FD", fmt::format("{}", uncached_fd));
+  Util::setenv("UNCACHED_ERR_FD", FMT("{}", uncached_fd));
 }
 
 static void
@@ -2084,12 +2081,12 @@ update_stats_and_maybe_move_cache_file(const Context& ctx,
   const bool use_stats_on_level_1 =
     counter_updates.get(Statistic::cache_size_kibibyte) != 0
     || counter_updates.get(Statistic::files_in_cache) != 0;
-  std::string level_string = fmt::format("{:x}", name.bytes()[0] >> 4);
+  std::string level_string = FMT("{:x}", name.bytes()[0] >> 4);
   if (!use_stats_on_level_1) {
-    level_string += fmt::format("/{:x}", name.bytes()[0] & 0xF);
+    level_string += FMT("/{:x}", name.bytes()[0] & 0xF);
   }
   const auto stats_file =
-    fmt::format("{}/{}/stats", ctx.config.cache_dir(), level_string);
+    FMT("{}/{}/stats", ctx.config.cache_dir(), level_string);
 
   auto counters =
     Statistics::update(stats_file, [&counter_updates](Counters& cs) {
@@ -2150,8 +2147,8 @@ finalize_stats_and_trigger_cleanup(Context& ctx)
     // Context::set_result_path hasn't been called yet, so we just choose one of
     // the stats files in the 256 level 2 directories.
     const auto bucket = getpid() % 256;
-    const auto stats_file = fmt::format(
-      "{}/{:x}/{:x}/stats", config.cache_dir(), bucket / 16, bucket % 16);
+    const auto stats_file =
+      FMT("{}/{:x}/{:x}/stats", config.cache_dir(), bucket / 16, bucket % 16);
     Statistics::update(
       stats_file, [&ctx](Counters& cs) { cs.increment(ctx.counter_updates); });
     return;
@@ -2175,8 +2172,8 @@ finalize_stats_and_trigger_cleanup(Context& ctx)
     return;
   }
 
-  const auto subdir = fmt::format(
-    "{}/{:x}", config.cache_dir(), ctx.result_name()->bytes()[0] >> 4);
+  const auto subdir =
+    FMT("{}/{:x}", config.cache_dir(), ctx.result_name()->bytes()[0] >> 4);
   bool need_cleanup = false;
 
   if (config.max_files() != 0
@@ -2219,7 +2216,7 @@ finalize_at_exit(Context& ctx)
 
   // Dump log buffer last to not lose any logs.
   if (ctx.config.debug() && !ctx.args_info.output_obj.empty()) {
-    const auto path = fmt::format("{}.ccache-log", ctx.args_info.output_obj);
+    const auto path = FMT("{}.ccache-log", ctx.args_info.output_obj);
     Logging::dump_log(path);
   }
 }
@@ -2364,8 +2361,7 @@ do_cache_compilation(Context& ctx, const char* const* argv)
   MTR_META_THREAD_NAME(ctx.args_info.output_obj.c_str());
 
   if (ctx.config.debug()) {
-    std::string path =
-      fmt::format("{}.ccache-input-text", ctx.args_info.output_obj);
+    std::string path = FMT("{}.ccache-input-text", ctx.args_info.output_obj);
     File debug_text_file(path, "w");
     if (debug_text_file) {
       ctx.hash_debug_files.push_back(std::move(debug_text_file));
index 307eb65e51dbda40399fa53fdeb2a866b5f1ba46..42e0179cd89c0f352385d5b149908db4dfedab95 100644 (file)
@@ -172,7 +172,7 @@ recompress_file(RecompressionStatistics& statistics,
 
   LOG("Recompressing {} to {}",
       cache_file.path(),
-      level ? fmt::format("level {}", wanted_level) : "uncompressed");
+      level ? FMT("level {}", wanted_level) : "uncompressed");
   AtomicFile atomic_new_file(cache_file.path(), AtomicFile::Mode::binary);
   auto writer =
     create_writer(atomic_new_file.stream(),
@@ -350,10 +350,10 @@ compress_recompress(Context& ctx,
   std::string incompr_size_str =
     Util::format_human_readable_size(statistics.incompressible_size());
   std::string size_difference_str =
-    fmt::format("{}{}",
-                size_difference < 0 ? "-" : (size_difference > 0 ? "+" : " "),
-                Util::format_human_readable_size(
-                  size_difference < 0 ? -size_difference : size_difference));
+    FMT("{}{}",
+        size_difference < 0 ? "-" : (size_difference > 0 ? "+" : " "),
+        Util::format_human_readable_size(
+          size_difference < 0 ? -size_difference : size_difference));
 
   PRINT(stdout, "Original data:         {:>8s}\n", content_size_str);
   PRINT(stdout,
index 32164929aebe4c557063909ea5530a04870cecfb..ec8703391d760fa55011f65058fb948d73540447 100644 (file)
@@ -27,6 +27,7 @@
 #include "Stat.hpp"
 #include "TemporaryFile.hpp"
 #include "Util.hpp"
+#include "fmtmacros.hpp"
 
 #ifdef _WIN32
 #  include "Win32Util.hpp"
@@ -110,7 +111,7 @@ win32execute(const char* path,
   if (args.length() > 8192) {
     TemporaryFile tmp_file(path);
     Util::write_fd(*tmp_file.fd, args.data(), args.length());
-    args = fmt::format("\"@{}\"", tmp_file.path);
+    args = FMT("\"@{}\"", tmp_file.path);
     tmp_file_path = tmp_file.path;
   }
   BOOL ret = CreateProcess(full_path.c_str(),
@@ -241,7 +242,7 @@ find_executable_in_path(const std::string& name,
     int ret = SearchPath(
       dir.c_str(), name.c_str(), nullptr, sizeof(namebuf), namebuf, nullptr);
     if (!ret) {
-      std::string exename = fmt::format("{}.exe", name);
+      std::string exename = FMT("{}.exe", name);
       ret = SearchPath(dir.c_str(),
                        exename.c_str(),
                        nullptr,
@@ -255,7 +256,7 @@ find_executable_in_path(const std::string& name,
     }
 #else
     ASSERT(!exclude_name.empty());
-    std::string fname = fmt::format("{}/{}", dir, name);
+    std::string fname = FMT("{}/{}", dir, name);
     auto st1 = Stat::lstat(fname);
     auto st2 = Stat::stat(fname);
     // Look for a normal executable file.
index 27e63f7f0b38312daa59cf7617963781c53ff5e2..9a017fae9bff54dc2422763928eef27f41ce7248 100644 (file)
 #include "third_party/fmt/core.h"
 #include "third_party/fmt/format.h"
 
+// Convenience macro for calling `fmt::format` with `FMT_STRING` around the
+// format string literal.
+#define FMT(format_, ...) fmt::format(FMT_STRING(format_), __VA_ARGS__)
+
 // Convenience macro for calling `fmt::print` with `FMT_STRING` around the
 // format string literal.
 #define PRINT(stream_, format_, ...)                                           \
index db5ad37238cdec5ec357663cff9edf4d495fc79f..072d821d50b144bd0f3d45bbc0decddb3a08ad44 100644 (file)
@@ -26,6 +26,7 @@
 #include "Stat.hpp"
 #include "ccache.hpp"
 #include "execute.hpp"
+#include "fmtmacros.hpp"
 #include "macroskip.hpp"
 
 #include "third_party/blake3/blake3_cpu_supports_avx2.h"
@@ -361,12 +362,12 @@ hash_command_output(Hash& hash,
   // Add "echo" command.
   bool using_cmd_exe;
   if (Util::starts_with(adjusted_command, "echo")) {
-    adjusted_command = fmt::format("cmd.exe /c \"{}\"", adjusted_command);
+    adjusted_command = FMT("cmd.exe /c \"{}\"", adjusted_command);
     using_cmd_exe = true;
   } else if (Util::starts_with(adjusted_command, "%compiler%")
              && compiler == "echo") {
     adjusted_command =
-      fmt::format("cmd.exe /c \"{}{}\"", compiler, adjusted_command.substr(10));
+      FMT("cmd.exe /c \"{}{}\"", compiler, adjusted_command.substr(10));
     using_cmd_exe = true;
   } else {
     using_cmd_exe = false;
index 04c4fe96ead6bcd1f571b15fa6d2d94d7dd6569b..5f53efeb1c66f29d5a78181aa51b4126f77577d4 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "../src/Util.hpp"
 #include "../src/exceptions.hpp"
+#include "../src/fmtmacros.hpp"
 
 namespace TestUtil {
 
@@ -31,8 +32,7 @@ TestContext::TestContext() : m_test_dir(Util::get_actual_cwd())
     throw Error("TestContext instantiated outside test directory");
   }
   ++m_subdir_counter;
-  std::string subtest_dir =
-    fmt::format("{}/test_{}", m_test_dir, m_subdir_counter);
+  std::string subtest_dir = FMT("{}/test_{}", m_test_dir, m_subdir_counter);
   Util::create_dir(subtest_dir);
   if (chdir(subtest_dir.c_str()) != 0) {
     abort();
index 7f9b78ce23d6fbdbb5066d489e0737df6a50c10f..6e9d02e1d4902f0b8bf5c3e4fcba19b411a8da4b 100644 (file)
@@ -35,7 +35,7 @@ main(int argc, char** argv)
   Util::unsetenv("GCC_COLORS"); // Don't confuse argument processing tests.
 
   std::string dir_before = Util::get_actual_cwd();
-  std::string testdir = fmt::format("testdir.{}", getpid());
+  std::string testdir = FMT("testdir.{}", getpid());
   Util::wipe_path(testdir);
   Util::create_dir(testdir);
   TestUtil::check_chdir(testdir);
index 95787dbac9f391e6cd4678bf77c85c5d68f3d03a..7543129abaaf5cea1da84e4738bcc27e9f059dea 100644 (file)
@@ -20,6 +20,7 @@
 #include "../src/Util.hpp"
 #include "../src/ccache.hpp"
 #include "../src/exceptions.hpp"
+#include "../src/fmtmacros.hpp"
 #include "TestUtil.hpp"
 
 #include "third_party/doctest.h"
@@ -82,9 +83,9 @@ TEST_CASE("Config::update_from_file")
   Util::setenv("USER", user);
 
 #ifndef _WIN32
-  std::string base_dir = fmt::format("/{0}/foo/{0}", user);
+  std::string base_dir = FMT("/{0}/foo/{0}", user);
 #else
-  std::string base_dir = fmt::format("C:/{0}/foo/{0}", user);
+  std::string base_dir = FMT("C:/{0}/foo/{0}", user);
 #endif
 
   Util::write_file(
@@ -132,7 +133,7 @@ TEST_CASE("Config::update_from_file")
   Config config;
   REQUIRE(config.update_from_file("ccache.conf"));
   CHECK(config.base_dir() == base_dir);
-  CHECK(config.cache_dir() == fmt::format("{0}$/{0}/.ccache", user));
+  CHECK(config.cache_dir() == FMT("{0}$/{0}/.ccache", user));
   CHECK(config.compiler() == "foo");
   CHECK(config.compiler_check() == "none");
   CHECK_FALSE(config.compression());
@@ -141,7 +142,7 @@ TEST_CASE("Config::update_from_file")
   CHECK(config.depend_mode());
   CHECK_FALSE(config.direct_mode());
   CHECK(config.disable());
-  CHECK(config.extra_files_to_hash() == fmt::format("a:b c:{}", user));
+  CHECK(config.extra_files_to_hash() == FMT("a:b c:{}", user));
   CHECK(config.file_clone());
   CHECK(config.hard_link());
   CHECK_FALSE(config.hash_dir());
@@ -149,12 +150,12 @@ TEST_CASE("Config::update_from_file")
   CHECK(config.ignore_options() == "-a=* -b");
   CHECK(config.keep_comments_cpp());
   CHECK(config.limit_multiple() == Approx(1.0));
-  CHECK(config.log_file() == fmt::format("{0}{0}", user));
+  CHECK(config.log_file() == FMT("{0}{0}", user));
   CHECK(config.max_files() == 17);
   CHECK(config.max_size() == 123 * 1000 * 1000);
-  CHECK(config.path() == fmt::format("{}.x", user));
+  CHECK(config.path() == FMT("{}.x", user));
   CHECK(config.pch_external_checksum());
-  CHECK(config.prefix_command() == fmt::format("x{}", user));
+  CHECK(config.prefix_command() == FMT("x{}", user));
   CHECK(config.prefix_command_cpp() == "y");
   CHECK(config.read_only());
   CHECK(config.read_only_direct());
@@ -166,7 +167,7 @@ TEST_CASE("Config::update_from_file")
             | SLOPPY_FILE_STAT_MATCHES_CTIME | SLOPPY_SYSTEM_HEADERS
             | SLOPPY_PCH_DEFINES | SLOPPY_CLANG_INDEX_STORE));
   CHECK_FALSE(config.stats());
-  CHECK(config.temporary_dir() == fmt::format("{}_foo", user));
+  CHECK(config.temporary_dir() == FMT("{}_foo", user));
   CHECK(config.umask() == 0777);
 }
 
@@ -408,7 +409,7 @@ TEST_CASE("Config::visit_items")
   config.visit_items([&](const std::string& key,
                          const std::string& value,
                          const std::string& origin) {
-    received_items.push_back(fmt::format("({}) {} = {}", origin, key, value));
+    received_items.push_back(FMT("({}) {} = {}", origin, key, value));
   });
 
   std::vector<std::string> expected = {
index d945848f276e82e65b56578088fcefdfd56bf9af..5d6892c8175cdd0f769b8451b70e51eb807f7986 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "../src/Statistics.hpp"
 #include "../src/Util.hpp"
+#include "../src/fmtmacros.hpp"
 #include "TestUtil.hpp"
 
 #include "third_party/doctest.h"
@@ -66,7 +67,7 @@ TEST_CASE("Read future counters")
   std::string content;
   size_t count = static_cast<size_t>(Statistic::END) + 1;
   for (size_t i = 0; i < count; ++i) {
-    content += fmt::format("{}\n", i);
+    content += FMT("{}\n", i);
   }
 
   Util::write_file("test", content);
index 5633c0220b529d12f0609defb1badf324cd72ae3..44054f35e1b7f4bfad74e6c880dcadbc81c8c7f8 100644 (file)
@@ -19,6 +19,7 @@
 #include "../src/Config.hpp"
 #include "../src/Fd.hpp"
 #include "../src/Util.hpp"
+#include "../src/fmtmacros.hpp"
 #include "TestUtil.hpp"
 
 #include "third_party/doctest.h"
@@ -910,7 +911,7 @@ TEST_CASE("Util::traverse")
 
   std::vector<std::string> visited;
   auto visitor = [&visited](const std::string& path, bool is_dir) {
-    visited.push_back(fmt::format("[{}] {}", is_dir ? 'd' : 'f', path));
+    visited.push_back(FMT("[{}] {}", is_dir ? 'd' : 'f', path));
   };
 
   SUBCASE("traverse nonexistent path")
index c0f349e35616e1983b3c9a55deb6fa6a4243fe3d..089d8495fc6e96be314191d18d3c529632def04f 100644 (file)
@@ -21,6 +21,7 @@
 #include "../src/Context.hpp"
 #include "../src/Statistics.hpp"
 #include "../src/Util.hpp"
+#include "../src/fmtmacros.hpp"
 #include "TestUtil.hpp"
 #include "argprocessing.hpp"
 
@@ -283,7 +284,7 @@ TEST_CASE("sysroot_should_be_rewritten_if_basedir_is_used")
   Util::write_file("foo.c", "");
   ctx.config.set_base_dir(get_root());
   std::string arg_string =
-    fmt::format("cc --sysroot={}/foo/bar -c foo.c", ctx.actual_cwd);
+    FMT("cc --sysroot={}/foo/bar -c foo.c", ctx.actual_cwd);
   ctx.orig_args = Args::from_string(arg_string);
 
   const ProcessArgsResult result = process_args(ctx);
@@ -300,8 +301,7 @@ TEST_CASE(
 
   Util::write_file("foo.c", "");
   ctx.config.set_base_dir(get_root());
-  std::string arg_string =
-    fmt::format("cc --sysroot {}/foo -c foo.c", ctx.actual_cwd);
+  std::string arg_string = FMT("cc --sysroot {}/foo -c foo.c", ctx.actual_cwd);
   ctx.orig_args = Args::from_string(arg_string);
 
   const ProcessArgsResult result = process_args(ctx);
@@ -436,8 +436,7 @@ TEST_CASE(
 
   Util::write_file("foo.c", "");
   ctx.config.set_base_dir(get_root());
-  std::string arg_string =
-    fmt::format("cc -isystem {}/foo -c foo.c", ctx.actual_cwd);
+  std::string arg_string = FMT("cc -isystem {}/foo -c foo.c", ctx.actual_cwd);
   ctx.orig_args = Args::from_string(arg_string);
 
   const ProcessArgsResult result = process_args(ctx);
@@ -455,7 +454,7 @@ TEST_CASE("isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used")
   ctx.config.set_base_dir("/"); // posix
   // Windows path doesn't work concatenated.
   std::string cwd = get_posix_path(ctx.actual_cwd);
-  std::string arg_string = fmt::format("cc -isystem{}/foo -c foo.c", cwd);
+  std::string arg_string = FMT("cc -isystem{}/foo -c foo.c", cwd);
   ctx.orig_args = Args::from_string(arg_string);
 
   const ProcessArgsResult result = process_args(ctx);
@@ -473,7 +472,7 @@ TEST_CASE("I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used")
   ctx.config.set_base_dir("/"); // posix
   // Windows path doesn't work concatenated.
   std::string cwd = get_posix_path(ctx.actual_cwd);
-  std::string arg_string = fmt::format("cc -I{}/foo -c foo.c", cwd);
+  std::string arg_string = FMT("cc -I{}/foo -c foo.c", cwd);
   ctx.orig_args = Args::from_string(arg_string);
 
   const ProcessArgsResult result = process_args(ctx);
index f204a74f5675e67576b86b69088d22a6324b3eb0..209094ed2c0b183c2a214c9e27a412d32f5eadee 100644 (file)
 // this program; if not, write to the Free Software Foundation, Inc., 51
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
-#include "Context.hpp"
+#include "../src/Context.hpp"
+#include "../src/ccache.hpp"
+#include "../src/fmtmacros.hpp"
 #include "TestUtil.hpp"
-#include "ccache.hpp"
 
 #include "third_party/doctest.h"
 #include "third_party/nonstd/optional.hpp"
@@ -161,10 +162,9 @@ TEST_CASE("rewrite_dep_file_paths")
   const auto cwd = ctx.actual_cwd;
   ctx.has_absolute_include_headers = true;
 
-  const auto content =
-    fmt::format("foo.o: bar.c {0}/bar.h \\\n {1}/fie.h {0}/fum.h\n",
-                cwd,
-                Util::dir_name(cwd));
+  const auto content = FMT("foo.o: bar.c {0}/bar.h \\\n {1}/fie.h {0}/fum.h\n",
+                           cwd,
+                           Util::dir_name(cwd));
 
   SUBCASE("Base directory not in dep file content")
   {
@@ -175,7 +175,7 @@ TEST_CASE("rewrite_dep_file_paths")
 
   SUBCASE("Base directory in dep file content but not matching")
   {
-    ctx.config.set_base_dir(fmt::format("{}/other", Util::dir_name(cwd)));
+    ctx.config.set_base_dir(FMT("{}/other", Util::dir_name(cwd)));
     CHECK(!rewrite_dep_file_paths(ctx, ""));
     CHECK(!rewrite_dep_file_paths(ctx, content));
   }
@@ -184,8 +184,8 @@ TEST_CASE("rewrite_dep_file_paths")
   {
     ctx.config.set_base_dir(cwd);
     const auto actual = rewrite_dep_file_paths(ctx, content);
-    const auto expected = fmt::format(
-      "foo.o: bar.c ./bar.h \\\n {}/fie.h ./fum.h\n", Util::dir_name(cwd));
+    const auto expected =
+      FMT("foo.o: bar.c ./bar.h \\\n {}/fie.h ./fum.h\n", Util::dir_name(cwd));
     REQUIRE(actual);
     CHECK(*actual == expected);
   }