VVVVVV/desktop_version/CMakeLists.txt

458 lines
15 KiB
CMake
Raw Normal View History

2020-01-01 21:29:24 +01:00
# CMake File for VVVVVV
# Written by Ethan "flibitijibibo" Lee
cmake_minimum_required(VERSION 2.8.12)
2020-01-01 21:29:24 +01:00
# CMake Options
option(ENABLE_WARNINGS "Enable compilation warnings" ON)
option(ENABLE_WERROR "Treat compilation warnings as errors" OFF)
option(BUNDLE_DEPENDENCIES "Use bundled TinyXML-2, PhysicsFS, FAudio, and UTF8-CPP (if disabled, TinyXML-2, PhysicsFS, and FAudio will be dynamically linked, LodePNG, UTF8-CPP and C-HashMap will still be statically linked)" ON)
set(CUSTOM_LEVEL_SUPPORT ENABLED CACHE STRING "Optionally disable playing and/or editing of custom levels")
set_property(CACHE CUSTOM_LEVEL_SUPPORT PROPERTY STRINGS ENABLED NO_EDITOR DISABLED)
option(STEAM "Use the Steam API" OFF)
option(GOG "Use the GOG API" OFF)
option(OFFICIAL_BUILD "Compile an official build of the game" OFF)
option(MAKEANDPLAY "Compile a version of the game without the main campaign (provided for convenience; consider modifying MakeAndPlay.h instead" OFF)
if(OFFICIAL_BUILD AND NOT MAKEANDPLAY)
set(STEAM ON)
set(GOG ON)
endif()
Add `REMOVE_ABSOLUTE_PATHS` CMake option This option is enabled by default and will replace absolute paths of all source directory file paths with relative paths in the compiled binary, if the compiler supports it. Of course, this isn't needed if you compile with all paths removed anyways (e.g. in Release mode). The purpose is to help make builds reproducible and to remove any potentially sensitive information about the user or the user's system from the compiled binary. Both Clang and GCC support -fdebug-prefix-map, -fmacro-prefix-map, and -ffile-prefix-map. In particular, -ffile-prefix-map is just a flag that does both -fdebug-prefix-map and -fmacro-prefix-map. According to https://reproducible-builds.org/docs/build-path/ , -fdebug-prefix-map is available in all GCC versions but only available starting from Clang 3.8, and -fmacro-prefix-map and -ffile-prefix-map are available since GCC 8 and Clang 10. So we check the compiler version and use the available flags depending on if the compiler supports it or not. This does make debugging a bit more annoying, but there are a couple ways to rectify this. Either disable it with -DREMOVE_ABSOLUTE_PATHS=OFF, or add a `.gdbinit` that consists of set substitute-path . ../.. so that `.` is considered to be `../..`. Of course, if you need to, replace `../..` with the actual source directory path (in my case it's `../../..` because I place my build folders in another subdirectory to have multiple build folders in one directory). This doesn't need to be a global `.gdbinit`, it can be in a directory-specific `.gdbinit` (similar to how `.gitignore`s can also be directory-specific). But then you need to add `add-auto-load-safe-path` to your `.gdbinit` to load any directory-specific `.gdbinit`s. The above is for GDB; I don't know what (if anything) needs to be done for LLDB; I don't use LLDB. Fixes #889.
2022-08-22 00:31:11 +02:00
option(REMOVE_ABSOLUTE_PATHS "If supported by the compiler, replace all absolute paths to source directories compiled into the binary (if any) with relative paths" ON)
2020-01-01 21:29:24 +01:00
# Architecture Flags
if(APPLE)
# Wow, Apple is a huge jerk these days huh?
set(OSX_10_9_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk)
if(NOT CMAKE_OSX_SYSROOT)
if(IS_DIRECTORY ${OSX_10_9_SDK_PATH})
set(CMAKE_OSX_SYSROOT ${OSX_10_9_SDK_PATH})
else()
message(WARNING "CMAKE_OSX_SYSROOT not set and macOS 10.9 SDK not found! Using default one.")
endif()
endif()
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
link_directories(/usr/local/lib)
add_compile_options(-Werror=partial-availability)
endif()
project(VVVVVV)
if(APPLE)
message(STATUS "Using macOS SDK at ${CMAKE_OSX_SYSROOT}")
endif()
# RPATH
if(NOT WIN32)
if(APPLE)
set(BIN_LIBROOT "osx")
set(BIN_RPATH "@executable_path/osx")
elseif(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(BIN_LIBROOT "lib64")
set(BIN_RPATH "\$ORIGIN/lib64")
else()
set(BIN_LIBROOT "lib")
set(BIN_RPATH "\$ORIGIN/lib")
endif()
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ${BIN_RPATH})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
endif()
2020-01-01 21:29:24 +01:00
# Source Lists
set(VVV_SRC
src/BinaryBlob.cpp
src/BlockV.cpp
src/CWrappers.cpp
src/Ent.cpp
src/Entity.cpp
src/FileSystemUtils.cpp
src/Finalclass.cpp
Start rewrite of font system This is still a work in progress, but the existing font system has been removed and replaced by a new one, in Font.cpp. Design goals of the new font system include supporting colored button glyphs, different fonts for different languages, and larger fonts than 8x8 for Chinese, Japanese and Korean, while being able to support their 30000+ characters without hiccups, slowdowns or high memory usage. And to have more flexibility with fonts in general. Plus, Graphics.cpp was long enough as-is, so it's good to have a dedicated file for font storage. The old font system worked with a std::vector<SDL_Surface*> to store 8x8 surfaces for each character, and a std::map<int,int> to store mappings between codepoints and vector indexes. The new system has a per-font collection of pages for every block of 0x1000 (4096) codepoints, that may be allocated as needed. A glyph on a page contains the index of the glyph in the image (giving its coordinates), the advance (how much the cursor should advance, so the width of that glyph) and some flags which would be at least whether the glyph exists and whether it is colored. Most of the *new* features aren't implemented yet; it's currently hardcoded to the regular 8x8 font.png, but it should be functionally equivalent to the previous behavior. The only thing that doesn't really work yet is level-specific font.png, but that'll be supported again soon enough. This commit also adds fontmeta (xml) support. Since the fonts folder is mounted at graphics/, there are two main options for recognizing non-font.png fonts: the font files have to be prefixed with font (or font_) or some special file extension is involved to signal what files are fonts. I always had a font.xml in mind (so font_cn.xml, font_ja.xml, etc) but if there's ever gonna be a need for further xml files inside the graphics folder, we have a problem. So I named them .fontmeta instead. A .fontmeta file looks somewhat like this: <?xml version="1.0" encoding="UTF-8"?> <font_metadata> <width>12</width> <height>12</height> <white_teeth>1</white_teeth> <chars> <range start="0x20" end="0x7E"/> <range start="0x80" end="0x80"/> <range start="0xA0" end="0xDF"/> <range start="0x250" end="0x2A8"/> <range start="0x2AD" end="0x2AD"/> <range start="0x2C7" end="0x2C7"/> <range start="0x2C9" end="0x2CB"/> ... </chars> <special> <range start="0x00" end="0x1F" advance="6"/> <range start="0x61" end="0x66" color="1"/> <range start="0x63" end="0x63" color="0"/> </special> </font_metadata> The <chars> tag can be used to specify characters instead of in a .txt. The original idea was to just always use the existing .txt system for specifying the font charset, and only use the XML for the other stuff that the .txt doesn't cover. However, it's probably better to keep it simple if possible - having to only have a .png and a .fontmeta seems simpler than having the data spread out over three files. And a major advantage: Chinese fonts can have about 30000 characters! It's more efficient to be able to have a tag saying "now there's 20902 characters starting at U+4E00" than to include them all in a text file and having to UTF-8 decode every single one of them. If a font.txt exists, it takes priority over the <chars> tag, and in that case, there's no reason to include the <chars> tag in the XML. But font.txt has to be in the same directory as font.png, otherwise it is rejected. Same for font.fontmeta. If neither font.txt nor <chars> exist, then the font is seen as a 2.2-and-below-style ASCII font. In <special>: advance is the number of pixels the cursor advances after drawing the character (so the width of the character, without affecting the grid in the source image), color is whether the character should have its original colors retained when printed (for button glyphs). As for <white_teeth>: The renderer PR has replaced draw-time whitening of sprites/etc (using BlitSurfaceColoured) by load-time whitening of entire images (using LoadImage with TEX_WHITE as an argument). This means we have a problem: fonts have always had their glyphs whitened at printing time, and since I'm adding support for colored button glyphs, I changed it so glyphs would sometimes not be whitened. But if we can't whiten at print time, then we'd need to whiten at load time, and if we whiten the entire font, any colored glyphs will get destroyed too. If you whiten the image selectively, well, we need more code to target specific squares in the image, and it's kind of a waste when you need to whiten 30000 12x12 Chinese characters when you're only going to need a handful, but you don't know which ones. The solution: Whitening fonts is useless if all the non-colored glyphs are already white, so we don't need to do it anyway! However, any existing fonts that have non-white glyphs (and I know of at least one level like that) will still need to be whitened. So there is now a font property <white_teeth> that can be specified in the fontmeta, which indicates that the font is already pre-whitened. If not specified, traditional whitening behavior will be used, and the font cannot use colored glyphs.
2023-01-02 05:14:53 +01:00
src/Font.cpp
src/Game.cpp
src/Graphics.cpp
src/GraphicsResources.cpp
src/GraphicsUtil.cpp
src/Input.cpp
src/KeyPoll.cpp
src/Labclass.cpp
src/Localization.cpp
src/LocalizationMaint.cpp
src/LocalizationStorage.cpp
src/Logic.cpp
src/Map.cpp
src/Music.cpp
src/Otherlevel.cpp
src/preloader.cpp
src/Render.cpp
src/RenderFixed.cpp
src/RoomnameTranslator.cpp
src/Screen.cpp
src/Script.cpp
src/Scripts.cpp
src/Spacestation2.cpp
src/TerminalScripts.cpp
src/Textbox.cpp
src/Tower.cpp
src/UtilityClass.cpp
src/WarpClass.cpp
src/XMLUtils.cpp
src/main.cpp
src/DeferCallbacks.c
src/GlitchrunnerMode.c
src/Network.c
src/Textbook.c
src/ThirdPartyDeps.c
src/UTF8.c
src/VFormat.c
src/Vlogging.c
src/Xoshiro.c
../third_party/physfs/extras/physfsrwops.c
2020-01-01 21:29:24 +01:00
)
if(NOT CUSTOM_LEVEL_SUPPORT STREQUAL "DISABLED")
list(APPEND VVV_SRC src/CustomLevels.cpp)
if(NOT CUSTOM_LEVEL_SUPPORT STREQUAL "NO_EDITOR")
LIST(APPEND VVV_SRC src/Editor.cpp)
endif()
endif()
if(STEAM)
list(APPEND VVV_SRC src/SteamNetwork.c)
endif()
if(GOG)
list(APPEND VVV_SRC src/GOGNetwork.c)
endif()
# Executable information
if(WIN32)
add_executable(VVVVVV WIN32 ${VVV_SRC} icon.rc)
else()
add_executable(VVVVVV ${VVV_SRC})
endif()
# Include Directories
if(BUNDLE_DEPENDENCIES)
target_include_directories(
VVVVVV PRIVATE
src
../third_party
../third_party/tinyxml2
../third_party/physfs/src
../third_party/physfs/extras
../third_party/lodepng
../third_party/c-hashmap
2022-03-09 22:35:29 +01:00
../third_party/FAudio/include
../third_party/FAudio/src
)
else()
target_include_directories(
VVVVVV PRIVATE
src
../third_party
../third_party/lodepng
../third_party/physfs/extras
../third_party/c-hashmap
2022-03-09 22:35:29 +01:00
../third_party/FAudio/src
)
endif()
if(MAKEANDPLAY)
target_compile_definitions(VVVVVV PRIVATE -DMAKEANDPLAY)
endif()
if(STEAM)
target_compile_definitions(VVVVVV PRIVATE -DSTEAM_NETWORK)
endif()
if(GOG)
target_compile_definitions(VVVVVV PRIVATE -DGOG_NETWORK)
endif()
set(XML2_SRC
../third_party/tinyxml2/tinyxml2.cpp
)
2022-03-09 22:35:29 +01:00
set(FAUDIO_SRC
../third_party/FAudio/src/FAudio.c
../third_party/FAudio/src/FAudio_internal.c
../third_party/FAudio/src/FAudio_internal_simd.c
../third_party/FAudio/src/FAudio_operationset.c
../third_party/FAudio/src/FAudio_platform_sdl2.c
)
set(PFS_SRC
../third_party/physfs/src/physfs.c
../third_party/physfs/src/physfs_archiver_dir.c
../third_party/physfs/src/physfs_archiver_unpacked.c
../third_party/physfs/src/physfs_archiver_zip.c
../third_party/physfs/src/physfs_byteorder.c
../third_party/physfs/src/physfs_unicode.c
../third_party/physfs/src/physfs_platform_posix.c
../third_party/physfs/src/physfs_platform_unix.c
../third_party/physfs/src/physfs_platform_windows.c
../third_party/physfs/src/physfs_platform_haiku.cpp
2020-01-01 21:29:24 +01:00
)
if(APPLE)
# Are you noticing a pattern with this Apple crap yet?
set(PFS_SRC ${PFS_SRC} ../third_party/physfs/src/physfs_platform_apple.m)
endif()
set(PNG_SRC src/lodepng_wrapper.c)
set(CHM_SRC ../third_party/c-hashmap/map.c)
2020-01-01 21:29:24 +01:00
if(NOT OFFICIAL_BUILD)
# Add interim commit hash and its date to the build
# find_package sets GIT_FOUND and GIT_EXECUTABLE
find_package(Git)
if(GIT_FOUND)
# These filenames have to be qualified, because when we run
# the CMake script, its work dir gets set to the build folder
Optimize recompilation from changing commit hash This reworks how the commit hash and date are compiled so that if they're changed (and they're changed often), only one source file needs to be recompiled in order to update it everywhere in the game, no matter how many source files use the hash or date. The commit hash and date are now declared in InterimVersion.h (and they need `extern "C"` guards because otherwise it results in a link fail on MSVC because MSVC is stupid). To do this, what now happens is that upon every rebuild, InterimVersion.in.c is processed to create InterimVersion.out.c, then InterimVersion.out.c is compiled into its own static library that is then linked with VVVVVV. (Why didn't I just simply add it to the list of VVVVVV source files? Well, doing it _now_ does nothing because at that point the horse is already out of the barn, and the VVVVVV executable has already been declared, so I can't modify its sources. And I can't do it before either, because we depend on the VVVVVV executable existing to do the interim version logic. I could probably work around this by cleverly moving around lines, but that'd separate related logic from each other.) And yes, the naming convention has changed. Not only did I rename Version to InterimVersion (to clearly differentiate it from ReleaseVersion, which I'll be adding later), I also named the files InterimVersion.in.c and InterimVersion.out.c instead of InterimVersion.c.in and InterimVersion.c.out. I needed to put the file extension on the end because otherwise CMake wouldn't recognize what kind of language it is, and I mean like yeah duh of course it doesn't, my text editor doesn't recognize it either.
2022-08-23 06:21:23 +02:00
set(VERSION_INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/InterimVersion.in.c)
set(VERSION_OUTPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/InterimVersion.out.c)
add_custom_target(
GenerateVersion ALL
# This BYPRODUCTS line is required for this to be ran every time
BYPRODUCTS ${VERSION_OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND}
# These args have to be passed through, otherwise the script can't see them
# Also, these args have to come BEFORE `-P`! (Otherwise it fails with an unclear error)
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
-DINPUT_FILE=${VERSION_INPUT_FILE}
-DOUTPUT_FILE=${VERSION_OUTPUT_FILE}
-P ${CMAKE_CURRENT_SOURCE_DIR}/version.cmake
)
add_dependencies(VVVVVV GenerateVersion)
Optimize recompilation from changing commit hash This reworks how the commit hash and date are compiled so that if they're changed (and they're changed often), only one source file needs to be recompiled in order to update it everywhere in the game, no matter how many source files use the hash or date. The commit hash and date are now declared in InterimVersion.h (and they need `extern "C"` guards because otherwise it results in a link fail on MSVC because MSVC is stupid). To do this, what now happens is that upon every rebuild, InterimVersion.in.c is processed to create InterimVersion.out.c, then InterimVersion.out.c is compiled into its own static library that is then linked with VVVVVV. (Why didn't I just simply add it to the list of VVVVVV source files? Well, doing it _now_ does nothing because at that point the horse is already out of the barn, and the VVVVVV executable has already been declared, so I can't modify its sources. And I can't do it before either, because we depend on the VVVVVV executable existing to do the interim version logic. I could probably work around this by cleverly moving around lines, but that'd separate related logic from each other.) And yes, the naming convention has changed. Not only did I rename Version to InterimVersion (to clearly differentiate it from ReleaseVersion, which I'll be adding later), I also named the files InterimVersion.in.c and InterimVersion.out.c instead of InterimVersion.c.in and InterimVersion.c.out. I needed to put the file extension on the end because otherwise CMake wouldn't recognize what kind of language it is, and I mean like yeah duh of course it doesn't, my text editor doesn't recognize it either.
2022-08-23 06:21:23 +02:00
target_compile_definitions(VVVVVV PRIVATE -DINTERIM_VERSION_EXISTS)
add_library(InterimVersion STATIC src/InterimVersion.out.c)
list(APPEND STATIC_LIBRARIES InterimVersion)
endif()
endif()
Update commit hash every time it changes, not just when CMake is re-ran The commit hash is now properly updated every time it gets changed, and not just when CMake gets re-ran. For this to work, we need to use a few CMake tricks. We add a custom target with ADD_CUSTOM_TARGET(), which is apparently always considered out-of-date (but I had to add a BYPRODUCTS line to get it to actually work), and we use the target to run a .cmake file every time we build. Also, VVVVVV needs to depend on this custom target, to ensure that the game gets built AFTER the version gets generated - otherwise there'll be an error. So we do an ADD_DEPENDENCIES() after the ADD_EXECUTABLE() for VVVVVV. This file, version.cmake, is just the Version.h.out generation that I added previously, but the important thing about all of this is that if the contents of Version.h.out doesn't change, and thus if the commit hash hasn't changed, then CMake will never recompile and relink anything at all. (At least with the Ninja generator.) On a small note, since the Version.h.out generation is now a separate script that is guaranteed to get ran on every single build, while the Git FIND_PACKAGE() gets ran only at configure time, it is possible for the cached path of the Git executable to get out of date. Fixing this requires a simple re-configure (ideally), but in case it wasn't fixed, the INTERIM_COMMIT and COMMIT_DATE variables would get set to empty strings instead of containing a value. To prevent this from happening, I've removed ERROR_QUIET from the EXECUTE_PROCESS() calls in version.cmake, because it's better to explicitly error if the Git executable wasn't found than implicitly carry on like nothing happened.
2020-12-26 05:24:14 +01:00
# Build options
if(ENABLE_WARNINGS)
# The weird syntax is due to CMake generator expressions.
# Saves quite a few lines and boilerplate at the price of readability.
target_compile_options(VVVVVV PRIVATE
$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Wall -Wpedantic $<$<BOOL:${ENABLE_WERROR}>:-Werror>>
$<$<CXX_COMPILER_ID:MSVC>:
/W4 $<$<BOOL:${ENABLE_WERROR}>:/WX>>)
endif()
if(CUSTOM_LEVEL_SUPPORT STREQUAL "NO_EDITOR")
target_compile_definitions(VVVVVV PRIVATE -DNO_EDITOR)
elseif(CUSTOM_LEVEL_SUPPORT STREQUAL "DISABLED")
target_compile_definitions(VVVVVV PRIVATE -DNO_CUSTOM_LEVELS -DNO_EDITOR)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(SUPPORTS_IMPLICIT_FALLTHROUGH TRUE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
set(SUPPORTS_IMPLICIT_FALLTHROUGH TRUE)
else()
set(SUPPORTS_IMPLICIT_FALLTHROUGH FALSE)
endif()
else()
set(SUPPORTS_IMPLICIT_FALLTHROUGH FALSE)
endif()
if(SUPPORTS_IMPLICIT_FALLTHROUGH)
target_compile_options(VVVVVV PRIVATE -Werror=implicit-fallthrough)
endif()
if(MSVC)
# Disable MSVC warnings about implicit conversion
target_compile_options(VVVVVV PRIVATE /wd4244)
endif()
# Disable warnings about `long long` in C++03 (from including PhysFS)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(VVVVVV PRIVATE -Wno-long-long)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(VVVVVV PRIVATE -Wno-c++11-long-long)
endif()
if(MSVC)
Fix C/C++ standards being unset for VVVVVV target if CMake is >= 3.1.3 So, it turns out we weren't quite done fighting CMake yet... To accommodate #869 (and actually also #272), the C standard was raised from C90 to C99. This turned out to require a bit of a fight with the CentOS CI's CMake version to get it to set the flags we wanted (and to not overwrite them later). Eventually the fix was to move the block that sets the standards to later in the file, which was done in 24353a54bb40665b64a93faebfb2ebd96cd0f6b5. As it apparently turns out, if your CMake is at least 3.1.3 and `CMAKE_<LANG>_STANDARD` is used instead of the workaround, the standard setting now has an effect on the third party libraries, but not on VVVVVV itself. The cause is (probably) the phrase "if it is set when a target is created" in the CMake documentation - the `CMAKE_<LANG>_STANDARD` values have to come before the VVVVVV target is defined. In other words, the compiler's default C/C++ standard will be used, probably something like C17 and C++17. As I can confirm with `__cplusplus` and `__STDC_VERSION__` with my recent-enough CMake. If I force the pre-3.1.3 workaround to be used, everything is compiled with C99/C++98 as expected; and the `-fno-exceptions` `-fno-rtti` flags appear everywhere regardless of version. So my fix is to make the CMakeLists a little less complex by simplifying away the `CMAKE_<LANG>_STANDARD` and `CMAKE_<LANG>_EXTENSIONS`, and always using the workaround regardless of CMake version. There's nothing wrong with the workaround, the same thing is also done for `-fno-exceptions` `-fno-rtti`, and it's good to have a less complicated CMakeLists that doesn't do different and unexpected things for different versions.
2022-03-22 20:50:49 +01:00
# MSVC doesn't have /std:c99 or /std:c++98 switches!
# Disable exceptions
string(REGEX REPLACE "/EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
# Disable RTTI
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
else()
Fix C/C++ standards being unset for VVVVVV target if CMake is >= 3.1.3 So, it turns out we weren't quite done fighting CMake yet... To accommodate #869 (and actually also #272), the C standard was raised from C90 to C99. This turned out to require a bit of a fight with the CentOS CI's CMake version to get it to set the flags we wanted (and to not overwrite them later). Eventually the fix was to move the block that sets the standards to later in the file, which was done in 24353a54bb40665b64a93faebfb2ebd96cd0f6b5. As it apparently turns out, if your CMake is at least 3.1.3 and `CMAKE_<LANG>_STANDARD` is used instead of the workaround, the standard setting now has an effect on the third party libraries, but not on VVVVVV itself. The cause is (probably) the phrase "if it is set when a target is created" in the CMake documentation - the `CMAKE_<LANG>_STANDARD` values have to come before the VVVVVV target is defined. In other words, the compiler's default C/C++ standard will be used, probably something like C17 and C++17. As I can confirm with `__cplusplus` and `__STDC_VERSION__` with my recent-enough CMake. If I force the pre-3.1.3 workaround to be used, everything is compiled with C99/C++98 as expected; and the `-fno-exceptions` `-fno-rtti` flags appear everywhere regardless of version. So my fix is to make the CMakeLists a little less complex by simplifying away the `CMAKE_<LANG>_STANDARD` and `CMAKE_<LANG>_EXTENSIONS`, and always using the workaround regardless of CMake version. There's nothing wrong with the workaround, the same thing is also done for `-fno-exceptions` `-fno-rtti`, and it's good to have a less complicated CMakeLists that doesn't do different and unexpected things for different versions.
2022-03-22 20:50:49 +01:00
string(REGEX REPLACE "-std=[a-z0-9]+" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
string(REGEX REPLACE "-std=[a-z0-9+]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
# Disable exceptions
string(REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
# Disable RTTI
string(REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif()
# Unfortunately, it doesn't seem like distros package LodePNG
add_library(lodepng-static STATIC ${PNG_SRC})
2020-01-01 21:29:24 +01:00
target_compile_definitions(lodepng-static PRIVATE
-DLODEPNG_NO_COMPILE_ALLOCATORS
-DLODEPNG_NO_COMPILE_DISK
-DLODEPNG_NO_COMPILE_ENCODER
)
Reduce dependency on libc functions During 2.3 development, there's been a gradual shift to using SDL stdlib functions instead of libc functions, but there are still some libc functions (or the same libc function but from the STL) in the code. Well, this patch replaces all the rest of them in one fell swoop. SDL's stdlib can replace most of these, but its SDL_min() and SDL_max() are inadequate - they aren't really functions, they're more like macros with a nasty penchant for double-evaluation. So I just made my own VVV_min() and VVV_max() functions and placed them in Maths.h instead, then replaced all the previous usages of min(), max(), std::min(), std::max(), SDL_min(), and SDL_max() with VVV_min() and VVV_max(). Additionally, there's no SDL_isxdigit(), so I just implemented my own VVV_isxdigit(). SDL has SDL_malloc() and SDL_free(), but they have some refcounting built in to them, so in order to use them with LodePNG, I have to replace the malloc() and free() that LodePNG uses. Which isn't too hard, I did it in a new file called ThirdPartyDeps.c, and LodePNG is now compiled with the LODEPNG_NO_COMPILE_ALLOCATORS definition. Lastly, I also refactored the awful strcpy() and strcat() usages in PLATFORM_migrateSaveData() to use SDL_snprintf() instead. I know save migration is getting axed in 2.4, but it still bothers me to have something like that in the codebase otherwise. Without further ado, here is the full list of functions that the codebase now uses: - SDL_strlcpy() instead of strcpy() - SDL_strlcat() instead of strcat() - SDL_snprintf() instead of sprintf(), strcpy(), or strcat() (see above) - VVV_min() instead of min(), std::min(), or SDL_min() - VVV_max() instead of max(), std::max(), or SDL_max() - VVV_isxdigit() instead of isxdigit() - SDL_strcmp() instead of strcmp() - SDL_strcasecmp() instead of strcasecmp() or Win32 strcmpi() - SDL_strstr() instead of strstr() - SDL_strlen() instead of strlen() - SDL_sscanf() instead of sscanf() - SDL_getenv() instead of getenv() - SDL_malloc() instead of malloc() (replacing in LodePNG as well) - SDL_free() instead of free() (replacing in LodePNG as well)
2021-01-12 01:17:45 +01:00
add_library(c-hashmap-static STATIC ${CHM_SRC})
if(BUNDLE_DEPENDENCIES)
list(APPEND STATIC_LIBRARIES physfs-static tinyxml2-static lodepng-static c-hashmap-static faudio-static)
else()
list(APPEND STATIC_LIBRARIES lodepng-static c-hashmap-static)
endif()
if(BUNDLE_DEPENDENCIES)
add_library(tinyxml2-static STATIC ${XML2_SRC})
add_library(physfs-static STATIC ${PFS_SRC})
target_compile_definitions(physfs-static PRIVATE
-DPHYSFS_SUPPORTS_DEFAULT=0 -DPHYSFS_SUPPORTS_ZIP=1
)
2022-03-09 22:35:29 +01:00
add_library(faudio-static STATIC ${FAUDIO_SRC})
target_include_directories(
faudio-static PRIVATE
../third_party/FAudio/include
)
# Disable FAudio debug stuff in release mode. This needs a generator expression for CMake reasons(TM)
target_compile_definitions(faudio-static PRIVATE $<$<CONFIG:Release>:FAUDIO_DISABLE_DEBUGCONFIGURATION>)
target_link_libraries(VVVVVV ${STATIC_LIBRARIES})
else()
find_package(utf8cpp CONFIG)
target_link_libraries(VVVVVV ${STATIC_LIBRARIES} physfs tinyxml2 utf8cpp FAudio)
endif()
2020-01-01 21:29:24 +01:00
Add `/MT` flag for MSVC This flag makes it so the MSVC runtime libraries are statically linked. This avoids needing Windows users to have these libraries installed. Apparently /MT stands for "MultiThreaded", and there's a bit of a history there where originally by default you could only have a single-threaded library, and then the multi-threaded flags were added in later. First I tried doing target_compile_options on VVVVVV, but then got a linker error. Then I tried doing add_compile_options because I figured /MT had to be applied everywhere, and it seemed to work, but it still linked to the runtime libraries. Apparently it was being overridden. Then I tried target_compile_options again but this time did it to everything, and that linked correctly and also removed the runtime dependency. I would've tried using the MSVC_RUNTIME_LIBRARY property - along with the CMP0091 policy - but those were only introduced in CMake 3.15. You can verify that a binary is built without dependencies by installing LLVM and running llvm-readobj --needed-libs path/to/binary. This is the output for a binary with runtime dependencies: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll MSVCP140.dll SDL2.dll SHELL32.dll USER32.dll VCRUNTIME140.dll api-ms-win-crt-heap-l1-1-0.dll api-ms-win-crt-locale-l1-1-0.dll api-ms-win-crt-math-l1-1-0.dll api-ms-win-crt-runtime-l1-1-0.dll api-ms-win-crt-stdio-l1-1-0.dll api-ms-win-crt-string-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll api-ms-win-crt-utility-l1-1-0.dll ] And this is the output for a binary with those dependencies having been statically-linked in: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll SDL2.dll SHELL32.dll USER32.dll ]
2022-06-29 02:49:03 +02:00
if(MSVC)
# Statically link Microsoft's runtime library so end users don't have to install it
list(APPEND GLOBAL_COMPILE_FLAGS /MT)
endif()
Add `/MT` flag for MSVC This flag makes it so the MSVC runtime libraries are statically linked. This avoids needing Windows users to have these libraries installed. Apparently /MT stands for "MultiThreaded", and there's a bit of a history there where originally by default you could only have a single-threaded library, and then the multi-threaded flags were added in later. First I tried doing target_compile_options on VVVVVV, but then got a linker error. Then I tried doing add_compile_options because I figured /MT had to be applied everywhere, and it seemed to work, but it still linked to the runtime libraries. Apparently it was being overridden. Then I tried target_compile_options again but this time did it to everything, and that linked correctly and also removed the runtime dependency. I would've tried using the MSVC_RUNTIME_LIBRARY property - along with the CMP0091 policy - but those were only introduced in CMake 3.15. You can verify that a binary is built without dependencies by installing LLVM and running llvm-readobj --needed-libs path/to/binary. This is the output for a binary with runtime dependencies: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll MSVCP140.dll SDL2.dll SHELL32.dll USER32.dll VCRUNTIME140.dll api-ms-win-crt-heap-l1-1-0.dll api-ms-win-crt-locale-l1-1-0.dll api-ms-win-crt-math-l1-1-0.dll api-ms-win-crt-runtime-l1-1-0.dll api-ms-win-crt-stdio-l1-1-0.dll api-ms-win-crt-string-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll api-ms-win-crt-utility-l1-1-0.dll ] And this is the output for a binary with those dependencies having been statically-linked in: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll SDL2.dll SHELL32.dll USER32.dll ]
2022-06-29 02:49:03 +02:00
Add `REMOVE_ABSOLUTE_PATHS` CMake option This option is enabled by default and will replace absolute paths of all source directory file paths with relative paths in the compiled binary, if the compiler supports it. Of course, this isn't needed if you compile with all paths removed anyways (e.g. in Release mode). The purpose is to help make builds reproducible and to remove any potentially sensitive information about the user or the user's system from the compiled binary. Both Clang and GCC support -fdebug-prefix-map, -fmacro-prefix-map, and -ffile-prefix-map. In particular, -ffile-prefix-map is just a flag that does both -fdebug-prefix-map and -fmacro-prefix-map. According to https://reproducible-builds.org/docs/build-path/ , -fdebug-prefix-map is available in all GCC versions but only available starting from Clang 3.8, and -fmacro-prefix-map and -ffile-prefix-map are available since GCC 8 and Clang 10. So we check the compiler version and use the available flags depending on if the compiler supports it or not. This does make debugging a bit more annoying, but there are a couple ways to rectify this. Either disable it with -DREMOVE_ABSOLUTE_PATHS=OFF, or add a `.gdbinit` that consists of set substitute-path . ../.. so that `.` is considered to be `../..`. Of course, if you need to, replace `../..` with the actual source directory path (in my case it's `../../..` because I place my build folders in another subdirectory to have multiple build folders in one directory). This doesn't need to be a global `.gdbinit`, it can be in a directory-specific `.gdbinit` (similar to how `.gitignore`s can also be directory-specific). But then you need to add `add-auto-load-safe-path` to your `.gdbinit` to load any directory-specific `.gdbinit`s. The above is for GDB; I don't know what (if anything) needs to be done for LLDB; I don't use LLDB. Fixes #889.
2022-08-22 00:31:11 +02:00
if(REMOVE_ABSOLUTE_PATHS)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.8)
set(SUPPORTS_DEBUG_PREFIX_MAP TRUE)
else()
set(SUPPORTS_DEBUG_PREFIX_MAP FALSE)
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0)
set(SUPPORTS_FILE_PREFIX_MAP TRUE)
else()
set(SUPPORTS_FILE_PREFIX_MAP FALSE)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(SUPPORTS_DEBUG_PREFIX_MAP TRUE)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)
set(SUPPORTS_FILE_PREFIX_MAP TRUE)
else()
set(SUPPORTS_FILE_PREFIX_MAP FALSE)
endif()
else()
set(SUPPORTS_DEBUG_PREFIX_MAP FALSE)
set(SUPPORTS_FILE_PREFIX_MAP FALSE)
endif()
get_filename_component(REPO_DIR ../ ABSOLUTE)
# Remove absolute source paths from compiled binary
if(SUPPORTS_FILE_PREFIX_MAP)
list(APPEND GLOBAL_COMPILE_FLAGS -ffile-prefix-map=${REPO_DIR}=.)
elseif(SUPPORTS_DEBUG_PREFIX_MAP)
list(APPEND GLOBAL_COMPILE_FLAGS -fdebug-prefix-map=${REPO_DIR}=.)
endif()
endif()
target_compile_options(VVVVVV PRIVATE ${GLOBAL_COMPILE_FLAGS})
foreach(static_library IN LISTS STATIC_LIBRARIES)
target_compile_options(${static_library} PRIVATE ${GLOBAL_COMPILE_FLAGS})
endforeach(static_library)
Add `/MT` flag for MSVC This flag makes it so the MSVC runtime libraries are statically linked. This avoids needing Windows users to have these libraries installed. Apparently /MT stands for "MultiThreaded", and there's a bit of a history there where originally by default you could only have a single-threaded library, and then the multi-threaded flags were added in later. First I tried doing target_compile_options on VVVVVV, but then got a linker error. Then I tried doing add_compile_options because I figured /MT had to be applied everywhere, and it seemed to work, but it still linked to the runtime libraries. Apparently it was being overridden. Then I tried target_compile_options again but this time did it to everything, and that linked correctly and also removed the runtime dependency. I would've tried using the MSVC_RUNTIME_LIBRARY property - along with the CMP0091 policy - but those were only introduced in CMake 3.15. You can verify that a binary is built without dependencies by installing LLVM and running llvm-readobj --needed-libs path/to/binary. This is the output for a binary with runtime dependencies: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll MSVCP140.dll SDL2.dll SHELL32.dll USER32.dll VCRUNTIME140.dll api-ms-win-crt-heap-l1-1-0.dll api-ms-win-crt-locale-l1-1-0.dll api-ms-win-crt-math-l1-1-0.dll api-ms-win-crt-runtime-l1-1-0.dll api-ms-win-crt-stdio-l1-1-0.dll api-ms-win-crt-string-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll api-ms-win-crt-utility-l1-1-0.dll ] And this is the output for a binary with those dependencies having been statically-linked in: infoteddy@fedorarune  ~/d  llvm-readobj --needed-libs VVVVVV.exe File: VVVVVV.exe Format: COFF-i386 Arch: i386 AddressSize: 32bit NeededLibraries [ ADVAPI32.dll KERNEL32.dll SDL2.dll SHELL32.dll USER32.dll ]
2022-06-29 02:49:03 +02:00
2020-01-01 21:29:24 +01:00
# SDL2 Dependency (Detection pulled from FAudio)
if(DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES)
message(STATUS "Using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES")
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(VVVVVV ${SDL2_LIBRARIES})
2022-03-09 22:35:29 +01:00
if(BUNDLE_DEPENDENCIES)
target_include_directories(faudio-static SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(faudio-static ${SDL2_LIBRARIES})
endif()
elseif (EMSCRIPTEN)
message(STATUS "Using Emscripten SDL2")
2022-03-09 22:35:29 +01:00
target_compile_options(VVVVVV PUBLIC -sUSE_SDL=2)
target_link_libraries(VVVVVV -sUSE_SDL=2)
if(BUNDLE_DEPENDENCIES)
target_compile_options(faudio-static PUBLIC -sUSE_SDL=2)
target_link_libraries(faudio-static -sUSE_SDL=2)
endif()
2020-01-01 21:29:24 +01:00
else()
# Only try to autodetect if both SDL2 variables aren't explicitly set
find_package(SDL2 CONFIG)
if(TARGET SDL2::SDL2)
message(STATUS "Using TARGET SDL2::SDL2")
2022-03-09 22:35:29 +01:00
target_link_libraries(VVVVVV SDL2::SDL2)
if(BUNDLE_DEPENDENCIES)
target_link_libraries(faudio-static SDL2::SDL2)
endif()
elseif(TARGET SDL2)
message(STATUS "Using TARGET SDL2")
2022-03-09 22:35:29 +01:00
target_link_libraries(VVVVVV SDL2)
if(BUNDLE_DEPENDENCIES)
target_link_libraries(faudio-static SDL2)
endif()
else()
message(STATUS "No TARGET SDL2::SDL2, or SDL2, using variables")
2022-03-09 22:35:29 +01:00
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(VVVVVV ${SDL2_LIBRARIES})
if(BUNDLE_DEPENDENCIES)
target_include_directories(faudio-static SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(faudio-static ${SDL2_LIBRARIES})
endif()
endif()
2020-01-01 21:29:24 +01:00
endif()
# Yes, more Apple Crap
if(APPLE)
find_library(FOUNDATION NAMES Foundation)
find_library(IOKIT NAMES IOKit)
target_link_libraries(VVVVVV objc ${IOKIT} ${FOUNDATION})
endif()
2020-01-14 05:31:14 +01:00
# But hey, also some Haiku crap
if(HAIKU)
find_library(BE_LIBRARY be)
find_library(ROOT_LIBRARY root)
target_link_libraries(VVVVVV ${BE_LIBRARY} ${ROOT_LIBRARY})
endif()
2021-03-31 20:27:23 +02:00
if(EMSCRIPTEN)
# 256MB is enough for everybody
target_link_libraries(VVVVVV -sFORCE_FILESYSTEM=1 -sTOTAL_MEMORY=256MB)
2021-03-31 20:27:23 +02:00
endif()