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 $<$: # 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 "$,EXCLUDE,^.*[/\\]Qt[^/\\]*[.]dll>") set_tests_properties(${${TARGET}_gtests} PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$,\;>" ) 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/$) 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 $ DESTINATION pdb OPTIONAL) endif() endif() endfunction()