Building NERVA From Source

Building the Nerva software yourself is the most thorough answer to "what am I running": you compile the daemon and wallet from the published source, on the machine and toolchain of your choosing. It is also how you get to run development code, test a change, or produce binaries for a platform the releases do not cover. This guide walks through the whole procedure on the three desktop platforms.

The build system is CMake behind a make wrapper that takes care of the common cases. Older build scripts still live under builder/ in the repository, but they are deprecated in favor of plain make and will be removed in a future release; nothing on this page uses them.

Dependencies

The table below summarizes the tools and libraries required to build. A few of the libraries are also vendored in the repository: by default the build uses whatever is installed on the system, and only falls back to the vendored copy if it cannot find one. Static builds always use the vendored sources, because distribution packages tend to ship shared objects without the static archives.

Dep Min. version Debian/Ubuntu pkg Optional Purpose
GCC 7 build-essential NO compiler
CMake 3.5 cmake NO build system
pkg-config any pkg-config NO
Boost 1.66 libboost-all-dev NO C++ libraries
OpenSSL any libssl-dev NO hashing, TLS
libzmq 4.2.0 libzmq3-dev NO ZeroMQ
OpenPGM ? libpgm-dev NO for ZeroMQ
libunbound 1.4.16 libunbound-dev NO DNS resolver
libsodium ? libsodium-dev NO cryptography
libunwind any libunwind8-dev YES stack traces
liblzma any liblzma-dev YES for libunwind
libreadline 6.3.0 libreadline6-dev YES input editing
expat 1.1 libexpat1-dev YES XML parsing
GTest 1.5 libgtest-dev YES test suite
ccache any ccache YES compilation cache
Doxygen, Graphviz any doxygen, graphviz YES documentation
lrelease ? qttools5-dev-tools YES translations
libhidapi, libusb, libprotobuf, protoc, libudev ? see your package manager YES hardware wallet support

On other distributions the package names are close cousins of the Debian ones: boost and cmake on Arch, boost-devel and cmake on Fedora and Void, and so on. If your distribution does not package one of the optional libraries, the build simply skips the corresponding feature rather than failing.

Installing the dependencies

On Ubuntu and Debian, one command installs everything required:

sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libpgm-dev libunbound-dev libsodium-dev git

On Windows, install MSYS2 and work from its shell. Update it with pacman -Syu, then install the toolchain for your target, 64-bit in this example:

pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-icu mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-unbound git

For 32-bit targets the same line with i686 in place of x86_64 does the job.

On macOS, install Xcode and its command line tools first:

xcode-select --install

Then install Homebrew if you do not have it, and use the Brewfile from the repository to pull the dependencies:

brew update && brew bundle --file=contrib/brew/Brewfile

Getting the source and building

Clone the repository with its submodules, since some vendored dependencies live in them:

git clone --recursive https://github.com/nerva-project/nerva.git
cd nerva

An existing clone is brought up to date the same way: git submodule init && git submodule update.

The simple build, on Linux and macOS:

make

On Windows only static builds are possible, so use one of:

make release-static-win64
make release-static-win32

The resulting executables land in build/release/bin: the nervad daemon, the nerva-wallet-cli and nerva-wallet-rpc wallets, and the assorted utilities. Add -jN to any make invocation to build with N parallel jobs, which on a modern machine is the difference between an afternoon and a coffee break.

A static build that does not depend on the libraries of the machine it was built on:

make release-static

And if the CPU is old enough to lack AES instructions, which shows up as the daemon crashing on startup with an illegal instruction:

make release-noaes

Portable and cross-compiled builds

Dynamically and even statically linked binaries still target the processor they were built on. To produce binaries that run across a whole processor family, use the portable targets:

make release-static-linux-x86_64    # any POSIX x86_64
make release-static-linux-armv8     # any POSIX arm64
make release-static-mac-x86_64      # any macOS x86_64
make release-static-mac-armv8       # any macOS Apple Silicon
make release-static-win64           # any 64-bit Windows

with linux-i686, linux-armv7, linux-armv6 and win32 completing the set.

Cross compiling goes through the depends system and builds static binaries for another platform on the one you are sitting at:

make depends target=x86_64-w64-mingw32    # Windows binaries from Linux
make depends target=x86_64-apple-darwin   # macOS binaries from Linux
make depends target=aarch64-linux-gnu     # arm64 binaries from x86_64 Linux

The full list of targets and their extra apt requirements is in the docs/BUILDING.md file of the repository; the depends system has been exercised on Ubuntu 18.04 and 20.04, and works on their successors. Using depends from Windows Subsystem for Linux is often easier than MSYS2 if you are only after Windows binaries.

One caveat travels with static Linux builds: the produced binaries still link libc dynamically, so a binary built on a current distribution may refuse to run on an older one. Passing -DBACKCOMPAT=ON to CMake extends compatibility down to libc 2.17, which covers anything you are likely to encounter in the wild.

Verifying what you built

The release process publishes hashes and signatures for official binaries, and the same discipline applies to your own. After building, record the hashes of the binaries you intend to deploy:

sha256sum build/release/bin/*

Genuinely paranoid builds start from a tagged release, verify the tag against the repository's history, and build in a clean environment; the multi-stage Dockerfile at the repository root is a reasonable starting point for that, since it compiles through the depends system in a defined container. For everyday use, building from master on a patched machine is fine, and the version string the daemon prints at startup will tell you exactly which commit you are running.