mirror of
https://github.com/gbdev/rgbds.git
synced 2026-03-25 14:23:04 +00:00
Besides the immediate performance improvement, reducing the frequency of downloads should make spurious failures (network, rate-limiting...) less bothersome.
178 lines
7.0 KiB
CMake
178 lines
7.0 KiB
CMake
# SPDX-License-Identifier: MIT
|
|
|
|
# - 3.24 is required for `FetchContent`'s `find_package` integration.
|
|
# Older versions *may* work, but we can't test them; compat patches are welcome.
|
|
# - 3.17 is required for `CHECK_*` messages to display properly, but is not essential.
|
|
# - 3.9 is required for LTO checks.
|
|
cmake_minimum_required(VERSION 3.24...4.2 FATAL_ERROR)
|
|
|
|
# Read the project version from the header (the canonical source of truth).
|
|
file(STRINGS "include/version.hpp" version_defines REGEX "^[ \t]*#define[ \t]+PACKAGE_VERSION_")
|
|
foreach(line IN LISTS version_defines)
|
|
# We want the `CMAKE_MATCH_n` variables, so we just need to run *some* regex op.
|
|
string(REGEX MATCH "PACKAGE_(VERSION_[^ \t]+)[ \t]+([0-9]+)" dummy "${line}")
|
|
set("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}")
|
|
endforeach()
|
|
|
|
project(rgbds
|
|
VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
|
|
LANGUAGES CXX
|
|
DESCRIPTION "Game Boy assembly toolchain"
|
|
HOMEPAGE_URL "https://rgbds.gbdev.io")
|
|
if(DEFINED VERSION_RC)
|
|
string(APPEND CMAKE_PROJECT_VERSION "-rc${VERSION_RC}")
|
|
endif()
|
|
|
|
# Reject in-source builds, as they may conflict with the Makefile.
|
|
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
|
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
|
|
if(srcdir STREQUAL bindir)
|
|
message(FATAL_ERROR "RGBDS should not be built in the source directory.
|
|
Instead, create a separate build directory and specify to CMake the path to the source directory.")
|
|
endif()
|
|
|
|
include(CTest) # Note: CTest only functions properly if included from the top-level CMakeLists.
|
|
include(GNUInstallDirs)
|
|
|
|
## Compiler switches.
|
|
|
|
include(CMakeDependentOption)
|
|
option(SANITIZERS "Build with sanitizers enabled" OFF)
|
|
cmake_dependent_option(MORE_WARNINGS "Turn on more warnings" OFF !MSVC OFF)
|
|
|
|
if(MSVC)
|
|
add_compile_options(
|
|
/wd5030 # Warning C5030 is about unknown attributes (`[[gnu::ATTR]]`), none of ours being load-bearing.
|
|
/wd4996 # Warning C4996 is about using POSIX names, which we want to do for portability.
|
|
/Zc:preprocessor # Opt into the C++20-conformant preprocessor.
|
|
)
|
|
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
|
|
|
if(SANITIZERS)
|
|
message(STATUS "ASan enabled")
|
|
add_compile_options(/fsanitize=address) # Note that this shouldn't be passed to the linker.
|
|
endif()
|
|
else()
|
|
add_compile_options(-Wall -pedantic -fno-exceptions -fno-rtti -Wno-unknown-warning-option
|
|
# C++20 allows macros to take zero variadic arguments.
|
|
# Some versions of Clang don't recognize this, and treat them as a GNU extension.
|
|
-Wno-gnu-zero-variadic-macro-arguments)
|
|
if(SANITIZERS)
|
|
message(STATUS "ASan and UBSan enabled")
|
|
set(SAN_FLAGS -fsanitize=address -fsanitize=undefined
|
|
-fsanitize=float-divide-by-zero)
|
|
add_compile_options(${SAN_FLAGS})
|
|
add_link_options(${SAN_FLAGS})
|
|
add_definitions(-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
|
|
# A non-zero optimization level is desired even in debug mode (especially for Clang),
|
|
# and the two codegen flags improve the sanitizers' backtraces, but we want the user to
|
|
# be able to override these easily so we put them first.
|
|
string(PREPEND CMAKE_CXX_FLAGS_DEBUG "-Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ")
|
|
endif()
|
|
|
|
if(MORE_WARNINGS)
|
|
add_compile_options(-Werror -Wextra
|
|
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
|
|
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2
|
|
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow
|
|
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
|
|
-Wno-format-nonliteral -Wno-strict-overflow
|
|
-Wno-unused-but-set-variable # bison's `yynerrs_` is incremented but unused
|
|
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare
|
|
-Wvla # MSVC does not support VLAs
|
|
-Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings
|
|
endif()
|
|
endif()
|
|
|
|
include_directories("include")
|
|
|
|
set(CMAKE_CXX_STANDARD 20)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|
|
|
message(CHECK_START "Checking if LTO is supported")
|
|
include(CheckIPOSupported)
|
|
check_ipo_supported(RESULT enable_lto)
|
|
if(enable_lto)
|
|
message(CHECK_PASS "yes (enabled only in release modes)")
|
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
|
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
|
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON)
|
|
else()
|
|
message(CHECK_FAIL "no")
|
|
endif()
|
|
|
|
# Use versioning consistent with Makefile:
|
|
# the git revision is used but uses the fallback in an archive.
|
|
|
|
message(CHECK_START "Determining RGBDS version from Git history")
|
|
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
|
set(GIT_REV "") # This fallback is important!
|
|
find_package(Git)
|
|
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
|
if(NOT Git_FOUND)
|
|
message(CHECK_FAIL "Git not found")
|
|
else()
|
|
execute_process(COMMAND "${GIT_EXECUTABLE}" --git-dir=.git -c safe.directory='*'
|
|
describe --tags --dirty --always --match "v[0-9]*"
|
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
|
OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
ERROR_VARIABLE git_err ERROR_STRIP_TRAILING_WHITESPACE
|
|
RESULT_VARIABLE result)
|
|
if(NOT result EQUAL 0)
|
|
# Note that this happens e.g. when building from a tarball, so it shouldn't fail the build!
|
|
message(CHECK_FAIL "error ${result} from Git:")
|
|
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
|
message("${git_err}")
|
|
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
|
else()
|
|
message(CHECK_PASS "${GIT_REV}")
|
|
if(NOT "${GIT_REV}" MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+(-rc[0-9]+)?")
|
|
# Can't find an ancestor tag! (That passes `--match`, anyway.)
|
|
message(WARNING "No `v*` Git tag reachable; falling back")
|
|
elseif(NOT CMAKE_MATCH_0 STREQUAL "v${CMAKE_PROJECT_VERSION}")
|
|
message(SEND_ERROR "\
|
|
Version mismatch! Git says ${CMAKE_MATCH_0},
|
|
version.hpp says v${CMAKE_PROJECT_VERSION}!")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
## Dependencies.
|
|
|
|
include(FetchContent)
|
|
include(cmake/deps.cmake)
|
|
|
|
FetchContent_MakeAvailable(ZLIB)
|
|
if(NOT DEFINED ZLIB_INCLUDE_DIRS)
|
|
set(ZLIB_INCLUDE_DIRS "${zlib_BINARY_DIR};${zlib_SOURCE_DIR}") # libpng's `genout` script relies on this variable to be set.
|
|
endif()
|
|
|
|
FetchContent_MakeAvailable(PNG)
|
|
if(NOT TARGET PNG::PNG)
|
|
if(PNG_SHARED)
|
|
add_library(PNG::PNG ALIAS png_shared)
|
|
else()
|
|
add_library(PNG::PNG ALIAS png_static)
|
|
endif()
|
|
endif()
|
|
|
|
## The actual stuff.
|
|
|
|
add_subdirectory(src)
|
|
add_subdirectory(test)
|
|
|
|
set(man1 "man/rgbasm.1"
|
|
"man/rgbfix.1"
|
|
"man/rgbgfx.1"
|
|
"man/rgblink.1")
|
|
set(man5 "man/rgbasm.5"
|
|
"man/rgbasm-old.5"
|
|
"man/rgblink.5"
|
|
"man/rgbds.5")
|
|
set(man7 "man/gbz80.7"
|
|
"man/rgbds.7")
|
|
|
|
foreach(SECTION "man1" "man5" "man7")
|
|
install(FILES ${${SECTION}} DESTINATION "${CMAKE_INSTALL_MANDIR}/${SECTION}")
|
|
endforeach()
|