From: Max Winkler Date: Tue, 28 Oct 2025 18:46:11 +0000 (-0700) Subject: feat: Add msvc_utf8 config option to allow disabling /utf-8 for MSVC (#1650) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e5f198c8135ade7c8c10d94435ddbd210f89b4c1;p=thirdparty%2Fccache.git feat: Add msvc_utf8 config option to allow disabling /utf-8 for MSVC (#1650) Add option to avoid adding to msvc command line for non-utf8 source code --- diff --git a/doc/manual.adoc b/doc/manual.adoc index 32a55ae3..fcfad31e 100644 --- a/doc/manual.adoc +++ b/doc/manual.adoc @@ -907,6 +907,16 @@ file in `/etc/rsyslog.d`: The default prefix is "`Note: including file:`". If you use a localized compiler, this should be set accordingly. +[#config_msvc_utf8] +*msvc_utf8* (*CCACHE_MSVC_UTF8*):: + + This option adds `/utf-8` to the msvc command line when executing the preprocessor to + ensure that filenames are not garbled for non-ascii characters. + This implicitly enables `/validate-charset` and treats the source code as utf-8 which + may cause compilation errors if comments in your code have characters in the [128, 255] + range for a given Windows system codepage which results in an invalid utf-8 sequence. + The default is true. + [#config_namespace] *namespace* (*CCACHE_NAMESPACE*):: @@ -1587,7 +1597,7 @@ An environment variable not supported by ccache was set. | Unsupported source encoding | Source file (or an included header) has unsupported encoding. ccache currently -requires UTF-8-encoded source code for MSVC. +requires UTF-8-encoded source code for MSVC when `msvc_utf8` is true. | Unsupported source language | A source language e.g. specified with `-x` was unsupported by ccache. diff --git a/src/ccache/ccache.cpp b/src/ccache/ccache.cpp index e442707d..681e061b 100644 --- a/src/ccache/ccache.cpp +++ b/src/ccache/ccache.cpp @@ -1412,7 +1412,9 @@ get_result_key_from_cpp(Context& ctx, util::Args& args, Hash& hash) // compilers that don't exit with a proper status on write error to stdout. // See also . if (ctx.config.is_compiler_group_msvc()) { - args.push_back("-utf-8"); // Avoid garbling filenames in output + if (ctx.config.msvc_utf8()) { + args.push_back("-utf-8"); // Avoid garbling filenames in output + } args.push_back("-P"); args.push_back(FMT("-Fi{}", preprocessed_path)); } else { @@ -1441,7 +1443,7 @@ get_result_key_from_cpp(Context& ctx, util::Args& args, Hash& hash) cpp_stderr_data = result->stderr_data; cpp_stdout_data = result->stdout_data; - if (ctx.config.is_compiler_group_msvc()) { + if (ctx.config.is_compiler_group_msvc() && ctx.config.msvc_utf8()) { // Check that usage of -utf-8 didn't garble the preprocessor output. static constexpr char warning_c4828[] = "warning C4828: The file contains a character starting at offset"; diff --git a/src/ccache/config.cpp b/src/ccache/config.cpp index dcf7c17d..95091d2a 100644 --- a/src/ccache/config.cpp +++ b/src/ccache/config.cpp @@ -101,6 +101,7 @@ enum class ConfigItem : uint8_t { max_files, max_size, msvc_dep_prefix, + msvc_utf8, namespace_, path, pch_external_checksum, @@ -157,6 +158,7 @@ const std::unordered_map {"max_files", {ConfigItem::max_files} }, {"max_size", {ConfigItem::max_size} }, {"msvc_dep_prefix", {ConfigItem::msvc_dep_prefix} }, + {"msvc_utf8", {ConfigItem::msvc_utf8} }, {"namespace", {ConfigItem::namespace_} }, {"path", {ConfigItem::path} }, {"pch_external_checksum", {ConfigItem::pch_external_checksum} }, @@ -207,6 +209,7 @@ const std::unordered_map {"MAXFILES", "max_files" }, {"MAXSIZE", "max_size" }, {"MSVC_DEP_PREFIX", "msvc_dep_prefix" }, + {"MSVC_UTF8", "msvc_utf8" }, {"NAMESPACE", "namespace" }, {"PATH", "path" }, {"PCH_EXTSUM", "pch_external_checksum" }, @@ -871,6 +874,9 @@ Config::get_string_value(const std::string& key) const case ConfigItem::msvc_dep_prefix: return m_msvc_dep_prefix; + case ConfigItem::msvc_utf8: + return format_bool(m_msvc_utf8); + case ConfigItem::namespace_: return m_namespace; @@ -1149,6 +1155,10 @@ Config::set_item(const std::string_view& key, m_msvc_dep_prefix = value; break; + case ConfigItem::msvc_utf8: + m_msvc_utf8 = parse_bool(value, env_var_key, negate); + break; + case ConfigItem::namespace_: m_namespace = value; break; diff --git a/src/ccache/config.hpp b/src/ccache/config.hpp index 83cd77ec..6351d073 100644 --- a/src/ccache/config.hpp +++ b/src/ccache/config.hpp @@ -85,6 +85,7 @@ public: uint64_t max_files() const; uint64_t max_size() const; const std::string& msvc_dep_prefix() const; + bool msvc_utf8() const; const std::string& path() const; bool pch_external_checksum() const; const std::string& prefix_command() const; @@ -126,6 +127,7 @@ public: void set_inode_cache(bool value); void set_max_files(uint64_t value); void set_msvc_dep_prefix(const std::string& value); + void set_msvc_utf8(bool value); void set_temporary_dir(const std::filesystem::path& value); // Where to write configuration changes. @@ -206,6 +208,7 @@ private: uint64_t m_max_files = 0; uint64_t m_max_size = 5ULL * 1024 * 1024 * 1024; std::string m_msvc_dep_prefix = "Note: including file:"; + bool m_msvc_utf8 = true; std::string m_path; bool m_pch_external_checksum = false; std::string m_prefix_command; @@ -431,6 +434,12 @@ Config::msvc_dep_prefix() const return m_msvc_dep_prefix; } +inline bool +Config::msvc_utf8() const +{ + return m_msvc_utf8; +} + inline const std::string& Config::path() const { @@ -629,6 +638,12 @@ Config::set_msvc_dep_prefix(const std::string& value) m_msvc_dep_prefix = value; } +inline void +Config::set_msvc_utf8(bool value) +{ + m_msvc_utf8 = value; +} + inline void Config::set_temporary_dir(const std::filesystem::path& value) { diff --git a/unittest/test_config.cpp b/unittest/test_config.cpp index 572966d9..6624827a 100644 --- a/unittest/test_config.cpp +++ b/unittest/test_config.cpp @@ -72,6 +72,7 @@ TEST_CASE("Config: default values") CHECK(config.max_files() == 0); CHECK(config.max_size() == static_cast(5) * 1024 * 1024 * 1024); CHECK(config.msvc_dep_prefix() == "Note: including file:"); + CHECK(config.msvc_utf8()); CHECK(config.path().empty()); CHECK_FALSE(config.pch_external_checksum()); CHECK(config.prefix_command().empty()); @@ -133,6 +134,7 @@ TEST_CASE("Config::update_from_file") "max_files = 17\n" "max_size = 123M\n" "msvc_dep_prefix = Some other prefix:\n" + "msvc_utf8 = false\n" "path = $USER.x\n" "pch_external_checksum = true\n" "prefix_command = x$USER\n" @@ -178,6 +180,7 @@ TEST_CASE("Config::update_from_file") CHECK(config.max_files() == 17); CHECK(config.max_size() == 123 * 1000 * 1000); CHECK(config.msvc_dep_prefix() == "Some other prefix:"); + CHECK_FALSE(config.msvc_utf8()); CHECK(config.path() == FMT("{}.x", user)); CHECK(config.pch_external_checksum()); CHECK(config.prefix_command() == FMT("x{}", user)); @@ -617,6 +620,7 @@ TEST_CASE("Config::visit_items") "max_files = 4711\n" "max_size = 98.7M\n" "msvc_dep_prefix = mdp\n" + "msvc_utf8 = true\n" "namespace = ns\n" "path = p\n" "pch_external_checksum = true\n" @@ -680,6 +684,7 @@ TEST_CASE("Config::visit_items") "(test.conf) max_files = 4711", "(test.conf) max_size = 98.7 MB", "(test.conf) msvc_dep_prefix = mdp", + "(test.conf) msvc_utf8 = true", "(test.conf) namespace = ns", "(test.conf) path = p", "(test.conf) pch_external_checksum = true",