Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add basic add_commonlibsf_plugin command #31

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
CMakeUserPresets.json
CMakeFiles
CMakeCache.txt
*.cmake
/out*
/.vs*
/.vscode*
Expand Down
136 changes: 136 additions & 0 deletions CommonLibSF/cmake/CommonLibSF.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
function(commonlibsf_parse_version VERSION)
message("${version_match_count}")
string(REGEX MATCHALL "^([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(\\.([0-9]+))?)?)?$" version_match "${VERSION}")
unset(COMMONLIBSF_VERSION_MAJOR PARENT_SCOPE)
unset(COMMONLIBSF_VERSION_MINOR PARENT_SCOPE)
unset(COMMONLIBSF_VERSION_PATCH PARENT_SCOPE)
unset(COMMONLIBSF_VERSION_TWEAK PARENT_SCOPE)

if ("${version_match} " STREQUAL " ")
set(COMMONLIBSF_VERSION_MATCH FALSE PARENT_SCOPE)
return()
endif ()

set(COMMONLIBSF_VERSION_MATCH TRUE PARENT_SCOPE)
set(COMMONLIBSF_VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
set(COMMONLIBSF_VERSION_MINOR "0" PARENT_SCOPE)
set(COMMONLIBSF_VERSION_PATCH "0" PARENT_SCOPE)
set(COMMONLIBSF_VERSION_TWEAK "0" PARENT_SCOPE)

if (DEFINED CMAKE_MATCH_3)
set(COMMONLIBSF_VERSION_MINOR "${CMAKE_MATCH_3}" PARENT_SCOPE)
endif ()
if (DEFINED CMAKE_MATCH_5)
set(COMMONLIBSF_VERSION_PATCH "${CMAKE_MATCH_5}" PARENT_SCOPE)
endif ()
if (DEFINED CMAKE_MATCH_7)
set(COMMONLIBSF_VERSION_TWEAK "${CMAKE_MATCH_7}" PARENT_SCOPE)
endif ()
endfunction()

function(target_commonlibsf_properties TARGET)
# EXCLUDE_FROM_ALL and SOURCES are supported here to simplify passing arguments from add_commonlibsf_plugin.
set(options OPTIONAL USE_ADDRESS_LIBRARY USE_SIGNATURE_SCANNING STRUCT_DEPENDENT EXCLUDE_FROM_ALL)
set(oneValueArgs NAME AUTHOR EMAIL VERSION MINIMUM_SFSE_VERSION)
set(multiValueArgs COMPATIBLE_RUNTIMES SOURCES)
cmake_parse_arguments(PARSE_ARGV 1 ADD_COMMONLIBSF_PLUGIN "${options}" "${oneValueArgs}"
"${multiValueArgs}")

set(commonlibsf_plugin_file "${CMAKE_CURRENT_BINARY_DIR}/__${TARGET}Plugin.cpp")

# Set the plugin name.
set(commonlibsf_plugin_name "${TARGET}")
if (DEFINED ADD_COMMONLIBSF_PLUGIN_NAME)
set(commonlibsf_plugin_name "${ADD_COMMONLIBSF_PLUGIN_NAME}")
endif ()

# Setup version number of the plugin.
set(commonlibsf_plugin_version "${PROJECT_VERSION}")
if (DEFINED ADD_COMMONLIBSF_PLUGIN_VERSION)
set(commonlibsf_plugin_version "${ADD_COMMONLIBSF_PLUGIN_VERSION}")
endif ()
commonlibsf_parse_version("${commonlibsf_plugin_version}")
if (NOT DEFINED COMMONLIBSF_VERSION_MAJOR)
message(FATAL_ERROR "Unable to parse plugin version number ${commonlibsf_plugin_version}.")
endif ()
set(commonlibsf_plugin_version "REL::Version{ ${COMMONLIBSF_VERSION_MAJOR}, ${COMMONLIBSF_VERSION_MINOR}, ${COMMONLIBSF_VERSION_PATCH}, ${COMMONLIBSF_VERSION_TWEAK} }")

# Handle minimum SFSE version constraints.
if (NOT DEFINED ADD_COMMONLIBSF_PLUGIN_MINIMUM_SFSE_VERSION)
set(ADD_COMMONLIBSF_PLUGIN_MINIMUM_SFSE_VERSION 0)
endif ()
commonlibsf_parse_version("${ADD_COMMONLIBSF_PLUGIN_MINIMUM_SFSE_VERSION}")
if (NOT COMMONLIBSF_VERSION_MATCH)
message(FATAL_ERROR "Unable to parse SFSE minimum SFSE version number "
"${ADD_COMMONLIBSF_PLUGIN_MINIMUM_SFSE_VERSION}.")
endif ()
set(commonlibsf_min_sfse_version "REL::Version{ ${COMMONLIBSF_VERSION_MAJOR}, ${COMMONLIBSF_VERSION_MINOR}, ${COMMONLIBSF_VERSION_PATCH}, ${COMMONLIBSF_VERSION_TWEAK} }")

# Setup compatibility configuration.
if (NOT ADD_COMMONLIBSF_PLUGIN_STRUCT_DEPENDENT)
set(commonlibsf_plugin_struct_compatibility "false")
else ()
set(commonlibsf_plugin_struct_compatibility "true")
endif ()

if (NOT ADD_COMMONLIBSF_PLUGIN_USE_SIGNATURE_SCANNING AND NOT DEFINED ADD_COMMONLIBSF_PLUGIN_COMPATIBLE_RUNTIMES)
set(ADD_COMMONLIBSF_PLUGIN_USE_ADDRESS_LIBRARY TRUE)
endif ()
if (ADD_COMMONLIBSF_PLUGIN_USE_ADDRESS_LIBRARY OR ADD_COMMONLIBSF_PLUGIN_USE_SIGNATURE_SCANNING)
if (DEFINED ADD_COMMONLIBSF_PLUGIN_COMPATIBLE_RUNTIMES)
message(FATAL_ERROR "COMPATIBLE_RUNTIMES option should not be used with USE_ADDRESS_LIBRARY or USE_SIGNATURE_SCANNING")
endif ()

if (NOT ADD_COMMONLIBSF_PLUGIN_USE_ADDRESS_LIBRARY)
set(commonlibsf_plugin_compatibility "false")
else ()
set(commonlibsf_plugin_compatibility "true")
endif ()
else ()
list(LENGTH ${ADD_COMMONLIBSF_PLUGIN_COMPATIBLE_RUNTIMES} commonlibsf_plugin_compatibility_count)
if(commonlibsf_plugin_compatibility_count GREATER 16)
message(FATAL_ERROR "No more than 16 version numbers can be provided for COMPATIBLE_RUNTIMES.")
endif()
foreach (STARFIELD_VERSION ${ADD_COMMONLIBSF_PLUGIN_COMPATIBLE_RUNTIMES})
if (DEFINED commonlibsf_plugin_compatibility)
set(commonlibsf_plugin_compatibility "${commonlibsf_plugin_compatibility}, ")
endif ()
commonlibsf_parse_version("${STARFIELD_VERSION}")
if (NOT COMMONLIBSF_VERSION_MATCH)
message(FATAL_ERROR "Unable to parse Starfield runtime version number ${STARFIELD_VERSION}.")
endif ()
set(commonlibsf_plugin_compatibility "${commonlibsf_plugin_compatibility}REL::Version{ ${COMMONLIBSF_VERSION_MAJOR}, ${COMMONLIBSF_VERSION_MINOR}, ${COMMONLIBSF_VERSION_PATCH}, ${COMMONLIBSF_VERSION_TWEAK} }")
endforeach ()
set(commonlibsf_plugin_compatibility "{ ${commonlibsf_plugin_compatibility} }")
endif ()

file(WRITE "${commonlibsf_plugin_file}"
"SFSEPluginVersion = []() noexcept {\n"
" SFSE::PluginVersionData data{};\n"
"\n"
" data.PluginVersion(${commonlibsf_plugin_version});\n"
" data.PluginName(${commonlibsf_plugin_name});\n"
" data.AuthorName(${ADD_COMMONLIBSF_PLUGIN_AUTHOR});\n"
" data.SupportEmail(${ADD_COMMONLIBSF_PLUGIN_EMAIL});\n"
" data.UsesAddressLibrary(${commonlibsf_plugin_compatibility});\n"
" data.IsLayoutDependent(${commonlibsf_plugin_struct_compatibility});\n"
" data.MinimumRequiredXSEVersion(${commonlibsf_min_sfse_version});\n"
"}\n")

target_sources("${TARGET}" PRIVATE "${commonlibsf_plugin_file}")
target_compile_definitions("${TARGET}" PRIVATE __CMAKE_COMMONLIBSF_PLUGIN=1)
target_link_libraries("${TARGET}" PUBLIC CommonLibSF::CommonLibSF)
target_include_directories("${TARGET}" PUBLIC CommonLibSF_INCLUDE_DIRS)
endfunction()

function(add_commonlibsf_plugin TARGET)
set(options OPTIONAL USE_ADDRESS_LIBRARY USE_SIGNATURE_SCANNING STRUCT_DEPENDENT EXCLUDE_FROM_ALL)
set(oneValueArgs NAME AUTHOR EMAIL VERSION MINIMUM_SFSE_VERSION)
set(multiValueArgs COMPATIBLE_RUNTIMES SOURCES)
cmake_parse_arguments(PARSE_ARGV 1 ADD_COMMONLIBSF_PLUGIN "${options}" "${oneValueArgs}"
"${multiValueArgs}")

add_library("${TARGET}" SHARED $<$<BOOL:${ADD_COMMONLIBSF_PLUGIN_EXCLUDE_FROM_ALL}>:EXCLUDE_FROM_ALL>
${ADD_COMMONLIBSF_PLUGIN_SOURCES})
target_commonlibsf_properties("${TARGET}" ${ARGN})
endfunction()
1 change: 1 addition & 0 deletions CommonLibSF/cmake/config.cmake.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
include(CMakeFindDependencyMacro)

find_dependency(spdlog CONFIG)
Expand Down
23 changes: 11 additions & 12 deletions CommonLibSF/include/SFSE/Interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,11 @@ namespace SFSE

constexpr void PluginVersion(std::uint32_t a_version) noexcept { pluginVersion = a_version; }
ThirdEyeSqueegee marked this conversation as resolved.
Show resolved Hide resolved

[[nodiscard]] constexpr std::uint32_t GetPluginVersion() const noexcept { return pluginVersion; }

constexpr void PluginName(std::string_view a_plugin) noexcept { SetCharBuffer(a_plugin, std::span{ pluginName }); }

[[nodiscard]] constexpr std::string_view GetPluginName() const noexcept { return std::string_view{ pluginName }; }

constexpr void AuthorName(std::string_view a_name) noexcept { SetCharBuffer(a_name, std::span{ author }); }

[[nodiscard]] constexpr std::string_view GetAuthorName() const noexcept { return std::string_view{ author }; }
constexpr void SupportEmail(std::string_view a_email) noexcept { SetCharBuffer(a_email, std::span{ email }); }

constexpr void UsesSigScanning(bool a_value) noexcept { addressIndependence = !a_value; }

Expand All @@ -138,6 +134,7 @@ namespace SFSE
std::uint32_t pluginVersion = 0;
char pluginName[256] = {};
char author[256] = {};
char email[252] = {};
ThirdEyeSqueegee marked this conversation as resolved.
Show resolved Hide resolved
std::uint32_t addressIndependence;
std::uint32_t structureCompatibility;
std::uint32_t compatibleVersions[16] = {};
Expand All @@ -158,13 +155,15 @@ namespace SFSE
static_assert(offsetof(PluginVersionData, pluginVersion) == 0x004);
static_assert(offsetof(PluginVersionData, pluginName) == 0x008);
static_assert(offsetof(PluginVersionData, author) == 0x108);
static_assert(offsetof(PluginVersionData, addressIndependence) == 0x208);
static_assert(offsetof(PluginVersionData, structureCompatibility) == 0x20C);
static_assert(offsetof(PluginVersionData, compatibleVersions) == 0x210);
static_assert(offsetof(PluginVersionData, xseMinimum) == 0x250);
static_assert(offsetof(PluginVersionData, reservedNonBreaking) == 0x254);
static_assert(offsetof(PluginVersionData, reservedBreaking) == 0x258);
static_assert(sizeof(PluginVersionData) == 0x25C);
static_assert(offsetof(PluginVersionData, email) == 0x208);
static_assert(offsetof(PluginVersionData, addressIndependence) == 0x304);
static_assert(offsetof(PluginVersionData, structureCompatibility) == 0x308);
static_assert(offsetof(PluginVersionData, compatibleVersions) == 0x30C);
static_assert(offsetof(PluginVersionData, xseMinimum) == 0x34C);
static_assert(offsetof(PluginVersionData, reservedNonBreaking) == 0x350);
static_assert(offsetof(PluginVersionData, reservedBreaking) == 0x354);
static_assert(sizeof(PluginVersionData) == 0x358);
} // namespace SFSE

#define SFSEPluginVersion extern "C" [[maybe_unused]] __declspec(dllexport) constinit SFSE::PluginVersionData SFSEPlugin_Version
#define SFSEPluginLoad(...) extern "C" [[maybe_unused]] __declspec(dllexport) bool SFSEPlugin_Load(__VA_ARGS__)