Compilation

To compile LIEF, you need at least the following requirements:

  • C++17 compiler (GCC, Clang, MSVC..)

  • CMake

  • Python >= 3.8 (for the bindings)

Note

A compilation from scratch with all the options enabled can take ~20 minutes on a regular laptop.

Libraries only (SDK)

$ git clone https://github.com/lief-project/LIEF.git
$ cd LIEF
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ cmake --build . --target LIB_LIEF --config Release

Warning

On Windows one can choose the CRT to use by setting the CMAKE_MSVC_RUNTIME_LIBRARY variable:

$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ..

For Debug, you should set the CRT to MTd:

$ cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug ..
$ cmake --build . --target LIB_LIEF --config Debug

Python bindings

Note

Since LIEF 0.13.0 the setup.py has moved from the project root directory to the api/python directory.

$ git clone https://github.com/lief-project/LIEF.git
$ cd LIEF/api/python
$ pip install [-e] [--user] .
# Or
$ pip install [-e] api/python

Note

You can speed-up the compilation by installing ccache or sccache

One can tweak the compilation by setting the environment variable PYLIEF_CONF to a Toml configuration file. By default, the Python bindings are using config-default.toml in the Python binding directory:

[lief.build]
type          = "Release"
cache         = true
ninja         = true
parallel-jobs = 0

[lief.formats]
elf     = true
pe      = false
macho   = true
...
$ PYLIEF_CONF=/tmp/my-custom.toml pip install .

Debugging

By default, LIEF is compiled with CMAKE_BUILD_TYPE set to Release. One can change this behavior by setting either RelWithDebInfo or Debug during the cmake’s configuration step:

$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo [...] ..

On the other hand, Python bindings can also be compiled with debug information by changing the type in the section [lief.build] of config-default.toml:

[lief.build]
type = "RelWithDebInfo"

Note

When developing on LIEF, you can use:

$ PYLIEF_CONF=~/lief-debug.toml pip install [-e] api/python

With lief-debug.toml set to:

[lief.build]
type = "RelWithDebInfo"
...

[lief.logging]
enabled = true
debug   = true

Third Party

LIEF relies on few external projects and we try to limit as much as possible the dependencies in the public headers. This table summarizes these dependencies and their scope. internal means that it is required to compile LIEF but it is not required to use LIEF. external means that it is required for both.

Dependency

Scope

Purpose

tcb/span

external

C++11 span interface

TL Expected

external

Error handling (see: Error Handling )

spdlog

internal

Logging

MbedTLS

internal

ASN.1 parser / Hash functions

utfcpp

internal

Unicode support (for PE and DEX files)

json

internal

Serialize LIEF’s object into JSON

nanobind

internal

Python bindings

Frozen

internal

constexpr containers

Catch2

internal

Testing

Melkor ELF Fuzzer

internal

ELF Fuzzing

Except MbedTLS, all these dependencies are header-only and they are by default embedded/managed by LIEF such as it eases the compilation and the integration.

Nevertheless, packages manager might require to not self-use/embed external dependencies [1] [2].

To address this requirement, the user can control the integration of LIEF’s dependencies using the following cmake’s options:

  • LIEF_OPT_NLOHMANN_JSON_EXTERNAL

  • LIEF_OPT_UTFCPP_EXTERNAL

  • LIEF_OPT_MBEDTLS_EXTERNAL

  • LIEF_EXTERNAL_SPDLOG

  • LIEF_OPT_FROZEN_EXTERNAL

  • LIEF_OPT_EXTERNAL_SPAN/LIEF_EXTERNAL_SPAN_DIR

  • LIEF_OPT_EXTERNAL_EXPECTED

  • LIEF_OPT_NANOBIND_EXTERNAL

By setting these flags, LIEF resolves the dependencies with CMake find_package(...) which is aware of <DEPS>_DIR to find the package.

As a result, LIEF can be, for instance, compiled with the following configuration:

$ cmake .. -GNinja \
           -DLIEF_OPT_NLOHMANN_JSON_EXTERNAL=ON \
           -Dnlohmann_json_DIR=/lief-third-party/json/install/lib/cmake/nlohmann_json \
           -DLIEF_OPT_MBEDTLS_EXTERNAL=on \
           -DMbedTLS_DIR=/lief-third-party/mbedtls/install/cmake

Warning

As mentioned previously, MbedTLS is not header-only which means that if it is externalized the static version of LIEF won’t include the MbedTLS object files and the end user will have to link again LIEF.a with a provided version of MbedTLS.

Continuous Integration

LIEF uses CI Github Action to test and release nightly builds. The configuration of this CI can also be a good source of information for the compilation process. In particular, scripts/docker/run_linux_sdk contains the build process to generate the Linux x86-64 SDK.

On Windows, the SDK is built with the following Python script: scripts/windows/package_sdk.py

For OSX & iOS, the CI configs .github/workflows/ios.yml and .github/workflows/osx.yml to compile (and cross-compile) LIEF for these platforms.

CMake Options

if(__add_lief_options)
  return()
endif()
set(__add_lief_options ON)
include(CMakeDependentOption)

option(LIEF_TESTS                      "Enable tests"                               OFF)
option(LIEF_DOC                        "Enable documentation"                       OFF)
option(LIEF_PYTHON_API                 "Enable Python Bindings"                     OFF)
option(LIEF_C_API                      "C API"                                      ON)
option(LIEF_EXAMPLES                   "Build LIEF C++ examples"                    ON)
option(LIEF_FORCE32                    "Force build LIEF 32 bits version"           OFF)
option(LIEF_USE_CCACHE                 "Use ccache to speed up compilation"         ON)
option(LIEF_EXTRA_WARNINGS             "Enable extra warning from the compiler"     OFF)
option(LIEF_LOGGING                    "Enable logging"                             ON)
option(LIEF_LOGGING_DEBUG              "Enable debug logging"                       ON)
option(LIEF_ENABLE_JSON                "Enable JSON-related APIs"                   ON)
option(LIEF_OPT_NLOHMANN_JSON_EXTERNAL "Use nlohmann/json externaly"                OFF)
option(LIEF_FORCE_API_EXPORTS          "Force exports of API symbols"               OFF)
option(LIEF_PY_LIEF_EXT                "Use a pre-installed version of LIEF for the bindings" OFF)
option(LIEF_RUST_API                   "Generate the C++ bridge for Rust's cxx" OFF)
option(LIEF_DISABLE_EXCEPTIONS         "Disable C++ exceptions on the core library" ON)

option(LIEF_DISABLE_FROZEN "Disable Frozen even if it is supported"     OFF)

option(LIEF_ELF            "Build LIEF with ELF module"                 ON)
option(LIEF_PE             "Build LIEF with PE  module"                 ON)
option(LIEF_MACHO          "Build LIEF with MachO module"               ON)

option(LIEF_DEX            "Build LIEF with DEX module"                 ON)
option(LIEF_ART            "Build LIEF with ART module"                 ON)

cmake_dependent_option(LIEF_PYTHON_EDITABLE "Make an editable build " OFF
                       "LIEF_PYTHON_API" OFF)

cmake_dependent_option(LIEF_PYTHON_STATIC "Internal usage" OFF
                       "LIEF_PYTHON_API" OFF)

# OAT support relies on the ELF and DEX format.
# Therefore, these options must be enabled to support use this format
cmake_dependent_option(LIEF_OAT "Build LIEF with OAT module" ON
                       "LIEF_ELF;LIEF_DEX" OFF)

# VDEX format depends on the DEX module
cmake_dependent_option(LIEF_VDEX "Build LIEF with VDEX module" ON
                       "LIEF_DEX" OFF)

# Sanitizer
option(LIEF_ASAN "Enable Address sanitizer"   OFF)
option(LIEF_LSAN "Enable Leak sanitizer"      OFF)
option(LIEF_TSAN "Enable Thread sanitizer"    OFF)
option(LIEF_USAN "Enable undefined sanitizer" OFF)

# Fuzzer
option(LIEF_FUZZING "Fuzz LIEF" OFF)

# Profiling
option(LIEF_PROFILING "Enable performance profiling" OFF)

# Install options
cmake_dependent_option(LIEF_INSTALL_COMPILED_EXAMPLES "Install LIEF Compiled examples" OFF
                       "LIEF_EXAMPLES" OFF)

# Use a user-provided version of spdlog
# It can be useful to reduce compile time
option(LIEF_EXTERNAL_SPDLOG OFF)

# This option enables to provide an external
# version of TartanLlama/expected  (e.g. present on the system)
option(LIEF_OPT_EXTERNAL_EXPECTED OFF)

# This option enables to provide an external version of utf8cpp
option(LIEF_OPT_UTFCPP_EXTERNAL OFF)

# This option enables to provide an external version of MbedTLS
option(LIEF_OPT_MBEDTLS_EXTERNAL OFF)

# This option enables to provide an external version of nanobind
option(LIEF_OPT_NANOBIND_EXTERNAL OFF)

# This option enables to provide an external
# version of https://github.com/tcbrindle/span (e.g. present on the system)
option(LIEF_OPT_EXTERNAL_SPAN OFF)
set(LIEF_EXTERNAL_SPAN_DIR )

# This option enables to provide an external version of Frozen
set(_LIEF_USE_FROZEN ON)
if(LIEF_DISABLE_FROZEN)
  set(_LIEF_USE_FROZEN OFF)
endif()

cmake_dependent_option(LIEF_OPT_FROZEN_EXTERNAL "Use an external provided version of Frozen" OFF
                       "_LIEF_USE_FROZEN" OFF)

# This option enables the install target in the cmake
option(LIEF_INSTALL "Generate the install target." ON)

set(LIEF_ELF_SUPPORT 0)
set(LIEF_PE_SUPPORT 0)
set(LIEF_MACHO_SUPPORT 0)

set(LIEF_OAT_SUPPORT 0)
set(LIEF_DEX_SUPPORT 0)
set(LIEF_VDEX_SUPPORT 0)
set(LIEF_ART_SUPPORT 0)

set(LIEF_JSON_SUPPORT 0)
set(LIEF_NLOHMANN_JSON_EXTERNAL 0)
set(LIEF_LOGGING_SUPPORT 0)
set(LIEF_LOGGING_DEBUG_SUPPORT 0)
set(LIEF_FROZEN_ENABLED 0)
set(LIEF_EXTERNAL_FROZEN 0)

set(LIEF_EXTERNAL_EXPECTED 0)
set(LIEF_EXTERNAL_UTF8CPP 0)
set(LIEF_EXTERNAL_MBEDTLS 0)
set(LIEF_EXTERNAL_SPAN 0)

if(LIEF_ELF)
  set(LIEF_ELF_SUPPORT 1)
endif()

if(LIEF_PE)
  set(LIEF_PE_SUPPORT 1)
endif()

if(LIEF_MACHO)
  set(LIEF_MACHO_SUPPORT 1)
endif()

if(LIEF_OAT)
  set(LIEF_OAT_SUPPORT 1)
endif()

if(LIEF_DEX)
  set(LIEF_DEX_SUPPORT 1)
endif()

if(LIEF_VDEX)
  set(LIEF_VDEX_SUPPORT 1)
endif()

if(LIEF_ART)
  set(LIEF_ART_SUPPORT 1)
endif()

if(LIEF_ENABLE_JSON)
  set(LIEF_JSON_SUPPORT 1)
  if(LIEF_OPT_NLOHMANN_JSON_EXTERNAL)
    set(LIEF_NLOHMANN_JSON_EXTERNAL 1)
  endif()
endif()

if(LIEF_LOGGING)
  set(LIEF_LOGGING_SUPPORT 1)
  if(LIEF_LOGGING_DEBUG)
    set(LIEF_LOGGING_DEBUG_SUPPORT 1)
  else()
    set(LIEF_LOGGING_DEBUG_SUPPORT 0)
  endif()
endif()

if(NOT LIEF_DISABLE_FROZEN)
  set(LIEF_FROZEN_ENABLED 1)
  if(LIEF_OPT_FROZEN_EXTERNAL)
    set(LIEF_EXTERNAL_FROZEN 1)
  endif()
endif()

if(LIEF_OPT_EXTERNAL_EXPECTED)
  set(LIEF_EXTERNAL_EXPECTED 1)
endif()

if(LIEF_OPT_UTFCPP_EXTERNAL)
  set(LIEF_EXTERNAL_UTF8CPP 1)
endif()

if(LIEF_OPT_MBEDTLS_EXTERNAL)
  set(LIEF_EXTERNAL_MBEDTLS 1)
endif()

if(LIEF_OPT_EXTERNAL_SPAN)
  set(LIEF_EXTERNAL_SPAN 1)
endif()

if(LIEF_PYTHON_API)
  if(LIEF_OPT_NANOBIND_EXTERNAL)
    set(LIEF_EXTERNAL_NANOBIND 1)
  endif()
endif()

Docker

See liefproject on Dockerhub