Awesome
Ledger Core Library
Core library which will be used by Ledger applications.
This project is considered "legacy", and no new coin support will arrive in the repo; only updates related to currently supported protocols.
- Clone project
- Dependencies
- Build of C++ library
- Documentation
- Binding to node.js
- Support
- Developement guidelines
- Q/A and troubleshooting
Clone project
git clone --recurse-submodules https://github.com/LedgerHQ/lib-ledger-core.git
If you had already forked / cloned the repository before issuing that command, it’s okay. You can initiate the submodules with the following commands:
cd lib-ledger-core
git submodule init
git submodule update
Dependencies
You can skip this dependencies step if you have nix installed.
Build
This project is based on cmake as a build system so you should install it before starting (at least version 3.7).
External dependencies:
- OpenSSL is needed to build tests of the library.
- Generation of binding is automated with Djinni.
- Build on multiple Operating Systems is based on polly toolchains.
Build of C++ library
Nix build
If you have remote builders you can use them with the nix derivation bundled in the repo
Architecture
Utilities/Libraries
pkgs.nix
holds the packages to use in all the other functionspinned.nix
controls the pins of nixpkgs and gitignoreSrc to clean the treeconfig.nix
controls the overrides for packages, most notablysbt
secp256k1.nix
is a function to build the fork of SECP256K1 used in libcore
Shells
libcore-jar.nix
is a shell used to build the JAR locally, or in github actions
Local development
default.nix
holds the function to build libcore derivation, and allows to enter a shell for development or running tests
Using nix-shell
The repository provides a default.nix that allows to get into an environment
ready for build. A hook sets the CMAKE_LIBCORE_FLAGS
environment variable in the shell that
has all the CMake flags you need to build libcore
# To be able to run tests
nix-shell --arg runTests true --arg jni false
# To be able to build a JAR from your local build
nix-shell
mkdir _build
cd _build
cmake .. $CMAKE_LIBCORE_FLAGS
make
ctest
Using nix-build
If you just need the artifact you can build the derivation directly
nix-build
Otherwise to run tests locally against your changes
nix-build --arg runTests true --arg jni false
Building a JAR locally
You can always build the JAR using this command
nix-shell --run "bash nix/scripts/build_jar.sh" nix/libcore-jar.nix --arg useLibcoreDerivation true
Non nix builds
cmake is building out of source, you should create a build directory (e.g. lib-ledger-core-build
):
. # Directory where clone command was launched
├── lib-ledger-core # Source files directory
├── lib-ledger-core-build # Build directory
If you respect this folder structure (and naming), after cd lib-ledger-core-build
, you can build the library by running:
cmake -DSYS_OPENSSL=ON -DOPENSSL_ROOT_DIR=<path-to-openssl-root-dir> -DOPENSSL_INCLUDE_DIR=<path-to-openssl-include-files> -DOPENSSL_SSL_LIBRARIES=<path-to-openssl-libraries> -DOPENSSL_USE_STATIC_LIBS=TRUE ../lib-ledger-core && make
NB. if you want to build on Windows
with Visual Studio by adding the argument -G "Visual Studio 16 2019"
in the above cmake command, instead of using make
to build the project, you should open the 'ledger-core.sln' solution file with Visual Studio and build the solution with it
If you struggle with how openssl is installed, for example, on
macOSX
,openssl
can be installed with
brew install openssl
you can then use the argument -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl
in the above cmake command
"DOPENSSL_INCLUDE_DIR" and "DOPENSSL_SSL_LIBRARIES" are not necessary on mac.
On
Linux
,
apt-get install libssl-dev
you can then use the argument -DOPENSSL_SSL_LIBRARIES=/usr/lib/x86_64-linux-gnu -DOPENSSL_INCLUDE_DIR=/usr/include/openssl
in the above cmake command
"DOPENSSL_ROOT_DIR" is not necessary on linux.
On
Windows
, Openssl can be downloaded and installed from https://slproweb.com/products/Win32OpenSSL.html "DOPENSSL_ROOT_DIR" is then the installed path of Openssl in the above cmake command "DOPENSSL_INCLUDE_DIR" and "DOPENSSL_SSL_LIBRARIES" are not necessary on windows.
Several CMake arguments might interest you there:
-DCMAKE_BUILD_TYPE=Debug
: you should always set that when testing as you will get DWARF debug symbols and debugging instruments support.-DCMAKE_EXPORT_COMPILE_COMMANDS=YES
: useful when you’re using a C++ linter, such as cquery.-G "Visual Studio 16 2019"
: build libcore with Visual Studio on Windows-G Xcode
: build libcore with Xcode on Mac-DBUILD_TESTS=OFF
: build libcore without unit tests. In this case, openssl arguments are not needed
Building for JNI
Building with JNI (Java Native Interface), allows you to use the library with Java based software. In order to enable JNI mode use
cmake -DTARGET_JNI=ON
This will add JNI files to the library compilation and remove tests. You need at least a JDK 7 to build for JNI (OpenJDK or Oracle JDK)
Build library with PostgreSQL
Dependencies
Make sure that your have PostgreSQL
installed on your machine, otherwise the CMake
command find_package(PostgreSQL REQUIRED)
will fail during configuration.
All Nix builds currently build with Postgres support by default.
Build
You need to add -DPostgreSQL_INCLUDE_DIR=path/to/include/dir
in your configuration
as a hint for headers' location (e.g. /usr/include/postgresql
).
All Nix builds currently build with Postgres support by default.
Wallet Pool Configuration
To use with libcore, simply set value of the key api::PoolConfiguration::DATABASE_NAME
to the database's URL connection and set it in the pool's configuration.
It is also possible to configure the size of the connection pool and read-only connection pool when instantiating the
PostgreSQL DatabaseBackend
: api::DatabaseBackend::getPostgreSQLBackend(int32_t connectionPoolSize, int32_t readonlyConnectionPoolSize)
.
Local testing
Make sure to have a running PostgreSQL server or PostgreSQL docker container.
As an example, if you are running it on localhost:5432
and test_db
as database name,
database's name forwarded to the pool (through configuration key api::PoolConfiguration::DATABASE_NAME
)
should look like : postgres://localhost:5432/test_db
.
In order to run local tests
cd lib-ledger-core-build
On
Linux
ormacOSX
,
ctest
On
Windows
,
ctest -C Debug -VV
if you want to run only one specific unit test. (e.g. the test case BitcoinLikeWalletSynchronization.MediumXpubSynchronization
in the test project ledger-core-integration-tests
)
./core/test/integration/build/ledger-core-integration-tests "--gtest_filter=BitcoinLikeWalletSynchronization.MediumXpubSynchronization"
Publish libcore JAR into local repository
First you need to build the libcore with JNI enabled
mkdir build_lib_jni
cd build_lib_jni
cmake .. -DSYS_OPENSSL=ON -DOPENSSL_USE_STATIC_LIBS=TRUE -DTARGET_JNI=ON -DPG_SUPPORT=ON
cmake --build . --parallel
Then you can build & publish the jar with sbt publishLocal
. A tool script wraps it:
./tools/publish-jar-local.sh ./lib_build_dir_jni
It will publish a maven artifact (available at ~/.ivy2/local/co.ledger/ledger-lib-core_2.12/local-SNAPSHOT) that can be used by any third party
Build production-like version of the library
To build the production-like version of the library use script tools/prod-like-build.sh
. This script requires
Docker. It starts from building Docker image with required versions of the dependencies. Next it starts the
Docker container with that image and the lib-ledger-core
source code from the current directory. The resulting
ledger-lib-core.jar
will be copied from the container to the artifacts
sub-directory of the current directory.
By default the Release
versions of the lib-ledger-core
is created. To specify the required build type add
it to the command line: ./tools/prod-like-build.sh Debug
.
Documentation
You can generate the Doxygen documentation by running the doc
target (for instance, make doc
with makefiles).
Use Code Coverage
:warning: Only available on Linux for now (with gcc).
- Make sure to have
lcov
installedsudo apt-get install -y lcov
- Set the
CODE_COVERAGE
cmake option toON
- Compute the coverage, in build directory:
- Based on unit tests only:
cmake --build . --config Debug --target coverage_unit
- Based on all tests:
cmake --build . --config Debug --target coverage_all
- Open the report:
./coverage/index.html
Use optional compilation checks
- clang-tidy checks can be activated by setting
CLANG_TIDY
cmake option toON
- include-what-you-use checks can be activated by setting
IWYU
cmake option toON
Use optional compilation optimization
- ccache compilation optimization can be activated by setting
CCACHE
cmake option toON
Binding to node.js
The library can be compiled and integrated as an node module in a pretty straightforward way. You will be interested in either using it, or making a new version of the node module.
Using the node module
The lib-ledger-core-node-bindings repository contains the node.js bindings you will need to
interface with lib-ledger-core
. You can either clone the git repository or simply install from
npm
directly:
npm i @ledgerhq/ledger-core
Generating a new node module for your system
Generating bindings is a several steps process:
- First, you need to make some changes to
lib-ledger-core
and generate a fresh version oflib-ledger-core
. - Clone lib-ledger-core-node-bindings and edit the
package.json
file in order to remove or comment the"preinstall"
line in"scripts"
. - In the folder of
lib-ledger-core
, run thetools/generateBindings.sh
script by giving it the path to the bindings (i.e. where you cloned lib-ledger-core-node-bindings) and as second argument the path to the directory where you built thelib-ledger-core
— it should be something like$(your-lib-ledger-core-dir)/../lib-ledger-core-build
or$(your-lib-ledger-core-dir)/build
.- This script requires an up-to-date djinni. To ensure it’s correctly up to date, go
into
lib-ledger-core/djinni
and runget fetch origin --prune && git rebase origin/master
. - You will need
sbt
andjava8
for a complete, working install. - The script will generate files in both projects. You’re advised to remove the ones created
in
lib-ledger-core
— if any — with agit checkout .
and/orgit reset .
.
- This script requires an up-to-date djinni. To ensure it’s correctly up to date, go
into
cd
intolib-ledger-core-bindings
and runyarn
to generate the bindings.- You will have the module in
build/Release/ledgerapp_nodejs.node
in the bindings project. npm i
should install your own version.
Support
Libcore:
Libcore can be built for following OSes:
- MacOS: minimum supported version is
macOS 9.0
, withx86_64
architecture, - Linux: Debian (stretch), Ubuntu and Arch are supported, with
x86_64
architecture, - Windows: 64-bit architecture is built with
MSVC
(starting from Visual Studio 15), 32-bit is built withMinGW
, - iOS:
x86_64
,armv7
andarm64
architectures are supported, minimum supported version isiOS 10.0
, - Android:
x86
,armeabi-v7a
andarm64-v8a
architectures are supported, minimum supported version isAndroid 7 (API 24)
(Java 8 is needed).
Bindings:
- NodeJS bindings:
- Please use
node
with version>=8.4.0
and<9.0.0
(other versions are not tested (yet)), - Node-gyp is used to build native module and requires
python
with version2.7.x
.
- Please use
Developement guidelines
Local tests
The best way to run tests locally is to use Nix:
nix-build --arg runTests true --arg jni false
If you don't want to, you can also provision the postgres
test database if necessary, and then run ctest
.
Code formating
We use clang-format >= 14, not available by default on ubuntu 20.04
Install
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main'
wget https://apt.llvm.org/llvm-snapshot.gpg.key
sudo apt-key add llvm-snapshot.gpg.key
sudo apt update
sudo apt install clang-format-14
CI
Rebasing
Rebasing is done easily. If your PR wants to merge feature/stuff -> develop
, you can do something
like this — assuming you have cloned the repository with a correctly set origin
remote:
git checkout feature/stuff
git rebase -i origin/develop
Change the pick
to r
or reword
at the beginning of each lines without changing the text of
the commits — this has no effect. Save the file and quit. You will be prompted to change the
commits’ messages one by one, allowing you to remove the [skip ci]
tag from all commits.
Release process
To release the libcore, a Github action automates everything:
- Go to Release libcore action
- Select "Run workflow"
- Set the version you want to tag
It will automatically:
- Push the tag
- Create the Release note
- Build libcore release (ubuntu 22 & macos 12)
- Publish libcore jar
- Update WD
Q/A and troubleshooting
I have updated an include file and test code doesn’t see the changes!
Currently, interface files (headers, .hpp) are not linked by copied directly into the test directory. That means that every time you make a change in the interface that is tested by any code in core/test/, you need to update the copy.
Just run this command:
cd $your_build_folder
rm -rf CMakeFiles CMakeCache.txt
I have upgraded my macOSX system and now I can’t compile anymore.
Especially if you’ve upgraded to Mojave for which there are some breaking changes, you will need to perform some manual tasks — here, for macOSX Mojave:
xcode-select --install
open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg