Skip to content

Commit

Permalink
fix: Move Windows config and cache to LOCALAPPDATA
Browse files Browse the repository at this point in the history
Throw a fatal error if a cache is detected in APPDATA.

Fix-up default cmake install directories and set system-wide config to
C:\ProgramData\ccache\ccache.conf .

Update manual.

Fix ccache#1023
Fix ccache#946

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
  • Loading branch information
rkitover committed Jul 21, 2022
1 parent af59e2f commit ae52dec
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 30 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ include(DefaultBuildType)
#
# Configuration
#
include(GNUInstallDirs)

include(InstallDirs)
include(GenerateConfigurationFile)
include(GenerateVersionFile)

Expand Down
27 changes: 27 additions & 0 deletions cmake/InstallDirs.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
if(WIN32)
set(programfiles "$ENV{ProgramFiles}")

# For 32 bit builds.
if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 4 AND ENV{ProgramFiles\(x86\)})
set(programfiles "$ENV{ProgramFiles\(x86\)}")
endif()

string(REPLACE "\\" "\\\\" programfiles "${programfiles}")

set(CMAKE_INSTALL_PREFIX "${programfiles}\\\\ccache" CACHE STRING "System-wide installation location" FORCE)

if(NOT CMAKE_INSTALL_SYSCONFDIR)
string(REPLACE "\\" "\\\\" programdata "$ENV{ALLUSERSPROFILE}")
if(NOT programdata)
set(programdata "C:\\\\ProgramData")
endif()

set(CMAKE_INSTALL_SYSCONFDIR "${programdata}\\\\ccache" CACHE STRING "Systemwide configuration location" FORCE)
endif()

set(CMAKE_INSTALL_BINDIR "" CACHE PATH "" FORCE)
set(CMAKE_INSTALL_LIBEXECDIR "" CACHE PATH "" FORCE)
set(CMAKE_INSTALL_SBINDIR "" CACHE PATH "" FORCE)
endif()

include(GNUInstallDirs)
15 changes: 10 additions & 5 deletions doc/MANUAL.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,17 @@ this:
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`.
(system-wide) configuration file then use `<cache_dir>/ccache.conf`. The
system-wide configuration on Windows is
`$env:ALLUSERSPROFILE\ccache\ccache.conf` by default, `$env:ALLUSERSPROFILE`
is usually `C:\ProgramData`.
4. Otherwise, if there is a legacy `$HOME/.ccache` directory 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),
`$HOME/.ccache/ccache.conf` (`$env:USERPROFILE` on Windows.)
6. Otherwise, if `XDG_CONFIG_HOME` is set then use
`$XDG_CONFIG_HOME/ccache/ccache.conf`. On Windows
`$env:LOCALAPPDATA\ccache\ccache.conf` is used first if it exists, otherwise
`$env:APPDATA\ccache\ccache.conf` is used if it exists.
6. Otherwise, for systems other than Windows, use
`$HOME/Library/Preferences/ccache/ccache.conf` (macOS) or
`$HOME/.config/ccache/ccache.conf` (other systems).

Expand Down
83 changes: 66 additions & 17 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,29 +424,27 @@ parse_config_file(const std::string& path,

} // 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)
Expand Down Expand Up @@ -477,11 +475,16 @@ void
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 = home_dir + DIR_SEP + ".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) {
Expand All @@ -490,9 +493,9 @@ Config::read()
// Only used for ccache tests:
const char* const env_ccache_configpath2 = getenv("CCACHE_CONFIGPATH2");

set_secondary_config_path(env_ccache_configpath2
? env_ccache_configpath2
: FMT("{}/ccache.conf", k_sysconfdir));
set_secondary_config_path(
env_ccache_configpath2 ? env_ccache_configpath2
: FMT("{}{}ccache.conf", k_sysconfdir, DIR_SEP));
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());
Expand All @@ -506,12 +509,32 @@ Config::read()
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(FMT("{}{}ccache{}ccache.conf",
env_local_appdata,
DIR_SEP,
DIR_SEP))) {
primary_config_dir = FMT("{}{}ccache", env_local_appdata, DIR_SEP);
} else if (env_appdata
&& Stat::stat(FMT(
"{}{}ccache{}ccache.conf", env_appdata, DIR_SEP, DIR_SEP))) {
primary_config_dir = FMT("{}{}ccache", env_appdata, DIR_SEP);
} else if (env_local_appdata) {
primary_config_dir = FMT("{}{}ccache", env_local_appdata, DIR_SEP);
} else {
throw core::Error(
"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 = FMT("{}{}ccache", env_xdg_config_home, DIR_SEP);
} else {
primary_config_dir = default_config_dir(home_dir);
}
set_primary_config_path(primary_config_dir + "/ccache.conf");
#endif
set_primary_config_path(primary_config_dir + DIR_SEP + "ccache.conf");
}

const std::string& cache_dir_before_primary_config = cache_dir();
Expand All @@ -531,12 +554,38 @@ Config::read()
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(FMT("{}{}ccache", env_local_appdata, DIR_SEP));
} else {
throw core::Error(
"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(FMT("{}{}ccache", env_xdg_cache_home, DIR_SEP));
} else {
set_cache_dir(default_cache_dir(home_dir));
}
#endif
}

// Check for previous default cachedir in APPDATA and throw a fatal error if
// it exists.
#ifdef _WIN32
if (const char* appdata = getenv("APPDATA")) {
if (Stat::stat(FMT("{}{}ccache{}tmp", appdata, DIR_SEP, DIR_SEP)))
throw core::Error(
"legacy cache detected in APPDATA directory {}{}ccache, "
"please move it to the LOCALAPPDATA directory {}{}ccache",
appdata,
DIR_SEP,
getenv("LOCALAPPDATA"),
DIR_SEP);
}
#endif

// else: cache_dir was set explicitly via environment or via secondary
// config.

Expand Down
12 changes: 5 additions & 7 deletions src/Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,16 +665,14 @@ get_extension(std::string_view path)
std::string
get_home_directory()
{
const char* p = getenv("HOME");
if (p) {
return p;
}
#ifdef _WIN32
p = getenv("APPDATA");
if (p) {
if (const char* p = getenv("USERPROFILE"))
#else
if (const char* p = getenv("HOME"))
#endif
{
return p;
}
#endif
#ifdef HAVE_GETPWUID
{
struct passwd* pwd = getpwuid(getuid());
Expand Down
7 changes: 7 additions & 0 deletions src/Util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@

class Context;

// Constant for the system directory separator.
#ifdef _WIN32
const char DIR_SEP = '\\';
#else
const char DIR_SEP = '/';
#endif

namespace Util {

using DataReceiver = std::function<void(const void* data, size_t size)>;
Expand Down

0 comments on commit ae52dec

Please sign in to comment.