diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
| commit | 7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch) | |
| tree | 27fb39be241fdb5ac2734c574de678977d1856d0 /libs/cmake_common/mo2_cpp.cmake | |
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem,
Proton/umu-run integration, and Flatpak packaging.
Key features:
- FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak)
- Proton/GE-Proton/umu-run launcher with env var forwarding
- Flatpak support (sandbox-aware VFS, NXM handler, umu-run)
- Wine prefix management UI
- Case-insensitive path resolution for Linux filesystems
- QSettings-safe INI handling (avoids Bethesda INI corruption)
- Portable instance support with auto-generated launcher scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/cmake_common/mo2_cpp.cmake')
| -rw-r--r-- | libs/cmake_common/mo2_cpp.cmake | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/libs/cmake_common/mo2_cpp.cmake b/libs/cmake_common/mo2_cpp.cmake new file mode 100644 index 0000000..1ed4250 --- /dev/null +++ b/libs/cmake_common/mo2_cpp.cmake @@ -0,0 +1,358 @@ +cmake_minimum_required(VERSION 3.21) + +include(CMakeParseArguments) +include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake) + +#! mo2_configure_warnings : configuration warning for C++ target +# +# \param:WARNINGS level of warnings, possible values are ON/All, OFF, or 1, 2, 3, 4 +# for corresponding /W flags (ON is All) (default ON) +# \param:EXTERNAL enable warnings for external libraries, possible values are +# the same as warnings, but ON is 3 (default 1) +# +function(mo2_configure_warnings TARGET) + cmake_parse_arguments(MO2 "" "WARNINGS;EXTERNAL" "" ${ARGN}) + + mo2_set_if_not_defined(MO2_WARNINGS ON) + mo2_set_if_not_defined(MO2_EXTERNAL 1) + + if (${MO2_WARNINGS} STREQUAL "ON") + set(MO2_WARNINGS "All") + endif() + + if (${MO2_EXTERNAL} STREQUAL "ON") + set(MO2_EXTERNAL "3") + endif() + + if(NOT (${MO2_WARNINGS} STREQUAL "OFF")) + if(MSVC) + string(TOLOWER ${MO2_WARNINGS} MO2_WARNINGS) + target_compile_options(${TARGET} PRIVATE "/W${MO2_WARNINGS}" "/wd4464") + + # external warnings + if (${MO2_EXTERNAL} STREQUAL "OFF") + target_compile_options(${TARGET} + PRIVATE "/external:anglebrackets" "/external:W0") + else() + string(TOLOWER ${MO2_EXTERNAL} MO2_EXTERNAL) + target_compile_options(${TARGET} + PRIVATE "/external:anglebrackets" "/external:W${MO2_EXTERNAL}") + endif() + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wno-unused-parameter) + endif() + endif() + +endfunction() + +#! mo2_target_sources : add sources to a given target, eventually putting them in +# a folder +# +# \param: FILES list of .ui files to add +# \param: RC_FILES list of .qrc or .rc files to add +# +function(mo2_target_sources TARGET) + cmake_parse_arguments(MO2 "" "FOLDER" "PRIVATE;PUBLIC" ${ARGN}) + + mo2_set_if_not_defined(MO2_PRIVATE "") + mo2_set_if_not_defined(MO2_PUBLIC "") + + set(_sources "") + + if (MO2_PRIVATE) + target_sources(${TARGET} PRIVATE ${MO2_PRIVATE}) + list(APPEND _sources ${MO2_PRIVATE}) + endif() + + if (MO2_PUBLIC) + target_sources(${TARGET} PUBLIC ${MO2_PUBLIC}) + list(APPEND _sources ${MO2_PUBLIC}) + endif() + + if ((DEFINED MO2_FOLDER) AND _sources) + source_group(${MO2_FOLDER} FILES ${_sources}) + endif() + +endfunction() + +#! mo2_default_source_group : configure default source groups for MO2 +# +# \param:NO_SRC if set, the src source_group will not be created, default if false +# +function(mo2_default_source_group) + cmake_parse_arguments(MO2 "SOURCE_TREE" "" "" ${ARGN}) + + # remove the CMake Rules autogenerated folder + source_group("CMake Rules" REGULAR_EXPRESSION "^$") + source_group(ui REGULAR_EXPRESSION ".*\\.ui") + source_group(cmake FILES CMakeLists.txt) + source_group(autogen REGULAR_EXPRESSION ".*\\cmake_pch.*|.*\\.rule") + source_group(resources REGULAR_EXPRESSION ".*\\.qrc|.*\\.rc") + + if (NOT NO_SRC) + source_group(src REGULAR_EXPRESSION ".*\\.(h|cpp)$") + endif() +endfunction() + +#! mo2_configure_sources : configure sources for the given C++ target +# +# \param:SOURCE_TREE if set, a source_group will be created using TREE +# +function(mo2_configure_sources TARGET) + cmake_parse_arguments(MO2 "SOURCE_TREE" "" "" ${ARGN}) + + # find source files + if(DEFINED AUTOGEN_BUILD_DIR) + set(UI_HEADERS_DIR ${AUTOGEN_BUILD_DIR}) + else() + set(UI_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_autogen/include_RelWithDebInfo) + endif() + + file(GLOB_RECURSE source_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + file(GLOB_RECURSE header_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + file(GLOB_RECURSE qrc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc) + file(GLOB_RECURSE rc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.rc) + file(GLOB_RECURSE ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui) + file(GLOB_RECURSE ui_header_files CONFIGURE_DEPENDS ${UI_HEADERS_DIR}/*.h) + file(GLOB_RECURSE rule_files CONFIGURE_DEPENDS ${CMAKE_BINARY_DIR}/*.rule) + + + + if (${MO2_SOURCE_TREE}) + mo2_default_source_group(NO_SRC) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} + PREFIX src FILES ${source_files} ${header_files}) + else() + mo2_default_source_group() + endif() + + target_sources(${TARGET} + PRIVATE + ${source_files} + ${header_files} + ${ui_files} + ${ui_header_files} + ${qrc_files} + ${rc_files} + ${misc_files} + ${qm_files}) + +endfunction() + +#! mo2_configure_msvc : set flags for C++ target with MSVC +# +# \param:PERMISSIVE permissive mode (default OFF) +# \param:BIGOBJ enable bigobj (default OFF) +# \param:CLI enable C++/CLR (default OFF) +# +function(mo2_configure_msvc TARGET) + + if (NOT MSVC) + return() + endif() + + cmake_parse_arguments(MO2 "" "PERMISSIVE;BIGOBJ;CLI" "" ${ARGN}) + + set(CXX_STANDARD 23) + if (${MO2_CLI}) + set(CXX_STANDARD 17) + endif() + set_target_properties(${TARGET} PROPERTIES + CXX_STANDARD ${CXX_STANDARD} CXX_EXTENSIONS OFF) + + if(NOT ${MO2_PERMISSIVE}) + target_compile_options(${TARGET} PRIVATE "/permissive-") + endif() + + if(${MO2_BIGOBJ}) + target_compile_options(${TARGET} PRIVATE "/bigobj") + endif() + + # multi-threaded compilation + target_compile_options(${TARGET} PRIVATE "/MP") + + # VS emits a warning for LTCG, at least for uibase, so maybe not required? + target_link_options(${TARGET} + PRIVATE + $<$<CONFIG:RelWithDebInfo>: + # enable link-time code generation + /LTCG + + # disable incremental linking + /INCREMENTAL:NO + + # eliminates functions and data that are never referenced + /OPT:REF + + # perform identical COMDAT folding + /OPT:ICF + >) + + if(${MO2_CLI}) + set_target_properties(${TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "") + endif() + + get_property(CURRENT_STARTUP_PROJECT + DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT) + + if (NOT CURRENT_STARTUP_PROJECT) + message(STATUS "MO2: Setting startup project to " ${TARGET} ".") + set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${TARGET}) + endif() + +endfunction() + +#! mo2_configure_target : do basic configuration for a MO2 C++ target +# +# this functions does many things: +# - glob relevant files and add them to the target +# - set many compile flags, definitions, etc. +# - add step to create translations (if not turned OFF) +# +# \param:SOURCE_TREE if set, a source_group will be created using TREE +# \param:NO_SOURCES if set, mo2_configure_sources will not be called +# \param:WARNINGS enable all warnings, possible values are ON/All, OFF, or 1, 2, 3, 4 +# for corresponding /W flags (ON is All) (default ON) +# \param:EXTERNAL_WARNINGS enable warnings for external libraries, possible values are +# the same as warnings, but ON is 3 (default 1) +# \param:PERMISSIVE permissive mode (default OFF) +# \param:BIGOBJ enable bigobj (default OFF) +# \param:CLI enable C++/CLR (default OFF) +# \param:TRANSLATIONS generate translations (default ON) +# \param:AUTOMOC automoc (and autouic, autoqrc), (default ON) +# \param:EXTRA_TRANSLATIONS extra translations to include (folder) +# +function(mo2_configure_target TARGET) + cmake_parse_arguments(MO2 "SOURCE_TREE;NO_SOURCES" + "WARNINGS;EXTERNAL_WARNINGS;PERMISSIVE;BIGOBJ;CLI;TRANSLATIONS;AUTOMOC" + "EXTRA_TRANSLATIONS" + ${ARGN}) + + # configure parameters and compiler flags + mo2_set_if_not_defined(MO2_NO_SOURCES OFF) + mo2_set_if_not_defined(MO2_PERMISSIVE OFF) + mo2_set_if_not_defined(MO2_BIGOBJ OFF) + mo2_set_if_not_defined(MO2_CLI OFF) + mo2_set_if_not_defined(MO2_TRANSLATIONS ON) + mo2_set_if_not_defined(MO2_AUTOMOC ON) + mo2_set_if_not_defined(MO2_EXTRA_TRANSLATIONS "") + + mo2_configure_warnings(${TARGET} ${ARGN}) + mo2_configure_msvc(${TARGET} ${ARGN}) + + if (NOT MO2_NO_SOURCES) + mo2_configure_sources(${TARGET} ${ARGN}) + endif() + + if (${MO2_AUTOMOC}) + find_package(Qt6 COMPONENTS Widgets REQUIRED) + set_target_properties(${TARGET} + PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON) + endif() + + if(${MO2_TRANSLATIONS}) + mo2_add_translations(${TARGET} + INSTALL_RELEASE + SOURCES ${CMAKE_CURRENT_SOURCE_DIR} ${MO2_EXTRA_TRANSLATIONS}) + endif() + + mo2_find_git_hash(GIT_COMMIT_HASH) + target_compile_definitions( + ${TARGET} PRIVATE NOMINMAX QT_MESSAGELOGCONTEXT GITID="${GIT_COMMIT_HASH}") + + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pch.h) + target_precompile_headers(${PROJECT_NAME} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.h) + endif() +endfunction() + +#! mo2_configure_tests : configure a target as a MO2 C++ tests +# +# this function creates a set of tests available in the ${TARGET}_gtests variable +# +# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are +# OFF by default +# +function(mo2_configure_tests TARGET) + cmake_parse_arguments(MO2 "NO_MOCK;NO_MAIN" "" "" ${ARGN}) + mo2_configure_target(${TARGET} TRANSLATIONS OFF AUTOMOC OFF ${MO2_UNPARSED_ARGUMENTS}) + + find_package(GTest REQUIRED) + target_link_libraries(${TARGET} PRIVATE GTest::gtest) + + if (NOT MO2_NO_MOCK) + target_link_libraries(${TARGET} PRIVATE GTest::gmock) + endif() + if (NOT MO2_NO_MAIN) + target_link_libraries(${TARGET} PRIVATE GTest::gtest_main) + endif() + + # gtest_discover_tests would be nice but it requires Qt DLL, uibase, etc., in the + # path, etc., and is not working right now + # + # there is an open CMake issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21453 + # + # gtest_discover_tests(${TARGET} + # WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin + # PROPERTIES + # VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin + # ) + # + + gtest_add_tests( + TARGET ${TARGET} + TEST_LIST ${TARGET}_gtests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + set(${TARGET}_gtests ${${TARGET}_gtests} PARENT_SCOPE) + + if(WIN32) + mo2_deploy_qt_for_tests( + TARGET ${TARGET} + BINARIES "$<FILTER:$<TARGET_RUNTIME_DLLS:${TARGET}>,EXCLUDE,^.*[/\\]Qt[^/\\]*[.]dll>") + + set_tests_properties(${${TARGET}_gtests} + PROPERTIES + ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$<JOIN:$<TARGET_RUNTIME_DLL_DIRS:${TARGET}>,\;>" + ) + endif() +endfunction() + +#! mo2_configure_plugin : configure a target as a MO2 C++ plugin +# +# this function automatically set uibase as a dependency +# +# extra arguments are given to mo2_configure_target +# +function(mo2_configure_plugin TARGET) + mo2_configure_target(${TARGET} ${ARGN}) + if(WIN32) + mo2_set_project_to_run_from_install( + ${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/${MO2_INSTALL_BIN}/ModOrganizer.exe) + endif() +endfunction() + +#! mo2_install_plugin : install the given MO2 plugin +# +# for this to work properly, the target must have been configured +# +# \param:FOLDER install the plugin as a folder, instead of a single DLL +# +function(mo2_install_plugin TARGET) + cmake_parse_arguments(MO2 "FOLDER" "" "" ${ARGN}) + + if (${MO2_FOLDER}) + install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALL_BIN}/plugins/$<TARGET_FILE_BASE_NAME:${TARGET}>) + else() + install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALL_BIN}/plugins) + endif() + + if (NOT MO2_INSTALL_IS_BIN) + install(TARGETS ${TARGET} ARCHIVE DESTINATION lib) + if(WIN32) + # install PDB if possible + install(FILES $<TARGET_PDB_FILE:${TARGET}> DESTINATION pdb OPTIONAL) + endif() + endif() + +endfunction() |
