*: Add some hardening compile options.
Also fix some warnings and potential issues that building the entire EuropaTools codebase under those flags showed. Later on once we drop the libpixel and stbiw dependencies, we can probably turn on -Werror for release builds.
This commit is contained in:
parent
bdc55f5483
commit
341f914e1d
12 changed files with 140 additions and 12 deletions
|
@ -13,14 +13,18 @@ if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
|
||||||
message(FATAL_ERROR "In-source builds are strictly prohibited.")
|
message(FATAL_ERROR "In-source builds are strictly prohibited.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(cmake/Policies.cmake)
|
|
||||||
|
|
||||||
project(EuropaTools
|
project(EuropaTools
|
||||||
VERSION 1.0.0
|
VERSION 1.0.0
|
||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
DESCRIPTION "Tools for working with LEC Europa based games (Star Wars: Starfighter & Star Wars: Jedi Starfighter)"
|
DESCRIPTION "Tools for working with LEC Europa based games (Star Wars: Starfighter & Star Wars: Jedi Starfighter)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
include(Policies)
|
||||||
|
include(ProjectFuncs)
|
||||||
|
include(CompilerFlags)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
# declare dependencies
|
# declare dependencies
|
||||||
|
|
67
cmake/CompilerFlags-GNU.cmake
Normal file
67
cmake/CompilerFlags-GNU.cmake
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# TODO: This currently assumes libstdc++, later on we should *probably* set this with some detection
|
||||||
|
# also TODO: Use a list so that this isn't one giant line (list JOIN should help.)
|
||||||
|
set(EUROPA_CORE_COMPILE_ARGS "-Wall -Wextra -Wformat=2 -Wimplicit-fallthrough -fvisibility=hidden")
|
||||||
|
set(EUROPA_CORE_LINKER_ARGS "-fuse-ld=${EUROPA_LINKER}")
|
||||||
|
|
||||||
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") # OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo"
|
||||||
|
# If on Release use link-time optimizations.
|
||||||
|
# On clang we use ThinLTO for even better build performance.
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
|
set(EUROPA_CORE_COMPILE_ARGS "${EUROPA_CORE_COMPILE_ARGS} -flto=thin -ffunction-sections -fdata-sections")
|
||||||
|
set(EUROPA_CORE_LINKER_ARGS "${EUROPA_CORE_LINKER_ARGS} -flto=thin -ffunction-sections -fdata-sections")
|
||||||
|
else()
|
||||||
|
set(EUROPA_CORE_COMPILE_ARGS "${EUROPA_CORE_COMPILE_ARGS} -flto -ffunction-sections -fdata-sections")
|
||||||
|
set(EUROPA_CORE_LINKER_ARGS "${EUROPA_CORE_LINKER_ARGS} -flto -ffunction-sections -fdata-sections")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_EUROPA_CORE_WANTED_SANITIZERS "")
|
||||||
|
|
||||||
|
if("asan" IN_LIST EUROPA_SANITIZERS)
|
||||||
|
# Error if someone's trying to mix asan and tsan together since they aren't compatible.
|
||||||
|
if("tsan" IN_LIST EUROPA_SANITIZERS)
|
||||||
|
message(FATAL_ERROR "ASAN and TSAN cannot be used together.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Enabling ASAN because it was in EUROPA_SANITIZERS")
|
||||||
|
list(APPEND _EUROPA_CORE_WANTED_SANITIZERS "address")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("tsan" IN_LIST EUROPA_SANITIZERS)
|
||||||
|
if("asan" IN_LIST EUROPA_SANITIZERS)
|
||||||
|
message(FATAL_ERROR "ASAN and TSAN cannot be used together.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Enabling TSAN because it was in EUROPA_SANITIZERS")
|
||||||
|
list(APPEND _EUROPA_CORE_WANTED_SANITIZERS "thread")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("ubsan" IN_LIST EUROPA_SANITIZERS)
|
||||||
|
message(STATUS "Enabling UBSAN because it was in EUROPA_SANITIZERS")
|
||||||
|
list(APPEND _EUROPA_CORE_WANTED_SANITIZERS "undefined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(LENGTH _EUROPA_CORE_WANTED_SANITIZERS _EUROPA_CORE_WANTED_SANITIZERS_LENGTH)
|
||||||
|
if(NOT _EUROPA_CORE_WANTED_SANITIZERS_LENGTH EQUAL 0)
|
||||||
|
list(JOIN _EUROPA_CORE_WANTED_SANITIZERS "," _EUROPA_CORE_WANTED_SANITIZERS_ARG)
|
||||||
|
message(STATUS "Enabled sanitizers: ${_EUROPA_CORE_WANTED_SANITIZERS_ARG}")
|
||||||
|
set(EUROPA_CORE_COMPILE_ARGS "${EUROPA_CORE_COMPILE_ARGS} -fsanitize=${_EUROPA_CORE_WANTED_SANITIZERS_ARG}")
|
||||||
|
set(EUROPA_CORE_LINKER_ARGS "${EUROPA_CORE_LINKER_ARGS} -fsanitize=${_EUROPA_CORE_WANTED_SANITIZERS_ARG}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set core CMake toolchain variables so that they get applied to all projects.
|
||||||
|
# A bit nasty, but /shrug, this way our third party libraries can be mostly sanitized/etc as well.
|
||||||
|
# We do NOT do this for CMake compiler features however.
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "${EUROPA_CORE_COMPILE_ARGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${EUROPA_CORE_COMPILE_ARGS}")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -O0 -g3")
|
||||||
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -O3 -g3")
|
||||||
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -DNDEBUG -O3 -s")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g3")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -O3 -g3")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -s")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${EUROPA_CORE_LINKER_ARGS} -Wl,-z,noexecstack,-z,relro,-z,now,--gc-sections")
|
17
cmake/CompilerFlags.cmake
Normal file
17
cmake/CompilerFlags.cmake
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#
|
||||||
|
# EuropaTools
|
||||||
|
#
|
||||||
|
# (C) 2021-2025 modeco80 <lily.modeco80@protonmail.ch>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
|
||||||
|
# Core compile arguments used for the whole project
|
||||||
|
#
|
||||||
|
# This is the driver, we include compiler/platform specific files here
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
include(CompilerFlags-GNU)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported (for now?) compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
|
endif()
|
37
cmake/ProjectFuncs.cmake
Normal file
37
cmake/ProjectFuncs.cmake
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#
|
||||||
|
# EuropaTools
|
||||||
|
#
|
||||||
|
# (C) 2021-2025 modeco80 <lily.modeco80@protonmail.ch>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
|
||||||
|
function(europa_target target)
|
||||||
|
# Set binary products to output in the build directory for easier access
|
||||||
|
set_target_properties(
|
||||||
|
${target} PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}"
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(europa_set_alternate_linker)
|
||||||
|
find_program(LINKER_EXECUTABLE ld.${EUROPA_LINKER} ${EUROPA_LINKER})
|
||||||
|
if(LINKER_EXECUTABLE)
|
||||||
|
message(STATUS "Using ${EUROPA_LINKER} as argument to -fuse-ld=")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Linker ${EUROPA_LINKER} does not exist on your system. Please specify one which does or omit this option from your configure command.")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# FIXME: Better MSVC detection
|
||||||
|
if(NOT WIN32)
|
||||||
|
# set the default linker based on compiler id, if one is not provided
|
||||||
|
# This is provided so that it can be overridden
|
||||||
|
if(NOT EUROPA_LINKER AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
|
set(EUROPA_LINKER "lld")
|
||||||
|
elseif(NOT EUROPA_LINKER)
|
||||||
|
set(EUROPA_LINKER "bfd")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
europa_set_alternate_linker()
|
||||||
|
endif()
|
|
@ -20,7 +20,7 @@ namespace europa::io {
|
||||||
struct YatfReader {
|
struct YatfReader {
|
||||||
explicit YatfReader(std::istream& is);
|
explicit YatfReader(std::istream& is);
|
||||||
|
|
||||||
void Init(std::istream& is);
|
void InitFromStream(std::istream& is);
|
||||||
|
|
||||||
void ReadImage();
|
void ReadImage();
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace europa::io {
|
||||||
|
|
||||||
// Read the archive TOC
|
// Read the archive TOC
|
||||||
stream.seekg(header_type.tocOffset, std::istream::beg);
|
stream.seekg(header_type.tocOffset, std::istream::beg);
|
||||||
for(auto i = 0; i < header_type.fileCount; ++i) {
|
for(std::uint32_t i = 0; i < header_type.fileCount; ++i) {
|
||||||
// The first part of the TOC entry is always a VLE string,
|
// The first part of the TOC entry is always a VLE string,
|
||||||
// which we don't store inside the type (because we can't)
|
// which we don't store inside the type (because we can't)
|
||||||
//
|
//
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace europa::io {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
constexpr T AlignBy(T value, std::size_t alignment) {
|
constexpr T AlignBy(T value, std::size_t alignment) {
|
||||||
return (-value) & alignment - 1;
|
return (-value) & (alignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PakWriter::Write(std::ostream& os, std::vector<FlattenedType>&& vec, PakProgressReportSink& sink, SectorAlignment sectorAlignment) {
|
void PakWriter::Write(std::ostream& os, std::vector<FlattenedType>&& vec, PakProgressReportSink& sink, SectorAlignment sectorAlignment) {
|
||||||
|
|
|
@ -47,7 +47,6 @@ namespace europa::io::impl {
|
||||||
|
|
||||||
std::string ReadPString(std::istream& is) {
|
std::string ReadPString(std::istream& is) {
|
||||||
std::string s;
|
std::string s;
|
||||||
char c;
|
|
||||||
|
|
||||||
if(!is)
|
if(!is)
|
||||||
return "";
|
return "";
|
||||||
|
@ -62,7 +61,7 @@ namespace europa::io::impl {
|
||||||
s.resize(length - 1);
|
s.resize(length - 1);
|
||||||
|
|
||||||
// Read the string
|
// Read the string
|
||||||
for(auto i = 0; i < length-1; ++i) {
|
for(std::uint32_t i = 0; i < length-1; ++i) {
|
||||||
s[i] = static_cast<char>(is.get());
|
s[i] = static_cast<char>(is.get());
|
||||||
}
|
}
|
||||||
static_cast<void>(is.get());
|
static_cast<void>(is.get());
|
||||||
|
|
|
@ -19,12 +19,12 @@ namespace europa::io {
|
||||||
|
|
||||||
YatfReader::YatfReader(std::istream& is)
|
YatfReader::YatfReader(std::istream& is)
|
||||||
: stream(is) {
|
: stream(is) {
|
||||||
Init(stream);
|
InitFromStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void YatfReader::Init(std::istream& is) {
|
void YatfReader::InitFromStream(std::istream& is) {
|
||||||
// Read the image header.
|
// Read the image header.
|
||||||
header = impl::ReadStreamType<structs::YatfHeader>(stream);
|
header = impl::ReadStreamType<structs::YatfHeader>(is);
|
||||||
|
|
||||||
if(!header.IsValid())
|
if(!header.IsValid())
|
||||||
invalid = true;
|
invalid = true;
|
||||||
|
|
|
@ -13,11 +13,13 @@ add_executable(texdump texdump.cpp)
|
||||||
target_link_libraries(texdump PUBLIC
|
target_link_libraries(texdump PUBLIC
|
||||||
europa
|
europa
|
||||||
)
|
)
|
||||||
|
europa_target(texdump)
|
||||||
|
|
||||||
add_executable(jsfscramble jsfscramble.cpp)
|
add_executable(jsfscramble jsfscramble.cpp)
|
||||||
target_link_libraries(jsfscramble PUBLIC
|
target_link_libraries(jsfscramble PUBLIC
|
||||||
europa
|
europa
|
||||||
)
|
)
|
||||||
|
europa_target(jsfscramble)
|
||||||
|
|
||||||
#add_executable(paktest paktest.cpp)
|
#add_executable(paktest paktest.cpp)
|
||||||
#target_link_libraries(paktest PUBLIC
|
#target_link_libraries(paktest PUBLIC
|
||||||
|
|
|
@ -29,3 +29,5 @@ configure_file(EupakConfig.hpp.in
|
||||||
|
|
||||||
target_include_directories(eupak PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(eupak PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
target_include_directories(eupak PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(eupak PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
europa_target(eupak)
|
|
@ -53,7 +53,7 @@ namespace eupak {
|
||||||
auto count = std::strftime(&buf[0], sizeof(buf), format.data(), &tmObject);
|
auto count = std::strftime(&buf[0], sizeof(buf), format.data(), &tmObject);
|
||||||
|
|
||||||
// an error occured, probably.
|
// an error occured, probably.
|
||||||
if(count == -1)
|
if(count == static_cast<std::size_t>(-1))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return { buf, count };
|
return { buf, count };
|
||||||
|
|
Loading…
Reference in a new issue