btrbk: add mainProgram (#356350)
[NixPkgs.git] / pkgs / development / compilers / crystal / build-package.nix
blob536ad3acda7b51f7573bc06a3d033f7870f53d0d
1 { stdenv
2 , lib
3 , crystal
4 , pcre2
5 , shards
6 , git
7 , pkg-config
8 , which
9 , linkFarm
10 , fetchgit
11 , fetchFromGitHub
12 , installShellFiles
13 , removeReferencesTo
17   # Some projects do not include a lock file, so you can pass one
18   lockFile ? null
19   # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root
20 , shardsFile ? null
21   # We support different builders. To make things more straight forward, make it
22   # user selectable instead of trying to autodetect
23 , format ? "make"
24 , installManPages ? true
25   # Specify binaries to build in the form { foo.src = "src/foo.cr"; }
26   # The default `crystal build` options can be overridden with { foo.options = [ "--optionname" ]; }
27 , crystalBinaries ? { }
28 , enableParallelBuilding ? true
29   # Copy all shards dependencies instead of symlinking and add write permissions
30   # to make environment more local-like
31 , copyShardDeps ? false
32 , ...
33 }@args:
35 assert (builtins.elem format [ "make" "crystal" "shards" ]);
36 let
37   mkDerivationArgs = builtins.removeAttrs args [
38     "format"
39     "installManPages"
40     "lockFile"
41     "shardsFile"
42     "crystalBinaries"
43   ];
45   crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList
46     (name: value: {
47       inherit name;
48       path =
49         if (builtins.hasAttr "url" value)
50         then fetchgit value
51         else fetchFromGitHub value;
52     })
53     (import shardsFile));
55   # We no longer use --no-debug in accordance with upstream's recommendation
56   defaultOptions = [ "--release" "--progress" "--verbose" ];
58   buildDirectly = shardsFile == null || crystalBinaries != { };
60   mkCrystalBuildArgs = bin: attrs:
61     lib.concatStringsSep " " ([
62       "crystal"
63       "build"
64     ] ++ lib.optionals enableParallelBuilding [
65       "--threads"
66       "$NIX_BUILD_CORES"
67     ] ++ [
68       "-o"
69       bin
70       (attrs.src or (throw "No source file for crystal binary ${bin} provided"))
71       (lib.concatStringsSep " " (attrs.options or defaultOptions))
72     ]);
75 stdenv.mkDerivation (mkDerivationArgs // {
77   configurePhase = args.configurePhase or (lib.concatStringsSep "\n" (
78       [
79         "runHook preConfigure"
80       ]
81       ++ lib.optional (lockFile != null) "cp ${lockFile} ./shard.lock"
82       ++ lib.optionals (shardsFile != null) [
83         "test -e lib || mkdir lib"
84         (if copyShardDeps then "for d in ${crystalLib}/*; do cp -r $d/ lib/; done; chmod -R +w lib/"
85           else "for d in ${crystalLib}/*; do ln -s $d lib/; done")
86         "cp shard.lock lib/.shards.info"
87       ]
88       ++ [ "runHook postConfigure" ]
89     ));
91   CRFLAGS = lib.concatStringsSep " " defaultOptions;
93   PREFIX = placeholder "out";
95   inherit enableParallelBuilding;
96   strictDeps = true;
97   buildInputs = args.buildInputs or [ ] ++ [ crystal ]
98     ++ lib.optional (lib.versionAtLeast crystal.version "1.8") pcre2;
100   nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
101     crystal
102     git
103     installShellFiles
104     removeReferencesTo
105     pkg-config
106     which
107   ] ++ lib.optional (format != "crystal") shards;
109   buildPhase = args.buildPhase or (lib.concatStringsSep "\n" ([
110     "runHook preBuild"
111   ] ++ lib.optional (format == "make")
112     "make \${buildTargets:-build} $makeFlags"
113   ++ lib.optionals (format == "crystal") (lib.mapAttrsToList mkCrystalBuildArgs crystalBinaries)
114   ++ lib.optional (format == "shards")
115     "shards build --local --production ${lib.concatStringsSep " " (args.options or defaultOptions)}"
116   ++ [ "runHook postBuild" ]));
118   installPhase = args.installPhase or (lib.concatStringsSep "\n" ([
119     "runHook preInstall"
120   ] ++ lib.optional (format == "make")
121     "make \${installTargets:-install} $installFlags"
122   ++ lib.optionals (format == "crystal") (map
123     (bin: ''
124       install -Dm555 ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]}
125     '')
126     (lib.attrNames crystalBinaries))
127   ++ lib.optional (format == "shards")
128     "install -Dm555 bin/* -t $out/bin"
129   ++ [
130     ''
131       for f in README* *.md LICENSE; do
132         test -f $f && install -Dm444 $f -t $out/share/doc/${args.pname}
133       done
134     ''
135   ] ++ (lib.optional installManPages ''
136     if [ -d man ]; then
137       installManPage man/*.?
138     fi
139   '') ++ [
140     "remove-references-to -t ${lib.getLib crystal} $out/bin/*"
141     "runHook postInstall"
142   ]));
144   doCheck = args.doCheck or true;
146   checkPhase = args.checkPhase or (lib.concatStringsSep "\n" ([
147     "runHook preCheck"
148   ] ++ lib.optional (format == "make")
149     "make \${checkTarget:-test} $checkFlags"
150   ++ lib.optional (format != "make")
151     "crystal \${checkTarget:-spec} $checkFlags"
152   ++ [ "runHook postCheck" ]));
154   doInstallCheck = args.doInstallCheck or true;
156   installCheckPhase = args.installCheckPhase or ''
157     for f in $out/bin/*; do
158       if [ $f == $out/bin/*.dwarf ]; then
159         continue
160       fi
161       $f --help > /dev/null
162     done
163   '';
165   meta = args.meta or { } // {
166     platforms = args.meta.platforms or crystal.meta.platforms;
167   };