From eeb721eed1d0e65d73074d6b27516d3b93307c5e Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Thu, 7 Nov 2019 15:31:23 +0100 Subject: [PATCH] Add nix recipe to build Nimbus wrappers --- default.nix | 14 ++++--- nix/mkFilter.nix | 38 +++++++++++++++++ nix/nim.nix | 13 ++++-- nix/nimbus-wrappers.nix | 90 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 nix/mkFilter.nix create mode 100644 nix/nimbus-wrappers.nix diff --git a/default.nix b/default.nix index c805c44ac..a76c518e4 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ let nixpkgsFn = import (fetchTarball { - url = https://github.com/NixOS/nixpkgs/archive/642499faefb17c3d36e074cf35b189f75ba43ee2.tar.gz; - sha256 = "16j7gl3gg839fy54z5v4aap8lgf1ffih5swmfk62zskk30nwzfbi"; + url = https://github.com/NixOS/nixpkgs/archive/85f3d86bea70fe0d76a7e3520966c58604f8e5e9.tar.gz; + sha256 = "1iacnd7ym6c5s9vizyiff0lmxjrlgh5gpya88mlavgvdppkcaiyn"; }); # nixcrpkgs = import (fetchTarball { @@ -50,11 +50,13 @@ let nimbus = pkgs: pkgs.callPackage ./nix/nimbus.nix {}; - mapAttrs = nixpkgs.lib.attrsets.mapAttrs; + inherit (nixpkgs.lib.attrsets) mapAttrs; crossPackages = mapAttrs (target: conf: nixpkgsFn { crossSystem = conf; }) targets; crossBuilds = mapAttrs (target: packages: nimbus packages) crossPackages; in - -(nimbus nixpkgs) // crossBuilds - + (nimbus nixpkgs) // + crossBuilds // + { + wrappers = nixpkgs.callPackage ./nix/nimbus-wrappers.nix {}; + } diff --git a/nix/mkFilter.nix b/nix/mkFilter.nix new file mode 100644 index 000000000..b0e6225da --- /dev/null +++ b/nix/mkFilter.nix @@ -0,0 +1,38 @@ +{ lib }: + +# This Nix expression allows filtering a local directory by specifying dirRootsToInclude, dirsToExclude and filesToInclude. +# It also filters out symlinks to result folders created by nix-build, as well as backup/swap/generated files + +let + inherit (lib) + any compare compareLists elem elemAt hasPrefix length min splitString take; + + isPathAllowed = allowedPath: path: + let + count = min (length allowedPathElements) (length pathElements); + pathElements = splitString "/" path; + allowedPathElements = splitString "/" allowedPath; + pathElementsSubset = take count pathElements; + allowedPathElementsSubset = take count allowedPathElements; + in (compareLists compare allowedPathElementsSubset pathElementsSubset) == 0; + + mkFilter = { dirRootsToInclude, # Relative paths of directories to include + dirsToExclude ? [ ], # Base names of directories to exclude + filesToInclude ? [ ], # Relative path of files to include + filesToExclude ? [ ], # Relative path of files to exclude + root }: + path: type: + let + baseName = baseNameOf (toString path); + subpath = elemAt (splitString "${toString root}/" path) 1; + spdir = elemAt (splitString "/" subpath) 0; + + in lib.cleanSourceFilter path type && ( + (type != "directory" && (elem spdir filesToInclude) && !(elem spdir filesToExclude)) || + # check if any part of the directory path is described in dirRootsToInclude + ((any (dirRootToInclude: isPathAllowed dirRootToInclude subpath) dirRootsToInclude) && ! ( + # Filter out version control software files/directories + (type == "directory" && (elem baseName dirsToExclude)) + ))); + +in mkFilter diff --git a/nix/nim.nix b/nix/nim.nix index cae1909ee..c0a30daf3 100644 --- a/nix/nim.nix +++ b/nix/nim.nix @@ -1,4 +1,7 @@ -{ stdenv, lib, makeWrapper, git, clang, nodejs, openssl, pcre, readline, sqlite }: +# based on https://github.com/nim-lang/Nim/blob/v0.18.0/.travis.yml + +{ stdenv, lib, makeWrapper, git, clang, nodejs, openssl, pcre, readline, + boehmgc, sfml, sqlite }: let csources = fetchTarball { @@ -45,9 +48,13 @@ in stdenv.mkDerivation rec { # used for bootstrapping, but koch insists on moving the nim compiler around # as part of building it, so it cannot be read-only + nativeBuildInputs = [ + makeWrapper + ]; + buildInputs = [ - makeWrapper nodejs - clang openssl pcre readline sqlite git + nodejs git + clang openssl pcre readline boehmgc sfml sqlite ]; buildPhase = '' diff --git a/nix/nimbus-wrappers.nix b/nix/nimbus-wrappers.nix new file mode 100644 index 000000000..5020c82ab --- /dev/null +++ b/nix/nimbus-wrappers.nix @@ -0,0 +1,90 @@ +{ stdenv, callPackage, fetchFromGitHub, clang, go, nim, sqlite, pcre, rocksdb }: + +{ buildSamples ? true }: + +let + inherit (stdenv.lib) concatMapStringsSep makeLibraryPath optional optionalString; + + mkFilter = callPackage ./mkFilter.nix { inherit (stdenv) lib; }; + vendorDeps = [ + "nim-chronicles" "nim-faststreams" "nim-json-serialization" "nim-chronos" "nim-eth" "nim-json" + "nim-metrics" "nim-secp256k1" "nim-serialization" "nim-stew" "nim-stint" "nimcrypto" + ]; + +in + +stdenv.mkDerivation rec { + name = "nimbus-${version}"; + version = "0.0.1"; + + src = + let path = ./..; # Import the root /android and /mobile/js_files folders clean of any build artifacts + in builtins.path { # We use builtins.path so that we can name the resulting derivation, otherwise the name would be taken from the checkout directory, which is outside of our control + inherit path; + name = "nimbus-sources"; + filter = + # Keep this filter as restrictive as possible in order to avoid unnecessary rebuilds and limit closure size + mkFilter { + dirRootsToInclude = [ + "vendor" "wrappers" + ]; + dirsToExclude = [ ".git" ".svn" "CVS" ".hg" "nimbus-build-system" "tests" ] + ++ (builtins.map (dep: "vendor/${dep}") vendorDeps); + filesToInclude = [ ]; + filesToExclude = [ "VERSION" "android/gradlew" ]; + root = path; + }; + }; + nativeBuildInputs = optional buildSamples go; + buildInputs = [ clang nim rocksdb pcre sqlite ]; + LD_LIBRARY_PATH = "${makeLibraryPath buildInputs}"; + + buildPhase = '' + mkdir -p $TMPDIR/.nimcache ./build + + BUILD_MSG="\\e[92mBuilding:\\e[39m" + export CC="${clang}/bin/clang" + + ln -s nimbus.nimble nimbus.nims + + vendorPathOpts="${concatMapStringsSep " " (dep: "--path:./vendor/${dep}") vendorDeps}" + echo -e $BUILD_MSG "build/libnimbus.so" && \ + ${nim}/bin/nim c --app:lib --noMain --nimcache:$TMPDIR/.nimcache -d:release ''${vendorPathOpts} -o:./build/libnimbus.so wrappers/libnimbus.nim + # For some reason nim doesn't output anything if we pass -o option when building the static lib + # so we just move it from the default location after it's built + echo -e $BUILD_MSG "build/libnimbus.a" && \ + ${nim}/bin/nim c --app:staticlib --noMain --nimcache:$TMPDIR/.nimcache -d:release ''${vendorPathOpts} wrappers/libnimbus.nim && \ + mv libnimbus build/libnimbus.a + + rm -rf $TMPDIR/.nimcache + '' + + optionalString buildSamples '' + mkdir -p $TMPDIR/.home/.cache + export HOME=$TMPDIR/.home + + echo -e $BUILD_MSG "build/C_wrapper_example" && \ + $CC wrappers/wrapper_example.c -Wl,-rpath,'$$ORIGIN' -Lbuild -lnimbus -lm -g -o build/C_wrapper_example + echo -e $BUILD_MSG "build/go_wrapper_example" && \ + ${go}/bin/go build -linkshared -o build/go_wrapper_example wrappers/wrapper_example.go wrappers/cfuncs.go + echo -e $BUILD_MSG "build/go_wrapper_whisper_example" && \ + ${go}/bin/go build -linkshared -o build/go_wrapper_whisper_example wrappers/wrapper_whisper_example.go wrappers/cfuncs.go + + rm -rf $TMPDIR/.home/.cache + ''; + installPhase = '' + mkdir -p $out/{include,lib} + cp ./wrappers/libnimbus.h $out/include/ + cp ./build/libnimbus.{a,so} $out/lib/ + '' + + optionalString buildSamples '' + mkdir -p $out/samples + cp ./build/{C_wrapper_example,go_wrapper_example,go_wrapper_whisper_example} $out/samples + ''; + + meta = with stdenv.lib; { + description = "A C wrapper of the Nimbus Ethereum 2.0 Sharding Client for Resource-Restricted Devices"; + homepage = https://github.com/status-im/nimbus; + license = with licenses; [ asl20 ]; + platforms = with platforms; unix ++ windows; + }; +}