17 # Some projects do not include a lock file, so you can pass one
19 # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root
21 # We support different builders. To make things more straight forward, make it
22 # user selectable instead of trying to autodetect
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
35 assert (builtins.elem format [ "make" "crystal" "shards" ]);
37 mkDerivationArgs = builtins.removeAttrs args [
45 crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList
49 if (builtins.hasAttr "url" value)
51 else fetchFromGitHub value;
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 " " ([
64 ] ++ lib.optionals enableParallelBuilding [
70 (attrs.src or (throw "No source file for crystal binary ${bin} provided"))
71 (lib.concatStringsSep " " (attrs.options or defaultOptions))
75 stdenv.mkDerivation (mkDerivationArgs // {
77 configurePhase = args.configurePhase or (lib.concatStringsSep "\n" (
79 "runHook preConfigure"
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"
88 ++ [ "runHook postConfigure" ]
91 CRFLAGS = lib.concatStringsSep " " defaultOptions;
93 PREFIX = placeholder "out";
95 inherit enableParallelBuilding;
97 buildInputs = args.buildInputs or [ ] ++ [ crystal ]
98 ++ lib.optional (lib.versionAtLeast crystal.version "1.8") pcre2;
100 nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
107 ] ++ lib.optional (format != "crystal") shards;
109 buildPhase = args.buildPhase or (lib.concatStringsSep "\n" ([
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" ([
120 ] ++ lib.optional (format == "make")
121 "make \${installTargets:-install} $installFlags"
122 ++ lib.optionals (format == "crystal") (map
124 install -Dm555 ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]}
126 (lib.attrNames crystalBinaries))
127 ++ lib.optional (format == "shards")
128 "install -Dm555 bin/* -t $out/bin"
131 for f in README* *.md LICENSE; do
132 test -f $f && install -Dm444 $f -t $out/share/doc/${args.pname}
135 ] ++ (lib.optional installManPages ''
137 installManPage man/*.?
140 "remove-references-to -t ${lib.getLib crystal} $out/bin/*"
141 "runHook postInstall"
144 doCheck = args.doCheck or true;
146 checkPhase = args.checkPhase or (lib.concatStringsSep "\n" ([
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
161 $f --help > /dev/null
165 meta = args.meta or { } // {
166 platforms = args.meta.platforms or crystal.meta.platforms;