To compile LIEF, you need at least the following:
C++17 compiler (GCC, Clang, MSVC, etc.)
CMake
Python >= 3.9 (for the bindings)
Note
Compiling from scratch with all options enabled can take approximately 20 minutes on a standard laptop.
$ 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, you can choose which 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
Note
Since LIEF 0.13.0, 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
You can customize the compilation by setting the PYLIEF_CONF environment variable to the path of a TOML configuration file. By default, the Python bindings use 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 .
By default, LIEF is compiled with CMAKE_BUILD_TYPE set to Release. You can change this behavior by setting it to either RelWithDebInfo or Debug during CMake’s configuration step:
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo [...] ..
Alternatively, the Python bindings can also be compiled with debug information by changing the type in the [lief.build] section of config-default.toml:
[lief.build]
type = "RelWithDebInfo"
Note
When developing 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
LIEF relies on several external projects, and we aim to limit dependencies in the public headers as much as possible. The following table summarizes these dependencies and their scopes. internal means that it is required to compile LIEF but not to use it. external means that it is required for both.
Dependency | Scope | Purpose |
|---|---|---|
| C++11 span interface | |
| Error handling (see: Error Handling ) | |
| Logging | |
| ASN.1 parser / Hash functions | |
| Unicode support (for PE and DEX files) | |
| Serialize LIEF objects into JSON | |
| Python bindings | |
|
| |
| ELF Fuzzing | |
| Unit Testing |
With the exception of MbedTLS, all of these dependencies are header-only. By default, they are embedded and managed by LIEF to simplify compilation and integration.
Nevertheless, package managers often require linking against system libraries rather than using vendored dependencies [1] [2].
To address this requirement, you can control the integration of LIEF’s dependencies using the following CMake 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 will resolve dependencies using CMake’s find_package(...), which relies on <DEPS>_DIR to locate the package.
For example, LIEF can be compiled using 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. This means that if it is externalized, the static version of LIEF will not include the MbedTLS object files, and the end user will have to manually link LIEF.a with a provided version of MbedTLS.
LIEF uses GitHub Actions 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/linux-sdk-x64 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, refer to the CI configs .github/workflows/ios.yml and .github/workflows/osx.yml to see how LIEF is compiled (and cross-compiled) for these platforms.
if(__add_lief_options)
return()
endif()
set(__add_lief_options ON)
include(CMakeDependentOption)
option(LIEF_TESTS "Enable tests" 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 externally" 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_SO_VERSION "Embed versioning for LIEF shared library target" OFF)
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_COFF "Build LIEF with COFF 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)
# Extended features
option(LIEF_DEBUG_INFO "Build LIEF with DWARF/PDB support" OFF)
option(LIEF_OBJC "Build LIEF with ObjC metadata support" OFF)
option(LIEF_DYLD_SHARED_CACHE "Build LIEF with Dyld shared cache support" OFF)
option(LIEF_ASM "Build LIEF with assembler/disassembler support" OFF)
if (LIEF_COFF AND NOT LIEF_PE)
message(FATAL_ERROR "COFF module requires LIEF_PE enabled")
endif()
if (LIEF_PE AND NOT LIEF_COFF)
message(FATAL_ERROR "PE module requires LIEF_COFF enabled")
endif()
cmake_dependent_option(LIEF_PYTHON_EDITABLE "Make an editable build " OFF
"LIEF_PYTHON_API" OFF)
cmake_dependent_option(LIEF_PY_LIEF_EXT_SHARED
"Use a 'SHARED' version of LIEF instead of a static one" OFF
"LIEF_PY_LIEF_EXT" OFF)
cmake_dependent_option(LIEF_PYTHON_STATIC "Internal usage" OFF
"LIEF_PYTHON_API" OFF)
cmake_dependent_option(LIEF_PYTHON_STABLE_ABI "Compile LIEF Python bindings with the stable ABI" OFF
"LIEF_PYTHON_API" OFF)
cmake_dependent_option(LIEF_PYTHON_FREE_THREADED "Compile LIEF Python bindings with free-threading enabled" OFF
"LIEF_PYTHON_API" OFF)
# OAT support relies on the ELF and DEX format.
# Therefore, these options must be enabled to support 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)
option(LIEF_USE_MELKOR "Build Melkor for testing" ON)
# 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_COFF_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)
set(LIEF_DEBUG_INFO_SUPPORT 0)
set(LIEF_OBJC_SUPPORT 0)
set(LIEF_DYLD_SHARED_CACHE_SUPPORT 0)
set(LIEF_ASM_SUPPORT 0)
set(LIEF_EXTENDED 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_COFF)
set(LIEF_COFF_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()
# ------------------------------------------------------------------------------
# Extended features
# ------------------------------------------------------------------------------
if (LIEF_DEBUG_INFO)
set(LIEF_DEBUG_INFO_SUPPORT 1)
endif()
if (LIEF_OBJC)
set(LIEF_OBJC_SUPPORT 1)
endif()
if (LIEF_DYLD_SHARED_CACHE)
set(LIEF_DYLD_SHARED_CACHE_SUPPORT 1)
endif()
if (LIEF_ASM)
set(LIEF_ASM_SUPPORT 1)
endif()
if (LIEF_DEBUG_INFO OR LIEF_OBJC OR LIEF_DYLD_SHARED_CACHE OR LIEF_ASM) # or any other extended feature
set(LIEF_EXTENDED 1)
endif()
See liefproject on Dockerhub