diff --git a/doc/languages-frameworks/crystal.section.md b/doc/languages-frameworks/crystal.section.md new file mode 100644 index 00000000000..07bfc65a553 --- /dev/null +++ b/doc/languages-frameworks/crystal.section.md @@ -0,0 +1,71 @@ +# Crystal + +## Building a Crystal package + +This section uses [Mint](https://github.com/mint-lang/mint) as an example for how to build a Crystal package. + +If the Crystal project has any dependencies, the first step is to get a `shards.nix` file encoding those. Get a copy of the project and go to its root directory such that its `shard.lock` file is in the current directory, then run `crystal2nix` in it +```bash +$ git clone https://github.com/mint-lang/mint +$ cd mint +$ git checkout 0.5.0 +$ nix-shell -p crystal2nix --run crystal2nix +``` + +This should have generated a `shards.nix` file. + +Next create a Nix file for your derivation and use `pkgs.crystal.buildCrystalPackage` as follows: +```nix +with import {}; +crystal.buildCrystalPackage rec { + pname = "mint"; + version = "0.5.0"; + + src = fetchFromGitHub { + owner = "mint-lang"; + repo = "mint"; + rev = version; + sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; + }; + + # Insert the path to your shards.nix file here + shardsFile = ./shards.nix; + + ... +} +``` + +This won't build anything yet, because we haven't told it what files build. We can specify a mapping from binary names to source files with the `crystalBinaries` attribute. The project's compilation instructions should show this. For Mint, the binary is called "mint", which is compiled from the source file `src/mint.cr`, so we'll specify this as follows: + +```nix + crystalBinaries.mint.src = "src/mint.cr"; + + # ... +``` + +Additionally you can override the default `crystal build` options (which are currently `--release --progress --no-debug --verbose`) with + +```nix + crystalBinaries.mint.options = [ "--release" "--verbose" ]; +``` + +Depending on the project, you might need additional steps to get it to compile successfully. In Mint's case, we need to link against openssl, so in the end the Nix file looks as follows: + +```nix +with import {}; +crystal.buildCrystalPackage rec { + version = "0.5.0"; + pname = "mint"; + src = fetchFromGitHub { + owner = "mint-lang"; + repo = "mint"; + rev = version; + sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; + }; + + shardsFile = ./shards.nix; + crystalBinaries.mint.src = "src/mint.cr"; + + buildInputs = [ openssl_1_0_2 ]; +} +``` diff --git a/doc/languages-frameworks/index.xml b/doc/languages-frameworks/index.xml index 4564df98fe9..cd4e95cfae6 100644 --- a/doc/languages-frameworks/index.xml +++ b/doc/languages-frameworks/index.xml @@ -32,4 +32,5 @@ + diff --git a/pkgs/development/compilers/crystal/build-package.nix b/pkgs/development/compilers/crystal/build-package.nix new file mode 100644 index 00000000000..8ffa89a11b4 --- /dev/null +++ b/pkgs/development/compilers/crystal/build-package.nix @@ -0,0 +1,53 @@ +{ stdenv, lib, crystal, linkFarm, fetchFromGitHub }: +{ # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root + shardsFile ? null + # Specify binaries to build in the form { foo.src = "src/foo.cr"; } + # The default `crystal build` options can be overridden with { foo.options = [ "--no-debug" ]; } +, crystalBinaries ? {} +, ... +}@args: +let + mkDerivationArgs = builtins.removeAttrs args [ "shardsFile" "crystalBinaries" ]; + + crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList (name: value: { + inherit name; + path = fetchFromGitHub value; + }) (import shardsFile)); + + defaultOptions = [ "--release" "--progress" "--no-debug" "--verbose" ]; + +in stdenv.mkDerivation (mkDerivationArgs // { + + configurePhase = args.configurePhase or '' + runHook preConfigure + ${lib.optionalString (shardsFile != null) "ln -s ${crystalLib} lib"} + runHook postConfigure + ''; + + buildInputs = args.buildInputs or [] ++ [ crystal ]; + + buildPhase = args.buildPhase or '' + runHook preBuild + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (bin: attrs: '' + crystal ${lib.escapeShellArgs ([ + "build" + "-o" bin + (attrs.src or (throw "No source file for crystal binary ${bin} provided")) + ] ++ attrs.options or defaultOptions)} + '') crystalBinaries)} + runHook postBuild + ''; + + installPhase = args.installPhase or '' + runHook preInstall + mkdir -p "$out/bin" + ${lib.concatMapStringsSep "\n" (bin: '' + mv ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]} + '') (lib.attrNames crystalBinaries)} + runHook postInstall + ''; + + meta = args.meta or {} // { + platforms = args.meta.platforms or crystal.meta.platforms; + }; +}) diff --git a/pkgs/development/compilers/mint/crystal2nix.cr b/pkgs/development/compilers/crystal/crystal2nix.cr similarity index 94% rename from pkgs/development/compilers/mint/crystal2nix.cr rename to pkgs/development/compilers/crystal/crystal2nix.cr index f608102a37b..0610de5cfa4 100644 --- a/pkgs/development/compilers/mint/crystal2nix.cr +++ b/pkgs/development/compilers/crystal/crystal2nix.cr @@ -26,7 +26,7 @@ File.open "shards.nix", "w+" do |file| sha256 = "" args = ["--url", url, "--rev", rev] - Process.run("nix-prefetch-git", args: args) do |x| + Process.run("@nixPrefetchGit@", args: args) do |x| x.error.each_line { |e| puts e } sha256 = PrefetchJSON.from_json(x.output).sha256 end diff --git a/pkgs/development/compilers/crystal/crystal2nix.nix b/pkgs/development/compilers/crystal/crystal2nix.nix new file mode 100644 index 00000000000..ac69b9b3d96 --- /dev/null +++ b/pkgs/development/compilers/crystal/crystal2nix.nix @@ -0,0 +1,16 @@ +{ lib, crystal, nix-prefetch-git }: +crystal.buildCrystalPackage { + pname = "crystal2nix"; + version = "unstable-2018-07-31"; + + nixPrefetchGit = "${lib.getBin nix-prefetch-git}/bin/nix-prefetch-git"; + unpackPhase = "substituteAll ${./crystal2nix.cr} crystal2nix.cr"; + + crystalBinaries.crystal2nix.src = "crystal2nix.cr"; + + meta = with lib; { + description = "Utility to convert Crystal's shard.lock files to a Nix file"; + license = licenses.mit; + maintainers = [ maintainers.manveru ]; + }; +} diff --git a/pkgs/development/compilers/crystal/default.nix b/pkgs/development/compilers/crystal/default.nix index db57bc3e9df..2bc3d396da6 100644 --- a/pkgs/development/compilers/crystal/default.nix +++ b/pkgs/development/compilers/crystal/default.nix @@ -1,6 +1,7 @@ { stdenv, lib, fetchFromGitHub, fetchurl, makeWrapper -, coreutils, git, gmp, nettools, openssl, readline, tzdata, libxml2, libyaml -, boehmgc, libatomic_ops, pcre, libevent, libiconv, llvm, clang, which, zlib }: +, coreutils, git, gmp, nettools, openssl_1_0_2, readline, tzdata, libxml2, libyaml +, boehmgc, libatomic_ops, pcre, libevent, libiconv, llvm, clang, which, zlib +, callPackage }: # We need multiple binaries as a given binary isn't always able to build # (even slightly) older or newer versions. @@ -19,7 +20,7 @@ let arch = archs."${stdenv.system}" or (throw "system ${stdenv.system} not supported"); - checkInputs = [ git gmp openssl readline libxml2 libyaml ]; + checkInputs = [ git gmp openssl_1_0_2 readline libxml2 libyaml ]; genericBinary = { version, sha256s, rel ? 1 }: stdenv.mkDerivation rec { @@ -37,7 +38,7 @@ let }; generic = { version, sha256, binary, doCheck ? true }: - stdenv.mkDerivation rec { + let compiler = stdenv.mkDerivation rec { pname = "crystal"; inherit doCheck version; @@ -72,7 +73,7 @@ let buildInputs = [ boehmgc libatomic_ops pcre libevent libyaml - llvm zlib openssl + llvm zlib openssl_1_0_2 ] ++ stdenv.lib.optionals stdenv.isDarwin [ libiconv ]; @@ -134,6 +135,10 @@ let export PATH=${lib.makeBinPath checkInputs}:$PATH ''; + passthru.buildCrystalPackage = callPackage ./build-package.nix { + crystal = compiler; + }; + meta = with lib; { description = "A compiled language with Ruby like syntax and type inference"; homepage = https://crystal-lang.org/; @@ -141,7 +146,7 @@ let maintainers = with maintainers; [ manveru david50407 peterhoeg ]; platforms = builtins.attrNames archs; }; - }; + }; in compiler; in rec { binaryCrystal_0_26 = genericBinary { @@ -207,4 +212,6 @@ in rec { }; crystal = crystal_0_30; + + crystal2nix = callPackage ./crystal2nix.nix {}; } diff --git a/pkgs/development/compilers/mint/default.nix b/pkgs/development/compilers/mint/default.nix index 1c8e9fb7eb2..5f72bd3649b 100644 --- a/pkgs/development/compilers/mint/default.nix +++ b/pkgs/development/compilers/mint/default.nix @@ -1,40 +1,7 @@ -# Updating the dependencies for this package: -# -# wget https://raw.githubusercontent.com/mint-lang/mint/0.3.1/shard.lock -# nix-shell -p crystal libyaml --run 'crystal run crystal2nix.cr' -# -{stdenv, lib, fetchFromGitHub, crystal, zlib, openssl, duktape, which, libyaml }: -let - crystalPackages = lib.mapAttrs (name: src: - stdenv.mkDerivation { - name = lib.replaceStrings ["/"] ["-"] name; - src = fetchFromGitHub src; - phases = "installPhase"; - installPhase = ''cp -r $src $out''; - passthru = { libName = name; }; - } - ) (import ./shards.nix); - - crystalLib = stdenv.mkDerivation { - name = "crystal-lib"; - src = lib.attrValues crystalPackages; - libNames = lib.mapAttrsToList (k: v: [k v]) crystalPackages; - phases = "buildPhase"; - buildPhase = '' - mkdir -p $out - linkup () { - while [ "$#" -gt 0 ]; do - ln -s $2 $out/$1 - shift; shift - done - } - linkup $libNames - ''; - }; -in -stdenv.mkDerivation rec { +{ lib, fetchFromGitHub, crystal, zlib, openssl_1_0_2, duktape, which, libyaml }: +crystal.buildCrystalPackage rec { version = "0.5.0"; - name = "mint-${version}"; + pname = "mint"; src = fetchFromGitHub { owner = "mint-lang"; repo = "mint"; @@ -42,23 +9,19 @@ stdenv.mkDerivation rec { sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; }; - nativeBuildInputs = [ which crystal zlib openssl duktape libyaml ]; + buildInputs = [ openssl_1_0_2 ]; - buildPhase = '' - mkdir -p $out/bin tmp - cd tmp - ln -s ${crystalLib} lib - cp -r $src/* . - crystal build src/mint.cr -o $out/bin/mint --verbose --progress --release --no-debug - ''; - - installPhase = ''true''; + # Update with + # nix-shell -p crystal2nix --run crystal2nix + # with mint's shard.lock file in the current directory + shardsFile = ./shards.nix; + crystalBinaries.mint.src = "src/mint.cr"; meta = { description = "A refreshing language for the front-end web"; homepage = https://mint-lang.com/; - license = stdenv.lib.licenses.bsd3; - maintainers = with stdenv.lib.maintainers; [ manveru ]; + license = lib.licenses.bsd3; + maintainers = with lib.maintainers; [ manveru ]; platforms = [ "x86_64-linux" "i686-linux" "x86_64-darwin" ]; }; } diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 22200239c9b..6c3af89bc8d 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -7451,7 +7451,8 @@ in crystal_0_27 crystal_0_29 crystal_0_30 - crystal; + crystal + crystal2nix; icr = callPackage ../development/tools/icr {};