Files

389 lines
13 KiB
CMake
Raw Permalink Normal View History

2022-04-17 17:39:15 +02:00
cmake_minimum_required(VERSION 3.16)
2023-07-22 18:51:53 +02:00
if (POLICY CMP0144)
cmake_policy(SET CMP0144 NEW)
endif()
2022-04-17 17:39:15 +02:00
include(CMakeParseArguments)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_targets.cmake)
2022-05-02 14:33:57 +02:00
#! mo2_configure_target : do basic configuration for a MO2 C++ target
2022-04-17 17:39:15 +02:00
#
# 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)
#
2022-05-02 14:33:57 +02:00
# \param:SOURCE_TREE if set, a source_group will be created using TREE
# \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)
2022-04-17 17:39:15 +02:00
# \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)
2022-05-02 14:33:57 +02:00
# \param:EXTRA_TRANSLATIONS extra translations to include (folder)
# \param:PUBLIC_DEPENDS adds PUBLIC dependencies to the target, see
# mo2_add_dependencies for information on what is available
# \param:PRIVATE_DEPENDS same a PUBLIC_DEPENDS, but link is PRIVATE instead of PUBLIC
2022-04-17 17:39:15 +02:00
#
2022-05-02 14:33:57 +02:00
function(mo2_configure_target TARGET)
2022-04-28 17:53:25 +02:00
cmake_parse_arguments(MO2 "SOURCE_TREE"
"WARNINGS;EXTERNAL_WARNINGS;PERMISSIVE;BIGOBJ;CLI;TRANSLATIONS;AUTOMOC"
2022-04-17 17:39:15 +02:00
"EXTRA_TRANSLATIONS;PUBLIC_DEPENDS;PRIVATE_DEPENDS"
${ARGN})
# configure parameters and compiler flags
mo2_set_if_not_defined(MO2_WARNINGS ON)
mo2_set_if_not_defined(MO2_EXTERNAL_WARNINGS 1)
2022-04-17 17:39:15 +02:00
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_set_if_not_defined(MO2_PUBLIC_DEPENDS "")
mo2_set_if_not_defined(MO2_PRIVATE_DEPENDS "")
if (${MO2_AUTOMOC})
find_package(Qt6 COMPONENTS Widgets REQUIRED)
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET}
2022-04-17 17:39:15 +02:00
PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON)
endif()
2022-05-02 14:33:57 +02:00
target_compile_options(${TARGET}
2022-04-18 01:02:53 +02:00
PRIVATE "/MP"
2022-04-18 22:31:40 +02:00
$<$<CONFIG:RelWithDebInfo>:/O2>
)
2022-04-17 17:39:15 +02:00
2022-04-18 01:02:53 +02:00
set(CXX_STANDARD 20)
if (${MO2_CLI})
set(CXX_STANDARD 17)
endif()
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET} PROPERTIES
2022-04-18 01:02:53 +02:00
CXX_STANDARD ${CXX_STANDARD}
CXX_EXTENSIONS OFF)
2022-04-17 17:39:15 +02:00
# VS emits a warning for LTCG, at least for uibase, so maybe not required?
2022-05-02 14:33:57 +02:00
target_link_options(${TARGET}
2022-04-18 22:31:40 +02:00
PRIVATE
$<$<CONFIG:RelWithDebInfo>:/LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF>)
2022-04-17 17:39:15 +02:00
2022-05-05 21:46:09 +02:00
if (${MO2_WARNINGS} STREQUAL "ON")
set(MO2_WARNINGS "All")
endif()
if (${MO2_EXTERNAL_WARNINGS} STREQUAL "ON")
set(MO2_EXTERNAL_WARNINGS "3")
endif()
2022-05-05 21:46:09 +02:00
if(NOT (${MO2_WARNINGS} STREQUAL "OFF"))
string(TOLOWER ${MO2_WARNINGS} MO2_WARNINGS)
target_compile_options(${TARGET} PRIVATE "/W${MO2_WARNINGS}" "/wd4464")
# external warnings
if (${MO2_EXTERNAL_WARNINGS} STREQUAL "OFF")
target_compile_options(${TARGET}
PRIVATE "/external:anglebrackets" "/external:W0")
else()
string(TOLOWER ${MO2_EXTERNAL_WARNINGS} MO2_EXTERNAL_WARNINGS)
target_compile_options(${TARGET}
PRIVATE "/external:anglebrackets" "/external:W${MO2_EXTERNAL_WARNINGS}")
endif()
2022-04-17 17:39:15 +02:00
endif()
if(NOT ${MO2_PERMISSIVE})
2022-05-02 14:33:57 +02:00
target_compile_options(${TARGET} PRIVATE "/permissive-")
2022-04-17 17:39:15 +02:00
endif()
if(${MO2_BIGOBJ})
2022-05-02 14:33:57 +02:00
target_compile_options(${TARGET} PRIVATE "/bigobj")
2022-04-17 17:39:15 +02:00
endif()
# 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()
2022-04-20 00:30:40 +02:00
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)
2022-04-17 17:39:15 +02:00
file(GLOB_RECURSE ui_header_files CONFIGURE_DEPENDS ${UI_HEADERS_DIR}/*.h)
file(GLOB_RECURSE rule_files CONFIGURE_DEPENDS ${CMAKE_BINARY_DIR}/*.rule)
file(GLOB_RECURSE misc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../*.natvis)
2022-04-28 17:53:25 +02:00
if (${MO2_SOURCE_TREE})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX src
FILES ${source_files} ${header_files})
else()
source_group(src REGULAR_EXPRESSION ".*\\.(h|cpp)")
endif()
2022-04-17 17:39:15 +02:00
source_group(ui REGULAR_EXPRESSION ".*\\.ui")
source_group(cmake FILES CMakeLists.txt)
source_group(autogen FILES ${rule_files} ${qm_files} ${ui_header_files})
source_group(autogen REGULAR_EXPRESSION ".*\\cmake_pch.*")
source_group(resources FILES ${rc_files} ${qrc_files})
2022-04-18 01:02:53 +02:00
2022-04-17 17:39:15 +02:00
if(${MO2_TRANSLATIONS})
2022-05-02 14:33:57 +02:00
mo2_add_translations(${TARGET}
2023-09-04 18:01:46 -05:00
INSTALL_RELEASE
SOURCES ${CMAKE_CURRENT_SOURCE_DIR} ${MO2_EXTRA_TRANSLATIONS})
2022-04-17 17:39:15 +02:00
endif()
2022-05-02 14:33:57 +02:00
target_sources(${TARGET}
2022-04-17 17:59:38 +02:00
PRIVATE
${source_files}
${header_files}
${ui_files}
${ui_header_files}
${qrc_files}
${rc_files}
${misc_files}
${qm_files})
2022-04-17 17:39:15 +02:00
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
target_compile_definitions(
2022-05-02 14:33:57 +02:00
${TARGET}
2022-04-17 17:39:15 +02:00
PRIVATE
_UNICODE
UNICODE
NOMINMAX
_CRT_SECURE_NO_WARNINGS
BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
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()
if(${MO2_CLI})
if (CMAKE_GENERATOR MATCHES "Visual Studio")
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "")
2022-04-17 17:39:15 +02:00
else()
# can this really happen?
2022-04-17 17:39:15 +02:00
set(COMPILE_FLAGS "${COMPILE_FLAGS} /clr")
string(REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
endif()
endif()
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET} PROPERTIES VS_STARTUP_PROJECT ${TARGET})
2022-04-17 17:39:15 +02:00
2022-05-02 14:33:57 +02:00
target_link_libraries(${TARGET} PRIVATE Version Dbghelp)
2022-04-17 17:39:15 +02:00
if (MO2_PUBLIC_DEPENDS)
2022-05-02 14:33:57 +02:00
mo2_add_dependencies(${TARGET} PUBLIC ${MO2_PUBLIC_DEPENDS})
2022-04-17 17:39:15 +02:00
endif()
if (MO2_PRIVATE_DEPENDS)
2022-05-02 14:33:57 +02:00
mo2_add_dependencies(${TARGET} PRIVATE ${MO2_PRIVATE_DEPENDS})
2022-04-17 17:39:15 +02:00
endif()
# set the VS startup project if not already set
get_property(startup_project DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT)
if (NOT startup_project)
2022-05-02 14:33:57 +02:00
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${TARGET})
endif()
2022-04-17 17:39:15 +02:00
endfunction()
#! mo2_configure_tests : configure a target as a MO2 C++ tests
#
2022-05-02 14:33:57 +02:00
# this function creates a set of tests available in the ${TARET}_gtests variable
#
2022-05-02 14:53:20 +02:00
# \param:DEPENDS dependencies to link to AND add folder for ctest to look for DLLs,
# typically the library being tests
#
2022-05-02 14:33:57 +02:00
# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are
# OFF by default
2022-04-17 17:39:15 +02:00
#
2022-05-02 13:52:55 +02:00
function(mo2_configure_tests TARGET)
mo2_configure_target(${TARGET} TRANSLATIONS OFF AUTOMOC OFF ${ARGN})
2022-05-02 14:53:20 +02:00
cmake_parse_arguments(MO2 "" "" "DEPENDS" ${ARGN})
2022-05-02 13:52:55 +02:00
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "tests")
2022-04-17 17:39:15 +02:00
find_package(GTest REQUIRED)
2022-05-02 13:52:55 +02:00
target_link_libraries(${TARGET} PRIVATE GTest::gtest GTest::gmock GTest::gtest_main)
2022-04-17 17:39:15 +02:00
2022-05-02 13:52:55 +02:00
# 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 ${MO2_INSTALL_PATH}/bin
# PROPERTIES
# VS_DEBUGGER_WORKING_DIRECTORY ${MO2_INSTALL_PATH}/bin
# )
#
2022-05-02 14:53:20 +02:00
set(extra_paths "${MO2_INSTALL_PATH}/bin/dlls")
foreach (DEPEND ${MO2_DEPENDS})
target_link_libraries(${TARGET} PUBLIC ${DEPEND})
string(APPEND extra_paths "\\;$<TARGET_FILE_DIR:${DEPEND}>")
endforeach()
2022-05-02 13:52:55 +02:00
gtest_add_tests(TARGET ${TARGET} TEST_LIST ${TARGET}_gtests)
set(${TARGET}_gtests ${${TARGET}_gtests} PARENT_SCOPE)
2022-05-02 14:53:20 +02:00
set_tests_properties(${${TARGET}_gtests}
2022-05-02 13:52:55 +02:00
PROPERTIES
WORKING_DIRECTORY "${MO2_INSTALL_PATH}/bin"
ENVIRONMENT_MODIFICATION
2022-05-02 14:53:20 +02:00
"PATH=path_list_prepend:${extra_paths}")
2022-04-17 17:39:15 +02:00
endfunction()
#! mo2_configure_uibase : configure the uibase target for MO2
#
# this function does mostly nothing except calling mo2_configure_target, but is useful
# to be consistent with other mo2_configure_XXX
#
2022-05-02 14:33:57 +02:00
function(mo2_configure_uibase TARGET)
if (NOT (${TARGET} STREQUAL "uibase"))
2022-04-17 17:39:15 +02:00
message(WARNING "mo2_configure_uibase() should only be used on the uibase target")
endif()
2022-05-02 14:33:57 +02:00
mo2_configure_target(${TARGET} ${ARGN})
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "uibase")
2022-04-17 17:39:15 +02:00
2022-05-02 14:33:57 +02:00
target_include_directories(${TARGET} PUBLIC
2022-04-17 17:39:15 +02:00
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/game_features)
mo2_set_project_to_run_from_install(
2022-05-02 14:33:57 +02:00
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
2022-04-17 17:39:15 +02:00
endfunction()
#! mo2_configure_plugin : configure a target as a MO2 C++ plugin
#
2022-05-02 14:33:57 +02:00
# this function automatically set uibase as a dependency
#
2022-04-17 17:39:15 +02:00
# extra arguments are given to mo2_configure_target
#
2022-05-02 13:52:55 +02:00
function(mo2_configure_plugin TARGET)
mo2_configure_target(${TARGET} ${ARGN})
mo2_add_dependencies(${TARGET} PUBLIC uibase)
2022-04-17 17:39:15 +02:00
2022-05-02 13:52:55 +02:00
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "plugin")
mo2_set_project_to_run_from_install(
2022-05-02 13:52:55 +02:00
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
2022-04-17 17:39:15 +02:00
endfunction()
2022-05-02 14:33:57 +02:00
#! mo2_configure_library : configure a C++ library (NOT a plugin), can be a STATIC
# or SHARED library
2022-04-17 17:39:15 +02:00
#
2022-05-02 14:33:57 +02:00
# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are
# OFF by default
2022-04-17 17:39:15 +02:00
#
2022-05-02 14:33:57 +02:00
function(mo2_configure_library TARGET)
mo2_configure_target(${TARGET} AUTOMOC OFF TRANSLATIONS OFF ${ARGN})
2022-04-17 17:39:15 +02:00
2022-05-02 14:33:57 +02:00
get_target_property(TARGET_TYPE ${TARGET} TYPE)
2022-04-17 17:39:15 +02:00
2022-05-02 14:33:57 +02:00
target_include_directories(${TARGET}
2022-04-17 21:45:57 +02:00
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
2022-04-17 17:39:15 +02:00
if (${TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "library-static")
2022-04-17 17:39:15 +02:00
else()
mo2_set_project_to_run_from_install(
2022-05-02 14:33:57 +02:00
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "library-shared")
2022-04-17 17:39:15 +02:00
endif()
endfunction()
#! mo2_configure_executable : configure a target as MO2 C++ executable
#
2022-05-02 14:33:57 +02:00
# \param:ELEVATED set flag on the executable to run as elevated by default
#
2022-04-17 17:39:15 +02:00
# extra arguments are given to mo2_configure_target
#
2022-05-02 14:33:57 +02:00
function(mo2_configure_executable TARGET)
2022-04-17 20:50:58 +02:00
cmake_parse_arguments(MO2 "ELEVATED" "" "" ${ARGN})
2022-05-02 14:33:57 +02:00
mo2_configure_target(${TARGET} ${ARGN})
set_target_properties(${TARGET}
2022-05-02 15:46:00 +02:00
PROPERTIES WIN32_EXECUTABLE TRUE MO2_TARGET_TYPE "executable")
2022-04-17 20:50:58 +02:00
2022-05-02 14:33:57 +02:00
get_target_property(output_name ${TARGET} OUTPUT_NAME)
if("${output_name}" STREQUAL "output_name-NOTFOUND")
2022-05-02 14:33:57 +02:00
set(output_name ${TARGET})
endif()
mo2_set_project_to_run_from_install(
2022-05-02 14:33:57 +02:00
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/${output_name})
2022-04-17 20:50:58 +02:00
if (${MO2_ELEVATED})
# does not work with target_link_options, so keeping it that way for now... this
# is not a very used option anyway
2022-05-02 14:33:57 +02:00
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS
2022-04-17 20:50:58 +02:00
"/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
endif()
2022-04-17 17:39:15 +02:00
endfunction()
#! mo2_install_target : set install for a MO2 target
#
# for this to work properly, the target must have been configured
#
2022-05-02 14:33:57 +02:00
# \param:FOLDER install the plugin as a folder, instead of a single DLL, ignore for
# other target types
# \param:INSTALLDIR installation directory, default is automatically deduced based on
# the target type, this parameter is ignored for plugins and static libraries
#
function(mo2_install_target TARGET)
2022-05-02 13:52:55 +02:00
cmake_parse_arguments(MO2 "FOLDER" "INSTALLDIR" "" ${ARGN})
2022-04-17 17:39:15 +02:00
2022-05-02 14:33:57 +02:00
get_target_property(MO2_TARGET_TYPE ${TARGET} MO2_TARGET_TYPE)
2022-04-17 17:39:15 +02:00
# core install: .lib, .dll or .exe, to the right folder
if (${MO2_TARGET_TYPE} STREQUAL "uibase")
2022-05-02 14:33:57 +02:00
mo2_set_if_not_defined(MO2_INSTALLDIR "bin")
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
2022-04-17 17:39:15 +02:00
elseif (${MO2_TARGET_TYPE} STREQUAL "plugin")
2022-05-02 13:52:55 +02:00
if (${MO2_FOLDER})
install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins/$<TARGET_FILE_BASE_NAME:${TARGET}>)
2022-05-02 13:52:55 +02:00
else()
2022-05-02 14:33:57 +02:00
install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins)
2022-05-02 13:52:55 +02:00
endif()
2022-05-02 14:33:57 +02:00
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
2022-04-17 17:39:15 +02:00
elseif (${MO2_TARGET_TYPE} STREQUAL "library-static")
2022-05-02 14:33:57 +02:00
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
2022-04-17 17:39:15 +02:00
elseif (${MO2_TARGET_TYPE} STREQUAL "library-shared")
2022-04-17 21:45:57 +02:00
mo2_set_if_not_defined(MO2_INSTALLDIR "bin/dlls")
2022-05-02 14:33:57 +02:00
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
2022-04-17 17:39:15 +02:00
elseif (${MO2_TARGET_TYPE} STREQUAL "executable")
2022-04-17 21:45:57 +02:00
mo2_set_if_not_defined(MO2_INSTALLDIR "bin")
2022-05-02 14:33:57 +02:00
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
2022-04-17 17:39:15 +02:00
else()
2022-05-02 15:46:00 +02:00
message(FATAL_ERROR "unknown MO2 target type for target '${TARGET}', did you forget using mo2_configure_XXX?")
2022-04-17 17:39:15 +02:00
endif()
# install PDB if possible
if (NOT (${MO2_TARGET_TYPE} STREQUAL "library-static"))
2022-05-02 14:33:57 +02:00
install(FILES $<TARGET_PDB_FILE:${TARGET}> DESTINATION pdb)
2022-04-17 17:39:15 +02:00
endif()
endfunction()