mirror of
https://github.com/JonathanSalwan/Triton
synced 2026-08-17 10:23:04 -04:00
259 lines
10 KiB
CMake
259 lines
10 KiB
CMake
##
|
|
## Copyright (C) - Triton
|
|
##
|
|
## This program is under the terms of the BSD License.
|
|
##
|
|
|
|
##################################################################################### CMake libtriton
|
|
|
|
cmake_minimum_required(VERSION 3.20)
|
|
|
|
set(TRITON_ROOT "${CMAKE_CURRENT_LIST_DIR}")
|
|
|
|
# Read the build version
|
|
file(READ ${TRITON_ROOT}/.build_number BUILD_NUMBER)
|
|
set(VERSION_MAJOR 1)
|
|
set(VERSION_MINOR 0)
|
|
set(VERSION_BUILD ${BUILD_NUMBER})
|
|
|
|
# Used for write_basic_package_version_file()
|
|
project(triton VERSION ${VERSION_MAJOR}.${VERSION_MINOR})
|
|
|
|
# Define cmake options
|
|
include(CMakeDependentOption)
|
|
|
|
option(ASAN "Enable the ASAN linking" OFF)
|
|
option(BITWUZLA_INTERFACE "Use Bitwuzla as SMT solver" OFF)
|
|
option(BUILD_SHARED_LIBS "Build a shared library" ON)
|
|
option(GCOV "Enable code coverage" OFF)
|
|
option(LLVM_INTERFACE "Use LLVM for lifting" OFF)
|
|
option(MSVC_STATIC "Use statically-linked runtime library" OFF)
|
|
option(Z3_INTERFACE "Use Z3 as SMT solver" ON)
|
|
option(BOOST_INTERFACE "Use Boost as multiprecision library" OFF)
|
|
option(PYTHON_BINDINGS_AUTOCOMPLETE "Generate an autocomplete stub file" OFF)
|
|
|
|
# Define cmake dependent options
|
|
cmake_dependent_option(BUILD_EXAMPLES "Build the examples" ON BUILD_SHARED_LIBS OFF)
|
|
cmake_dependent_option(ENABLE_TEST "Do testing" ON BUILD_SHARED_LIBS OFF)
|
|
cmake_dependent_option(PYTHON_BINDINGS "Enable Python bindings" ON BUILD_SHARED_LIBS OFF)
|
|
|
|
#Enable ctest
|
|
include(CTest)
|
|
add_custom_target(check
|
|
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH="${CMAKE_CURRENT_BINARY_DIR}/src/libtriton" ctest --output-on-failure
|
|
DEPENDS triton
|
|
)
|
|
|
|
if(PYTHON_BINDINGS)
|
|
message(STATUS "Compiling with Python bindings")
|
|
|
|
if(NOT PYTHON_VERSION AND NOT PYTHON_EXECUTABLE)
|
|
# On Windows, python3 points to the Windows Store version of Python.
|
|
# Installations from the Python website do not contain python3.exe
|
|
if(WIN32)
|
|
set(PYTHON_NAMES python python3)
|
|
else()
|
|
set(PYTHON_NAMES python3 python)
|
|
endif()
|
|
# Find the python version the user has in the PATH
|
|
# This prevents an issue where an unexpected python version is used
|
|
# (eg the system/homebrew python in a virtual environment)
|
|
find_program(PYTHON_EXECUTABLE
|
|
NAMES ${PYTHON_NAMES}
|
|
NO_PACKAGE_ROOT_PATH
|
|
NO_CMAKE_PATH
|
|
NO_CMAKE_ENVIRONMENT_PATH
|
|
NO_CMAKE_SYSTEM_PATH
|
|
NO_CMAKE_INSTALL_PREFIX
|
|
REQUIRED
|
|
)
|
|
endif()
|
|
|
|
if(PYTHON_EXECUTABLE)
|
|
# Make sure the specified python is not fully broken
|
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} --version
|
|
RESULT_VARIABLE PYTHON_RESULT
|
|
OUTPUT_QUIET
|
|
)
|
|
if(NOT PYTHON_RESULT EQUAL 0)
|
|
message(FATAL_ERROR "Broken python: ${PYTHON_EXECUTABLE}")
|
|
endif()
|
|
endif()
|
|
|
|
# Set the hints for the Python3 package
|
|
# Reference: https://cmake.org/cmake/help/latest/module/FindPython3.html#hints
|
|
# The PYTHON_XXX variables are not used by FindPython3, but they are translated
|
|
# for backwards compatibility with previous Triton versions
|
|
set(Python3_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
|
if(PYTHON_LIBRARY)
|
|
set(Python3_LIBRARY "${PYTHON_LIBRARY}")
|
|
elseif(PYTHON_LIBRARIES)
|
|
set(Python3_LIBRARY "${PYTHON_LIBRARIES}")
|
|
endif()
|
|
if(PYTHON_INCLUDE_DIRS)
|
|
set(Python3_INCLUDE_DIR "${PYTHON_INCLUDE_DIRS}")
|
|
endif()
|
|
set(Python3_FIND_VIRTUALENV "FIRST")
|
|
|
|
find_package(Python3 ${PYTHON_VERSION} COMPONENTS Interpreter Development REQUIRED)
|
|
message(STATUS "Python3 includes: ${Python3_INCLUDE_DIRS}")
|
|
message(STATUS "Python3 libraries: ${Python3_LIBRARIES}")
|
|
|
|
# For backwards compatibility with existing CMake
|
|
set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
|
|
|
|
set(PYTHONPATH_CMD ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:triton>/)
|
|
add_custom_target(test-python
|
|
COMMAND ${PYTHONPATH_CMD} ${PYTHON_EXECUTABLE} -m unittest discover ${TRITON_ROOT}/src/testers/unittests
|
|
DEPENDS python-triton
|
|
)
|
|
|
|
add_test(NAME test-python
|
|
COMMAND ${PYTHON_EXECUTABLE} -m unittest discover ${triton_SOURCE_DIR}/src/testers/unittests
|
|
)
|
|
set_property(TEST test-python
|
|
PROPERTY ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:triton>/"
|
|
)
|
|
else()
|
|
add_custom_target(test-python
|
|
COMMAND echo "No python test as python support is disabled"
|
|
)
|
|
endif()
|
|
|
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND GCOV)
|
|
message(STATUS "Compiled with GCOV")
|
|
add_custom_target(gcov-test
|
|
COMMAND lcov --zerocounters --directory $<TARGET_FILE_DIR:triton>
|
|
COMMAND lcov --capture --initial --directory $<TARGET_FILE_DIR:triton> --output-file app
|
|
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test-python
|
|
COMMAND ctest --output-on-failure
|
|
COMMAND lcov --no-checksum --directory $<TARGET_FILE_DIR:triton> --capture --output-file coverage.info
|
|
COMMAND lcov --ignore-errors unused --remove coverage.info '/usr*' --remove coverage.info 'pintools*' --remove coverage.info 'examples*' -o coverage.info
|
|
COMMAND genhtml coverage.info -o coverage
|
|
COMMAND ${CMAKE_COMMAND} -E echo "-- Report generated in ${CMAKE_CURRENT_BINARY_DIR}/coverage/index.html"
|
|
)
|
|
add_dependencies(gcov-test triton)
|
|
add_dependencies(check gcov-test)
|
|
add_compile_options(--coverage)
|
|
add_link_options(--coverage)
|
|
endif()
|
|
|
|
# Specific OSX POLICY
|
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
if(POLICY CMP0025)
|
|
cmake_policy(SET CMP0025 NEW) # report Apple's Clang as just Clang
|
|
endif()
|
|
if(POLICY CMP0042)
|
|
cmake_policy(SET CMP0042 NEW) # MACOSX_RPATH
|
|
endif()
|
|
endif()
|
|
|
|
# Custom cmake search
|
|
list(APPEND CMAKE_MODULE_PATH "${TRITON_ROOT}/CMakeModules/")
|
|
|
|
# Find Z3
|
|
if(Z3_INTERFACE)
|
|
message(STATUS "Compiling with Z3 SMT solver")
|
|
find_package(Z3 REQUIRED)
|
|
message(STATUS "Z3 version: ${Z3_VERSION}")
|
|
if(TARGET z3::libz3)
|
|
link_libraries(z3::libz3)
|
|
elseif(DEFINED Z3_INCLUDE_DIRS)
|
|
include_directories(${Z3_INCLUDE_DIRS})
|
|
else()
|
|
message(FATAL_ERROR "Unexpected Z3 package search outcome: neither target z3::libz3 not variable Z3_INCLUDE_DIRS exists.")
|
|
endif()
|
|
set(TRITON_Z3_INTERFACE ON)
|
|
endif()
|
|
|
|
# Find bitwuzla
|
|
if(BITWUZLA_INTERFACE)
|
|
message(STATUS "Compiling with Bitwuzla SMT solver")
|
|
find_package(BITWUZLA REQUIRED)
|
|
if(TARGET Bitwuzla::bitwuzla)
|
|
link_libraries(Bitwuzla::bitwuzla)
|
|
elseif(DEFINED BITWUZLA_INCLUDE_DIRS)
|
|
include_directories(${BITWUZLA_INCLUDE_DIRS})
|
|
else()
|
|
message(FATAL_ERROR "Unexpected Bitwuzla package search outcome: neither target Bitwuzla::bitwuzla not variable BITWUZLA_INCLUDE_DIRS exists.")
|
|
endif()
|
|
set(TRITON_BITWUZLA_INTERFACE ON)
|
|
endif()
|
|
|
|
# Find LLVM
|
|
if(LLVM_INTERFACE)
|
|
message(STATUS "Compiling with LLVM")
|
|
if(NOT DEFINED LLVM_INCLUDE_DIRS)
|
|
find_package(LLVM REQUIRED CONFIG)
|
|
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
|
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
|
if(LLVM_LINK_LLVM_DYLIB)
|
|
set(LLVM_LIBRARIES LLVM)
|
|
else()
|
|
set(LLVM_LIBRARIES ${LLVM_AVAILABLE_LIBS})
|
|
endif()
|
|
# LLVM 18+ Linux prebuilts are compiled without exception handling and
|
|
# propagate -fno-exceptions via INTERFACE_COMPILE_OPTIONS. Since those
|
|
# options are applied after Triton's own compile flags in the compiler
|
|
# command (last-flag-wins), they would override Triton's exceptions. Strip them.
|
|
if(NOT MSVC AND LLVM_VERSION_MAJOR GREATER_EQUAL 18)
|
|
foreach(_lib IN ITEMS LLVM ${LLVM_AVAILABLE_LIBS})
|
|
if(TARGET ${_lib})
|
|
get_target_property(_opts ${_lib} INTERFACE_COMPILE_OPTIONS)
|
|
if(_opts)
|
|
list(REMOVE_ITEM _opts -fno-exceptions -fno-rtti)
|
|
set_target_properties(${_lib} PROPERTIES INTERFACE_COMPILE_OPTIONS "${_opts}")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
# LLVM 19+ Linux prebuilts ship static archives compiled with thin LTO.
|
|
# They contain LLVM bitcode rather than ELF objects, which GNU ld cannot
|
|
# link. lld handles thin-LTO archives transparently; force it here.
|
|
# Note: only static-archive builds (not dylib) on LLVM 19+; older
|
|
# distro-packaged LLVMs use plain ELF archives and may not have lld.
|
|
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
|
AND NOT "$CACHE{LLVM_LINK_LLVM_DYLIB}"
|
|
AND LLVM_VERSION_MAJOR GREATER_EQUAL 19)
|
|
add_link_options(-B${LLVM_TOOLS_BINARY_DIR} -fuse-ld=lld)
|
|
message(STATUS "Using lld for thin-LTO static archives")
|
|
endif()
|
|
endif()
|
|
include_directories(${LLVM_INCLUDE_DIRS})
|
|
set(TRITON_LLVM_INTERFACE ON)
|
|
endif()
|
|
|
|
# Find Capstone
|
|
message(STATUS "Compiling with Capstone")
|
|
find_package(CAPSTONE 5 REQUIRED)
|
|
message(STATUS "CAPSTONE version: ${CAPSTONE_VERSION}")
|
|
if(TARGET capstone::capstone)
|
|
link_libraries(capstone::capstone)
|
|
elseif(DEFINED CAPSTONE_INCLUDE_DIRS)
|
|
include_directories(${CAPSTONE_INCLUDE_DIRS})
|
|
else()
|
|
message(FATAL_ERROR "Unexpected capstone package search outcome: neither target capstone::capstone not variable CAPSTONE_INCLUDE_DIRS exists.")
|
|
endif()
|
|
|
|
# Find boost
|
|
if(BOOST_INTERFACE)
|
|
message(STATUS "Compiling with Boost headers")
|
|
find_package(Boost 1.55.0)
|
|
if (Boost_FOUND)
|
|
include_directories("${Boost_INCLUDE_DIRS}")
|
|
set(TRITON_BOOST_INTERFACE ON)
|
|
else()
|
|
message(STATUS "Boost headers not found, compiling with wide-integer headers")
|
|
set(TRITON_BOOST_INTERFACE OFF)
|
|
endif()
|
|
else()
|
|
message(STATUS "Compiling with wide-integer headers")
|
|
set(TRITON_BOOST_INTERFACE OFF)
|
|
endif()
|
|
|
|
if(PYTHON_BINDINGS_AUTOCOMPLETE)
|
|
message(STATUS "Compiling with Python autocomplete stub")
|
|
endif()
|
|
|
|
add_subdirectory(src)
|
|
add_subdirectory(doc)
|