Skip to content

Commit

Permalink
fix: Move Windows config and cache to LOCALAPPDATA
Browse files Browse the repository at this point in the history
Add a variadic template helper function PATH(std::string...) to
construct native paths using std::filesystem.

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 22, 2022
1 parent af59e2f commit 95b0d66
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 29 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
29 changes: 29 additions & 0 deletions cmake/InstallDirs.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
if(WIN32)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
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)
endif()

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 "System-wide 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)
22 changes: 20 additions & 2 deletions doc/MANUAL.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ configuration file won't be read.
=== Location of the primary configuration file

The location of the primary (cache-specific) configuration is determined like
this:
this on systems other than Windows:

1. If `CCACHE_CONFIGPATH` is set, use that path.
2. Otherwise, if the environment variable `CCACHE_DIR` is set then use
Expand All @@ -314,10 +314,28 @@ this:
`$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:

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
`$env:ALLUSERSPROFILE\ccache\ccache.conf` by default, `$env:ALLUSERSPROFILE`
is usually `C:\ProgramData`.
4. Otherwise, if there is a legacy `$env:USERPROFILE\.ccache` directory then use
`$env:USERPROFILE\.ccache\ccache.conf`.
6. Otherwise, if `$env:LOCALAPPDATA\ccache\ccache.conf` exists it is used.
7. Otherwise, if `$env:APPDATA\ccache\ccache.conf` exists it is used.

The default cache dir on Windows is `$env:LOCALAPPDATA\ccache` unless specified
otherwise by the config. If a cache is detected in `$env:APPDATA\ccache`, which
was the default previously, a fatal error is thrown.

=== Configuration file syntax

Expand Down
80 changes: 65 additions & 15 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 = 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) {
Expand All @@ -490,9 +493,15 @@ Config::read()
// Only used for ccache tests:
const char* const env_ccache_configpath2 = getenv("CCACHE_CONFIGPATH2");

std::string sysconfdir = k_sysconfdir;
#ifdef _WIN32
if (const char* program_data = getenv("ALLUSERSPROFILE"))
sysconfdir = PATH(program_data, "ccache");
#endif

set_secondary_config_path(env_ccache_configpath2
? env_ccache_configpath2
: FMT("{}/ccache.conf", k_sysconfdir));
: 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());
Expand All @@ -506,12 +515,29 @@ 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(
PATH(env_local_appdata, "ccache", "ccache.conf"))) {
primary_config_dir = PATH(env_local_appdata, "ccache");
} else if (env_appdata
&& Stat::stat(PATH(env_appdata, "ccache", "ccache.conf"))) {
primary_config_dir = PATH(env_appdata, "ccache");
} else if (env_local_appdata) {
primary_config_dir = PATH(env_local_appdata, "ccache");
} 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 = 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(PATH(primary_config_dir, "ccache.conf"));
}

const std::string& cache_dir_before_primary_config = cache_dir();
Expand All @@ -531,12 +557,36 @@ 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(PATH(env_local_appdata, "ccache"));
} 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(PATH(env_xdg_cache_home, "ccache"));
} else {
set_cache_dir(default_cache_dir(home_dir));
}
#endif
}

// Check for legacy default cachedir in APPDATA and throw a fatal error if it
// exists.
#ifdef _WIN32
if (env_appdata) {
if (Stat::stat(PATH(env_appdata, "ccache", "tmp")).is_directory())
throw core::Error(
"legacy cache detected in APPDATA directory {}, "
"please move it to the LOCALAPPDATA directory {}",
PATH(env_appdata, "ccache"),
PATH(env_local_appdata, "ccache"));
}
#endif

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

Expand Down
16 changes: 5 additions & 11 deletions src/Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ extern "C" {
#include <fstream>
#include <locale>

#ifndef HAVE_DIRENT_H
# include <filesystem>
#endif

#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
Expand Down Expand Up @@ -665,16 +661,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
18 changes: 18 additions & 0 deletions src/Util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <util/Tokenizer.hpp>

#include <cstdint>
#include <filesystem>
#include <functional>
#include <ios>
#include <memory>
Expand All @@ -33,6 +34,23 @@

class Context;

// Helper variadic function to construct native paths.
// Used like: P("usr", "local", "bin");
template<typename... T>
std::string
PATH(T&... args)
{
std::vector<std::string> arg_list{args...};
std::filesystem::path full;

for (auto&& p_str : arg_list) {
std::filesystem::path p(p_str);
full = full / p;
}

return full.string();
}

namespace Util {

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

0 comments on commit 95b0d66

Please sign in to comment.