CCache: Difference between revisions

From NixOS Wiki
imported>Milahu
No edit summary
(Not related to NixOS, read https://ccache.dev/manual/4.8.2.html#_cache_statistics and run ccache -vs)
 
(6 intermediate revisions by 5 users not shown)
Line 1: Line 1:
ccache is useful for [[Packaging]] large packages with [[Incremental builds]]
CCache is useful for [[Packaging]] large packages with [[Incremental builds]].


with ccache, recompile time can be reduced from many hours to a few minutes
With CCache, recompile time can be reduced from many hours to a few minutes.


== add ccache to sandbox ==
== NixOS ==
On NixOS, the <code>programs.ccache</code> module can be used to partially enable CCache.


add to <code>/etc/nixos/configuration.nix</code>
<syntaxhighlight lang="nix">
programs.ccache.enable = true;
</syntaxhighlight>
 
However, without specifying <code>programs.ccache.packageNames</code> the CCache wrapper is not configured. The wrapper configuration can be added to your Nix overlays.
 
<syntaxhighlight lang="nix">
nixpkgs.overlays = [
  (self: super: {
    ccacheWrapper = super.ccacheWrapper.override {
      extraConfig = ''
        export CCACHE_COMPRESS=1
        export CCACHE_DIR="${config.programs.ccache.cacheDir}"
        export CCACHE_UMASK=007
        if [ ! -d "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' does not exist"
          echo "Please create it with:"
          echo "  sudo mkdir -m0770 '$CCACHE_DIR'"
          echo "  sudo chown root:nixbld '$CCACHE_DIR'"
          echo "====="
          exit 1
        fi
        if [ ! -w "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)"
          echo "Please verify its access permissions"
          echo "====="
          exit 1
        fi
      '';
    };
  })
];
</syntaxhighlight>
 
The CCache directory also needs to be added to the builder sandboxes.
 
<syntaxhighlight lang="nix">
nix.settings.extra-sandbox-paths = [ config.programs.ccache.cacheDir ];
</syntaxhighlight>
 
Run <code>sudo nixos-rebuild switch</code> to enable these options before attempting to use CCache for a derivation.
 
=== Derivation CCache ===
Packages can built with CCache by overriding <code>stdenv</code> in the derivation.
 
<syntaxhighlight lang="nix">
nixpkgs.overlays = [
  (self: super: {
    ffmpeg = super.ffmpeg.override { stdenv = super.ccacheStdenv; };
  })
];
</syntaxhighlight>
 
Some packages do not use <code>stdenv</code> directly. You may need to plumb it through other dependencies first.
 
Note, that if the package is a top-level package, you may instead add it to the <code>programs.ccache.packageNames</code> list.
 
<syntaxhighlight lang="nix">
programs.ccache.packageNames = [ "ffmpeg" ];
</syntaxhighlight>
 
=== System CCache ===
 
todo
 
=== Monitor CCache ===
 
The NixOS module creates a script that can be used to monitor the CCache directory without sudo.


<pre>
<pre>
          nix.extraOptions = ''
nix-ccache --show-stats
            extra-sandbox-paths = /nix/var/cache/ccache
          '';
</pre>
</pre>


todo: use <code>nix.sandboxPaths</code>? [https://github.com/NixOS/nixpkgs/issues/153343]
== Non-NixOS ==
 
run <code>sudo nixos-rebuild switch</code>
 
now <code>/etc/nix/nix.conf</code> should have <code>sandbox-paths = /nix/var/cache/ccache</code>


create the cache folder
Create the cache folder:


<pre>
<pre>
Line 31: Line 95:
</pre>
</pre>


== derivation ccache ==
Add the path to the derivation sandbox by adding <code>extra-sandbox-paths</code> to <code>nix.conf</code>
 
to enable ccache only for one derivation
 
patch the <code>default.nix</code> file


<pre>
<pre>
{ stdenv
extra-sandbox-paths = /nix/var/cache/ccache
, ccacheStdenv
</pre>
# ...
}:
 
#stdenv.mkDerivation {
ccacheStdenv.mkDerivation {
 
  preConfigure = ''
    export CCACHE_DIR=/nix/var/cache/ccache
    export CCACHE_UMASK=007
  ''


# ...
Then configure the CCache wrapper script.
</pre>


add <code>ccacheStdenv</code> to dependencies
<syntaxhighlight lang="nix">
nixpkgs.overlays = [
  (self: super: {
    ccacheWrapper = super.ccacheWrapper.override {
      extraConfig = ''
        export CCACHE_COMPRESS=1
        export CCACHE_DIR="/nix/var/cache/ccache"
        export CCACHE_UMASK=007
        if [ ! -d "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' does not exist"
          echo "Please create it with:"
          echo "  sudo mkdir -m0770 '$CCACHE_DIR'"
          echo "  sudo chown root:nixbld '$CCACHE_DIR'"
          echo "====="
          exit 1
        fi
        if [ ! -w "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)"
          echo "Please verify its access permissions"
          echo "====="
          exit 1
        fi
      '';
    };
  })
];
</syntaxhighlight>


run <code>nix-build</code>
=== Derivation CCache ===
Packages can built with CCache by overriding <code>stdenv</code> in the derivation.


== system ccache ==
<syntaxhighlight lang="nix">
nixpkgs.overlays = [
  (self: super: {
    ffmpeg = super.ffmpeg.override { stdenv = super.ccacheStdenv; };
  })
];
</syntaxhighlight>


todo
Some packages do not use <code>stdenv</code> directly. You may need to plumb it through other dependencies first.


== monitor ccache status ==
=== Monitor CCache status ===


<pre>
<pre>
Line 69: Line 153:


# watch ccache stats
# watch ccache stats
sudo watch ccache --dir /nix/var/cache/ccache --show-stats --verbose
sudo watch ccache --dir /nix/var/cache/ccache --show-stats
</pre>
</pre>


== uncacheable ==
== Sloppiness ==


todo: why are some compilations "uncacheable" according to <code>ccache --show-stats</code>
By default, <code>stdenv</code> inserts <code>-frandom-seed</code> C compiler flag with a value that changes whenever the derivation hash has changed.
Consequently, this behavior completely defeats any usage of <code>ccacheWrapper</code>
To counterpart this behavior, add the following line to the ccache config (typically <code>/var/cache/ccache/ccache.conf</code>):
<pre>
sloppiness = random_seed
</pre>


== see also ==
Be warned that this configuration option might affect reproducibility of builds, and could lead to cache poisoning.
See [https://github.com/NixOS/nixpkgs/issues/109033 issue 109033] for more details.
 
== See also ==


* https://leanprover.github.io/lean4/doc/make/nix.html
* https://leanprover.github.io/lean4/doc/make/nix.html
* [https://nixos.org/manual/nix/stable/command-ref/conf-file.html sandbox-paths in nix.conf]
* [https://nixos.org/manual/nix/stable/command-ref/conf-file.html sandbox-paths in nix.conf]
[[Category: Development]]

Latest revision as of 16:02, 18 June 2024

CCache is useful for Packaging large packages with Incremental builds.

With CCache, recompile time can be reduced from many hours to a few minutes.

NixOS

On NixOS, the programs.ccache module can be used to partially enable CCache.

programs.ccache.enable = true;

However, without specifying programs.ccache.packageNames the CCache wrapper is not configured. The wrapper configuration can be added to your Nix overlays.

nixpkgs.overlays = [
  (self: super: {
    ccacheWrapper = super.ccacheWrapper.override {
      extraConfig = ''
        export CCACHE_COMPRESS=1
        export CCACHE_DIR="${config.programs.ccache.cacheDir}"
        export CCACHE_UMASK=007
        if [ ! -d "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' does not exist"
          echo "Please create it with:"
          echo "  sudo mkdir -m0770 '$CCACHE_DIR'"
          echo "  sudo chown root:nixbld '$CCACHE_DIR'"
          echo "====="
          exit 1
        fi
        if [ ! -w "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)"
          echo "Please verify its access permissions"
          echo "====="
          exit 1
        fi
      '';
    };
  })
];

The CCache directory also needs to be added to the builder sandboxes.

nix.settings.extra-sandbox-paths = [ config.programs.ccache.cacheDir ];

Run sudo nixos-rebuild switch to enable these options before attempting to use CCache for a derivation.

Derivation CCache

Packages can built with CCache by overriding stdenv in the derivation.

nixpkgs.overlays = [
  (self: super: {
    ffmpeg = super.ffmpeg.override { stdenv = super.ccacheStdenv; };
  })
];

Some packages do not use stdenv directly. You may need to plumb it through other dependencies first.

Note, that if the package is a top-level package, you may instead add it to the programs.ccache.packageNames list.

programs.ccache.packageNames = [ "ffmpeg" ];

System CCache

todo

Monitor CCache

The NixOS module creates a script that can be used to monitor the CCache directory without sudo.

nix-ccache --show-stats

Non-NixOS

Create the cache folder:

sudo mkdir -m0770 -p /nix/var/cache/ccache

# Linux
sudo chown --reference=/nix/store /nix/var/cache/ccache

# macOS workaround for chown --reference
nix-shell -p coreutils --run 'sudo chown --reference=/nix/store /nix/var/cache/ccache'

Add the path to the derivation sandbox by adding extra-sandbox-paths to nix.conf

extra-sandbox-paths = /nix/var/cache/ccache

Then configure the CCache wrapper script.

nixpkgs.overlays = [
  (self: super: {
    ccacheWrapper = super.ccacheWrapper.override {
      extraConfig = ''
        export CCACHE_COMPRESS=1
        export CCACHE_DIR="/nix/var/cache/ccache"
        export CCACHE_UMASK=007
        if [ ! -d "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' does not exist"
          echo "Please create it with:"
          echo "  sudo mkdir -m0770 '$CCACHE_DIR'"
          echo "  sudo chown root:nixbld '$CCACHE_DIR'"
          echo "====="
          exit 1
        fi
        if [ ! -w "$CCACHE_DIR" ]; then
          echo "====="
          echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)"
          echo "Please verify its access permissions"
          echo "====="
          exit 1
        fi
      '';
    };
  })
];

Derivation CCache

Packages can built with CCache by overriding stdenv in the derivation.

nixpkgs.overlays = [
  (self: super: {
    ffmpeg = super.ffmpeg.override { stdenv = super.ccacheStdenv; };
  })
];

Some packages do not use stdenv directly. You may need to plumb it through other dependencies first.

Monitor CCache status

# watch ccache size
sudo watch du -sh /nix/var/cache/ccache

# watch ccache stats
sudo watch ccache --dir /nix/var/cache/ccache --show-stats

Sloppiness

By default, stdenv inserts -frandom-seed C compiler flag with a value that changes whenever the derivation hash has changed. Consequently, this behavior completely defeats any usage of ccacheWrapper To counterpart this behavior, add the following line to the ccache config (typically /var/cache/ccache/ccache.conf):

sloppiness = random_seed

Be warned that this configuration option might affect reproducibility of builds, and could lead to cache poisoning. See issue 109033 for more details.

See also