362 lines
13 KiB
CMake
362 lines
13 KiB
CMake
# Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
|
|
|
|
cmake_minimum_required(VERSION 3.15.0)
|
|
|
|
if (APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL 4.0.0 AND NOT CMAKE_OSX_SYSROOT)
|
|
# We are going to need having CMAKE_OSX_SYSROOT point to the macOS SDK
|
|
# path. However, starting with CMake 4.0, CMAKE_OSX_SYSROOT is not set
|
|
# automatically anymore. So we follow the guidance from the CMake 4.0
|
|
# release notes here:
|
|
#
|
|
# Builds targeting macOS no longer choose any SDK or pass an "-isysroot"
|
|
# flag to the compiler by default. Instead, compilers are expected to
|
|
# choose a default macOS SDK on their own. In order to use a compiler
|
|
# that does not do this, users must now specify
|
|
# "-DCMAKE_OSX_SYSROOT=macosx" when configuring their build.
|
|
#
|
|
# The described situation ("let the compiler choose") doesn't quite match
|
|
# ours, but this does lead to CMAKE_OSX_SYSROOT pointing to the macOS SDK
|
|
# path when we need it.
|
|
set(CMAKE_OSX_SYSROOT "macosx")
|
|
endif ()
|
|
|
|
project(spicy LANGUAGES C CXX)
|
|
|
|
set(flex_minimum_version "2.5.37")
|
|
set(bison_minimum_version "3.0")
|
|
set(macos_minimum_version "19.0.0") # macOS 10.15.0 (Catalina)
|
|
|
|
## Initialize defaults & global options
|
|
|
|
if (NOT CMAKE_BUILD_TYPE)
|
|
# CMake doesn't set build type by default.
|
|
set(CMAKE_BUILD_TYPE "Debug")
|
|
endif ()
|
|
|
|
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
|
|
|
include(Util)
|
|
|
|
set(CMAKE_CXX_STANDARD 17)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
|
|
# CMake uses -O2 by default with RelWithDebInfo.
|
|
string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
|
|
|
include(CheckCompiler)
|
|
|
|
include(GNUInstallDirs)
|
|
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
|
|
endif ()
|
|
|
|
if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
|
endif ()
|
|
|
|
if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
|
endif ()
|
|
|
|
if (BINARY_PACKAGING_MODE)
|
|
# Binary packaging mode uses a static link which causes issues with
|
|
# unresolved symbols for a number of tests.
|
|
if (USE_SANITIZERS)
|
|
message(FATAL_ERROR "Sanitizers are unsupported in binary packaging mode")
|
|
endif ()
|
|
|
|
set(BUILD_SHARED_LIBS OFF)
|
|
set(CMAKE_SKIP_RPATH ON)
|
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF)
|
|
set(CMAKE_MACOSX_RPATH OFF)
|
|
else ()
|
|
make_install_rpath(rpath ${CMAKE_INSTALL_FULL_BINDIR} ${CMAKE_INSTALL_FULL_LIBDIR})
|
|
set(CMAKE_INSTALL_RPATH "${rpath}")
|
|
endif ()
|
|
|
|
if (USE_CCACHE)
|
|
find_program(CCACHE_PROGRAM ccache)
|
|
if (CCACHE_PROGRAM)
|
|
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
|
|
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
|
|
else ()
|
|
set(USE_CCACHE "no (error: could not find ccache)")
|
|
endif ()
|
|
else ()
|
|
set(USE_CCACHE "no")
|
|
endif ()
|
|
|
|
if (USE_SANITIZERS)
|
|
# Recommended flags per https://github.com/google/sanitizers/wiki/AddressSanitizer
|
|
set(sanitizer_cxx_flags
|
|
"-fsanitize=${USE_SANITIZERS} -fno-omit-frame-pointer -fno-optimize-sibling-calls -O1")
|
|
set(sanitizer_ld_flags "-fsanitize=${USE_SANITIZERS}")
|
|
|
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
set(sanitizer_cxx_flags "${sanitizer_cxx_flags} -shared-libasan")
|
|
set(sanitizer_ld_flags "${sanitizer_ld_flags} -frtlib-add-rpath -shared-libasan")
|
|
endif ()
|
|
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${sanitizer_cxx_flags}")
|
|
set(EXTRA_CXX_FLAGS "${EXTRA_CXX_FLAGS} ${sanitizer_cxx_flags}")
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${sanitizer_ld_flags}")
|
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${sanitizer_ld_flags}")
|
|
set(EXTRA_LD_FLAGS "${EXTRA_LD_FLAGS} ${sanitizer_ld_flags}")
|
|
|
|
set(HILTI_DEV_PRECOMPILE_HEADERS "no")
|
|
endif ()
|
|
|
|
if (USE_WERROR)
|
|
set(werror_flags "-Werror")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${werror_flags}")
|
|
set(EXTRA_CXX_FLAGS "${EXTRA_CXX_FLAGS} ${werror_flags}")
|
|
endif ()
|
|
|
|
## Load modules
|
|
|
|
# If the user specified dedicated prefixes for Flex or Bison, look in these
|
|
# prefixes first. As the upstream modules do not support specifying these we
|
|
# inject them here by hand.
|
|
#
|
|
# The implementation relies on the fact that the `find_*` commands do not search
|
|
# again should the output variable already be set successfully. We first search
|
|
# for the artifacts with `NO_DEFAULT_PATH` and then later trigger the upstream
|
|
# `find_package` logic. With that any user-specified prefix takes precedence
|
|
# over what could be found in the default search locations.
|
|
if (FLEX_ROOT)
|
|
find_program(
|
|
FLEX_EXECUTABLE
|
|
NAMES flex win_flex
|
|
PATHS ${FLEX_ROOT}
|
|
PATH_SUFFIXES bin
|
|
NO_DEFAULT_PATH)
|
|
find_library(
|
|
FL_LIBRARY
|
|
NAMES fl
|
|
PATHS ${FLEX_ROOT}
|
|
PATH_SUFFIXES lib
|
|
NO_DEFAULT_PATH)
|
|
find_path(
|
|
FLEX_INCLUDE_DIR FlexLexer.h
|
|
PATHS ${FLEX_ROOT}
|
|
PATH_SUFFIXES include
|
|
NO_DEFAULT_PATH)
|
|
endif ()
|
|
|
|
if (BISON_ROOT)
|
|
find_program(
|
|
BISON_EXECUTABLE
|
|
NAMES bison win_bison
|
|
PATHS ${BISON_ROOT}
|
|
PATH_SUFFIXES bin
|
|
NO_DEFAULT_PATH)
|
|
endif ()
|
|
|
|
find_package(FLEX REQUIRED)
|
|
find_package(BISON REQUIRED)
|
|
find_package(ZLIB REQUIRED)
|
|
find_package(Backtrace)
|
|
|
|
if (Backtrace_FOUND AND NOT APPLE)
|
|
# On systems other than MacOS there's a libexecinfo that's not working for us:
|
|
# it seems to break when compiling without frame pointers so we disable it.
|
|
if ("${Backtrace_LIBRARY}" MATCHES "libexecinfo")
|
|
message(STATUS "Disabling backtrace because we found libexecinfo")
|
|
set(Backtrace_FOUND "no")
|
|
endif ()
|
|
endif ()
|
|
|
|
# Prettify output
|
|
if (Backtrace_FOUND)
|
|
set(HILTI_HAVE_BACKTRACE "yes")
|
|
else ()
|
|
set(HILTI_HAVE_BACKTRACE "no")
|
|
endif ()
|
|
|
|
if (APPLE)
|
|
set(MACOS_FOUND "yes")
|
|
require_version("macOS" MACOS_FOUND ${CMAKE_SYSTEM_VERSION} "${macos_minimum_version}" true)
|
|
endif ()
|
|
|
|
require_version("Flex" FLEX_FOUND FLEX_VERSION "${flex_minimum_version}" true)
|
|
require_version("Bison" BISON_FOUND BISON_VERSION "${bison_minimum_version}" true)
|
|
|
|
find_package(GoldLinker)
|
|
find_package(Threads)
|
|
|
|
option(BUILD_TOOLCHAIN "Build the Spicy compiler toolchain" ON)
|
|
|
|
if (BUILD_TOOLCHAIN)
|
|
set(HAVE_TOOLCHAIN yes)
|
|
else ()
|
|
set(HAVE_TOOLCHAIN no)
|
|
endif ()
|
|
|
|
set(HILTI_COMPILER_LAUNCHER "" CACHE STRING "C++ compiler launcher to use by default during JIT")
|
|
|
|
# Set up testing infrastructure.
|
|
enable_testing()
|
|
|
|
# Get project version.
|
|
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/VERSION SPICY_VERSION LIMIT_COUNT 1)
|
|
set(CMAKE_PROJECT_VERSION ${SPICY_VERSION})
|
|
|
|
# Get Spicy commit. If we cannot get the current commit (e.g., no .git
|
|
# directory present for release tarballs), this will leave SPICY_COMMIT unset.
|
|
execute_process(
|
|
COMMAND ${CMAKE_COMMAND} -E env GIT_DIR=${CMAKE_CURRENT_SOURCE_DIR}/.git git rev-parse --short
|
|
HEAD
|
|
OUTPUT_VARIABLE SPICY_COMMIT
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
ERROR_VARIABLE ignored)
|
|
|
|
string(REGEX MATCH "([0-9]*)\.([0-9]*)\.([0-9]*).*" _ ${CMAKE_PROJECT_VERSION})
|
|
math(EXPR SPICY_VERSION_NUMBER
|
|
"${CMAKE_MATCH_1} * 10000 + ${CMAKE_MATCH_2} * 100 + ${CMAKE_MATCH_3}")
|
|
|
|
if (NOT "${SPICY_COMMIT}" STREQUAL "")
|
|
set(SPICY_VERSION_LONG "${SPICY_VERSION} (${SPICY_COMMIT})")
|
|
else ()
|
|
set(SPICY_VERSION_LONG ${SPICY_VERSION})
|
|
endif ()
|
|
|
|
# Add subdirectories.
|
|
add_subdirectory(hilti)
|
|
add_subdirectory(spicy)
|
|
add_subdirectory(scripts)
|
|
add_subdirectory(3rdparty)
|
|
|
|
## Print build summary
|
|
string(TOUPPER ${CMAKE_BUILD_TYPE} BuildType)
|
|
|
|
string(STRIP "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BuildType}}" cflags)
|
|
string(STRIP "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BuildType}}" cxxflags)
|
|
|
|
# Precompiled headers.
|
|
|
|
option("HILTI_DEV_PRECOMPILE_HEADERS" "Precompile headers for developer tests" ON)
|
|
|
|
if (${HILTI_DEV_PRECOMPILE_HEADERS} AND TARGET hilti-config AND TARGET spicy-config)
|
|
# Precompile libhilti for use in JIT during development.
|
|
#
|
|
# We only use precompiled headers during JIT, but e.g., not to during
|
|
# compilation of Spicy itself. This gives us the benefits of JIT without
|
|
# e.g., making it harder for ccache to work during development. It also
|
|
# allows us to punt on some trickier cleanups of header files.
|
|
add_custom_command(
|
|
OUTPUT ${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libhilti.h
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libhilti.h.gch
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libhilti_debug.h
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libhilti_debug.h.gch
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libspicy.h
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libspicy.h.gch
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libspicy_debug.h
|
|
${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libspicy_debug.h.gch
|
|
COMMENT "Generating precompiled headers"
|
|
COMMAND ${CMAKE_COMMAND} -E env SPICY_CACHE=${PROJECT_BINARY_DIR}/cache/spicy
|
|
${PROJECT_SOURCE_DIR}/scripts/precompile-headers.sh --bindir ${CMAKE_BINARY_DIR}/bin
|
|
DEPENDS ${PROJECT_SOURCE_DIR}/scripts/precompile-headers.sh
|
|
${CMAKE_CURRENT_SOURCE_DIR}/hilti/runtime/include/libhilti.h
|
|
${CMAKE_CURRENT_SOURCE_DIR}/spicy/runtime/include/libspicy.h
|
|
hilti-config
|
|
spicy-config)
|
|
add_custom_target(precompiled-headers ALL COMMENT "Generating precompiled headers"
|
|
DEPENDS ${PROJECT_BINARY_DIR}/cache/spicy/precompiled_libhilti.h)
|
|
endif ()
|
|
|
|
# Global test target
|
|
add_custom_target(
|
|
check
|
|
COMMAND ctest --output-on-failure -C $<CONFIG>
|
|
DEPENDS tests
|
|
COMMENT "Running unit tests")
|
|
add_custom_target(tests DEPENDS hilti-tests spicy-tests COMMENT "Running unit tests")
|
|
|
|
# Packaging.
|
|
# Check tags the HEAD commit corresponds to. If we cannot get the current
|
|
# commit (e.g., no .git directory present for release tarballs), this will
|
|
# leave SPICY_TAGS unset which is fine for users working from tarballs.
|
|
execute_process(COMMAND git tag --points-at HEAD v* OUTPUT_VARIABLE SPICY_TAGS
|
|
ERROR_VARIABLE ignored)
|
|
|
|
if ("${SPICY_TAGS}" STREQUAL "")
|
|
# If the HEAD commit does not correspond to a tag it is not a release. Hide
|
|
# the version number in packaging artifacts so we can e.g., provide stable
|
|
# links to the latest version.
|
|
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-dev")
|
|
else ()
|
|
# If the HEAD commit corresponds to a tag it is a release and we expect a
|
|
# version number in packaging artifacts.
|
|
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}")
|
|
endif ()
|
|
|
|
set(CPACK_PACKAGE_CONTACT "info@zeek.org")
|
|
|
|
set(CPACK_STRIP_FILES ON)
|
|
set(CPACK_SOURCE_STRIP_FILES ON)
|
|
|
|
set(CPACK_BINARY_DEB OFF)
|
|
set(CPACK_BINARY_RPM OFF)
|
|
set(CPACK_BINARY_STGZ OFF)
|
|
set(CPACK_BINARY_TZ OFF)
|
|
set(CPACK_BINARY_TGZ ON)
|
|
|
|
find_program(RPMBUILD rpmbuild)
|
|
if (RPMBUILD)
|
|
set(CPACK_BINARY_RPM ON)
|
|
endif ()
|
|
|
|
find_program(DPKG_DEB dpkg-deb)
|
|
if (DPKG_DEB)
|
|
set(CPACK_BINARY_DEB ON)
|
|
endif ()
|
|
|
|
# While this should be sufficient to set a prefix for installation, we still
|
|
# bake in other absolute paths by using `CMAKE_INSTALL_FULL_*`-style variables,
|
|
# e.g., when baking details about the installation into binaries.
|
|
set(CPACK_SET_DESTDIR ON)
|
|
set(CPACK_INSTALL_PREFIX "/opt/spicy")
|
|
set(CPACK_PACKAGE_RELOCATABLE OFF)
|
|
|
|
include(CPack)
|
|
|
|
# Emit configuration summary.
|
|
|
|
set(SPICY_HOST_SYSTEM "${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_VERSION} (${CMAKE_SYSTEM_PROCESSOR})")
|
|
set(SPICY_C_COMPILER "${CMAKE_C_COMPILER} (${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION})")
|
|
set(SPICY_CXX_COMPILER
|
|
"${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION})")
|
|
|
|
message(
|
|
"\n====================| Spicy Build Summary |===================="
|
|
"\n"
|
|
"\nVersion: ${SPICY_VERSION_LONG}"
|
|
"\n"
|
|
"\nBuild type: ${CMAKE_BUILD_TYPE}"
|
|
"\nBuild directory: ${PROJECT_BINARY_DIR}"
|
|
"\nInstall prefix: ${CMAKE_INSTALL_PREFIX}"
|
|
"\nBuild shared libs: ${BUILD_SHARED_LIBS}"
|
|
"\n"
|
|
"\nHost system: ${SPICY_HOST_SYSTEM}"
|
|
"\nC compiler: ${SPICY_C_COMPILER}"
|
|
"\nC++ compiler: ${SPICY_CXX_COMPILER}"
|
|
"\n"
|
|
"\nBuilding toolchain: ${HAVE_TOOLCHAIN}"
|
|
"\n"
|
|
"\nUse ccache: ${USE_CCACHE}"
|
|
"\nUse gold linker: ${GOLD_FOUND}"
|
|
"\nUse sanitizers: ${USE_SANITIZERS}"
|
|
"\nUse backtrace: ${HILTI_HAVE_BACKTRACE}"
|
|
"\n"
|
|
"\nWarnings are errors: ${USE_WERROR}"
|
|
"\nPrecompile headers: ${HILTI_DEV_PRECOMPILE_HEADERS}"
|
|
"\n"
|
|
"\nBison version: ${BISON_VERSION}"
|
|
"\nCMake version: ${CMAKE_VERSION}"
|
|
"\nFlex version: ${FLEX_VERSION}"
|
|
"\nzlib version: ${ZLIB_VERSION_STRING}"
|
|
"\n"
|
|
"\n================================================================\n")
|