blob: bbebe3fb74275825c99abfa91cae1929c00e3878 [file] [log] [blame]
cmake_minimum_required(VERSION 3.9)
cmake_policy(SET CMP0048 NEW)
project (Bloaty VERSION 1.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_GENERATOR "Ninja")
include(CTest)
set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Group projects in visual studio
# Options we define for users.
option(BLOATY_ENABLE_ASAN "Enable address sanitizer." OFF)
option(BLOATY_ENABLE_UBSAN "Enable undefined behavior sanitizer." OFF)
option(BLOATY_ENABLE_CMAKETARGETS "Enable installing cmake target files." ON)
option(BLOATY_ENABLE_BUILDID "Enable build id." ON)
option(BLOATY_ENABLE_RE2 "Enable the support for regular expression functions." ON)
if(APPLE)
# When building bloaty on macOS infra builders,
# need to add the libc++.a from the CIPD toolchain, otherwise there are linker errors
# e.g. https://ci.chromium.org/p/fuchsia/builders/try/bloaty-x64-mac/b8874842054253378656?
#
# To achieve this, find the libc++.a location from the location of the clang binary.
# CMAKE_CXX_COMPILER
get_filename_component(CLANG_CIPD_TOOLCHAIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY CACHE)
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} ${CLANG_CIPD_TOOLCHAIN_DIR}/../lib/libc++.a")
endif(APPLE)
if(UNIX)
find_package(PkgConfig)
find_package(ZLIB)
if(BLOATY_ENABLE_RE2)
pkg_search_module(RE2 re2)
endif()
pkg_search_module(CAPSTONE capstone)
# Always use bundled protobuf, to accommodate building for other systems
# without protobuf installed.
# pkg_search_module(PROTOBUF protobuf)
if(BLOATY_ENABLE_RE2)
if(RE2_FOUND)
MESSAGE(STATUS "System re2 found, using")
else()
MESSAGE(STATUS "System re2 not found, using bundled version")
endif()
endif()
if(CAPSTONE_FOUND)
MESSAGE(STATUS "System capstone found, using")
else()
MESSAGE(STATUS "System capstone not found, using bundled version")
endif()
if(PROTOBUF_FOUND)
MESSAGE(STATUS "System protobuf found, using")
else()
MESSAGE(STATUS "System protobuf not found, using bundled version")
endif()
if (ZLIB_FOUND)
MESSAGE(STATUS "System zlib found, using")
else()
MESSAGE(STATUS "System zlib not found, using bundled version")
endif()
endif()
# Set default build type.
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
# Check out Git submodules.
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules")
execute_process (COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
# Add third_party libraries, disabling as much as we can of their builds.
add_definitions(-D_LIBCXXABI_FUNC_VIS=) # For Demumble.
if(BLOATY_ENABLE_RE2)
add_definitions(-DUSE_RE2)
endif()
# Set MSVC runtime before including thirdparty libraries
if(MSVC)
# Link also the runtime library statically so that MSVCR*.DLL is not required at runtime.
# https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
# This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (flag_var MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach()
endif()
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
if(UNIX)
if(BLOATY_ENABLE_RE2)
if(RE2_FOUND)
include_directories(${RE2_INCLUDE_DIRS})
else()
set(RE2_BUILD_TESTING OFF CACHE BOOL "enable testing for RE2" FORCE)
add_subdirectory(third_party/re2)
include_directories(third_party/re2)
endif()
endif()
if(CAPSTONE_FOUND)
include_directories(${CAPSTONE_INCLUDE_DIRS})
else()
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE)
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
add_subdirectory(third_party/capstone)
include_directories(third_party/capstone/include)
endif()
if(PROTOBUF_FOUND)
include_directories(${PROTOBUF_INCLUDE_DIRS})
else()
set(protobuf_BUILD_TESTS OFF CACHE BOOL "enable tests for proto2" FORCE)
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "enable shared libs for proto2" FORCE)
add_subdirectory(third_party/protobuf/cmake)
include_directories(SYSTEM third_party/protobuf/src)
endif()
if(NOT ZLIB_FOUND)
add_subdirectory(third_party/zlib)
include_directories(third_party/zlib)
endif()
else()
if(BLOATY_ENABLE_RE2)
set(RE2_BUILD_TESTING OFF CACHE BOOL "enable testing for RE2" FORCE)
add_subdirectory(third_party/re2)
include_directories(third_party/re2)
set_property(TARGET re2 PROPERTY FOLDER "third_party")
endif()
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE)
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
add_subdirectory(third_party/capstone)
include_directories(third_party/capstone/include)
set_property(TARGET capstone-static PROPERTY FOLDER "third_party")
set(protobuf_BUILD_TESTS OFF CACHE BOOL "enable tests for proto2" FORCE)
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "enable shared libs for proto2" FORCE)
add_subdirectory(third_party/protobuf/cmake)
include_directories(SYSTEM third_party/protobuf/src)
add_subdirectory(third_party/zlib)
include_directories(third_party/zlib)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib)
set_property(TARGET example PROPERTY FOLDER "third_party")
set_property(TARGET minigzip PROPERTY FOLDER "third_party")
set_property(TARGET zlib PROPERTY FOLDER "third_party")
set_property(TARGET zlibstatic PROPERTY FOLDER "third_party")
set_property(TARGET libprotobuf PROPERTY FOLDER "third_party")
set_property(TARGET libprotobuf-lite PROPERTY FOLDER "third_party")
set_property(TARGET libprotoc PROPERTY FOLDER "third_party")
set_property(TARGET protoc PROPERTY FOLDER "third_party")
endif()
include_directories(.)
include_directories(src)
include_directories(third_party/abseil-cpp)
include_directories(third_party/rustc-demangle/crates/capi/include)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/src")
# Baseline build flags.
if(MSVC)
set(CMAKE_CXX_FLAGS "/EHsc /wd4018 /D_CRT_SECURE_NO_WARNINGS /DNOMINMAX")
else()
set(CMAKE_CXX_FLAGS "-std=c++17 -W -Wall -Wno-sign-compare")
set(CMAKE_CXX_FLAGS_DEBUG "-g1")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g1")
set_source_files_properties(third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough)
endif()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions -ffunction-sections -fdata-sections")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -ffunction-sections -fdata-sections")
if (APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
endif()
if(APPLE)
elseif(UNIX)
if(BLOATY_ENABLE_BUILDID)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id")
endif()
endif()
# When using Ninja, compiler output won't be colorized without this.
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(-fdiagnostics-color=always SUPPORTS_COLOR_ALWAYS)
if(SUPPORTS_COLOR_ALWAYS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
endif()
# Implement ASAN/UBSAN options
if(BLOATY_ENABLE_ASAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address")
endif()
if(BLOATY_ENABLE_UBSAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=undefined")
endif()
if(DEFINED ENV{CXXFLAGS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{CXXFLAGS}")
endif()
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/src)
if(PROTOC_FOUND)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/bloaty.pb.cc
DEPENDS protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/bloaty.proto
COMMAND protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/bloaty.proto
--cpp_out=${CMAKE_CURRENT_BINARY_DIR}/src
-I${CMAKE_CURRENT_SOURCE_DIR}/src
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/report.pb.cc
DEPENDS protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/report.proto
COMMAND protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/report.proto
--cpp_out=${CMAKE_CURRENT_BINARY_DIR}/src
-I${CMAKE_CURRENT_SOURCE_DIR}/src
)
else()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/bloaty.pb.cc
COMMAND protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/bloaty.proto
--cpp_out=${CMAKE_CURRENT_BINARY_DIR}/src
-I${CMAKE_CURRENT_SOURCE_DIR}/src
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/report.pb.cc
COMMAND protoc ${CMAKE_CURRENT_SOURCE_DIR}/src/report.proto
--cpp_out=${CMAKE_CURRENT_BINARY_DIR}/src
-I${CMAKE_CURRENT_SOURCE_DIR}/src
)
endif()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/bloaty_package.bloaty
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_library(libbloaty STATIC
src/bloaty.cc
src/bloaty.h
src/disassemble.cc
${CMAKE_CURRENT_BINARY_DIR}/src/bloaty.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/src/report.pb.cc
src/dwarf.cc
src/dwarf_constants.h
src/elf.cc
src/link_map.cc
src/macho.cc
src/pe.cc
third_party/lief_pe/pe_structures.h
src/range_map.cc
src/range_map.h
src/re.h
src/util.cc
src/util.h
src/webassembly.cc
src/write_bloaty_report.cc
# Until Abseil has a proper CMake build system
third_party/abseil-cpp/absl/base/internal/raw_logging.cc # Grrrr...
third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
third_party/abseil-cpp/absl/debugging/internal/demangle.cc
third_party/abseil-cpp/absl/numeric/int128.cc
third_party/abseil-cpp/absl/strings/ascii.cc
third_party/abseil-cpp/absl/strings/charconv.cc
third_party/abseil-cpp/absl/strings/escaping.cc
third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc
third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc
third_party/abseil-cpp/absl/strings/internal/escaping.cc
third_party/abseil-cpp/absl/strings/internal/memutil.cc
third_party/abseil-cpp/absl/strings/internal/utf8.cc
third_party/abseil-cpp/absl/strings/match.cc
third_party/abseil-cpp/absl/strings/numbers.cc
third_party/abseil-cpp/absl/strings/str_cat.cc
third_party/abseil-cpp/absl/strings/string_view.cc
third_party/abseil-cpp/absl/strings/str_split.cc
third_party/abseil-cpp/absl/strings/substitute.cc
third_party/abseil-cpp/absl/types/bad_optional_access.cc
# One source file, no special build system needed.
third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp
)
set_property(TARGET libbloaty PROPERTY FOLDER "bloaty")
# Teach CMake how to build rustc-demangle
# RUST_TOOLCHAIN_PREFIX is the directory containing the `cargo` executable.
if(NOT RUST_TOOLCHAIN_PREFIX)
find_program(CARGO_PATH cargo)
if(CARGO_PATH)
message(STATUS "Found cargo: ${CARGO_PATH}")
else()
set(HAVE_GMSH NO)
message(FATAL_ERROR "cargo not found. Please specify RUST_TOOLCHAIN_PREFIX")
endif()
else()
set(CARGO_PATH ${RUST_TOOLCHAIN_PREFIX}/cargo CACHE FILEPATH "Path to the cargo executable")
endif()
file(
GLOB_RECURSE
RUSTC_DEMANGLE_SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/*.rs"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/*.toml"
)
if(NOT APPLE)
# Rust uses libunwind, and embeds the libunwind runtime inside any static
# library produced from the build.
# Bloaty uses C++ exceptions to trigger failure. Use of C++ exceptions also
# requires libunwind, but specifically the version coming with GCC/Clang.
# Their interaction causes strange failures when compiled using GCC 9.3.
# To fix this, take out the unwind-related members from the Rust static lib.
set(RUSTC_DEMANGLE_FIXUP_ARCHIVE ar d target/release/librustc_demangle.a Unwind-EHABI.o Unwind-seh.o Unwind-sjlj.o UnwindLevel1-gcc-ext.o UnwindLevel1.o UnwindRegistersRestore.o UnwindRegistersSave.o libunwind.o)
else()
# On macOS, there doesn't appear to be such problem.
set(RUSTC_DEMANGLE_FIXUP_ARCHIVE "")
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/target/release/librustc_demangle.a
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/Cargo.toml
DEPENDS ${RUSTC_DEMANGLE_SRC_FILES}
COMMAND ${CARGO_PATH} build -p rustc-demangle-capi --release
COMMAND ${RUSTC_DEMANGLE_FIXUP_ARCHIVE}
)
add_custom_target(
rustc-demangle-lib
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/target/release/librustc_demangle.a
)
add_dependencies(libbloaty rustc-demangle-lib)
if(UNIX)
set(LIBBLOATY_LIBS libbloaty)
if(PROTOBUF_FOUND)
list(APPEND LIBBLOATY_LIBS ${PROTOBUF_LIBRARIES})
else()
list(APPEND LIBBLOATY_LIBS libprotoc)
endif()
if(BLOATY_ENABLE_RE2)
if(RE2_FOUND)
list(APPEND LIBBLOATY_LIBS ${RE2_LIBRARIES})
else()
list(APPEND LIBBLOATY_LIBS re2)
endif()
endif()
if(CAPSTONE_FOUND)
list(APPEND LIBBLOATY_LIBS ${CAPSTONE_LIBRARIES})
else()
list(APPEND LIBBLOATY_LIBS capstone-static)
endif()
if(ZLIB_FOUND)
list(APPEND LIBBLOATY_LIBS ZLIB::ZLIB)
else()
list(APPEND LIBBLOATY_LIBS zlib)
endif()
set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/target/release/librustc_demangle.a" dl)
else()
set(LIBBLOATY_LIBS libbloaty libprotoc capstone-static "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rustc-demangle/target/release/librustc_demangle.a" dl)
if(BLOATY_ENABLE_RE2)
list(APPEND LIBBLOATY_LIBS re2)
endif()
list(APPEND LIBBLOATY_LIBS zlibstatic)
endif()
if(UNIX)
if(BLOATY_ENABLE_RE2)
if(RE2_FOUND)
link_directories(${RE2_LIBRARY_DIRS})
endif()
endif()
if(CAPSTONE_FOUND)
link_directories(${CAPSTONE_LIBRARY_DIRS})
endif()
if(PROTOBUF_FOUND)
link_directories(${PROTOBUF_LIBRARY_DIRS})
endif()
endif()
list(APPEND LIBBLOATY_LIBS Threads::Threads)
if(DEFINED ENV{LIB_FUZZING_ENGINE})
message("LIB_FUZZING_ENGINE set, building fuzz_target instead of Bloaty")
add_executable(fuzz_target tests/fuzz_target.cc)
target_link_libraries(fuzz_target ${LIBBLOATY_LIBS} $ENV{LIB_FUZZING_ENGINE})
else()
include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
add_executable(bloaty src/main.cc)
target_link_libraries(bloaty ${LIBBLOATY_LIBS})
if(ipo_supported)
message(STATUS "IPO / LTO enabled")
set_property(TARGET bloaty PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
message(STATUS "IPO / LTO not supported: <${ipo_error}>")
endif()
# All of this is to add -pthread, which is required by re2 (not us).
find_package(Threads REQUIRED)
if(THREADS_HAVE_PTHREAD_ARG)
set_property(TARGET bloaty PROPERTY COMPILE_OPTIONS "-pthread")
set_property(TARGET bloaty PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread")
endif()
if(CMAKE_THREAD_LIBS_INIT)
target_link_libraries(bloaty "${CMAKE_THREAD_LIBS_INIT}")
endif()
set_property(TARGET bloaty PROPERTY FOLDER "bloaty")
if(BLOATY_ENABLE_CMAKETARGETS)
install(
TARGETS bloaty
EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION bin
)
else()
install(
TARGETS bloaty
RUNTIME DESTINATION bin
)
endif()
if (IS_DIRECTORY "${PROJECT_SOURCE_DIR}/tests")
enable_testing()
if(BUILD_TESTING)
option(INSTALL_GTEST "" OFF)
add_subdirectory(third_party/googletest)
include_directories(third_party/googletest/googletest/include)
include_directories(third_party/googletest/googlemock/include)
set(TEST_TARGETS
bloaty_test
bloaty_report_test
bloaty_test_pe
bloaty_misc_test
link_map_test
range_map_test
)
foreach(target ${TEST_TARGETS})
add_executable(${target} tests/${target}.cc)
target_link_libraries(${target} ${LIBBLOATY_LIBS} gtest_main gmock)
set_property(TARGET ${target} PROPERTY FOLDER "tests")
endforeach(target)
add_executable(fuzz_test tests/fuzz_target.cc tests/fuzz_driver.cc)
target_link_libraries(fuzz_test ${LIBBLOATY_LIBS})
set_property(TARGET fuzz_test PROPERTY FOLDER "tests")
foreach(testlib gmock gmock_main gtest gtest_main)
set_property(TARGET ${testlib} PROPERTY FOLDER "tests/libs")
endforeach(testlib)
file(GLOB fuzz_corpus tests/testdata/fuzz_corpus/*)
add_test(NAME link_map_test COMMAND link_map_test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/link_map)
add_test(NAME range_map_test COMMAND range_map_test)
add_test(NAME bloaty_test_x86-64 COMMAND bloaty_test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/linux-x86_64)
add_test(NAME bloaty_test_x86 COMMAND bloaty_test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/linux-x86)
add_test(NAME bloaty_report_test_x86-64 COMMAND bloaty_report_test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/linux-x86_64)
add_test(NAME bloaty_test_pe_x64 COMMAND bloaty_test_pe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/PE/x64)
add_test(NAME bloaty_test_pe_x86 COMMAND bloaty_test_pe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/PE/x86)
add_test(NAME bloaty_misc_test COMMAND bloaty_misc_test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/misc)
add_test(NAME fuzz_test COMMAND fuzz_test ${fuzz_corpus} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata/fuzz_corpus)
endif()
endif()
if(BLOATY_ENABLE_CMAKETARGETS)
install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})
endif()
endif()