#
# Configuration
#
-include(GNUInstallDirs)
+
+include(InstallDirs)
include(GenerateConfigurationFile)
include(GenerateVersionFile)
set(INODE_CACHE_SUPPORTED 1)
endif()
+# Escape backslashes in SYSCONFDIR for C.
+file(TO_NATIVE_PATH "${CMAKE_INSTALL_FULL_SYSCONFDIR}" CONFIG_SYSCONFDIR_C_ESCAPED)
+string(REPLACE "\\" "\\\\" CONFIG_SYSCONFDIR_C_ESCAPED "${CONFIG_SYSCONFDIR_C_ESCAPED}")
+
configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in
${CMAKE_BINARY_DIR}/config.h @ONLY)
--- /dev/null
+if(WIN32)
+ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(program_files "$ENV{ProgramFiles}")
+
+ # For 32 bit builds.
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND ENV{ProgramFiles\(x86\)})
+ set(program_files "$ENV{ProgramFiles\(x86\)}")
+ endif()
+
+ if(NOT program_files)
+ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(program_files "/Program Files")
+ else()
+ set(program_files "/Program Files (x86)")
+ endif()
+ endif()
+
+ file(TO_CMAKE_PATH "${program_files}/ccache" CMAKE_INSTALL_PREFIX)
+
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE STRING "System-wide installation prefix" FORCE)
+ endif()
+
+ if(NOT CMAKE_INSTALL_SYSCONFDIR)
+ set(program_data "$ENV{ALLUSERSPROFILE}")
+
+ if(NOT program_data)
+ set(program_data "/ProgramData")
+ endif()
+
+ file(TO_CMAKE_PATH "${program_data}/ccache" CMAKE_INSTALL_SYSCONFDIR)
+
+ set(CMAKE_INSTALL_SYSCONFDIR "${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH "System-wide config file location" FORCE)
+ endif()
+
+ set(CMAKE_INSTALL_BINDIR "" CACHE PATH "executables subdirectory" FORCE)
+ set(CMAKE_INSTALL_SBINDIR "" CACHE PATH "system administration executables subdirectory" FORCE)
+ set(CMAKE_INSTALL_LIBEXECDIR "" CACHE PATH "dependent executables subdirectory" FORCE)
+ set(CMAKE_INSTALL_LIBDIR "" CACHE PATH "object libraries subdirectory" FORCE)
+endif()
+
+include(GNUInstallDirs)
# define ESTALE -1
#endif
-#define SYSCONFDIR "@CMAKE_INSTALL_FULL_SYSCONFDIR@"
+#define SYSCONFDIR "@CONFIG_SYSCONFDIR_C_ESCAPED@"
#cmakedefine INODE_CACHE_SUPPORTED
=== Location of the primary configuration file
-The location of the primary (cache-specific) configuration is determined like
-this:
+The location of the primary (cache-specific) configuration is determined as
+follows on non-Windows systems:
1. If `CCACHE_CONFIGPATH` is set, use that path.
2. Otherwise, if the environment variable `CCACHE_DIR` is set then use
`$HOME/.ccache/ccache.conf`.
5. Otherwise, if `XDG_CONFIG_HOME` is set then use
`$XDG_CONFIG_HOME/ccache/ccache.conf`.
-6. Otherwise, use `%APPDATA%/ccache/ccache.conf` (Windows),
+6. Otherwise, use
`$HOME/Library/Preferences/ccache/ccache.conf` (macOS) or
`$HOME/.config/ccache/ccache.conf` (other systems).
+On Windows, this is the method used to find the configuration file:
+
+1. If `CCACHE_CONFIGPATH` is set, use that path.
+2. Otherwise, if the environment variable `CCACHE_DIR` is set then use
+ `%CCACHE_DIR%/ccache.conf`.
+3. Otherwise, if <<config_cache_dir,*cache_dir*>> is set in the secondary
+ (system-wide) configuration file then use `<cache_dir>\ccache.conf`. The
+ system-wide configuration on Windows is
+ `%ALLUSERSPROFILE%\ccache\ccache.conf` by default, the `ALLUSERSPROFILE`
+ environment variable is usually `C:\ProgramData`.
+4. Otherwise, if there is a legacy `%USERPROFILE%\.ccache` directory then use
+ `%USERPROFILE%\.ccache\ccache.conf`.
+5. Otherwise, if `%LOCALAPPDATA%\ccache\ccache.conf` exists it is used.
+6. Otherwise, if `%APPDATA%\ccache\ccache.conf` exists it is used.
+
+See also the <<config_cache_dir,*cache_dir*>> configuration option for how the
+cache directory location is determined.
=== Configuration file syntax
[#config_cache_dir]
*cache_dir* (*CCACHE_DIR*)::
- This option specifies where ccache will keep its cached compiler outputs.
- The default is `$XDG_CACHE_HOME/ccache` if `XDG_CACHE_HOME` is set,
- otherwise `%APPDATA%/ccache` (Windows), `$HOME/Library/Caches/ccache`
- (macOS) or `$HOME/.config/ccache` (other systems). Exception: If the legacy
- directory `$HOME/.ccache` exists then that directory is the default.
+ This option specifies where ccache will keep its cached compiler outputs if
+ specified in the first found configuration files, with the `$CCACHE_DIR`
+ environment variable taking precedence over it.
++
+The location of the cache directory is determined as follows on non-Windows
+systems:
++
+--
+1. `$CCACHE_DIR` if set.
+2. `cache_dir` in the first found configuration if specified.
+3. `$HOME/.ccache` if it exists.
+4. `$XDG_CACHE_HOME/ccache` if `$XDG_CACHE_HOME` is set.
+5. Otherwise `~/.cache/ccache` or `~/Library/Caches/ccache` on Apple systems.
+--
++
+The cache directory on Windows is determined as follows:
++
+--
+1. `%CCACHE_DIR%` if set.
+2. `cache_dir` in the first found configuration if specified.
+3. `%USERPROFILE%\.ccache` if it exists.
+4. Otherwise `%LOCALAPPDATA%\ccache`.
+--
++
+WARNING: Previous builds of ccache for Windows defaulted to storing the cache in
+`%APPDATA%\ccache`. This can result in large network file transfers of the cache
+in domain environments and similar problems. Please check this directory for
+cache directories and either delete them or the whole directory, or move them to
+the `%LOCALAPPDATA%\ccache` directory.
+
See also _<<Location of the primary configuration file>>_.
+
} // namespace
+#ifndef _WIN32
static std::string
default_cache_dir(const std::string& home_dir)
{
-#ifdef _WIN32
- return home_dir + "/ccache";
-#elif defined(__APPLE__)
+# ifdef __APPLE__
return home_dir + "/Library/Caches/ccache";
-#else
+# else
return home_dir + "/.cache/ccache";
-#endif
+# endif
}
static std::string
default_config_dir(const std::string& home_dir)
{
-#ifdef _WIN32
- return home_dir + "/ccache";
-#elif defined(__APPLE__)
+# ifdef __APPLE__
return home_dir + "/Library/Preferences/ccache";
-#else
+# else
return home_dir + "/.config/ccache";
-#endif
+# endif
}
+#endif
std::string
compiler_type_to_string(CompilerType compiler_type)
Config::read()
{
const std::string home_dir = Util::get_home_directory();
- const std::string legacy_ccache_dir = home_dir + "/.ccache";
+ const std::string legacy_ccache_dir = Util::make_path(home_dir, ".ccache");
const bool legacy_ccache_dir_exists =
Stat::stat(legacy_ccache_dir).is_directory();
+#ifdef _WIN32
+ const char* const env_appdata = getenv("APPDATA");
+ const char* const env_local_appdata = getenv("LOCALAPPDATA");
+#else
const char* const env_xdg_cache_home = getenv("XDG_CACHE_HOME");
const char* const env_xdg_config_home = getenv("XDG_CONFIG_HOME");
+#endif
const char* env_ccache_configpath = getenv("CCACHE_CONFIGPATH");
if (env_ccache_configpath) {
// Only used for ccache tests:
const char* const env_ccache_configpath2 = getenv("CCACHE_CONFIGPATH2");
+ std::string sysconfdir = Util::make_path(k_sysconfdir);
+#ifdef _WIN32
+ if (const char* program_data = getenv("ALLUSERSPROFILE"))
+ sysconfdir = Util::make_path(program_data, "ccache");
+#endif
+
set_secondary_config_path(env_ccache_configpath2
? env_ccache_configpath2
- : FMT("{}/ccache.conf", k_sysconfdir));
+ : Util::make_path(sysconfdir, "ccache.conf"));
MTR_BEGIN("config", "conf_read_secondary");
// A missing config file in SYSCONFDIR is OK so don't check return value.
update_from_file(secondary_config_path());
primary_config_dir = cache_dir();
} else if (legacy_ccache_dir_exists) {
primary_config_dir = legacy_ccache_dir;
+#ifdef _WIN32
+ } else if (env_local_appdata
+ && Stat::stat(
+ Util::make_path(env_local_appdata, "ccache", "ccache.conf"))) {
+ primary_config_dir = Util::make_path(env_local_appdata, "ccache");
+ } else if (env_appdata
+ && Stat::stat(
+ Util::make_path(env_appdata, "ccache", "ccache.conf"))) {
+ primary_config_dir = Util::make_path(env_appdata, "ccache");
+ } else if (env_local_appdata) {
+ primary_config_dir = Util::make_path(env_local_appdata, "ccache");
+ } else {
+ throw core::Fatal(
+ "could not find config file and the LOCALAPPDATA "
+ "environment variable is not set");
+ }
+#else
} else if (env_xdg_config_home) {
- primary_config_dir = FMT("{}/ccache", env_xdg_config_home);
+ primary_config_dir = Util::make_path(env_xdg_config_home, "ccache");
} else {
primary_config_dir = default_config_dir(home_dir);
}
- set_primary_config_path(primary_config_dir + "/ccache.conf");
+#endif
+ set_primary_config_path(Util::make_path(primary_config_dir, "ccache.conf"));
}
const std::string& cache_dir_before_primary_config = cache_dir();
if (cache_dir().empty()) {
if (legacy_ccache_dir_exists) {
set_cache_dir(legacy_ccache_dir);
+#ifdef _WIN32
+ } else if (env_local_appdata) {
+ set_cache_dir(Util::make_path(env_local_appdata, "ccache"));
+ } else {
+ throw core::Fatal(
+ "could not find cache dir and the LOCALAPPDATA "
+ "environment variable is not set");
+ }
+#else
} else if (env_xdg_cache_home) {
- set_cache_dir(FMT("{}/ccache", env_xdg_cache_home));
+ set_cache_dir(Util::make_path(env_xdg_cache_home, "ccache"));
} else {
set_cache_dir(default_cache_dir(home_dir));
}
+#endif
}
+
// else: cache_dir was set explicitly via environment or via secondary
// config.
#include <fcntl.h>
-#ifndef HAVE_DIRENT_H
-# include <filesystem>
-#endif
-
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
std::string
get_home_directory()
{
- const char* p = getenv("HOME");
- if (p) {
+#ifdef _WIN32
+ if (const char* p = getenv("USERPROFILE")) {
return p;
}
-#ifdef _WIN32
- p = getenv("APPDATA");
- if (p) {
+ throw core::Fatal(
+ "The USERPROFILE environment variable must be set to your user profile "
+ "folder");
+#else
+ if (const char* p = getenv("HOME")) {
return p;
}
-#endif
-#ifdef HAVE_GETPWUID
+# ifdef HAVE_GETPWUID
{
struct passwd* pwd = getpwuid(getuid());
if (pwd) {
return pwd->pw_dir;
}
}
-#endif
+# endif
throw core::Fatal(
"Could not determine home directory from $HOME or getpwuid(3)");
+#endif
}
const char*
#include <util/Tokenizer.hpp>
#include <cstdint>
+#include <filesystem>
#include <functional>
#include <ios>
#include <memory>
// time of day is used.
std::optional<tm> localtime(std::optional<time_t> time = {});
+// Construct a normalized native path, used like:
+// std::string path = Util::make_path("usr", "local", "bin");
+template<typename... T>
+std::string
+make_path(const T&... args)
+{
+ return (std::filesystem::path{} / ... / args).lexically_normal().string();
+}
+
// Make a relative path from current working directory (either `actual_cwd` or
// `apparent_cwd`) to `path` if `path` is under `base_dir`.
std::string make_relative_path(const std::string& base_dir,