426 lines
15 KiB
CMake
426 lines
15 KiB
CMake
# cmake configuration
|
|
cmake_minimum_required(VERSION 3.9...3.19)
|
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
|
message(FATAL_ERROR
|
|
"In-tree builds are not supported; please perform an out-of-tree build:\n"
|
|
" rm -rf CMakeCache.txt CMakeFiles/\n"
|
|
" mkdir build && cd build && cmake ..")
|
|
endif()
|
|
|
|
list(APPEND CMAKE_MODULE_PATH
|
|
"${CMAKE_SOURCE_DIR}/cmake/")
|
|
|
|
set(CMAKE_CXX_STANDARD 11)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
|
|
|
# for /MT on MSVC
|
|
set(CMAKE_USER_MAKE_RULES_OVERRIDE
|
|
"${CMAKE_SOURCE_DIR}/cmake/c_flag_overrides.cmake")
|
|
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
|
|
"${CMAKE_SOURCE_DIR}/cmake/cxx_flag_overrides.cmake")
|
|
|
|
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
|
endif()
|
|
|
|
if (APPLE)
|
|
# Docs say this must be set before the first project() call
|
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "macOS minimum supported version")
|
|
endif()
|
|
|
|
# project
|
|
|
|
# NOTE TO PACKAGERS: The embedded git commit hash is critical for rapid bug triage when the builds
|
|
# can come from a variety of sources. If you are mirroring the sources or otherwise build when
|
|
# the .git directory is not present, please comment the following line:
|
|
include(GetGitCommitHash)
|
|
# and instead uncomment the following, adding the complete git hash of the checkout you are using:
|
|
# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000)
|
|
|
|
string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH)
|
|
project(solvespace
|
|
VERSION 3.1
|
|
LANGUAGES C CXX ASM)
|
|
|
|
set(ENABLE_GUI ON CACHE BOOL
|
|
"Whether the graphical interface is enabled")
|
|
set(ENABLE_CLI ON CACHE BOOL
|
|
"Whether the command line interface is enabled")
|
|
set(ENABLE_TESTS ON CACHE BOOL
|
|
"Whether the test suite will be built and run")
|
|
set(ENABLE_COVERAGE OFF CACHE BOOL
|
|
"Whether code coverage information will be collected")
|
|
set(ENABLE_SANITIZERS OFF CACHE BOOL
|
|
"Whether to enable Clang's AddressSanitizer and UndefinedBehaviorSanitizer")
|
|
set(ENABLE_OPENMP OFF CACHE BOOL
|
|
"Whether geometric operations will be parallelized using OpenMP")
|
|
set(ENABLE_LTO OFF CACHE BOOL
|
|
"Whether interprocedural (global) optimizations are enabled")
|
|
option(FORCE_VENDORED_Eigen3
|
|
"Whether we should use our bundled Eigen even in the presence of a system copy"
|
|
OFF)
|
|
|
|
set(OPENGL 3 CACHE STRING "OpenGL version to use (one of: 1 3)")
|
|
|
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
|
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
|
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/bin>)
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
|
# GCC 4.8/4.9 ship with broken but present <regex>. meh.
|
|
message(FATAL_ERROR "GCC 5.0+ is required")
|
|
endif()
|
|
endif()
|
|
|
|
# common compiler flags
|
|
include(CheckCXXCompilerFlag)
|
|
|
|
if (NOT APPLE)
|
|
set(FILE_PREFIX_MAP "-ffile-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.")
|
|
check_cxx_compiler_flag("${FILE_PREFIX_MAP}" HAS_FILE_PREFIX_MAP)
|
|
if(HAS_FILE_PREFIX_MAP)
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FILE_PREFIX_MAP}")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FILE_PREFIX_MAP}")
|
|
endif()
|
|
endif()
|
|
|
|
if(MINGW)
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
|
endif()
|
|
|
|
# Ensure that all platforms use 64-bit IEEE floating point operations for consistency;
|
|
# this is most important for the testsuite, which compares savefiles directly
|
|
# and depends on consistent rounding of intermediate results.
|
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X86")
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|
set(FLOAT_FLAGS "-mfpmath=sse -msse2")
|
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
set(FLOAT_FLAGS "-msse2")
|
|
endif()
|
|
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLOAT_FLAGS}")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLOAT_FLAGS}")
|
|
endif()
|
|
|
|
if(ENABLE_LTO)
|
|
include(CheckIPOSupported)
|
|
check_ipo_supported()
|
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
endif()
|
|
|
|
if(ENABLE_OPENMP)
|
|
find_package( OpenMP REQUIRED )
|
|
if(OPENMP_FOUND)
|
|
add_library(slvs_openmp INTERFACE)
|
|
target_compile_options(slvs_openmp INTERFACE ${OpenMP_CXX_FLAGS})
|
|
target_link_libraries(slvs_openmp INTERFACE
|
|
${OpenMP_CXX_LIBRARIES})
|
|
target_include_directories(slvs_openmp INTERFACE SYSTEM
|
|
${OpenMP_CXX_INCLUDE_DIRS})
|
|
message(STATUS "found OpenMP, compiling with flags: " ${OpenMP_CXX_FLAGS} )
|
|
endif()
|
|
endif()
|
|
|
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}")
|
|
endif()
|
|
|
|
if(ENABLE_SANITIZERS)
|
|
if(NOT SANITIZERS)
|
|
set(SANITIZERS "address;undefined")
|
|
endif()
|
|
|
|
if("thread" IN_LIST SANITIZERS)
|
|
list(REMOVE_ITEM SANITIZERS "thread")
|
|
list(APPEND SANITIZE_OPTIONS thread)
|
|
endif()
|
|
if("address" IN_LIST SANITIZERS)
|
|
list(REMOVE_ITEM SANITIZERS "address")
|
|
list(APPEND SANITIZE_OPTIONS address)
|
|
endif()
|
|
if("undefined" IN_LIST SANITIZERS)
|
|
list(REMOVE_ITEM SANITIZERS "undefined")
|
|
list(APPEND SANITIZE_OPTIONS alignment bounds)
|
|
list(APPEND SANITIZE_OPTIONS shift signed-integer-overflow integer-divide-by-zero)
|
|
list(APPEND SANITIZE_OPTIONS null bool enum)
|
|
list(APPEND SANITIZE_OPTIONS return)
|
|
endif()
|
|
if(SANITIZERS)
|
|
message(FATAL_ERROR "Unknown sanitizer(s) ${SANITIZERS}")
|
|
else()
|
|
message(STATUS "Using sanitizer options ${SANITIZE_OPTIONS}")
|
|
endif()
|
|
|
|
string(REPLACE ";" "," SANITIZE_OPTIONS "${SANITIZE_OPTIONS}")
|
|
|
|
if (NOT APPLE)
|
|
set(SANITIZE_FLAGS "-O1 -fsanitize=${SANITIZE_OPTIONS} -fno-sanitize-recover=address,undefined")
|
|
else()
|
|
set(SANITIZE_FLAGS "-O1 -fsanitize=${SANITIZE_OPTIONS}")
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
|
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fuse-ld=gold")
|
|
else()
|
|
message(FATAL_ERROR "Sanitizers are only available when using GCC or Clang")
|
|
endif()
|
|
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}")
|
|
endif()
|
|
|
|
# common dependencies
|
|
|
|
if(APPLE)
|
|
set(CMAKE_FIND_FRAMEWORK LAST)
|
|
endif()
|
|
|
|
message(STATUS "Using in-tree libdxfrw")
|
|
add_subdirectory(extlib/libdxfrw)
|
|
|
|
message(STATUS "Using in-tree mimalloc")
|
|
set(MI_OVERRIDE OFF CACHE BOOL "")
|
|
set(MI_BUILD_SHARED OFF CACHE BOOL "")
|
|
set(MI_BUILD_OBJECT OFF CACHE BOOL "")
|
|
set(MI_BUILD_TESTS OFF CACHE BOOL "")
|
|
add_subdirectory(extlib/mimalloc EXCLUDE_FROM_ALL)
|
|
set(MIMALLOC_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/extlib/mimalloc/include)
|
|
|
|
if(NOT FORCE_VENDORED_Eigen3)
|
|
find_package(Eigen3 CONFIG)
|
|
endif()
|
|
if(FORCE_VENDORED_Eigen3 OR NOT EIGEN3_INCLUDE_DIRS)
|
|
message(STATUS "Using in-tree Eigen")
|
|
set(EIGEN3_FOUND YES)
|
|
set(EIGEN3_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extlib/eigen)
|
|
else()
|
|
message(STATUS "Using system Eigen: ${EIGEN3_INCLUDE_DIRS}")
|
|
endif()
|
|
if(NOT EXISTS "${EIGEN3_INCLUDE_DIRS}")
|
|
message(FATAL_ERROR "Eigen 3 not found on system or in-tree")
|
|
endif()
|
|
|
|
|
|
if(WIN32 OR APPLE)
|
|
# On Win32 and macOS we use vendored packages, since there is little to no benefit
|
|
# to trying to find system versions. In particular, trying to link to libraries from
|
|
# Homebrew or macOS system libraries into the .app file is highly likely to result
|
|
# in incompatibilities after upgrades.
|
|
|
|
include(FindVendoredPackage)
|
|
include(AddVendoredSubdirectory)
|
|
|
|
set(FORCE_VENDORED_ZLIB ON)
|
|
set(FORCE_VENDORED_PNG ON)
|
|
set(FORCE_VENDORED_Freetype ON)
|
|
|
|
find_vendored_package(ZLIB zlib
|
|
ZLIB_LIBRARY zlibstatic
|
|
ZLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/extlib/zlib)
|
|
list(APPEND ZLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR}/extlib/zlib)
|
|
|
|
find_vendored_package(PNG libpng
|
|
SKIP_INSTALL_ALL ON
|
|
PNG_LIBRARY png_static
|
|
PNG_ARM_NEON "off"
|
|
PNG_SHARED OFF
|
|
PNG_STATIC ON
|
|
PNG_EXECUTABLES OFF
|
|
PNG_TESTS OFF
|
|
PNG_FRAMEWORK OFF
|
|
PNG_PNG_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/extlib/libpng)
|
|
list(APPEND PNG_PNG_INCLUDE_DIR ${CMAKE_BINARY_DIR}/extlib/libpng)
|
|
|
|
find_vendored_package(Freetype freetype
|
|
WITH_ZLIB OFF
|
|
WITH_BZip2 OFF
|
|
WITH_PNG OFF
|
|
WITH_HarfBuzz OFF
|
|
FREETYPE_LIBRARY freetype
|
|
FREETYPE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extlib/freetype/include)
|
|
|
|
message(STATUS "Using in-tree pixman")
|
|
set(PIXMAN_FOUND YES)
|
|
set(PIXMAN_LIBRARY pixman)
|
|
set(PIXMAN_BUILD_TESTS OFF CACHE BOOL "")
|
|
set(PIXMAN_BUILD_DEMOS OFF CACHE BOOL "")
|
|
|
|
set(PIXMAN_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extlib/pixman/pixman)
|
|
list(APPEND PIXMAN_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/extlib/pixman/pixman)
|
|
add_vendored_subdirectory(extlib/pixman)
|
|
|
|
message(STATUS "Using in-tree cairo")
|
|
add_vendored_subdirectory(extlib/cairo)
|
|
set(CAIRO_FOUND YES)
|
|
set(CAIRO_LIBRARIES cairo)
|
|
set(CAIRO_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extlib/cairo/src)
|
|
list(APPEND CAIRO_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/extlib/cairo/src)
|
|
else()
|
|
# On Linux and BSDs we're a good citizen and link to system libraries.
|
|
find_package(Backtrace)
|
|
find_package(PkgConfig REQUIRED)
|
|
find_package(ZLIB REQUIRED)
|
|
find_package(PNG REQUIRED)
|
|
find_package(Freetype REQUIRED)
|
|
pkg_check_modules(CAIRO REQUIRED cairo)
|
|
endif()
|
|
|
|
# GUI dependencies
|
|
|
|
if(ENABLE_GUI)
|
|
if(WIN32)
|
|
if(OPENGL STREQUAL "3")
|
|
message(STATUS "Using in-tree ANGLE")
|
|
set(ANGLE_STATIC ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_D3D9 ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_D3D11 ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_OPENGL ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_ESSL ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_GLSL ON CACHE INTERNAL "")
|
|
set(ANGLE_ENABLE_HLSL ON CACHE INTERNAL "")
|
|
add_vendored_subdirectory(extlib/angle)
|
|
set(OPENGL_LIBRARIES EGL GLESv2)
|
|
set(OPENGL_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/extlib/angle/include)
|
|
else()
|
|
find_package(OpenGL REQUIRED)
|
|
endif()
|
|
|
|
if(MSVC AND ${CMAKE_SIZEOF_VOID_P} EQUAL 4)
|
|
message(STATUS "Using prebuilt SpaceWare")
|
|
set(SPACEWARE_FOUND TRUE)
|
|
set(SPACEWARE_INCLUDE_DIR
|
|
"${CMAKE_SOURCE_DIR}/extlib/si")
|
|
set(SPACEWARE_LIBRARIES
|
|
"${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib")
|
|
endif()
|
|
elseif(APPLE)
|
|
find_package(OpenGL REQUIRED)
|
|
find_library(APPKIT_LIBRARY AppKit REQUIRED)
|
|
else()
|
|
find_package(OpenGL REQUIRED)
|
|
find_package(SpaceWare)
|
|
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
|
|
pkg_check_modules(JSONC REQUIRED json-c)
|
|
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0>=3.18 pangomm-1.4 x11)
|
|
endif()
|
|
endif()
|
|
|
|
# code coverage
|
|
|
|
if(ENABLE_COVERAGE)
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
|
find_program(GCOV gcov)
|
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
|
find_program(LLVM_COV llvm-cov)
|
|
|
|
if(LLVM_COV)
|
|
set(GCOV ${CMAKE_CURRENT_BINARY_DIR}/llvm-gcov.sh)
|
|
file(WRITE ${GCOV} "#!/bin/sh -e\n${LLVM_COV} gcov $*")
|
|
execute_process(COMMAND chmod +x ${GCOV})
|
|
endif()
|
|
endif()
|
|
|
|
find_program(LCOV lcov)
|
|
find_program(GENHTML genhtml)
|
|
if(NOT GCOV OR NOT LCOV OR NOT GENHTML)
|
|
message(FATAL_ERROR "gcov/llvm-cov and lcov are required for producing coverage reports")
|
|
endif()
|
|
endif()
|
|
|
|
# translations
|
|
|
|
find_program(XGETTEXT xgettext)
|
|
find_program(MSGINIT msginit)
|
|
find_program(MSGMERGE msgmerge)
|
|
if(XGETTEXT AND MSGINIT AND MSGMERGE)
|
|
set(HAVE_GETTEXT TRUE)
|
|
else()
|
|
message(WARNING "Gettext not found, translations will not be updated")
|
|
set(HAVE_GETTEXT FALSE)
|
|
endif()
|
|
|
|
# solvespace-only compiler flags
|
|
|
|
if(WIN32)
|
|
add_definitions(
|
|
-D_CRT_SECURE_NO_DEPRECATE
|
|
-D_CRT_SECURE_NO_WARNINGS
|
|
-D_SCL_SECURE_NO_WARNINGS
|
|
-DWINVER=0x0501
|
|
-D_WIN32_WINNT=0x0501
|
|
-D_WIN32_IE=_WIN32_WINNT
|
|
-DISOLATION_AWARE_ENABLED
|
|
-DWIN32
|
|
-DWIN32_LEAN_AND_MEAN
|
|
-DUNICODE
|
|
-D_UNICODE
|
|
-DNOMINMAX
|
|
-D_USE_MATH_DEFINES)
|
|
endif()
|
|
|
|
if(MSVC)
|
|
# Many versions of MSVC do not have the (C99) inline keyword, instead
|
|
# they have their own __inline; this breaks `static inline` functions.
|
|
# We do not want to care and so we fix this with a definition.
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
|
|
# Same for the (C99) __func__ special variable; we use it only in C++ code.
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D__func__=__FUNCTION__")
|
|
|
|
# We rely on these /we flags. They correspond to the GNU-style flags below as
|
|
# follows: /w4062=-Wswitch
|
|
set(WARNING_FLAGS "${WARNING_FLAGS} /we4062")
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
set(WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
set(WARNING_FLAGS "${WARNING_FLAGS} -Wfloat-conversion")
|
|
endif()
|
|
# We rely on these -Werror flags.
|
|
set(WARNING_FLAGS "${WARNING_FLAGS} -Werror=switch")
|
|
endif()
|
|
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
|
|
|
if(WIN32)
|
|
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -l0")
|
|
endif()
|
|
|
|
if(ENABLE_COVERAGE)
|
|
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
|
|
CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
|
message(FATAL_ERROR "Code coverage is only available on GCC and Clang")
|
|
endif()
|
|
|
|
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
message(FATAL_ERROR "Code coverage produces reliable results only on Debug builds")
|
|
endif()
|
|
|
|
# With -fexceptions, every call becomes a branch. While technically accurate,
|
|
# this is not useful for us.
|
|
set(COVERAGE_FLAGS -fno-exceptions --coverage)
|
|
set(COVERAGE_LIBRARY --coverage)
|
|
endif()
|
|
|
|
# application components
|
|
|
|
add_subdirectory(res)
|
|
add_subdirectory(src)
|
|
add_subdirectory(exposed)
|
|
if(ENABLE_TESTS)
|
|
add_subdirectory(test)
|
|
endif()
|
|
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
|
add_subdirectory(bench)
|
|
else()
|
|
message(STATUS "Benchmarking disabled in debug builds.")
|
|
endif()
|