Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distributable Binaries For Macos #185

Merged
merged 8 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ jobs:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v18
with:
# https://discourse.nixos.org/t/understanding-binutils-darwin-wrapper-nix-support-bad-substitution/11475/2
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: run cabal check
run: nix-shell --pure --command "cabal check --verbose=3"
- name: build hevm
run: nix-build
run: nix build .#withTests -L
- name: run rpc tests
run: nix-shell --pure --command "cabal run rpc-tests"
- name: run ethereum tests
Expand Down
28 changes: 25 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,48 @@ on:
- 'release/[0-9]+.[0-9]+.[0-9]+'

jobs:
macosRelease:
name: Build MacOS Binary
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v18
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: build hevm
run: |
nix build .#redistributable --out-link hevmMacos
cp ./hevmMacos/bin/hevm ./hevm-x86_64-macos
- uses: actions/upload-artifact@v3
with:
name: hevm-x86_64-macos
path: ./hevm-x86_64-macos
linuxRelease:
name: Create Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v18
with:
# https://discourse.nixos.org/t/understanding-binutils-darwin-wrapper-nix-support-bad-substitution/11475/2
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: build hevm
run: |
nix build .#hevmUnwrapped --out-link hevmLinux
nix build .#redistributable --out-link hevmLinux
cp ./hevmLinux/bin/hevm ./hevm-x86_64-linux
- name: upload linux binary
- name: download macos binary
uses: actions/download-artifact@v3
with:
name: hevm-x86_64-macos
- name: create github release & upload binaries
uses: softprops/action-gh-release@v0.1.15
with:
files: |
./hevm-x86_64-linux
./hevm-x86_64-macos
- name: prepare hackage artifacts
run: |
nix-shell --command "cabal sdist --builddir=${{ runner.temp }}/packages"
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved equivalence checker that avoids checking similar branches more than once.
- Improved simplification for arithmetic expressions
- Construction of storage counterexamples based on the model returned by the SMT solver.
- Static binaries for macos

## [0.50.2] - 2023-01-06

Expand Down
81 changes: 64 additions & 17 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
secp256k1-static = pkgs.secp256k1.overrideAttrs (attrs: {

secp256k1-static = stripDylib (pkgs.secp256k1.overrideAttrs (attrs: {
configureFlags = attrs.configureFlags ++ [ "--enable-static" ];
});
}));

hevmUnwrapped = (with pkgs; lib.pipe (
haskellPackages.callCabal2nix "hevm" ./. {
# Haskell libs with the same names as C libs...
Expand All @@ -33,49 +35,94 @@
inherit secp256k1;
})
[
(haskell.lib.compose.overrideCabal (old : {
testTarget = "test";
}))
(haskell.lib.compose.overrideCabal (old: { testTarget = "test"; }))
(haskell.lib.compose.addTestToolDepends [ solc z3 cvc5 ])
(haskell.lib.compose.appendBuildFlags ["-v3"])
(haskell.lib.compose.appendConfigureFlags (
[ "--ghc-option=-O2" "-fci" ]
[ "-fci"
"--extra-lib-dirs=${stripDylib (pkgs.gmp.override { withStatic = true; })}/lib"
"--extra-lib-dirs=${stripDylib secp256k1-static}/lib"
"--extra-lib-dirs=${stripDylib (libff.override { enableStatic = true; })}/lib"
"--extra-lib-dirs=${zlib.static}/lib"
"--extra-lib-dirs=${stripDylib (libffi.overrideAttrs (_: { dontDisableStatic = true; }))}/lib"
"--extra-lib-dirs=${stripDylib (ncurses.override { enableStatic = true; })}/lib"
]
++ lib.optionals stdenv.isLinux [
"--enable-executable-static"
"--extra-lib-dirs=${gmp.override { withStatic = true; }}/lib"
"--extra-lib-dirs=${secp256k1-static}/lib"
"--extra-lib-dirs=${libff.override { enableStatic = true; }}/lib"
"--extra-lib-dirs=${ncurses.override { enableStatic = true; }}/lib"
"--extra-lib-dirs=${zlib.static}/lib"
"--extra-lib-dirs=${libffi.overrideAttrs (_: { dontDisableStatic = true; })}/lib"
# TODO: replace this with musl: https://stackoverflow.com/a/57478728
"--extra-lib-dirs=${glibc}/lib"
"--extra-lib-dirs=${glibc.static}/lib"
]))
haskell.lib.compose.doBenchmark
haskell.lib.dontHaddock
]).overrideAttrs(final: prev: {
HEVM_SOLIDITY_REPO = solidity;
HEVM_ETHEREUM_TESTS_REPO = ethereum-tests;
});

# wrapped binary for use on systems with nix available. ensures all
# required runtime deps are available and on path
hevmWrapped = with pkgs; symlinkJoin {
name = "hevm";
paths = [ hevmUnwrapped ];
paths = [ (haskell.lib.dontCheck hevmUnwrapped) ];
buildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram $out/bin/hevm \
--prefix PATH : "${lib.makeBinPath ([ bash coreutils git solc z3 cvc5 ])}"
'';
};

# "static" binary for distribution
# on linux this is actually a real fully static binary
# on macos this has everything except libcxx, libsystem and libiconv
# statically linked. we can be confident that these three will always
# be provided in a well known location by macos itself.
hevmRedistributable = let
grep = "${pkgs.gnugrep}/bin/grep";
otool = "${pkgs.darwin.binutils.bintools}/bin/otool";
install_name_tool = "${pkgs.darwin.binutils.bintools}/bin/install_name_tool";
in if pkgs.stdenv.isLinux
then pkgs.haskell.lib.dontCheck hevmWrapped
else pkgs.runCommand "stripNixRefs" {} ''
mkdir -p $out/bin
cp ${pkgs.haskell.lib.dontCheck hevmUnwrapped}/bin/hevm $out/bin/

# get the list of dynamic libs from otool and tidy the output
libs=$(${otool} -L $out/bin/hevm | tail -n +2 | sed 's/^[[:space:]]*//' | cut -d' ' -f1)
d-xo marked this conversation as resolved.
Show resolved Hide resolved

# get the paths for libcxx and libiconv
cxx=$(echo "$libs" | ${grep} '^/nix/store/.*-libcxx')
iconv=$(echo "$libs" | ${grep} '^/nix/store/.*-libiconv')

# rewrite /nix/... library paths to point to /usr/lib
chmod 777 $out/bin/hevm
${install_name_tool} -change "$cxx" /usr/lib/libc++.1.dylib $out/bin/hevm
${install_name_tool} -change "$iconv" /usr/lib/libiconv.dylib $out/bin/hevm
chmod 555 $out/bin/hevm
'';

# if we pass a library folder to ghc via --extra-lib-dirs that contains
# only .a files, then ghc will link that library statically instead of
# dynamically (even if --enable-executable-static is not passed to cabal).
# we use this trick to force static linking of some libraries on macos.
stripDylib = drv : pkgs.runCommand "${drv.name}-strip-dylibs" {} ''
mkdir -p $out
mkdir -p $out/lib
cp -r ${drv}/* $out/
rm -rf $out/**/*.dylib
'';

in rec {

# --- packages ----

packages.withTests = hevmUnwrapped;
packages.hevm = hevmWrapped;
packages.hevmUnwrapped = hevmUnwrapped;
packages.default = hevmWrapped;
packages.redistributable = hevmRedistributable;
packages.default = packages.hevm;

# --- apps ----

apps.hevm = flake-utils.lib.mkApp { drv = hevmWrapped; };
apps.hevm = flake-utils.lib.mkApp { drv = packages.hevm; };
apps.default = apps.hevm;

# --- shell ---
Expand Down
35 changes: 33 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,39 @@ User facing documentation can be found in the [hevm book](https://hevm.dev/).

## Installation

Static binaries for x86 linux are available for each [release](https://github.com/ethereum/hevm/releases).
### Static Binaries

Alternatively `hevm` can be installed using nix flakes via the following command:
Static binaries for x86 linux and macos are available for each
[release](https://github.com/ethereum/hevm/releases). These binaries expect to be able to find the
following programs on `PATH`:

- `git`
- `solc`
- `z3`
- `cvc5`

### nixpkgs

hevm is available in
[`nixpkgs`](https://search.nixos.org/packages?channel=unstable&show=haskellPackages.hevm&from=0&size=50&sort=relevance&type=packages&query=hevm) (unstable only for now), and can be installed via:

- flakes: `nix profile install nixpkgs#haskellPackages.hevm`
- legacy: `nix-env -iA haskellPackages.hevm`

### nix flakes

hevm can be installed directly from the `main` branch of this repo via the following command:

```
nix profile install github:ethereum/hevm
```

to install a specific commit you can run:

```
nix profile install github:ethereum/hevm/<COMMIT_ID>
```

## Development

We use `nix` to manage project dependencies. To start hacking on hevm you should first [install
Expand All @@ -40,19 +65,25 @@ Once in the shell you can use the usual `cabal` commands to build and test hevm:
$ cabal build # build the hevm library
$ cabal build exe:hevm # build the cli binary
$ cabal build test # build the test binary
$ cabal build bench # build the benchmarks

$ cabal repl # enter a repl for the library
$ cabal repl exe:hevm # enter a repl for the cli
$ cabal repl test # enter a repl for the tests
$ cabal repl bench # enter a repl for the benchmarks

$ cabal run hevm # run the cli binary
$ cabal run test # run the test binary
$ cabal run bench # run the benchmarks

# run the cli binary with profiling enabled
$ cabal run --enable-profiling hevm -- <CLI SUBCOMMAND> +RTS -s -p -RTS

# run the test binary with profiling enabled
$ cabal run --enable-profiling test -- +RTS -s -p -RTS

# run the benchmarks with profiling enabled
$ cabal run --enable-profiling bench -- +RTS -s -p -RTS
```

A high level overview of the architecture can be found in [architecture.md](./architecture.md).