美文网首页
nix 静态编译haskell应用

nix 静态编译haskell应用

作者: Lupino | 来源:发表于2021-01-22 22:04 被阅读0次

nix可以帮我们构建一个静态编译环境,我们选定一个特定的版本,这个版本可以从 postgrest 这个应用里面获取。

我们建立 nix 目录,新建 nix/nix/nixpkgs-version.nix, 内容如下:

{
  date = "2020-12-22";
  rev = "2a058487cb7a50e7650f1657ee0151a19c59ec3b";
  tarballHash = "1h8c0mk6jlxdmjqch6ckj30pax3hqh6kwjlvp2021x3z4pdzrn9p";
}

我们要使用 static-haskell-nix 来帮我们搞定各个软件包静态编译的处理。

我们新建 nix/static-haskell-package.nix, 内容如下:

 # Derive a fully static Haskell package based on musl instead of glibc.
{ nixpkgs, compiler, allOverlays }:

name: src:
let
  # The nh2/static-haskell-nix project does all the hard work for us.
  static-haskell-nix =
    let
      rev = "749707fc90b781c3e653e67917a7d571fe82ae7b";
    in
    builtins.fetchTarball {
      url = "https://github.com/nh2/static-haskell-nix/archive/${rev}.tar.gz";
      sha256 = "155spda2lww378bhx68w6dxwqd5y6s9kin3qbgl2m23r3vmk3m3w";
    };

  extraOverrides =
    final: prev:
    rec {
      # We need to add our package needs to the package set that we pass to
      # static-haskell-nix. Using callCabal2nix on the haskellPackages that
      # it returns would result in a dynamic build based on musl, and not the
      # fully static build that we want.
      "${name}" =
        prev.callCabal2nix name src { };
    };

  overlays =
    [
      (allOverlays.haskell-packages { inherit compiler extraOverrides; })
    ];

  # Apply our overlay to the given pkgs.
  normalPkgs =
    import nixpkgs { inherit overlays; };

  # Each version of GHC needs a specific version of Cabal.
  defaultCabalPackageVersionComingWithGhc =
    {
      ghc884 = "Cabal_3_2_1_0";
    }."${compiler}";

  # The static-haskell-nix 'survey' derives a full static set of Haskell
  # packages, applying fixes where necessary.
  survey =
    import "${static-haskell-nix}/survey" { inherit normalPkgs compiler defaultCabalPackageVersionComingWithGhc; };
in
survey.haskellPackages."${name}"

将要编译的软件包和自定义库添加到 static-haskell-nix/survey 里面,

我们添加 overlays 库,定义我们要用到的软件包

新建目录 nix/overlays
添加文件 nix/overlays/haskell-packages.nix 内容如下:

{ compiler, extraOverrides ? (final: prev: { }) }:

self: super:
let
  lib =
    self.haskell.lib;

  overrides =
    final: prev:
    rec {
      # To pin custom versions of Haskell packages:
      #   protolude =
      #     prev.callHackageDirect
      #       {
      #         pkg = "protolude";
      #         ver = "0.3.0";
      #         sha256 = "0iwh4wsjhb7pms88lw1afhdal9f86nrrkkvv65f9wxbd1b159n72";
      #       }
      #       { };
      #
      # To get the sha256:
      #   nix-prefetch-url --unpack https://hackage.haskell.org/package/protolude-0.3.0/protolude-0.3.0.tar.gz
      ptr =
        lib.dontCheck (lib.unmarkBroken prev.ptr);
    } // extraOverrides final prev;
in
{
  haskell =
    super.haskell // {
      packages = super.haskell.packages // {
        "${compiler}" =
          super.haskell.packages."${compiler}".override { inherit overrides; };
      };
    };
}

添加文件nix/overlays/gitignore.nix内容如下:

self: super:
# Overlay that adds the `gitignoreSource` function from Hercules-CI.
# This function is useful for filtering which files are added to the Nix store.
# See: https://github.com/hercules-ci/gitignore.nix

# To update to a newer revision, the simplest way is to add a new commit hash
# from GitHub under `rev` and to then add the hash that Nix suggests on first
# use.
{
  gitignoreSource =
    let
      gitignoreSrc = super.fetchFromGitHub {
        owner = "hercules-ci";
        repo = "gitignore";
        rev = "c4662e662462e7bf3c2a968483478a665d00e717";
        sha256 = "1npnx0h6bd0d7ql93ka7azhj40zgjp815fw2r6smg8ch9p7mzdlx";
      };
    in
    (super.callPackage gitignoreSrc { }).gitignoreSource;
}

添加文件nix/overlays/default.nix 内容如下:

{
  gitignore = import ./gitignore.nix;
  haskell-packages = import ./haskell-packages.nix;
}

添加 release.nix 内容如下:

let
  # We are using lts-15.13 stack resolver which uses ghc883 (cf https://www.stackage.org/lts-15.13)
  compiler = "ghc884";

  # pin nixpkgs for reproducible build
  nixpkgsVersion = import nix/nixpkgs-version.nix;
  nixpkgs =
    builtins.fetchTarball {
      url = "https://github.com/nixos/nixpkgs/archive/${nixpkgsVersion.rev}.tar.gz";
      sha256 = nixpkgsVersion.tarballHash;
    };


  # overlays define packages we need to build our project
  allOverlays = import nix/overlays;
  overlays = [
    allOverlays.gitignore # helper to use gitignoreSource
    (allOverlays.haskell-packages { inherit compiler; })
  ];

  pkgs = import nixpkgs { inherit overlays; };

  # We define our packages by giving them names and a list of source files
  youpkg = {
    name = "youpkg";
    src = pkgs.lib.sourceFilesBySuffices (pkgs.gitignoreSource ./.)[ ".cabal" ".hs" "LICENSE" ];
  };

  # Some patches are unfortunately necessary to work with libpq
  patches = pkgs.callPackage nix/patches {};

  lib = pkgs.haskell.lib;

  # call our script which add our packages to nh2/static-haskell-nix project
  staticHaskellPackage = import nix/static-haskell-package.nix { inherit nixpkgs compiler patches allOverlays; } ;
in
rec {
  inherit nixpkgs pkgs;

  # if instead we want to generated a fully static executable we need:
  haskell-hole-static = lib.justStaticExecutables (lib.dontCheck staticHaskellPackage youpkg.name youpkg.src);
}

最后我们通过 nix-build release.nix 来编译,最终完成静态编译。

相关文章

网友评论

      本文标题:nix 静态编译haskell应用

      本文链接:https://www.haomeiwen.com/subject/dgpezktx.html