Merge branch 'rust-rewrite' into master

This commit is contained in:
Oliver Hamlet
2025-06-11 21:21:55 +01:00
251 changed files with 33700 additions and 16477 deletions
+271 -176
View File
File diff suppressed because it is too large Load Diff
+25 -43
View File
@@ -5,10 +5,8 @@ on:
tags: '*'
env:
BOOST_VERSION: 1.87.0
CBINDGEN_VERSION: 0.28.0
CARGO_TERM_COLOR: always
MSVC_CONFIG: RelWithDebInfo
CMAKE_CONFIG: RelWithDebInfo
jobs:
create_release:
@@ -42,7 +40,12 @@ jobs:
strategy:
matrix:
platform: [Win32, x64]
target:
- platform: Win32
triple: i686-pc-windows-msvc
- platform: x64
triple: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
@@ -57,54 +60,34 @@ jobs:
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
~/.cargo/.crates.toml
~/.cargo/.crates2.json
key: ${{ runner.os }}-cargo-cbindgen-${{ env.CBINDGEN_VERSION }}
target/
key: ${{ runner.os }}-${{ matrix.target.platform }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust i686-pc-windows-msvc target
run: rustup target add i686-pc-windows-msvc
if: matrix.platform == 'Win32'
if: matrix.target.platform == 'Win32'
- name: Get Boost metadata
id: boost-metadata
run: |
$BOOST_ROOT="${{ github.workspace }}/boost_" + $env:BOOST_VERSION -replace "\.", "_"
echo "root=$BOOST_ROOT" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
- name: Boost cache
id: boost-cache
uses: actions/cache@v4
with:
path: |
${{ steps.boost-metadata.outputs.root }}/boost
${{ steps.boost-metadata.outputs.root }}/stage
key: ${{ runner.os }}-x64-Boost-${{ env.BOOST_VERSION }}
# Need to build Boost's 'system' stub to generate the CMake config file.
- name: Download & build Boost
run: |
curl -sSfLO https://raw.githubusercontent.com/Ortham/ci-scripts/2.2.1/install_boost.py
python install_boost.py --directory ${{ github.workspace }} --boost-version ${{ env.BOOST_VERSION }} -a 64 system
if: steps.boost-cache.outputs.cache-hit != 'true'
- name: Install cbindgen
run: cargo install --version $env:CBINDGEN_VERSION cbindgen
- name: Set LIBLOOT_REVISION
shell: bash
run: echo "LIBLOOT_REVISION=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
- name: Run CMake
working-directory: cpp
run: |
cmake -G "Visual Studio 17 2022" `
-A ${{ matrix.platform }} `
-DCMAKE_PREFIX_PATH="${{ steps.boost-metadata.outputs.root }}\stage" `
-A ${{ matrix.target.platform }} `
-DCPACK_PACKAGE_VERSION="${{ needs.create_release.outputs.git_tag }}" `
-DCPACK_THREADS=0 `
-DRUST_TARGET="${{ matrix.target.triple }}" `
-B build
cmake --build build --parallel --config ${{ env.MSVC_CONFIG }}
cmake --build build --parallel --config ${{ env.CMAKE_CONFIG }}
- uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.13'
- name: Install packages for building docs
working-directory: docs
run: |
curl -sSfLO https://github.com/doxygen/doxygen/releases/download/Release_1_13_2/doxygen-1.13.2.windows.x64.bin.zip
Expand-Archive doxygen-1.13.2.windows.x64.bin.zip
@@ -112,28 +95,27 @@ jobs:
echo "${{ github.workspace }}\doxygen-1.13.2.windows.x64.bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
pipx install uv
cd docs
uv sync
- name: Build docs
working-directory: docs
run: uv run -- sphinx-build -b html . ../build/docs/html
run: uv run -- sphinx-build -b html . build/html
- name: Build archive
id: build-archive
shell: bash
working-directory: cpp/build
run: |
cd build
cpack -C ${{ env.MSVC_CONFIG }}
cpack -C ${{ env.CMAKE_CONFIG }}
if [[ "${{ matrix.platform }}" == "Win32" ]]
if [[ "${{ matrix.target.platform }}" == "Win32" ]]
then
PLATFORM=win32
else
PLATFORM=win64
fi
echo "filename=libloot-${{ needs.create_release.outputs.git_tag }}-${PLATFORM}.7z" >> $GITHUB_OUTPUT
echo "filename=libloot-${{ needs.create_release.outputs.git_tag }}-${PLATFORM}.7z" >> "$GITHUB_OUTPUT"
- name: Upload Archive
uses: actions/upload-release-asset@v1
@@ -141,6 +123,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_path: build/package/${{ steps.build-archive.outputs.filename }}
asset_path: cpp/build/package/${{ steps.build-archive.outputs.filename }}
asset_name: ${{ steps.build-archive.outputs.filename }}
asset_content_type: application/x-7z-compressed
+3 -53
View File
@@ -1,54 +1,4 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# Temporary files #
##################3
*~
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
# Other #
#########
*.user
*.suo
*.sdf
*.opensdf
build
/target
/testing-plugins
.venv/
.vscode/
.idea/
build/
-498
View File
@@ -1,498 +0,0 @@
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)
include(ExternalProject)
include(FetchContent)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
option(BUILD_SHARED_LIBS "Build a shared library" 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)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
##############################
# Get Build Revision
##############################
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_STRING
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(NOT GIT_COMMIT_STRING)
set(GIT_COMMIT_STRING "unknown")
endif()
message(STATUS "Git revision: ${GIT_COMMIT_STRING}")
# Write to file.
configure_file("${CMAKE_SOURCE_DIR}/src/api/loot_version.cpp.in" "${CMAKE_BINARY_DIR}/generated/loot_version.cpp" @ONLY)
##############################
# External Projects
##############################
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED CONFIG)
if(NOT DEFINED RUST_TARGET AND WIN32)
if(MSVC)
set(RUST_TARGET_ENV "msvc")
elseif(MINGW)
set(RUST_TARGET_ENV "gnu")
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(RUST_TARGET_ARCH "i686")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(RUST_TARGET_ARCH "x86_64")
endif()
if(DEFINED RUST_TARGET_ENV AND DEFINED RUST_TARGET_ARCH)
set(RUST_TARGET "${RUST_TARGET_ARCH}-pc-windows-${RUST_TARGET_ENV}")
endif()
endif()
if(DEFINED RUST_TARGET)
set(RUST_TARGET_ARGS --target ${RUST_TARGET})
set(RUST_CLEANUP_COMMAND ${CMAKE_COMMAND} -E rm -r "target/${RUST_TARGET}/release/deps" "target/release")
else()
set(RUST_CLEANUP_COMMAND ${CMAKE_COMMAND} -E rm -r "target/release/build" "target/release/deps")
endif()
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
find_package(ICU REQUIRED COMPONENTS data uc)
find_package(TBB REQUIRED)
endif()
if(NOT DEFINED ESPLUGIN_URL)
set(ESPLUGIN_URL "https://github.com/Ortham/esplugin/archive/refs/tags/6.1.3.tar.gz")
set(ESPLUGIN_HASH "SHA256=d11373b9108036e8d8453ff77000ae2961f9d1243c99c42dd732dad0c83d8618")
endif()
ExternalProject_Add(esplugin
PREFIX "external"
URL ${ESPLUGIN_URL}
URL_HASH ${ESPLUGIN_HASH}
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND cargo build --release --config debug="limited" --manifest-path ffi/Cargo.toml ${RUST_TARGET_ARGS} &&
cbindgen ffi/ -o ffi/include/esplugin.hpp
COMMAND ${RUST_CLEANUP_COMMAND}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS "<SOURCE_DIR>/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}esplugin_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Get_Property(esplugin SOURCE_DIR)
set(ESPLUGIN_INCLUDE_DIRS "${SOURCE_DIR}/ffi/include")
set(ESPLUGIN_LIBRARIES "${SOURCE_DIR}/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}esplugin_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(ESPLUGIN_LIBRARIES ${ESPLUGIN_LIBRARIES} userenv ntdll)
else()
set(ESPLUGIN_LIBRARIES ${ESPLUGIN_LIBRARIES} dl)
endif()
if(NOT DEFINED LIBLOADORDER_URL)
set(LIBLOADORDER_URL "https://github.com/Ortham/libloadorder/archive/refs/tags/18.4.0.tar.gz")
set(LIBLOADORDER_HASH "SHA256=c83f1f48829e013f2634041b62fed8c4957fb7469a401250b3793953ed3c3d2c")
endif()
ExternalProject_Add(libloadorder
PREFIX "external"
URL ${LIBLOADORDER_URL}
URL_HASH ${LIBLOADORDER_HASH}
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND cargo build --release --config debug="limited" --manifest-path ffi/Cargo.toml ${RUST_TARGET_ARGS} &&
cbindgen ffi/ -l c++ -o ffi/include/libloadorder.hpp
COMMAND ${RUST_CLEANUP_COMMAND}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS "<SOURCE_DIR>/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}loadorder_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Get_Property(libloadorder SOURCE_DIR)
set(LIBLOADORDER_INCLUDE_DIRS "${SOURCE_DIR}/ffi/include")
set(LIBLOADORDER_LIBRARIES "${SOURCE_DIR}/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}loadorder_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(LIBLOADORDER_LIBRARIES ${LIBLOADORDER_LIBRARIES} ntdll propsys userenv windowsapp)
else()
set(LIBLOADORDER_LIBRARIES ${LIBLOADORDER_LIBRARIES} dl)
endif()
if(NOT DEFINED LOOT_CONDITION_INTERPRETER_URL)
set(LOOT_CONDITION_INTERPRETER_URL "https://github.com/loot/loot-condition-interpreter/archive/refs/tags/5.3.2.tar.gz")
set(LOOT_CONDITION_INTERPRETER_HASH "SHA256=11a2c62898f6450cdae6db607c63fd7898f62bf67d4874b7ceed3d3693331af3")
endif()
ExternalProject_Add(loot-condition-interpreter
PREFIX "external"
URL ${LOOT_CONDITION_INTERPRETER_URL}
URL_HASH ${LOOT_CONDITION_INTERPRETER_HASH}
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND cargo build --release --config debug="limited" --manifest-path ffi/Cargo.toml ${RUST_TARGET_ARGS} &&
cbindgen ffi/ -o ffi/include/loot_condition_interpreter.h
COMMAND ${RUST_CLEANUP_COMMAND}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS "<SOURCE_DIR>/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}loot_condition_interpreter_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Get_Property(loot-condition-interpreter SOURCE_DIR)
set(LCI_INCLUDE_DIRS "${SOURCE_DIR}/ffi/include")
set(LCI_LIBRARIES "${SOURCE_DIR}/target/${RUST_TARGET}/release/${CMAKE_STATIC_LIBRARY_PREFIX}loot_condition_interpreter_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(LCI_LIBRARIES ${LCI_LIBRARIES} userenv)
else()
set(LCI_LIBRARIES ${LCI_LIBRARIES} dl)
endif()
FetchContent_Declare(
fmt
URL "https://github.com/fmtlib/fmt/archive/refs/tags/11.2.0.tar.gz"
URL_HASH "SHA256=bc23066d87ab3168f27cef3e97d545fa63314f5c79df5ea444d41d56f962c6af"
FIND_PACKAGE_ARGS)
set(SPDLOG_FMT_EXTERNAL ON)
FetchContent_Declare(
spdlog
URL "https://github.com/gabime/spdlog/archive/v1.15.3.tar.gz"
URL_HASH "SHA256=15a04e69c222eb6c01094b5c7ff8a249b36bb22788d72519646fb85feb267e67"
FIND_PACKAGE_ARGS)
set(YAML_MSVC_SHARED_RT ON)
set(YAML_CPP_BUILD_CONTRIB OFF)
set(YAML_CPP_BUILD_TOOLS OFF)
set(YAML_BUILD_SHARED_LIBS OFF)
set(YAML_CPP_BUILD_TESTS OFF)
# Suppress additional targets added by CTest, which is pulled in by yaml-cpp.
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
FetchContent_Declare(
yaml-cpp
URL "https://github.com/loot/yaml-cpp/archive/0.8.0+merge-key-support.3.tar.gz"
URL_HASH "SHA256=e2067f1ab8f658aeb8a8795fd0e06a753b4150b9352cae047280e659078dd44f")
# Set BUILD_SHARED_LIBS=OFF to prevent fmt and spdlog from being built as shared
# libraries.
set(LIBLOOT_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(fmt spdlog yaml-cpp)
# Restore the original value of BUILD_SHARED_LIBS.
set(BUILD_SHARED_LIBS ${LIBLOOT_BUILD_SHARED_LIBS})
##############################
# General Settings
##############################
set(LIBLOOT_SRC_API_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/api/api.cpp"
"${CMAKE_SOURCE_DIR}/src/api/api_database.cpp"
"${CMAKE_SOURCE_DIR}/src/api/bsa.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/cyclic_interaction_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/undefined_group_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/condition_evaluator.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/file.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/filename.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/group.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/location.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message_content.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_cleaning_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/tag.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game/game.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game/game_cache.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game/load_order_handler.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata_list.cpp"
"${CMAKE_SOURCE_DIR}/src/api/plugin.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/group_sort.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sort.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_graph.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sorting_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/crc.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/logging.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/text.cpp"
"${CMAKE_SOURCE_DIR}/src/api/vertex.cpp")
set(LIBLOOT_INCLUDE_H_FILES
"${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/include/loot/api_decorator.h"
"${CMAKE_SOURCE_DIR}/include/loot/database_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/plugin_not_loaded_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/undefined_group_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/edge_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/log_level.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/message_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/game_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/loot_version.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/file.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/filename.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/group.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/location.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message_content.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_cleaning_data.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/tag.h"
"${CMAKE_SOURCE_DIR}/include/loot/plugin_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/vertex.h")
set(LIBLOOT_SRC_API_H_FILES
"${CMAKE_SOURCE_DIR}/src/api/api_database.h"
"${CMAKE_SOURCE_DIR}/src/api/bsa.h"
"${CMAKE_SOURCE_DIR}/src/api/bsa_detail.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/condition_evaluator.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/file.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/group.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/location.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/message.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/message_content.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/plugin_cleaning_data.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/set.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata/yaml/tag.h"
"${CMAKE_SOURCE_DIR}/src/api/game/game.h"
"${CMAKE_SOURCE_DIR}/src/api/game/game_cache.h"
"${CMAKE_SOURCE_DIR}/src/api/game/load_order_handler.h"
"${CMAKE_SOURCE_DIR}/src/api/metadata_list.h"
"${CMAKE_SOURCE_DIR}/src/api/plugin.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/group_sort.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sort.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_graph.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sorting_data.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/crc.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/logging.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/text.h")
source_group(TREE "${CMAKE_SOURCE_DIR}/src/api"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_API_CPP_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/include"
PREFIX "Header Files"
FILES ${LIBLOOT_INCLUDE_H_FILES})
source_group(TREE "${CMAKE_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}
"${CMAKE_BINARY_DIR}/generated/loot_version.cpp"
"${CMAKE_SOURCE_DIR}/src/api/resource.rc")
##############################
# Define Targets
##############################
# Build API.
add_library(loot ${LIBLOOT_ALL_SOURCES})
add_dependencies(loot
esplugin
libloadorder
loot-condition-interpreter)
target_link_libraries(loot PRIVATE
Boost::headers
${ESPLUGIN_LIBRARIES}
${LIBLOADORDER_LIBRARIES}
${LCI_LIBRARIES}
fmt::fmt
spdlog::spdlog
yaml-cpp::yaml-cpp)
##############################
# Set Target-Specific Flags
##############################
set(LIBLOOT_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include")
set(LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS
${LIBLOADORDER_INCLUDE_DIRS}
${ESPLUGIN_INCLUDE_DIRS}
${LCI_INCLUDE_DIRS})
target_include_directories(loot PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_include_directories(loot PRIVATE ${LIBLOOT_INCLUDE_DIRS})
target_include_directories(loot SYSTEM PRIVATE
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(loot PRIVATE
UNICODE _UNICODE LOOT_EXPORT YAML_CPP_STATIC_DEFINE)
set(LOOT_LIBS ws2_32 bcrypt)
if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(LOOT_LIBS ${LOOT_LIBS} tbb_static)
endif()
target_link_libraries(loot PRIVATE ${LOOT_LIBS})
else()
set(LOOT_LIBS ICU::data ICU::uc pthread TBB::tbb)
target_link_libraries(loot PUBLIC ${LOOT_LIBS})
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(loot PRIVATE "-Wall" "-Wextra")
endif()
if(MSVC)
target_compile_options(loot PRIVATE
"/Zc:__cplusplus"
"/permissive-"
"/W4"
"/GL")
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(loot
PROPERTIES
CXX_CLANG_TIDY "${CLANG_TIDY_LIB}")
endif()
##############################
# Tests
##############################
if(LIBLOOT_BUILD_TESTS)
include("cmake/tests.cmake")
endif()
########################################
# Install
########################################
set(LIBLOOT_VERSION "0.27.0")
set_property(TARGET loot PROPERTY VERSION ${LIBLOOT_VERSION})
set_property(TARGET loot PROPERTY SOVERSION 0)
set_property(TARGET loot PROPERTY INTERFACE_libloot_MAJOR_VERSION 0)
set_property(TARGET loot APPEND PROPERTY COMPATIBLE_INTERFACE_STRING libloot_MAJOR_VERSION)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
VERSION "${LIBLOOT_VERSION}"
COMPATIBILITY AnyNewerVersion
)
install(TARGETS loot
EXPORT liblootTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(MSVC)
install(FILES $<TARGET_PDB_FILE:loot>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL
CONFIGURATIONS RelWithDebInfo)
endif()
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(LIBLOOT_INSTALL_DOCS)
install(DIRECTORY "${CMAKE_BINARY_DIR}/docs/html/"
DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
install(EXPORT liblootTargets
FILE liblootTargets.cmake
NAMESPACE libloot::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
########################################
# CPack
########################################
if(NOT DEFINED CPACK_PACKAGE_VERSION)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --always --abbrev=7
WORKING_DIRECTORY ${CMAKE_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(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CPACK_GENERATOR "7Z")
else()
set(CPACK_GENERATOR "TXZ")
endif()
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
include(CPack)
-17
View File
@@ -20,20 +20,3 @@ The best way to get started is to comment on something in GitHub's commit log or
Surprise pull requests aren't recommended because everything you touched may have been rewritten, making your changes a pain to integrate, or obsolete. There are only generally a few contributors at any one time though, so there's not much chance of painful conflicts requiring resolution, provided you're working off the correct branch.
When you do make a pull request, please do so from a branch which doesn't have the same name as they branch you're requesting your changes to be merged into. It's a lot easier to keep track of what pull request branches do when they're named something like `you:specific-cool-feature` rather than `you:master`.
## Code Style
libloot's code style is based on the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). Formatting style is codified in the repository's `.clang-format` file, but is not enforced.
### C++ Features
* Static variables may contain non-POD types.
* Reference arguments don't need to be `const` (ie. they can be used for output variables).
* Exceptions can be used.
* Unsigned integer types can be used.
* There's no restriction on which Boost libraries can be used.
* Specialising `std::hash` is allowed.
### Naming
* Constant, enumerator and variable names should use `camelCase` or `underscore_separators`, but they should be consistent within the same scope.
Generated
+1510
View File
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
[package]
name = "libloot"
version = "0.27.0"
edition = "2024"
license = "GPL-3.0-or-later"
[dependencies]
crc32fast = "1.4.2"
esplugin = "6.1.3"
fancy-regex = "0.14.0"
libloadorder = "18.4.0"
log = { version = "0.4.26", features = ["std"] }
loot-condition-interpreter = "5.3.2"
petgraph = "0.8.1"
rayon = "1.10.0"
rustc-hash = "2.1.1"
saphyr = "0.0.4"
unicase = "2.8.1"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.61.1", features = ["Win32_Storage_FileSystem"] }
[dev-dependencies]
parameterized-test = { path = "./parameterized-test" }
tempfile = "3.17.1"
[workspace]
members = ["cpp", "ffi-errors", "nodejs", "parameterized-test", "python"]
[profile.release]
debug = "limited"
lto = "thin"
[profile.rel-with-deb-info]
inherits = "release"
opt-level = 2
debug = "limited"
+44 -32
View File
@@ -11,11 +11,12 @@ LOOT also provides some load order error checking, including checks for requirem
libloot provides access to LOOT's metadata and sorting functionality, and the LOOT application is built using it.
libloot's core is written in Rust, and C++, Python and Node.js wrappers can be found in the `cpp`, `python` and `nodejs` subdirectories respectively.
## Downloads
Releases are hosted on [GitHub](https://github.com/loot/libloot/releases).
Snapshot builds are available as artifacts from [GitHub Actions runs](https://github.com/loot/libloot/actions), though they are only kept for 90 days and can only be downloaded when logged into a GitHub account. To mitigate these restrictions, snapshot build artifacts include a GPG signature that can be verified using the public key hosted [here](https://loot.github.io/.well-known/openpgpkey/hu/mj86by43a9hz8y8rbddtx54n3bwuuucg), which means it's possible to re-upload the artifacts elsewhere and still prove their authenticity.
The snapshot build artifacts are named like so:
@@ -24,48 +25,59 @@ The snapshot build artifacts are named like so:
libloot-<last tag>-<revisions since tag>-g<short revision ID>_<branch>-<platform>.<file extension>
```
## Building libloot
## Build
Refer to `.github/workflows/release.yml` for the build process.
Make sure you have [Rust](https://www.rust-lang.org/) installed.
### Linux
To build the library, set the `LIBLOOT_REVISION` env var and then run Cargo.
The build process assumes that you have already cloned the libloot repository,
that the current working directory is its root, and that the following
applications are already installed:
Using PowerShell:
- `cmake`
- `curl`
- `git`
- `pip3` (and therefore Python 3)
- `cargo` and the rest of the Rust toolchain (e.g. via
[rustup](https://rustup.rs/))
- `wget`
```powershell
$env:LIBLOOT_REVISION = git rev-parse --short HEAD
cargo build --release
```
The list above may be incomplete.
Using a POSIX shell:
### CMake Variables
```sh
export LIBLOOT_REVISION=$(git rev-parse --short HEAD)
cargo build --release
```
libloot uses the following CMake variables to set build parameters:
`LIBLOOT_REVISION` is used to embed the commit hash into the build, if it's not defined then `unknown` will be used instead.
Parameter | Values | Default |Description
----------|--------|---------|-----------
`BUILD_SHARED_LIBS` | `ON`, `OFF` | `ON` | Whether or not to build a shared libloot binary.
`LIBLOOT_BUILD_TESTS` | `ON`, `OFF` | `ON` | Whether or not to build libloot's tests.
`LIBLOOT_INSTALL_DOCS` | `ON`, `OFF` | `ON` | Whether or not to install libloot's docs (which need to be built separately).
`RUN_CLANG_TIDY` | `ON`, `OFF` | `OFF` | Whether or not to run clang-tidy during build. Has no effect when using CMake's MSVC generator.
`ESPLUGIN_URL` | A URL | A GitHub release archive URL | The URL to get a source code archive from. This can be used to supply a local path if the archive has already been downloaded (e.g. for offline builds).
`LIBLOADORDER_URL` | A URL | A GitHub release archive URL | The URL to get a source code archive from. This can be used to supply a local path if the archive has already been downloaded (e.g. for offline builds).
`LOOT_CONDITION_INTERPRETER_URL` | A URL | A GitHub release archive URL | The URL to get a source code archive from. This can be used to supply a local path if the archive has already been downloaded (e.g. for offline builds).
`FETCHCONTENT_SOURCE_DIR_YAML-CPP` | A path | Unset | The path to an existing yaml-cpp source folder to build yaml-cpp from. Note that libloot relies on [a fork of yaml-cpp](https://github.com/loot/yaml-cpp) to support YAML merge keys in metadata files. If unset, CMake will download the source from GitHub when the libloot build is configured.
### Tests
You may also need to set `CMAKE_PREFIX_PATH` if CMake cannot find Boost.
Before running the tests, first extract the [testing-plugins](https://github.com/Ortham/testing-plugins) archive to this readme's directory (so that there's a `testing-plugins` directory there).
## Building The Documentation
To do that using `curl` and `tar` in a POSIX shell:
Install [Doxygen](https://www.doxygen.nl/), Python and [uv](https://docs.astral.sh/uv/getting-started/installation/) and make sure they're accessible from your `PATH`, then run:
```sh
curl -sSfL https://github.com/Ortham/testing-plugins/archive/refs/tags/1.6.2.tar.gz | tar -xz --strip=1 --one-top-level=testing-plugins
```
To do that in PowerShell:
```powershell
Invoke-WebRequest https://github.com/Ortham/testing-plugins/archive/refs/tags/1.6.2.zip -OutFile testing-plugins-1.6.2.zip
Expand-Archive testing-plugins-1.6.2.zip .
Move-Item testing-plugins-1.6.2 testing-plugins
Remove-Item testing-plugins-1.6.2.zip
```
The tests can then be run using:
```
cd docs
uv run -- sphinx-build -b html . ../build/docs/html
cargo test
```
### API documentation
The Rust API's reference documentation can be built and viewed using:
```
cargo doc --open
```
The `docs` directory contains more general documentation.
+6
View File
@@ -0,0 +1,6 @@
# Config for building the CXX wrapper against the debug MSVC runtime, so that it
# can be used from Debug builds of C++ code.
# From <https://github.com/dtolnay/cxx/issues/880#issuecomment-2521375384>
[env]
CFLAGS = "/MDd"
CXXFLAGS = "/MDd"
View File
+315
View File
@@ -0,0 +1,315 @@
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)
include(ExternalProject)
include(FetchContent)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
option(BUILD_SHARED_LIBS "Build a shared library" 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)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
##############################
# External Projects
##############################
if(MSVC)
set(LIBLOOT_CPP_FILENAME "libloot_cpp.lib")
else()
set(LIBLOOT_CPP_FILENAME "liblibloot_cpp.a")
endif()
if(DEFINED RUST_TARGET)
set(TARGET_PATH "${CMAKE_SOURCE_DIR}/../target/${RUST_TARGET}")
else()
set(TARGET_PATH "${CMAKE_SOURCE_DIR}/../target")
endif()
add_custom_target(libloot-cpp-build
COMMAND cargo build
$<$<NOT:$<CONFIG:Debug>>:--release>
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:--config>
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:${CMAKE_SOURCE_DIR}/.cargo/msvc-debug-config.toml>
$<$<BOOL:${RUST_TARGET}>:--target>
$<$<BOOL:${RUST_TARGET}>:${RUST_TARGET}>
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-cpp-build)
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")
##############################
# General Settings
##############################
set(LIBLOOT_SRC_API_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/api/api.cpp"
"${CMAKE_SOURCE_DIR}/src/api/convert.cpp"
"${CMAKE_SOURCE_DIR}/src/api/database.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/cyclic_interaction_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/exception.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/undefined_group_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/file.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/filename.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/group.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/location.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message_content.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_cleaning_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/tag.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game.cpp"
"${CMAKE_SOURCE_DIR}/src/api/plugin.cpp"
"${CMAKE_SOURCE_DIR}/src/api/vertex.cpp")
set(LIBLOOT_INCLUDE_H_FILES
"${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/include/loot/api_decorator.h"
"${CMAKE_SOURCE_DIR}/include/loot/database_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/plugin_not_loaded_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/undefined_group_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/edge_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/log_level.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/message_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/game_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/loot_version.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/file.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/filename.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/group.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/location.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message_content.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_cleaning_data.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/tag.h"
"${CMAKE_SOURCE_DIR}/include/loot/plugin_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/vertex.h")
set(LIBLOOT_SRC_API_H_FILES
"${CMAKE_SOURCE_DIR}/src/api/convert.h"
"${CMAKE_SOURCE_DIR}/src/api/database.h"
"${CMAKE_SOURCE_DIR}/src/api/exception/exception.h"
"${CMAKE_SOURCE_DIR}/src/api/game.h"
"${CMAKE_SOURCE_DIR}/src/api/plugin.h")
source_group(TREE "${CMAKE_SOURCE_DIR}/src/api"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_API_CPP_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/include"
PREFIX "Header Files"
FILES ${LIBLOOT_INCLUDE_H_FILES})
source_group(TREE "${CMAKE_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}
"${CMAKE_SOURCE_DIR}/src/api/resource.rc")
##############################
# Define Targets
##############################
# Build API.
add_library(loot ${LIBLOOT_ALL_SOURCES})
target_link_libraries(loot PRIVATE libloot-cpp)
##############################
# Set Target-Specific Flags
##############################
set(LIBLOOT_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include")
set(LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS
${LIBLOADORDER_INCLUDE_DIRS}
${ESPLUGIN_INCLUDE_DIRS}
${LCI_INCLUDE_DIRS})
target_include_directories(loot PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_include_directories(loot PRIVATE ${LIBLOOT_INCLUDE_DIRS})
target_include_directories(loot SYSTEM PRIVATE
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(loot PRIVATE UNICODE _UNICODE LOOT_EXPORT)
set(LOOT_LIBS ntdll ws2_32 bcrypt)
target_link_libraries(loot PRIVATE ${LOOT_LIBS})
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(loot PRIVATE "-Wall" "-Wextra")
endif()
if(MSVC)
# Turn off permissive mode to be more standards-compliant and avoid compiler errors.
target_compile_options(loot PRIVATE "/permissive-" "/W4" "/Zc:__cplusplus" "/GL")
target_link_options(loot PRIVATE "/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(loot
PROPERTIES
CXX_CLANG_TIDY "${CLANG_TIDY_LIB}")
endif()
##############################
# Tests
##############################
if(LIBLOOT_BUILD_TESTS)
include("cmake/tests.cmake")
endif()
########################################
# Install
########################################
set(LIBLOOT_VERSION "0.27.0")
set_property(TARGET loot PROPERTY VERSION ${LIBLOOT_VERSION})
set_property(TARGET loot PROPERTY SOVERSION 0)
set_property(TARGET loot PROPERTY INTERFACE_libloot_MAJOR_VERSION 0)
set_property(TARGET loot APPEND PROPERTY COMPATIBLE_INTERFACE_STRING libloot_MAJOR_VERSION)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
VERSION "${LIBLOOT_VERSION}"
COMPATIBILITY AnyNewerVersion
)
install(TARGETS loot
EXPORT liblootTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(MSVC)
install(FILES $<TARGET_PDB_FILE:loot>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL
CONFIGURATIONS RelWithDebInfo)
endif()
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(LIBLOOT_INSTALL_DOCS)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/../docs/build/html/"
DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
install(EXPORT liblootTargets
FILE liblootTargets.cmake
NAMESPACE libloot::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
########################################
# 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 ${CMAKE_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(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CPACK_GENERATOR "7Z")
else()
set(CPACK_GENERATOR "TXZ")
endif()
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
include(CPack)
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "libloot-cpp"
version = "0.27.0"
edition = "2024"
license = "GPL-3.0-or-later"
[dependencies]
cxx = { version = "1.0", features = ["c++17"] }
delegate = "0.13.2"
libloot = { path = ".." }
libloot-ffi-errors = { path = "../ffi-errors" }
[build-dependencies]
cxx-build = "1.0"
[lib]
crate-type = ["staticlib"]
View File
+79
View File
@@ -0,0 +1,79 @@
# libloot-rs C++ wrapper
This is a wrapper around libloot that provides a C++ interface that's ABI-compatible with libloot v0.27.0.
The wrapper has two layers:
- a static library built using Cargo, which provides a C++ interface
- a shared library built using CMake, which wraps that C++ interface to provide another that is ABI-compatible with C++ libloot.
## Building
libloot uses the following CMake variables to set build parameters:
Parameter | Values | Default |Description
----------|--------|---------|-----------
`BUILD_SHARED_LIBS` | `ON`, `OFF` | `ON` | Whether or not to build a shared libloot binary.
`LIBLOOT_BUILD_TESTS` | `ON`, `OFF` | `ON` | Whether or not to build libloot's tests.
`LIBLOOT_INSTALL_DOCS` | `ON`, `OFF` | `ON` | Whether or not to install libloot's docs (which need to be built separately).
`RUN_CLANG_TIDY` | `ON`, `OFF` | `OFF` | Whether or not to run clang-tidy during build. Has no effect when using CMake's MSVC generator.
### Windows
To build a release build with debug info:
```
cmake -B build .
cmake --build build --parallel --config RelWithDebInfo
```
To build a debug build:
```
cmake -B build .
cmake --build build --parallel --config Debug
```
### Linux
To build a release build with debug info:
```
cmake -B build . -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --parallel
```
to build a debug build:
```
cargo build
cmake -B build . -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
```
### Tests
The build process also builds the test suite by default. To skip building the tests, pass `-DLIBLOOT_BUILD_TESTS=OFF` when first running CMake.
If built, the tests can be run using:
```
ctest --test-dir build --output-on-failure --parallel -V
```
### Documentation
Install [Doxygen](https://www.doxygen.nl/), Python and [uv](https://docs.astral.sh/uv/getting-started/installation/) and make sure they're accessible from your `PATH`, then run:
```
cd ../docs
uv run -- sphinx-build -b html . build/html
```
### Packaging
To package the build:
```
cpack --config build/CPackConfig.cmake -C RelWithDebInfo
```
+20
View File
@@ -0,0 +1,20 @@
fn main() {
cxx_build::bridge("src/lib.rs")
.std("c++17")
.flag_if_supported("/Zc:__cplusplus")
.flag_if_supported("/permissive-")
.compile("libloot-cpp");
// From <https://github.com/dtolnay/cxx/issues/880#issuecomment-2521375384>
if std::env::var("TARGET").is_ok_and(|s| s.contains("windows-msvc")) {
// MSVC compiler suite
if std::env::var("CFLAGS").is_ok_and(|s| s.contains("/MDd")) {
// debug runtime flag is set
// Don't link the default CRT
println!("cargo::rustc-link-arg=/nodefaultlib:msvcrt");
// Link the debug CRT instead
println!("cargo::rustc-link-arg=/defaultlib:msvcrtd");
}
}
}
+12 -44
View File
@@ -36,28 +36,7 @@ set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_INITIAL})
set(LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/main.cpp")
set(LIBLOOT_SRC_TESTS_INTERNALS_H_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/bsa_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_cache_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/load_order_handler_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/crc_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/text_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/condition_evaluator_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/file_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/group_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/location_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/message_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/message_content_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/plugin_cleaning_data_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/plugin_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/yaml/tag_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/plugin_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/sorting/group_sort_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/sorting/plugin_sort_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/sorting/plugin_graph_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/sorting/plugin_sorting_data_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata_list_test.h")
# set(LIBLOOT_SRC_TESTS_INTERNALS_H_FILES)
set(LIBLOOT_SRC_TESTS_INTERFACE_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/main.cpp")
@@ -75,16 +54,15 @@ set(LIBLOOT_SRC_TESTS_INTERFACE_H_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/message_content_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_cleaning_data_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/tag_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/plugin_interface_test.h")
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/tag_test.h")
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals"
PREFIX "Header Files"
FILES ${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES})
# source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals"
# PREFIX "Header Files"
# FILES ${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/interface"
PREFIX "Source Files"
@@ -98,7 +76,7 @@ source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/interface"
set(LIBLOOT_INTERNALS_TESTS_ALL_SOURCES
${LIBLOOT_ALL_SOURCES}
${LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES}
${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES}
# ${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES}
"${CMAKE_SOURCE_DIR}/src/tests/common_game_test_fixture.h"
"${CMAKE_SOURCE_DIR}/src/tests/test_helpers.h"
"${CMAKE_SOURCE_DIR}/src/tests/printers.h")
@@ -117,24 +95,14 @@ set(LIBLOOT_INTERFACE_TESTS_ALL_SOURCES
# Build tests.
add_executable(libloot_internals_tests ${LIBLOOT_INTERNALS_TESTS_ALL_SOURCES})
add_dependencies(libloot_internals_tests
esplugin
libloadorder
loot-condition-interpreter)
target_link_libraries(libloot_internals_tests PRIVATE
Boost::headers
${ESPLUGIN_LIBRARIES}
${LIBLOADORDER_LIBRARIES}
${LCI_LIBRARIES}
fmt::fmt
spdlog::spdlog
yaml-cpp::yaml-cpp
libloot-cpp
GTest::gtest_main)
# Build API tests.
add_executable(libloot_tests ${LIBLOOT_INTERFACE_TESTS_ALL_SOURCES})
add_dependencies(libloot_tests loot)
target_link_libraries(libloot_tests PRIVATE loot Boost::headers GTest::gtest_main)
target_link_libraries(libloot_tests PRIVATE loot GTest::gtest_main)
enable_testing()
gtest_discover_tests(libloot_internals_tests DISCOVERY_TIMEOUT 10)
@@ -156,16 +124,16 @@ target_include_directories(libloot_tests SYSTEM PRIVATE
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(libloot_internals_tests PRIVATE
UNICODE _UNICODE LOOT_STATIC YAML_CPP_STATIC_DEFINE)
UNICODE _UNICODE LOOT_STATIC)
target_compile_definitions(libloot_tests PRIVATE UNICODE _UNICODE)
if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(libloot_tests PRIVATE LOOT_STATIC)
endif()
endif()
target_link_libraries(libloot_internals_tests PRIVATE ${LOOT_LIBS})
target_link_libraries(libloot_tests PRIVATE ${LOOT_LIBS})
target_link_libraries(libloot_internals_tests PRIVATE ${LOOT_LIBS})
target_link_libraries(libloot_tests PRIVATE ${LOOT_LIBS})
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(libloot_internals_tests PRIVATE "-Wall" "-Wextra")

Some files were not shown because too many files have changed in this diff Show More