1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7
8let
9 cfg = config.programs.ccache;
10in
11{
12 options.programs.ccache = {
13 # host configuration
14 enable = lib.mkEnableOption "CCache, a compiler cache for fast recompilation of C/C++ code";
15 cacheDir = lib.mkOption {
16 type = lib.types.path;
17 description = "CCache directory";
18 default = "/var/cache/ccache";
19 };
20 # target configuration
21 packageNames = lib.mkOption {
22 type = lib.types.listOf lib.types.str;
23 description = "Nix top-level packages to be compiled using CCache";
24 default = [ ];
25 example = [
26 "wxGTK32"
27 "ffmpeg"
28 "libav_all"
29 ];
30 };
31 owner = lib.mkOption {
32 type = lib.types.str;
33 default = "root";
34 description = "Owner of CCache directory";
35 };
36 group = lib.mkOption {
37 type = lib.types.str;
38 default = "nixbld";
39 description = "Group owner of CCache directory";
40 };
41 };
42
43 config = lib.mkMerge [
44 # host configuration
45 (lib.mkIf cfg.enable {
46 systemd.tmpfiles.rules = [ "d ${cfg.cacheDir} 0770 ${cfg.owner} ${cfg.group} -" ];
47
48 # "nix-ccache --show-stats" and "nix-ccache --clear"
49 security.wrappers.nix-ccache = {
50 inherit (cfg) owner group;
51 setuid = false;
52 setgid = true;
53 source = pkgs.writeScript "nix-ccache.pl" ''
54 #!${pkgs.perl}/bin/perl
55
56 %ENV=( CCACHE_DIR => '${cfg.cacheDir}' );
57 sub untaint {
58 my $v = shift;
59 return '-C' if $v eq '-C' || $v eq '--clear';
60 return '-V' if $v eq '-V' || $v eq '--version';
61 return '-s' if $v eq '-s' || $v eq '--show-stats';
62 return '-z' if $v eq '-z' || $v eq '--zero-stats';
63 exec('${pkgs.ccache}/bin/ccache', '-h');
64 }
65 exec('${pkgs.ccache}/bin/ccache', map { untaint $_ } @ARGV);
66 '';
67 };
68 })
69
70 # target configuration
71 (lib.mkIf (cfg.packageNames != [ ]) {
72 nixpkgs.overlays = [
73 (
74 self: super:
75 lib.genAttrs cfg.packageNames (
76 pn: super.${pn}.override { stdenv = builtins.trace "with ccache: ${pn}" self.ccacheStdenv; }
77 )
78 )
79
80 (self: super: {
81 ccacheWrapper = super.ccacheWrapper.override {
82 extraConfig = ''
83 export CCACHE_COMPRESS=1
84 export CCACHE_DIR="${cfg.cacheDir}"
85 export CCACHE_UMASK=007
86 if [ ! -d "$CCACHE_DIR" ]; then
87 echo "====="
88 echo "Directory '$CCACHE_DIR' does not exist"
89 echo "Please create it with:"
90 echo " sudo mkdir -m0770 '$CCACHE_DIR'"
91 echo " sudo chown ${cfg.owner}:${cfg.group} '$CCACHE_DIR'"
92 echo "====="
93 exit 1
94 fi
95 if [ ! -w "$CCACHE_DIR" ]; then
96 echo "====="
97 echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)"
98 echo "Please verify its access permissions"
99 echo "====="
100 exit 1
101 fi
102 '';
103 };
104 })
105 ];
106 })
107 ];
108}