mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Some tests have been updated because UTF-8 is used as the native path encoding with MinGW/Wine, unlike MSVC/Windows. Some of the tests fail: - 4 Rust tests fail because long paths are not enabled and so the paths used when creating symlinks and junction paths are too long. I've tested them with x86_64-pc-windows-gnu and x86_64-pc-windows-gnullvm, and both see the same behaviour. The tests pass when the MinGW-built executable is run on Windows, so this is a Wine limitation. - 12 C++ tests fail because directory symlink creation is not implemented. They fail whether the MinGW-built executable is run in Wine or on Windows, so this is a MinGW limitation. - 1 C++ filesystem test fails because long paths are not enabled. The failing tests are skipped at runtime when built with MinGW, aside from the one test for long paths being enabled, which expects them to be disabled when built with MinGW. If long paths are enabled, e.g. by running wine reg add HKLM\\System\\CurrentControlSet\\Control\\Filesystem /v LongPathsEnabled /t REG_DWORD /d 1 /f then many more tests fail because the C++ tests create long paths when that Registry value is set, but it doesn't seem to actually enable long path support in Wine, so various filesystem operations fail.
397 lines
13 KiB
CMake
397 lines
13 KiB
CMake
cmake_minimum_required(VERSION 3.24)
|
|
if(POLICY CMP0135)
|
|
cmake_policy(SET CMP0135 NEW)
|
|
endif()
|
|
if(POLICY CMP0167)
|
|
cmake_policy(SET CMP0167 NEW)
|
|
endif()
|
|
project(libloot VERSION "0.28.4")
|
|
include(CMakeDependentOption)
|
|
include(CMakePackageConfigHelpers)
|
|
include(GNUInstallDirs)
|
|
|
|
cmake_dependent_option(LIBLOOT_BUILD_SHARED
|
|
"Build a shared library"
|
|
ON
|
|
"NOT BUILD_SHARED_LIBS"
|
|
ON)
|
|
option(RUN_CLANG_TIDY "Whether or not to run clang-tidy during build. Has no effect when using CMake's MSVC generator." OFF)
|
|
option(LIBLOOT_BUILD_TESTS "Whether or not to build libloot's tests." ON)
|
|
option(LIBLOOT_INSTALL_DOCS "Whether or not to install libloot's docs (which need to be built separately)." ON)
|
|
|
|
##############################
|
|
# External Projects
|
|
##############################
|
|
|
|
if(MSVC)
|
|
set(LIBLOOT_CPP_FILENAME "libloot_cpp.lib")
|
|
else()
|
|
set(LIBLOOT_CPP_FILENAME "liblibloot_cpp.a")
|
|
endif()
|
|
|
|
if(CMAKE_CROSSCOMPILING AND NOT DEFINED RUST_TARGET)
|
|
if(WIN32 AND MINGW AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
set(RUST_TARGET "x86_64-pc-windows-gnu")
|
|
elseif(WIN32 AND MINGW AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
|
set(RUST_TARGET "i686-pc-windows-gnu")
|
|
else()
|
|
message(FATAL_ERROR "Cross-compiling without RUST_TARGET set, and an appropriate value could not be set automatically!")
|
|
endif()
|
|
endif()
|
|
|
|
if(DEFINED RUST_TARGET)
|
|
message(STATUS "Building for Rust target ${RUST_TARGET}")
|
|
set(TARGET_PATH "${PROJECT_SOURCE_DIR}/../target/${RUST_TARGET}")
|
|
else()
|
|
set(TARGET_PATH "${PROJECT_SOURCE_DIR}/../target")
|
|
endif()
|
|
|
|
set(CARGO_COMMAND cargo build
|
|
$<$<NOT:$<CONFIG:Debug>>:--release>
|
|
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:--config>
|
|
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:${PROJECT_SOURCE_DIR}/.cargo/msvc-debug-config.toml>
|
|
$<$<BOOL:${RUST_TARGET}>:--target>
|
|
$<$<BOOL:${RUST_TARGET}>:${RUST_TARGET}>)
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
set(CARGO_COMMAND ${CMAKE_COMMAND} -E env --modify "CXXFLAGS=string_append: -fno-lto" -- ${CARGO_COMMAND})
|
|
endif()
|
|
|
|
add_custom_target(libloot_cargo
|
|
# Force LTO to be disabled when building the first layer of the C++ wrapper,
|
|
# as it may be enabled by default, and if so that leads to undefined symbols
|
|
# in the C++ wrapper's shared library. It's not enough to just pass -fno-lto
|
|
# when building libloot-cpp itself, it also needs to be passed when building
|
|
# the cxx crate, as otherwise there will be missing cxxbridge symbols.
|
|
COMMAND ${CARGO_COMMAND}
|
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
|
BYPRODUCTS
|
|
"${TARGET_PATH}/$<IF:$<CONFIG:Debug>,debug,release>/${LIBLOOT_CPP_FILENAME}"
|
|
"${TARGET_PATH}/cxxbridge/libloot-cpp/src/lib.rs.cc"
|
|
"${TARGET_PATH}/cxxbridge/libloot-cpp/src/lib.rs.h"
|
|
"${TARGET_PATH}/cxxbridge/rust/cxx.h"
|
|
)
|
|
|
|
add_library(libloot_cpp INTERFACE)
|
|
add_dependencies(libloot_cpp libloot_cargo)
|
|
|
|
target_link_libraries(libloot_cpp INTERFACE
|
|
optimized "${TARGET_PATH}/release/${LIBLOOT_CPP_FILENAME}"
|
|
debug "${TARGET_PATH}/debug/${LIBLOOT_CPP_FILENAME}")
|
|
target_include_directories(libloot_cpp INTERFACE "${TARGET_PATH}/cxxbridge")
|
|
|
|
if(WIN32)
|
|
target_link_libraries(libloot_cpp INTERFACE ntdll ws2_32 bcrypt)
|
|
endif()
|
|
|
|
|
|
##############################
|
|
# General Settings
|
|
##############################
|
|
|
|
set(LIBLOOT_SRC_API_CPP_FILES
|
|
"${PROJECT_SOURCE_DIR}/src/api/api.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/convert.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/database.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/exception/cyclic_interaction_error.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/exception/exception.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/exception/undefined_group_error.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/file.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/filename.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/group.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/location.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/message.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/message_content.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/plugin_cleaning_data.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/plugin_metadata.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/metadata/tag.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/game.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/plugin.cpp"
|
|
"${PROJECT_SOURCE_DIR}/src/api/vertex.cpp")
|
|
|
|
set(LIBLOOT_INCLUDE_H_FILES
|
|
"${PROJECT_SOURCE_DIR}/include/loot/api.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/api_decorator.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/database_interface.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/exception/plugin_not_loaded_error.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/exception/undefined_group_error.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/enum/edge_type.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/enum/game_type.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/enum/log_level.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/enum/message_type.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/game_interface.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/loot_version.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/file.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/filename.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/group.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/location.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/message.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/message_content.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/plugin_cleaning_data.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/plugin_metadata.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/metadata/tag.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/plugin_interface.h"
|
|
"${PROJECT_SOURCE_DIR}/include/loot/vertex.h")
|
|
|
|
set(LIBLOOT_SRC_API_H_FILES
|
|
"${PROJECT_SOURCE_DIR}/src/api/convert.h"
|
|
"${PROJECT_SOURCE_DIR}/src/api/database.h"
|
|
"${PROJECT_SOURCE_DIR}/src/api/exception/exception.h"
|
|
"${PROJECT_SOURCE_DIR}/src/api/game.h"
|
|
"${PROJECT_SOURCE_DIR}/src/api/plugin.h")
|
|
|
|
source_group(TREE "${PROJECT_SOURCE_DIR}/src/api"
|
|
PREFIX "Source Files"
|
|
FILES ${LIBLOOT_SRC_API_CPP_FILES})
|
|
|
|
source_group(TREE "${PROJECT_SOURCE_DIR}/include"
|
|
PREFIX "Header Files"
|
|
FILES ${LIBLOOT_INCLUDE_H_FILES})
|
|
|
|
source_group(TREE "${PROJECT_SOURCE_DIR}/src/api"
|
|
PREFIX "Header Files"
|
|
FILES ${LIBLOOT_SRC_API_H_FILES})
|
|
|
|
set(LIBLOOT_ALL_SOURCES
|
|
${LIBLOOT_SRC_API_CPP_FILES}
|
|
${LIBLOOT_INCLUDE_H_FILES}
|
|
${LIBLOOT_SRC_API_H_FILES}
|
|
"${PROJECT_SOURCE_DIR}/src/api/resource.rc")
|
|
|
|
##############################
|
|
# Define Targets
|
|
##############################
|
|
|
|
if(LIBLOOT_BUILD_SHARED)
|
|
set(LIBLOOT_LIBRARY_TYPE "SHARED")
|
|
else()
|
|
set(LIBLOOT_LIBRARY_TYPE "STATIC")
|
|
endif()
|
|
|
|
# Build API.
|
|
add_library(libloot ${LIBLOOT_LIBRARY_TYPE} ${LIBLOOT_ALL_SOURCES})
|
|
target_link_libraries(libloot PRIVATE libloot_cpp)
|
|
|
|
##############################
|
|
# Set Target-Specific Flags
|
|
##############################
|
|
|
|
set(LIBLOOT_INCLUDE_DIRS
|
|
"${PROJECT_SOURCE_DIR}/src"
|
|
"${PROJECT_SOURCE_DIR}/include")
|
|
|
|
set(LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS
|
|
${LIBLOADORDER_INCLUDE_DIRS}
|
|
${ESPLUGIN_INCLUDE_DIRS}
|
|
${LCI_INCLUDE_DIRS})
|
|
|
|
target_include_directories(libloot PUBLIC
|
|
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
|
target_include_directories(libloot PRIVATE ${LIBLOOT_INCLUDE_DIRS})
|
|
target_include_directories(libloot SYSTEM PRIVATE
|
|
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
|
|
|
|
set_target_properties(libloot PROPERTIES
|
|
CXX_STANDARD 17
|
|
CXX_STANDARD_REQUIRED ON
|
|
# Stop the "lib" prefix being added on Linux, since it's already in the target name.
|
|
PREFIX "")
|
|
|
|
if(WIN32)
|
|
target_compile_definitions(libloot PRIVATE UNICODE _UNICODE LOOT_EXPORT)
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
target_compile_options(libloot PRIVATE
|
|
"-Wall"
|
|
"-Wextra"
|
|
"-Wpedantic"
|
|
"-Wconversion"
|
|
"-Wdeprecated"
|
|
"-Wuninitialized"
|
|
"-Winit-self"
|
|
"-Wswitch-enum"
|
|
"-Wstrict-overflow=5"
|
|
"-Wstringop-overflow=4"
|
|
"-Wduplicated-branches"
|
|
"-Wduplicated-cond"
|
|
"-Wzero-as-null-pointer-constant"
|
|
"-Wfloat-equal"
|
|
"-Wshadow"
|
|
"-Wcast-qual"
|
|
"-Wcast-align"
|
|
"-Wsign-conversion"
|
|
"-Wlogical-op"
|
|
"-Wvla"
|
|
"-Wno-xor-used-as-pow")
|
|
endif()
|
|
|
|
if(MSVC)
|
|
# Turn off permissive mode to be more standards-compliant and avoid compiler errors.
|
|
target_compile_options(libloot PRIVATE
|
|
"/permissive-"
|
|
"/W4"
|
|
"/Wall"
|
|
"/wd4514"
|
|
"/wd4623"
|
|
"/wd4625"
|
|
"/wd4626"
|
|
"/wd4710"
|
|
"/wd4711"
|
|
"/wd4738"
|
|
"/wd4820"
|
|
"/wd5026"
|
|
"/wd5027"
|
|
"/wd5045"
|
|
"/external:anglebrackets"
|
|
"/external:W0"
|
|
"/Zc:__cplusplus"
|
|
"/GL"
|
|
"/MP"
|
|
"/sdl"
|
|
"$<$<CONFIG:Debug>:/RTC1>")
|
|
target_link_options(libloot PRIVATE "/INCREMENTAL:NO" "/LTCG")
|
|
endif()
|
|
|
|
##############################
|
|
# Configure clang-tidy
|
|
##############################
|
|
|
|
if(RUN_CLANG_TIDY)
|
|
set(CLANG_TIDY_COMMON_CHECKS
|
|
"cppcoreguidelines-avoid-c-arrays"
|
|
"cppcoreguidelines-c-copy-assignment-signature"
|
|
"cppcoreguidelines-explicit-virtual-functions"
|
|
"cppcoreguidelines-init-variables"
|
|
"cppcoreguidelines-interfaces-global-init"
|
|
"cppcoreguidelines-macro-usage"
|
|
"cppcoreguidelines-narrowing-conventions"
|
|
"cppcoreguidelines-no-malloc"
|
|
"cppcoreguidelines-pro-bounds-array-to-pointer-decay"
|
|
"cppcoreguidelines-pro-bounds-constant-array-index"
|
|
"cppcoreguidelines-pro-bounds-pointer-arithmetic"
|
|
"cppcoreguidelines-pro-type-const-cast"
|
|
"cppcoreguidelines-pro-type-cstyle-cast"
|
|
"cppcoreguidelines-pro-type-member-init"
|
|
"cppcoreguidelines-pro-type-reinterpret-cast"
|
|
"cppcoreguidelines-pro-type-static-cast-downcast"
|
|
"cppcoreguidelines-pro-type-union-access"
|
|
"cppcoreguidelines-pro-type-vararg"
|
|
"cppcoreguidelines-pro-type-slicing")
|
|
|
|
set(CLANG_TIDY_LIB_CHECKS
|
|
${CLANG_TIDY_COMMON_CHECKS}
|
|
"cppcoreguidelines-avoid-goto"
|
|
"cppcoreguidelines-avoid-magic-numbers"
|
|
"cppcoreguidelines-non-private-member-variables-in-classes"
|
|
"cppcoreguidelines-special-member-functions")
|
|
|
|
list(JOIN CLANG_TIDY_LIB_CHECKS "," CLANG_TIDY_LIB_CHECKS_JOINED)
|
|
|
|
set(CLANG_TIDY_LIB
|
|
clang-tidy "-header-filter=.*" "-checks=${CLANG_TIDY_LIB_CHECKS_JOINED}")
|
|
|
|
set_target_properties(libloot
|
|
PROPERTIES
|
|
CXX_CLANG_TIDY "${CLANG_TIDY_LIB}")
|
|
endif()
|
|
|
|
##############################
|
|
# Tests
|
|
##############################
|
|
|
|
if(LIBLOOT_BUILD_TESTS)
|
|
include("cmake/tests.cmake")
|
|
endif()
|
|
|
|
########################################
|
|
# Install
|
|
########################################
|
|
|
|
add_library(libloot::libloot ALIAS libloot)
|
|
|
|
if(LIBLOOT_BUILD_SHARED)
|
|
set_property(TARGET libloot PROPERTY VERSION ${libloot_VERSION})
|
|
set_property(TARGET libloot PROPERTY SOVERSION ${libloot_VERSION_MAJOR})
|
|
set_property(TARGET libloot PROPERTY INTERFACE_libloot_MAJOR_VERSION ${libloot_VERSION_MAJOR})
|
|
set_property(TARGET libloot APPEND PROPERTY COMPATIBLE_INTERFACE_STRING libloot_MAJOR_VERSION)
|
|
|
|
configure_package_config_file(
|
|
${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in
|
|
"${PROJECT_BINARY_DIR}/liblootConfig.cmake"
|
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot
|
|
)
|
|
|
|
write_basic_package_version_file(
|
|
"${PROJECT_BINARY_DIR}/liblootConfigVersion.cmake"
|
|
VERSION "${libloot_VERSION}"
|
|
COMPATIBILITY AnyNewerVersion
|
|
)
|
|
|
|
install(TARGETS libloot
|
|
EXPORT liblootTargets
|
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
|
|
install(EXPORT liblootTargets
|
|
NAMESPACE libloot::
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
|
|
|
|
export(TARGETS libloot
|
|
NAMESPACE libloot::
|
|
FILE "${PROJECT_BINARY_DIR}/liblootTargets.cmake")
|
|
|
|
if(MSVC)
|
|
install(FILES $<TARGET_PDB_FILE:libloot>
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
OPTIONAL
|
|
CONFIGURATIONS RelWithDebInfo)
|
|
endif()
|
|
|
|
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
|
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
|
|
if(LIBLOOT_INSTALL_DOCS)
|
|
install(DIRECTORY "${PROJECT_SOURCE_DIR}/../docs/build/html/"
|
|
DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
|
endif()
|
|
|
|
install(FILES
|
|
"${PROJECT_BINARY_DIR}/liblootConfig.cmake"
|
|
"${PROJECT_BINARY_DIR}/liblootConfigVersion.cmake"
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
|
|
endif()
|
|
|
|
########################################
|
|
# CPack
|
|
########################################
|
|
|
|
if(NOT DEFINED CPACK_PACKAGE_VERSION)
|
|
find_package(Git)
|
|
|
|
if(GIT_FOUND)
|
|
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --always --abbrev=7
|
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
|
OUTPUT_VARIABLE GIT_DESCRIBE_STRING
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
else()
|
|
set(GIT_DESCRIBE_STRING "unknown-version")
|
|
endif()
|
|
|
|
set(CPACK_PACKAGE_VERSION ${GIT_DESCRIBE_STRING})
|
|
endif()
|
|
|
|
if(WIN32)
|
|
set(CPACK_GENERATOR "7Z")
|
|
else()
|
|
set(CPACK_GENERATOR "TXZ")
|
|
endif()
|
|
|
|
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/package")
|
|
|
|
include(CPack)
|