0ad/cmake/0ad-BuildFlags.cmake
Cayleb-Ordo dac1036c44 Add Root CMakeLists.txt and custom cmake modules
CMake is de facto the industrie standard for building C/C++ Code.
It is cross platform, supports presets and packaging for
Linux Distributions can be made with CPack. This also eliminates
the dependency to build and patch premake. Furthermore a lot of
IDE's are supported.

Add a BuildFlags CMake module with an INTERFACE library encapsulating
relevant build Flags and definitions. To provide support for multi
configuration generators use generator expressions as much as possible.
Add a (currently) empty 0ad-Functions module for later usage.
2026-05-17 18:22:05 +02:00

303 lines
11 KiB
CMake

cmake_minimum_required(VERSION 3.25.1...4.0.0)
# Add an interface library with common set of build/linker flags and definitions.
set(BUILD_FLAGS_TARGET BuildFlags)
add_library(${BUILD_FLAGS_TARGET} INTERFACE)
# Enable and require C++20 standard.
target_compile_features(${BUILD_FLAGS_TARGET} INTERFACE cxx_std_20)
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
# Settings for build types
if(with-lto)
include(CheckIPOSupported)
check_ipo_supported(RESULT lto_supported OUTPUT lto_supported_error)
if(lto_supported)
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
INTERPROCEDURAL_OPTIMIZATION TRUE
)
else()
message(WARNING "IPO / LTO not supported: <${lto_supported_error}>")
endif()
endif()
target_compile_definitions(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CONFIG:Release>:NDEBUG>
$<$<CONFIG:Release>:CONFIG_FINAL=1>
$<$<CONFIG:Debug>:DEBUG>
)
if(sanitize-address)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=address)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=address)
endif()
if(sanitize-thread)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=thread)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=thread)
endif()
if(sanitize-undefined-behaviour)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=undefined)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=undefined)
endif()
if(mozjs_is_debug_build)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE DEBUG)
endif()
if(gles)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_GLES=1)
endif()
if(without-audio)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_AUDIO=0)
endif()
if(without-nvtt)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_NVTT=0)
endif()
if(without-lobby)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_LOBBY=0)
endif()
if(without-miniupnpc)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_MINIUPNPC=0)
endif()
if(without-dap-interface)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE CONFIG2_DAP_INTERFACE=0)
endif()
# hide warnings caused by library includes (Nothing to do for gcc/clang)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/external:W0>
)
# various platform-specific build flags
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/MP>
# Since KB4088875 Windows 7 has a soft requirement for SSE2.
# Windows 8+ and Firefox ESR52 make it hard requirement.
# Finally since VS2012 it's enabled implicitely when not set.
$<$<CXX_COMPILER_ID:MSVC>:/arch:SSE2>
# use native wchar_t type (not typedef to unsigned short)
$<$<CXX_COMPILER_ID:MSVC>:/Zc:wchar_t>
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
# SpiderMonkey only supports building with MSVC on a best-effort basis,
# and the traditional MSVC preprocessor is incompatible with some headers.
# Use the modern, standard-compliant MSVC preprocessor instead.
$<$<CXX_COMPILER_ID:MSVC>:/Zc:preprocessor>
# enable most of the standard warnings
$<$<CXX_COMPILER_ID:MSVC>:/W4>
# FIXME: conversion warnings, should add -Wconversion to gcc and clang flags as well
$<$<CXX_COMPILER_ID:MSVC>:/wd4267>
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:MSVC>>:/O2>
)
# disable LNK4221 warning, to avoid spending energy ordering projects in linker invocations
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"/ignore:4221"
)
# mozilla 115 linked list destructor in debug build
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE "__PRETTY_FUNCTION__=__FUNCSIG__")
# disable Windows debug heap, since it makes malloc/free hugely slower when running inside a debugger
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
VS_DEBUGGER_ENVIRONMENT "_NO_DEBUG_HEAP=1"
)
elseif(UNIX)
if(NOT minimal-flags)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
# most of the standard warnings
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wall>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wextra>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wpedantic>
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wconversion> # FIXME: should seriously consider fixing so this warning can be enabled.
# add some other useful warnings that need to be enabled explicitly
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wunused-parameter> # (useful for finding some multiply-included header files)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wredundant-decls>
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wformat=2> # (useful sometimes, but a bit noisy, so skip it by default)
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wcast-qual> # (useful for checking const-correctness, but a bit noisy, so skip it by default)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wnon-virtual-dtor> # (sometimes noisy but finds real bugs)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wundef> # (useful for finding macro name typos)
# disable some warnings that currently trigger
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-missing-field-initializers> # (this is common in external headers we can't fix)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-reorder> # order of initialization list in constructors (lots of noise)
# enable security features (stack checking etc) that shouldn't have a significant effect on performance and can catch bugs
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fstack-protector-strong>
# always enable strict aliasing (useful in debug builds because of the warnings)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fstrict-aliasing>
# don't omit frame pointers (for now), because performance will be impacted negatively by the way this breaks profilers more than it will be impacted positively by the optimisation
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fno-omit-frame-pointer>
# FORTIFY_SOURCE needs optimizations to be enabled
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang,AppleClang,GNU>>:-U_FORTIFY_SOURCE> # (avoid redefinition warning if already defined)
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang,AppleClang,GNU>>:-D_FORTIFY_SOURCE=2>
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<PLATFORM_ID:Darwin>:-multiply_defined>
$<$<PLATFORM_ID:Darwin>:suppress>
)
if(NOT without-pch)
# do something (?) so that ccache can handle compilation with PCH enabled (ccache 3.1+ also requires CCACHE_SLOPPINESS=time_macros for this to work)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fpch-preprocess>
)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_NAME MATCHES ".*BSD*")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fPIC>
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-Wl,--no-undefined"
"-Wl,--as-needed"
"-Wl,-z,relro"
)
endif()
if(ARCH STREQUAL "x86")
# To support intrinsics like __sync_bool_compare_and_swap on x86 we need to set -march to something that supports them (i686).
# We use pentium3 to also enable other features like mmx and sse, while tuning for generic to have good performance on every supported CPU.
# Note that all these features are already supported on amd64.
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-march=pentium3>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-mtune=generic>
# This allows x86 operating systems to handle the 2GB+ INTERFACE mod.
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-mtune=generic-D_FILE_OFFSET_BITS=64>
)
endif()
if(ARCH STREQUAL "arm")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
# disable warnings about va_list ABI change and use compile-time flags for futher configuration.
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-psabi>
# Android uses softfp, so we should too.
$<$<AND:$<CXX_COMPILER_ID:Clang,AppleClang,GNU>,$<BOOL:${android}>>:-mfloat-abi=softfp>
)
endif()
endif()
if(coverage)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fprofile-arcs>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-ftest-coverage>
)
target_link_libraries(${BUILD_FLAGS_TARGET} gcov)
endif()
# MacOS 10.12 only supports intel processors with SSE 4.1, so enable that.
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND ARCH STREQUAL "amd64")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-msse4.1"
)
endif()
# Check if SDK path should be used
if(sysroot)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-isysroot ${sysroot}"
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-Wl,-syslibroot, ${sysroot}"
)
endif()
# On OS X, sometimes we need to specify the minimum API version to use
if(macosx-version-min)
# clang and llvm-gcc look at mmacosx-version-min to determine link target and CRT version, and use it to set the macosx_version_min linker flag
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-mmacosx-version-min=${macosx-version-min}"
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-mmacosx-version-min=${macosx-version-min}"
)
endif()
# Only libc++ is supported on MacOS
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
-stdlib=libc++
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-stdlib=libc++
)
endif()
# Hide symbols in dynamic shared objects by default, for efficiency and for equivalence with Windows
# - they should be exported explicitly with __attribute__ ((visibility ("default")))
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
-fvisibility=hidden
)
if(bindir)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE INSTALLED_BINDIR=${bindir})
endif()
if(datadir)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE INSTALLED_DATADIR=${datadir})
endif()
if(libdir)
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE INSTALLED_LIBDIR=${libdir})
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME MATCHES ".*BSD*")
if(libdir)
# To use our local shared libraries, they need to be found in the runtime dynamic linker path. Add their path to -rpath.
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-Wl,-rpath,${libdir}
)
else()
# On FreeBSD we need to allow use of $ORIGIN
if(CMAKE_SYSTEM_NAME MATCHES ".*BSD*")
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-Wl,-z,origin
)
endif()
# Adding the executable path and taking care of correct escaping
if(NOT CMAKE_GENERATOR STREQUAL "Ninja") # Checks if any Makefile generator is selected
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-Wl,-rpath,'$$ORIGIN'
)
elseif(CMAKE_EXTRA_GENERATOR STREQUAL "CodeBlocks")
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-Wl,-R\\\\$$$ORIGIN
)
endif()
endif()
endif()
endif()