Merge pull request #19 from ModOrganizer2/update-cmake-common-qt6

Update cmake common qt6
This commit is contained in:
Mikaël Capelle
2022-04-28 17:53:34 +02:00
committed by GitHub
6 changed files with 1490 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
# This is a modified version of Qt5LinguistToolsMacros.cmake which calls
# pylupdate5 instead of lupdate, allowing Python strings to be extracted,
# too. It still requires the Qt version of the file to be included, but
# only this version of the function needs to be called. You also need to
# have PYTHON_ROOT set to a directory where a working pylupdate5.bat can
# be found. If you aren't using Windows, your platform's equivalent may
# work, too.
#=============================================================================
# Copyright 2005-2011 Kitware, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of Kitware, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
include(CMakeParseArguments)
function(PYQT5_CREATE_TRANSLATION _qm_files)
set(options)
set(oneValueArgs)
set(multiValueArgs OPTIONS)
cmake_parse_arguments(_LUPDATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(_lupdate_files ${_LUPDATE_UNPARSED_ARGUMENTS})
set(_lupdate_options ${_LUPDATE_OPTIONS})
set(_my_sources)
set(_my_tsfiles)
foreach(_file ${_lupdate_files})
get_filename_component(_ext ${_file} EXT)
get_filename_component(_abs_FILE ${_file} ABSOLUTE)
if(_ext MATCHES "ts")
list(APPEND _my_tsfiles ${_abs_FILE})
else()
list(APPEND _my_sources ${_abs_FILE})
endif()
endforeach()
foreach(_ts_file ${_my_tsfiles})
set(_lst_file_srcs)
if(_my_sources)
# Qt made a file listing all sources and used that as an argument, but pylupdate5 doesn't support that.
# Qt allowed directories to be listed as sources, but pylupdate5 requires their contents to be listed.
get_filename_component(_ts_name ${_ts_file} NAME_WE)
foreach(_lst_file_src ${_my_sources})
if(IS_DIRECTORY ${_lst_file_src})
file(GLOB _directory_contents ${_lst_file_src}/*.py ${_lst_file_src}/*.ui)
list(APPEND _lst_file_srcs ${_directory_contents})
else()
list(APPEND _lst_file_srcs ${_lst_file_src})
endif()
endforeach()
endif()
add_custom_command(OUTPUT ${_ts_file}
COMMAND ${PYTHON_ROOT}/PCbuild/amd64/python.exe
ARGS -I -m PyQt5.pylupdate_main ${_lupdate_options} ${_lst_file_srcs} -ts ${_ts_file}
DEPENDS ${_lst_file_srcs}
WORKING_DIRECTORY ${PYTHON_ROOT}
VERBATIM)
endforeach()
qt5_add_translation(${_qm_files} ${_my_tsfiles})
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
endfunction()
+53
View File
@@ -0,0 +1,53 @@
cmake_minimum_required(VERSION 3.16)
if (DEFINED MO2_INCLUDED)
return()
endif()
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
# setup path for find_package(), etc.
mo2_required_variable(NAME BOOST_ROOT TYPE PATH)
mo2_required_variable(NAME QT_ROOT TYPE PATH)
mo2_required_variable(NAME FMT_ROOT TYPE PATH)
mo2_required_variable(NAME PYTHON_ROOT TYPE PATH)
mo2_required_variable(NAME CMAKE_INSTALL_PREFIX TYPE PATH)
get_filename_component(MO2_BUILD_PATH "${CMAKE_CURRENT_LIST_DIR}/../.." REALPATH)
get_filename_component(MO2_SUPER_PATH "${MO2_BUILD_PATH}/modorganizer_super" REALPATH)
get_filename_component(MO2_UIBASE_PATH "${MO2_SUPER_PATH}/uibase" REALPATH)
get_filename_component(MO2_INSTALL_PATH "${MO2_SUPER_PATH}/../../install" REALPATH)
get_filename_component(MO2_INSTALL_LIBS_PATH "${MO2_INSTALL_PATH}/libs" REALPATH)
list(APPEND CMAKE_PREFIX_PATH
${QT_ROOT}/lib/cmake
${FMT_ROOT}/build
${BOOST_ROOT}/build
${MO2_BUILD_PATH}/googletest/build/lib/cmake/GTest)
# find Qt major version and set QT_DEFAULT_MAJOR_VERSION to avoid issues
# when including LinguistTools without a QtCore
mo2_find_qt_version(QT_VERSION)
string(REPLACE "." ";" QT_VERSION_LIST ${QT_VERSION})
list(GET QT_VERSION_LIST 0 QT_MAJOR_VERSION)
# we add the Qt DLL to the paths for some tools
set(ENV{PATH} "${QT_ROOT}/bin;$ENV{PATH}")
# custom property, used to keep track of the type of target
define_property(TARGET PROPERTY MO2_TARGET_TYPE INHERITED)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP autogen)
set_property(GLOBAL PROPERTY AUTOMOC_SOURCE_GROUP autogen)
set_property(GLOBAL PROPERTY AUTORCC_SOURCE_GROUP autogen)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_cpp.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_python.cmake)
# mark as included
set(MO2_DEFINED true)
+316
View File
@@ -0,0 +1,316 @@
cmake_minimum_required(VERSION 3.16)
include(CMakeParseArguments)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_targets.cmake)
#! mo2_configure_target : do basic configuration for a MO2 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:WARNINGS enable all warnings (default ON)
# \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:BOOST add boost includes or library (OFF, INC, LIB), (default OFF)
# \param:EXTRA_TRANSLATIONS extra translations to include
#
function(mo2_configure_target MO2_TARGET)
cmake_parse_arguments(MO2 "SOURCE_TREE"
"WARNINGS;PERMISSIVE;BIGOBJ;CLI;TRANSLATIONS;AUTOMOC"
"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_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)
set_target_properties(${MO2_TARGET}
PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON)
endif()
target_compile_options(${MO2_TARGET}
PRIVATE "/MP"
$<$<CONFIG:RelWithDebInfo>:/O2>
)
set(CXX_STANDARD 20)
if (${MO2_CLI})
set(CXX_STANDARD 17)
endif()
set_target_properties(${MO2_TARGET} PROPERTIES
CXX_STANDARD ${CXX_STANDARD}
CXX_EXTENSIONS OFF)
# VS emits a warning for LTCG, at least for uibase, so maybe not required?
target_link_options(${MO2_TARGET}
PRIVATE
$<$<CONFIG:RelWithDebInfo>:/LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF>)
if(${MO2_WARNINGS})
target_compile_options(${MO2_TARGET} PRIVATE "/Wall" "/wd4464")
endif()
if(NOT ${MO2_PERMISSIVE})
target_compile_options(${MO2_TARGET} PRIVATE "/permissive-")
endif()
if(${MO2_BIGOBJ})
target_compile_options(${MO2_TARGET} PRIVATE "/bigobj")
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()
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)
file(GLOB_RECURSE misc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../*.natvis)
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()
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})
if(${MO2_TRANSLATIONS})
mo2_add_translations(${MO2_TARGET}
SOURCES ${CMAKE_CURRENT_SOURCE_DIR} ${MO2_EXTRA_TRANSLATIONS})
endif()
target_sources(${MO2_TARGET}
PRIVATE
${source_files}
${header_files}
${ui_files}
${ui_header_files}
${qrc_files}
${rc_files}
${misc_files}
${qm_files})
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(
${MO2_TARGET}
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")
set_target_properties(${MO2_TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "")
else()
# can this really happen?
set(COMPILE_FLAGS "${COMPILE_FLAGS} /clr")
string(REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
endif()
endif()
set_target_properties(${MO2_TARGET} PROPERTIES VS_STARTUP_PROJECT ${MO2_TARGET})
target_link_libraries(${MO2_TARGET} PRIVATE Version Dbghelp)
if (MO2_PUBLIC_DEPENDS)
mo2_add_dependencies(${MO2_TARGET} PUBLIC ${MO2_PUBLIC_DEPENDS})
endif()
if (MO2_PRIVATE_DEPENDS)
mo2_add_dependencies(${MO2_TARGET} PRIVATE ${MO2_PRIVATE_DEPENDS})
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)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${MO2_TARGET})
endif()
endfunction()
#! mo2_configure_tests : configure a target as a MO2 C++ tests
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_tests MO2_TARGET)
mo2_find_uibase()
mo2_configure_target(${MO2_TARGET} TRANSLATIONS OFF AUTOMOC OFF ${ARGN})
set_target_properties(${MO2_TARGET} PROPERTIES MO2_TARGET_TYPE "tests")
find_package(GTest REQUIRED)
set_property(TARGET ${MO2_TARGET} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_link_libraries(${MO2_TARGET}
PRIVATE mo2::uibase GTest::gtest GTest::gmock GTest::gtest_main)
# this would be nice but it requires Qt DLL in the path, etc., which is kind of
# a PITA, and not working right now
# gtest_discover_tests(${MO2_TARGET} WORKING_DIRECTORY ${MO2_INSTALL_PATH}/bin)
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
#
function(mo2_configure_uibase MO2_TARGET)
if (NOT (${MO2_TARGET} STREQUAL "uibase"))
message(WARNING "mo2_configure_uibase() should only be used on the uibase target")
endif()
mo2_configure_target(${MO2_TARGET} ${ARGN})
set_target_properties(${MO2_TARGET} PROPERTIES MO2_TARGET_TYPE "uibase")
target_include_directories(${MO2_TARGET} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/game_features)
mo2_set_project_to_run_from_install(
${MO2_TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
endfunction()
#! mo2_configure_plugin : configure a target as a MO2 C++ plugin
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_plugin MO2_TARGET)
mo2_configure_target(${MO2_TARGET} ${ARGN})
mo2_add_dependencies(${MO2_TARGET} PRIVATE uibase)
set_target_properties(${MO2_TARGET} PROPERTIES MO2_TARGET_TYPE "plugin")
mo2_set_project_to_run_from_install(
${MO2_TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
endfunction()
#! mo2_configure_library : configure a C++ library (NOT a plugin)
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_library MO2_TARGET)
mo2_configure_target(${MO2_TARGET} AUTOMOC OFF TRANSLATIONS OFF ${ARGN})
get_target_property(TARGET_TYPE ${MO2_TARGET} TYPE)
target_include_directories(${MO2_TARGET}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
if (${TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
set_target_properties(${MO2_TARGET} PROPERTIES MO2_TARGET_TYPE "library-static")
else()
mo2_set_project_to_run_from_install(
${MO2_TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
set_target_properties(${MO2_TARGET} PROPERTIES MO2_TARGET_TYPE "library-shared")
endif()
endfunction()
#! mo2_configure_executable : configure a target as MO2 C++ executable
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_executable MO2_TARGET)
cmake_parse_arguments(MO2 "ELEVATED" "" "" ${ARGN})
mo2_configure_target(${MO2_TARGET} ${ARGN})
set_target_properties(${MO2_TARGET}
PROPERTIES
WIN32_EXECUTABLE TRUE
MO2_TARGET_TYPE "executable")
get_target_property(output_name ${MO2_TARGET} OUTPUT_NAME)
if("${output_name}" STREQUAL "output_name-NOTFOUND")
set(output_name ${MO2_TARGET})
endif()
mo2_set_project_to_run_from_install(
${MO2_TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/${output_name})
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
set_target_properties(${MO2_TARGET} PROPERTIES LINK_FLAGS
"/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
endif()
endfunction()
#! mo2_install_target : set install for a MO2 target
#
# for this to work properly, the target must have been configured
#
function(mo2_install_target MO2_TARGET)
cmake_parse_arguments(MO2 "" "INSTALLDIR" "" ${ARGN})
get_target_property(MO2_TARGET_TYPE ${MO2_TARGET} MO2_TARGET_TYPE)
# core install: .lib, .dll or .exe, to the right folder
if (${MO2_TARGET_TYPE} STREQUAL "uibase")
install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION bin)
install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "plugin")
install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION bin/plugins)
install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "library-static")
install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "library-shared")
mo2_set_if_not_defined(MO2_INSTALLDIR "bin/dlls")
install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "executable")
mo2_set_if_not_defined(MO2_INSTALLDIR "bin")
install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
else()
message(ERROR "unknown MO2 target type for target '${MO2_TARGET}', did you forget using mo2_configure_XXX?")
endif()
# install PDB if possible
if (NOT (${MO2_TARGET_TYPE} STREQUAL "library-static"))
install(FILES $<TARGET_PDB_FILE:${MO2_TARGET}> DESTINATION pdb)
endif()
endfunction()
+302
View File
@@ -0,0 +1,302 @@
cmake_minimum_required(VERSION 3.16)
include(${CMAKE_CURRENT_LIST_DIR}/helpers/PyQt6TranslationMacros.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
#! mo2_python_uifiles : create .py files from .ui files for a python target
#
# \param:INPLACE if specified, .py files are generated next to the .ui files, useful
# for Python modules, otherwise files are generated in the binary directory
# \param:FILES list of .ui files to generate .py files from
#
function(mo2_python_uifiles MO2_TARGET)
cmake_parse_arguments(MO2 "INPLACE" "" "FILES" ${ARGN})
if (NOT MO2_FILES)
return()
endif()
message(DEBUG "generating .py from ui files: ${MO2_FILES}")
set(pyui_files "")
foreach (UI_FILE ${MO2_FILES})
get_filename_component(name "${UI_FILE}" NAME_WLE)
if (${MO2_INPLACE})
get_filename_component(folder "${UI_FILE}" DIRECTORY)
else()
set(folder "${CMAKE_CURRENT_BINARY_DIR}")
endif()
set(output "${folder}/${name}.py")
add_custom_command(
OUTPUT "${output}"
COMMAND ${PYTHON_ROOT}/PCbuild/amd64/python.exe
-I
-m PyQt${QT_MAJOR_VERSION}.uic.pyuic
-o "${output}"
"${UI_FILE}"
WORKING_DIRECTORY ${PYTHON_ROOT}
DEPENDS "${UI_FILE}"
)
list(APPEND pyui_files "${output}")
endforeach()
if (${MO2_INPLACE})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX autogen FILES ${pyui_files})
endif()
add_custom_target("${MO2_TARGET}_uic" DEPENDS ${pyui_files})
set_target_properties("${MO2_TARGET}_uic" PROPERTIES FOLDER autogen)
add_dependencies(${MO2_TARGET} "${MO2_TARGET}_uic")
endfunction()
#! mo2_python_rcfiles : create .py files from .qrc files for a python target
#
# \param:INPLACE if specified, .py files are generated next to the .qrc files, useful
# for Python modules, otherwise files are generated in the binary directory
# \param:FILES list of .qrc files to generate .py files from
#
function(mo2_python_rcfiles MO2_TARGET)
cmake_parse_arguments(MO2 "" "INPLACE" "FILES" ${ARGN})
if (NOT MO2_FILES)
return()
endif()
message(DEBUG "generating .py from qrc files: ${MO2_FILES}")
set(pyrc_files "")
foreach (RC_FILE ${MO2_FILES})
get_filename_component(name "${RC_FILE}" NAME_WLE)
get_filename_component(folder "${RC_FILE}" DIRECTORY)
if (${MO2_INPLACE})
get_filename_component(folder "${RC_FILE}" DIRECTORY)
else()
set(folder "${CMAKE_CURRENT_BINARY_DIR}")
endif()
set(output "${folder}/${name}_rc.py")
add_custom_command(
OUTPUT "${output}"
COMMAND ${PYTHON_ROOT}/PCbuild/amd64/python.exe
-I
-m PyQt5.pyrcc_main
-o "${output}"
"${RC_FILE}"
WORKING_DIRECTORY ${PYTHON_ROOT}
DEPENDS "${RC_FILE}"
)
list(APPEND pyrc_files "${output}")
endforeach()
if (${MO2_INPLACE})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX autogen FILES ${pyrc_files})
endif()
add_custom_target("${MO2_TARGET}_qrc" DEPENDS ${pyrc_files})
set_target_properties("${MO2_TARGET}_qrc" PROPERTIES FOLDER autogen)
add_dependencies(${MO2_TARGET} "${MO2_TARGET}_qrc")
endfunction()
#! mo2_python_requirements : install requirements for a python target
#
function(mo2_python_requirements MO2_TARGET)
cmake_parse_arguments(MO2 "" "LIBDIR" "")
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pip.log"
COMMAND ${PYTHON_ROOT}/PCbuild/amd64/python.exe
-I
-m pip
install --force --upgrade --disable-pip-version-check
--target="${lib_dir}"
--log="${CMAKE_CURRENT_BINARY_DIR}/pip.log"
-r "${PROJECT_SOURCE_DIR}/plugin-requirements.txt"
WORKING_DIRECTORY ${PYTHON_ROOT}
DEPENDS "${PROJECT_SOURCE_DIR}/plugin-requirements.txt"
)
add_custom_target("${MO2_TARGET}_libs"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pip.log")
set_target_properties("${MO2_TARGET}_libs" PROPERTIES FOLDER autogen)
add_dependencies(${MO2_TARGET} "${MO2_TARGET}_libs")
install(
DIRECTORY "${lib_dir}"
DESTINATION "${MO2_INSTALL_PATH}/bin/plugins/${MO2_TARGET}"
)
endfunction()
function(mo2_configure_python_module MO2_TARGET)
cmake_parse_arguments(MO2 "" "LIBDIR;RESDIR" "" ${ARGN})
mo2_set_if_not_defined(MO2_LIBDIR "lib")
mo2_set_if_not_defined(MO2_RESDIR "res")
set(res_dir "${PROJECT_SOURCE_DIR}/${MO2_RESDIR}")
set(lib_dir "${PROJECT_SOURCE_DIR}/${MO2_LIBDIR}")
# py files
file(GLOB_RECURSE py_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.py)
set(all_src_files ${py_files} ${ui_files} ${qrc_files})
set(src_files ${all_src_files})
list(FILTER src_files EXCLUDE REGEX "${lib_dir}[/\\].*")
set(lib_files ${all_src_files})
list(FILTER lib_files INCLUDE REGEX "${lib_dir}[/\\].*")
target_sources(${MO2_TARGET} PRIVATE ${src_files})
source_group(cmake FILES CMakeLists.txt)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX src
FILES ${src_files})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX ${MO2_LIBDIR}
FILES ${lib_files})
# ui files
file(GLOB_RECURSE ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui)
mo2_python_uifiles(${MO2_TARGET} INPLACE FILES ${ui_files})
# qrc file
file(GLOB_RECURSE qrc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc)
mo2_python_rcfiles(${MO2_TARGET} INPLACE FILES ${qrc_files})
# install requirements if there are any
if(EXISTS "${PROJECT_SOURCE_DIR}/plugin-requirements.txt")
mo2_python_requirements(${MO2_TARGET} LIBDIR "${lib_dir}")
target_sources(${MO2_TARGET} PRIVATE
"${PROJECT_SOURCE_DIR}/plugin-requirements.txt"
)
source_group(requirements
FILES "${PROJECT_SOURCE_DIR}/plugin-requirements.txt")
endif()
set(install_dir "${MO2_INSTALL_PATH}/bin/plugins/${MO2_TARGET}")
# directories that go in bin/plugins/${name}
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/"
DESTINATION ${install_dir}
FILES_MATCHING PATTERN "*.py"
PATTERN ".git*" EXCLUDE
PATTERN "vsbuild" EXCLUDE)
# copy the resource directory if it exists
if(EXISTS "${res_dir}")
install(
DIRECTORY "${res_dir}"
DESTINATION ${install_dir}
)
endif()
endfunction()
function(mo2_configure_python_simple MO2_TARGET)
# this copies all the .py files that are directly in src/ into
# ${install_dir}/
#
# any folder that contains at least one .py file (recursive) is copied in
# bin/plugins/data
#
# ui files
file(GLOB ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui)
mo2_python_uifiles(${MO2_TARGET} FILES ${ui_files})
# qrc file
file(GLOB qrc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc)
mo2_python_rcfiles(${MO2_TARGET} FILES ${qrc_files})
# .py files directly in the directory
file(GLOB py_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.py)
# .json files directly in the directory
file(GLOB json_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.json)
file(GLOB_RECURSE extra_py_files CONFIGURE_DEPENDS
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/**/*.py)
set(src_files ${py_files} ${ui_files} ${json_files} ${extra_py_files})
target_sources(${MO2_TARGET} PRIVATE ${src_files})
source_group(cmake FILES CMakeLists.txt)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX src
FILES ${src_files})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX data
FILES ${json_files})
set(install_dir "${MO2_INSTALL_PATH}/bin/plugins")
# .py files directly in src/ go to plugins/
install(FILES ${py_files} DESTINATION ${install_dir})
# folders with Python files go into plugins/data
set(extra_py_dirs ${extra_py_files})
list(TRANSFORM extra_py_dirs REPLACE "[/\\][^/\\]+" "")
list(REMOVE_DUPLICATES extra_py_dirs)
install(DIRECTORY ${extra_py_dirs}
DESTINATION "${install_dir}/data"
FILES_MATCHING PATTERN "*.py")
# JSON file go in plugins/data
install(FILES ${json_files} DESTINATION "${install_dir}/data")
# generated files go in plugins/data
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
DESTINATION "${install_dir}/data"
FILES_MATCHING
PATTERN "*.py"
PATTERN "CMakeFiles" EXCLUDE
PATTERN "x64" EXCLUDE)
endfunction()
#! mo2_configure_python : configure a MO2 python target
#
# \param:MODULE indicates if this is a Python module plugin or a file plugin
#
function(mo2_configure_python MO2_TARGET)
cmake_parse_arguments(MO2 "MODULE;SIMPLE" "TRANSLATIONS;LIB;RES" "" ${ARGN})
mo2_set_if_not_defined(MO2_TRANSLATIONS ON)
if ((${MO2_MODULE} AND ${MO2_SIMPLE}) OR (NOT(${MO2_MODULE}) AND NOT(${MO2_SIMPLE})))
message(FATAL_ERROR "mo2_configure_python should be called with either SIMPLE or MODULE")
endif()
if (${MO2_MODULE})
mo2_configure_python_module(${MO2_TARGET} ${ARGN})
else()
mo2_configure_python_simple(${MO2_TARGET} ${ARGN})
endif()
# do this AFTER configure_ to properly handle the the ui files
if(${MO2_TRANSLATIONS})
mo2_add_translations(${MO2_TARGET} SOURCES ${CMAKE_CURRENT_SOURCE_DIR})
endif()
file(GLOB_RECURSE py_files CONFIGURE_DEPENDS *.py)
file(GLOB_RECURSE rc_files CONFIGURE_DEPENDS *.rc)
file(GLOB_RECURSE ui_files CONFIGURE_DEPENDS *.ui)
target_sources(${MO2_TARGET}
PRIVATE ${py_files} ${ui_files} ${rc_files} ${qm_files})
endfunction()
+435
View File
@@ -0,0 +1,435 @@
cmake_minimum_required(VERSION 3.16)
include(ExternalProject)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
#! mo2_add_dependencies : add dependencies to the given target
#
# the name of the dependencies should be valid mo2 "libraries", as per
# mo2_find_libraries, or "boost" (for include only) or "boost::XXX" for a specific
# boost component or Qt::XXX for a specific Qt component
#
function(mo2_add_dependencies MO2_TARGET PRIVATE_OR_PUBLIC)
# remove everything boost related
set(standard_deps ${ARGN})
list(FILTER standard_deps EXCLUDE REGEX "^boost.*")
list(FILTER standard_deps EXCLUDE REGEX "^Qt::.*")
# keep everything boost related
set(boost_deps ${ARGN})
list(FILTER boost_deps INCLUDE REGEX "^boost.*")
# keep everything Qt related
set(qt_deps ${ARGN})
list(FILTER qt_deps INCLUDE REGEX "^Qt::.*")
message(DEBUG "deps: standards[ ${standard_deps} ], boost_deps[ ${boost_deps} ], qt_deps[ ${qt_deps} ]")
# handle "standard" dependencies
mo2_find_libraries(${standard_deps})
list(TRANSFORM standard_deps REPLACE "^(.+)$" "mo2::\\1")
message(DEBUG "standard: ${standard_deps}")
target_link_libraries(${MO2_TARGET} ${PRIVATE_OR_PUBLIC} ${standard_deps})
# handle Qt dependencies
if (qt_deps)
# remove Qt:: for find_package
list(TRANSFORM qt_deps REPLACE "Qt::" "")
find_package(Qt${QT_MAJOR_VERSION} COMPONENTS ${qt_deps} REQUIRED)
# add QtX:: for target ink
list(TRANSFORM qt_deps REPLACE "^(.+)$" "Qt${QT_MAJOR_VERSION}::\\1")
target_link_libraries(${MO2_TARGET} ${PRIVATE_OR_PUBLIC} ${qt_deps})
endif()
# handle boost dependencies
if (boost_deps)
find_package(Boost REQUIRED)
target_include_directories(
${MO2_TARGET} ${PRIVATE_OR_PUBLIC} ${Boost_INCLUDE_DIRS})
list(TRANSFORM boost_deps REPLACE "boost(::)?" "")
list(FILTER boost_deps EXCLUDE REGEX "^$")
message(DEBUG "boost: ${boost_deps}")
if (boost_deps)
find_package(Boost COMPONENTS ${boost_deps} REQUIRED)
message(DEBUG "boost: ${Boost_LIBRARIES}")
target_link_libraries(${MO2_TARGET} ${PRIVATE_OR_PUBLIC} ${Boost_LIBRARIES})
endif()
endif()
endfunction()
#! mo2_find_uibase : find and create a mo2::uibase target
#
function(mo2_find_uibase)
# target was already created
if (TARGET mo2-uibase)
return()
endif()
# if the uibase target exists, we use it
if (TARGET uibase)
add_library(mo2-uibase ALIAS uibase)
add_library(mo2::uibase ALIAS uibase)
else()
if (NOT DEFINED MO2_UIBASE_INCLUDE)
set(MO2_UIBASE_INCLUDE ${MO2_UIBASE_PATH}/src)
endif()
add_library(mo2-uibase IMPORTED SHARED)
set_target_properties(mo2-uibase PROPERTIES
IMPORTED_IMPLIB ${MO2_INSTALL_LIBS_PATH}/uibase.lib)
mo2_add_dependencies(mo2-uibase
INTERFACE fmt Qt::Widgets Qt::Network Qt::QuickWidgets)
target_include_directories(mo2-uibase
INTERFACE ${MO2_UIBASE_INCLUDE} ${MO2_UIBASE_INCLUDE}/game_features)
add_library(mo2::uibase ALIAS mo2-uibase)
endif()
endfunction()
#! mo2_find_corelib : find a static core library, e.g., bsatk or esptk, and create
# an appropriate target
function(mo2_find_corelib LIBRARY)
cmake_parse_arguments(MO2 "" "" "DEPENDS" ${ARGN})
mo2_set_if_not_defined(MO2_DEPENDS "")
# target was already created
if (TARGET mo2-${LIBRARY})
return()
endif()
# if the target exists, we use it
if (TARGET ${LIBRARY})
message(STATUS "Found existing ${LIBRARY} target, using it.")
add_library(mo2-${LIBRARY} ALIAS ${LIBRARY})
add_library(mo2::${LIBRARY} ALIAS ${LIBRARY})
else()
message(STATUS "Existing ${LIBRARY} target not found, creating it.")
add_library(mo2-${LIBRARY} IMPORTED STATIC)
set_target_properties(mo2-${LIBRARY} PROPERTIES
IMPORTED_LOCATION ${MO2_INSTALL_LIBS_PATH}/${LIBRARY}.lib)
target_include_directories(mo2-${LIBRARY}
INTERFACE ${MO2_SUPER_PATH}/${LIBRARY}/src)
if (MO2_DEPENDS)
mo2_add_dependencies(mo2-${LIBRARY} INTERFACE ${MO2_DEPENDS})
endif()
add_library(mo2::${LIBRARY} ALIAS mo2-${LIBRARY})
endif()
endfunction()
#! mo2_find_bsatk : find and create a mo2::bsatk target
#
function(mo2_find_bsatk)
mo2_find_corelib(bsatk DEPENDS boost::thread zlib lz4)
endfunction()
#! mo2_find_esptk : find and create a mo2::esptk target
#
function(mo2_find_esptk)
mo2_find_corelib(esptk)
endfunction()
#! mo2_find_archive : find and create a mo2::archive target
#
function(mo2_find_archive)
mo2_find_corelib(archive)
endfunction()
#! mo2_find_githubpp : find and create a mo2::githubpp target
#
function(mo2_find_githubpp)
mo2_find_corelib(githubpp DEPENDS Qt::Core Qt::Network)
endfunction()
#! mo2_find_lootcli : find and create a mo2::lootcli target
#
function(mo2_find_lootcli)
if (TARGET mo2-lootcli)
return()
endif()
add_library(mo2-lootcli IMPORTED INTERFACE)
target_include_directories(mo2-lootcli INTERFACE
${MO2_SUPER_PATH}/lootcli/include)
add_library(mo2::lootcli ALIAS mo2-lootcli)
endfunction()
#! mo2_find_gamebryo : find and create a mo2::gamebryo target
#
function(mo2_find_gamebryo)
# this does not use mo2_find_corelib because the target name do not match (we
# want gamebryo, the target is game_gamebryo), and the src folder is not the same
# other lib (src/gamebryo instead of src/)
# target was already created
if (TARGET mo2-gamebryo)
return()
endif()
# if the target exists, we use it
if (TARGET game_gamebryo)
message(STATUS "Found existing game_gamebryo target, using it.")
add_library(mo2-gamebryo ALIAS game_gamebryo)
add_library(mo2::gamebryo ALIAS game_gamebryo)
else()
message(STATUS "Existing game_gamebryo target not found, creating it.")
add_library(mo2-gamebryo IMPORTED STATIC)
set_target_properties(mo2-gamebryo PROPERTIES
IMPORTED_LOCATION ${MO2_INSTALL_LIBS_PATH}/game_gamebryo.lib)
target_include_directories(mo2-gamebryo
INTERFACE ${MO2_SUPER_PATH}/game_gamebryo/src/gamebryo)
mo2_add_dependencies(mo2-gamebryo INTERFACE lz4)
add_library(mo2::gamebryo ALIAS mo2-gamebryo)
endif()
endfunction()
#! mo2_find_creation : find and create a mo2::creation target
#
function(mo2_find_creation)
# same as mo2_find_gamebryo, we do not use mo2_find_corelib (see mo2_find_gamebryo
# comment for why)
# target was already created
if (TARGET mo2-creation)
return()
endif()
# if the target exists, we use it
if (TARGET game_creation)
message(STATUS "Found existing game_creation target, using it.")
add_library(mo2-creation ALIAS game_creation)
add_library(mo2::creation ALIAS game_creation)
else()
message(STATUS "Existing game_creation target not found, creating it.")
add_library(mo2-creation IMPORTED STATIC)
set_target_properties(mo2-creation PROPERTIES
IMPORTED_LOCATION ${MO2_INSTALL_LIBS_PATH}/game_creation.lib)
target_include_directories(mo2-creation
INTERFACE ${MO2_SUPER_PATH}/game_gamebryo/src/creation)
add_library(mo2::creation ALIAS mo2-creation)
mo2_add_dependencies(mo2-creation INTERFACE gamebryo lz4)
endif()
endfunction()
#! mo2_find_loot : find and create a mo2::loot target
#
function(mo2_find_loot)
if (TARGET mo2-loot)
return()
endif()
mo2_required_variable(NAME LOOT_PATH TYPE PATH)
find_package(Boost COMPONENTS locale REQUIRED)
add_library(mo2-loot IMPORTED SHARED)
set_target_properties(mo2-loot PROPERTIES IMPORTED_LOCATION ${LOOT_PATH}/loot.dll)
set_target_properties(mo2-loot PROPERTIES IMPORTED_IMPLIB ${LOOT_PATH}/loot.lib)
target_include_directories(mo2-loot INTERFACE ${LOOT_PATH}/include)
target_link_libraries(mo2-loot INTERFACE ${Boost_LIBRARIES})
add_library(mo2::loot ALIAS mo2-loot)
endfunction()
#! mo2_find_spdlog : find and carete a mo2::spdlog target
#
function(mo2_find_spdlog)
if (TARGET mo2-spdlog)
return()
endif()
mo2_required_variable(NAME SPDLOG_ROOT TYPE PATH)
add_library(mo2-spdlog INTERFACE)
target_include_directories(mo2-spdlog INTERFACE ${SPDLOG_ROOT}/include)
add_library(mo2::spdlog ALIAS mo2-spdlog)
endfunction()
#! mo2_find_libbsarch : find and create a mo2::libbsarch target
#
function(mo2_find_libbsarch)
if (TARGET mo2-libbsarch)
return()
endif()
mo2_required_variable(NAME LIBBSARCH_ROOT TYPE PATH)
add_library(mo2-libbsarch IMPORTED STATIC)
set_target_properties(mo2-libbsarch PROPERTIES
IMPORTED_LOCATION
${LIBBSARCH_ROOT}/libbsarch.lib
)
target_include_directories(mo2-libbsarch INTERFACE ${LIBBSARCH_ROOT})
target_link_libraries(mo2-libbsarch INTERFACE ${LIBBSARCH_ROOT}/libbsarch_OOP.lib)
add_library(mo2::libbsarch ALIAS mo2-libbsarch)
endfunction()
#! mo2_find_zlib : find and carete a mo2::zlib target
#
function(mo2_find_zlib)
if (TARGET mo2-zlib)
return()
endif()
mo2_required_variable(NAME ZLIB_ROOT TYPE PATH)
# not using find_package(ZLIB) because we want the static version
add_library(mo2-zlib IMPORTED STATIC)
set_target_properties(mo2-zlib PROPERTIES
IMPORTED_LOCATION ${ZLIB_ROOT}/lib/zlibstatic.lib)
target_include_directories(mo2-zlib INTERFACE ${ZLIB_ROOT}/include)
add_library(mo2::zlib ALIAS mo2-zlib)
endfunction()
#! mo2_find_lz4 : find and carete a mo2::lz4 target
#
function(mo2_find_lz4)
if (TARGET mo2-lz4)
return()
endif()
mo2_required_variable(NAME LZ4_ROOT TYPE PATH)
add_library(mo2-lz4 IMPORTED SHARED)
set_target_properties(mo2-lz4 PROPERTIES
IMPORTED_LOCATION ${LZ4_ROOT}/bin/liblz4.dll
IMPORTED_IMPLIB ${LZ4_ROOT}/bin/liblz4.lib
)
target_include_directories(mo2-lz4 INTERFACE ${LZ4_ROOT}/lib)
add_library(mo2::lz4 ALIAS mo2-lz4)
endfunction()
#! mo2_find_7z : find and carete a mo2::7z target
#
function(mo2_find_7z)
if (TARGET mo2-7z)
return()
endif()
mo2_required_variable(NAME SEVENZ_ROOT TYPE PATH)
add_library(mo2-7z INTERFACE)
target_include_directories(mo2-7z INTERFACE ${SEVENZ_ROOT}/CPP)
add_library(mo2::7z ALIAS mo2-7z)
endfunction()
#! mo2_find_fmt : find and carete a mo2::fmt target
#
function(mo2_find_fmt)
if (TARGET mo2-fmt)
return()
endif()
find_package(fmt REQUIRED)
add_library(mo2-fmt ALIAS fmt::fmt)
add_library(mo2::fmt ALIAS fmt::fmt)
endfunction()
#! mo2_find_cpptoml : find and create a mo2::cpptoml target
#
function(mo2_find_cpptoml)
if (TARGET mo2-cpptoml)
return()
endif()
ExternalProject_Add(
cpptoml
PREFIX "external"
URL "https://github.com/skystrife/cpptoml/archive/2051836a96a25e5a2d5283be7f633a157848f15e.tar.gz"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
ExternalProject_Get_Property(cpptoml SOURCE_DIR)
add_library(mo2-cpptoml INTERFACE)
target_include_directories(mo2-cpptoml INTERFACE "${SOURCE_DIR}/include")
add_dependencies(mo2-cpptoml cpptoml)
add_library(mo2::cpptoml ALIAS mo2-cpptoml)
endfunction()
#! mo2_find_usvfs : find and create a mo2::usvfs target
#
function(mo2_find_usvfs)
if (TARGET mo2-usvfs)
return()
endif()
set(USVFS_PATH "${MO2_BUILD_PATH}/usvfs")
set(USVFS_INC_PATH "${USVFS_PATH}/include")
set(USVFS_LIB_PATH "${USVFS_PATH}/lib")
add_library(mo2-usvfs IMPORTED SHARED)
set_target_properties(mo2-usvfs PROPERTIES
IMPORTED_LOCATION "${USVFS_LIB_PATH}/usvfs_x64.dll"
)
set_target_properties(mo2-usvfs PROPERTIES
IMPORTED_IMPLIB "${USVFS_LIB_PATH}/usvfs_x64.lib"
)
target_include_directories(mo2-usvfs INTERFACE ${USVFS_INC_PATH})
add_library(mo2::usvfs ALIAS mo2-usvfs)
endfunction()
#! mo2_find_libraries : find and create library
#
# this function find the given libraries and generate (if the libraries are found)
# targets mo2::LIBRARY_NAME
#
# example: mo2_find_libraries(uibase, loot) will create mo2::uibase and mo2::loot
#
function(mo2_find_libraries)
foreach(target ${ARGN})
cmake_language(CALL "mo2_find_${target}")
endforeach()
endfunction()
#! mo2_target_add_boost : add boosts to the given target
#
# with only target name, include boost directories, extra names are considered
# boost components
#
function(mo2_target_add_boost MO2_TARGET)
find_package(Boost COMPONENTS ${ARGN} REQUIRED)
target_include_directories(${MO2_TARGET} PRIVATE ${Boost_INCLUDE_DIRS})
if (${ARGN})
target_link_libraries(${MO2_TARGET} PRIVATE ${Boost_LIBRARIES})
endif()
endfunction()
+297
View File
@@ -0,0 +1,297 @@
# this file contains utility code that is not directly related to MO2
cmake_minimum_required(VERSION 3.16)
include(CMakeParseArguments)
if (DEFINED MO2_UTILS_DEFINED)
return()
endif()
#! mo2_set_if_not_defined : set a variable to the given value if not defined
#
# \param:NAME name of the variable
# \param:VALUE value of the variable to set (if not defined)
#
function (mo2_set_if_not_defined NAME VALUE)
if (NOT DEFINED ${NAME})
set(${NAME} ${VALUE} PARENT_SCOPE)
endif()
endfunction()
#! mo2_set_project_to_run_from_install : set a PROJECT to run from a given executable
#
# this function only works for VS generator
#
# \param:PROJECT name of the project
# \param:EXECUTABLE full path to the executable
# \param:WORKDIR working directory (optional, default is the directory of the executable)
#
function(mo2_set_project_to_run_from_install TARGET)
cmake_parse_arguments(MO2 "" "EXECUTABLE;WORKDIR" "" ${ARGN})
# extract directory
if (NOT DEFINED MO2_WORKDIR)
get_filename_component(MO2_WORKDIR ${MO2_EXECUTABLE} DIRECTORY)
endif()
set_target_properties(${MO2_TARGET} PROPERTIES
VS_DEBUGGER_WORKING_DIRECTORY "${MO2_WORKDIR}"
VS_DEBUGGER_COMMAND "${MO2_EXECUTABLE}")
endfunction()
#! mo2_required_variable : check that a variable is defined, fails otherwise
#
# this function checks that a variable with the given NAME is defined, if it's not
# it fails with a FATAL_ERROR, otherwise it caches the variable
#
# \param:NAME name of the variable
# \param:TYPE type of the variable (optional)
# \param:DESC description of the variable (optional)
#
macro(mo2_required_variable)
cmake_parse_arguments(REQ_VAR "" "NAME;TYPE;DESC" "" ${ARGN})
if(NOT DEFINED REQ_VAR_DESC)
set(REQ_VAR_DESC "${name}")
endif()
if(NOT DEFINED ${REQ_VAR_NAME})
message(FATAL_ERROR "${REQ_VAR_NAME} is not defined")
endif()
set(${REQ_VAR_NAME} ${${REQ_VAR_NAME}} CACHE ${REQ_VAR_TYPE} "${REQ_VAR_DESC}")
endmacro()
#! mo2_add_filter : add source_group based on the given names
#
# \param:NAME name of the group
# \param:FILES files to add
# \param:GROUPS files to add
#
function(mo2_add_filter)
cmake_parse_arguments(PARSE_ARGV 0 add_filter "" "NAME" "FILES;GROUPS")
set(files ${add_filter_FILES})
foreach(f ${add_filter_GROUPS})
set(files ${files} ${f}.cpp ${f}.h ${f}.inc)
endforeach()
string(REPLACE "/" "\\" filter_name ${add_filter_NAME})
source_group(${filter_name} FILES ${files})
endfunction()
#! mo2_find_qt_version : try to deduce Qt version from variables
#
function(mo2_find_qt_version VAR)
if (DEFINED CACHE{${VAR}})
return()
endif()
# TODO: deduce version from the QT_ROOT folder
get_filename_component(VFOLDER ${QT_ROOT} DIRECTORY)
get_filename_component(${VAR} ${VFOLDER} NAME)
message(STATUS "deduced Qt version to ${${VAR}}")
set(${VAR} ${${VAR}} CACHE STRING "Qt Version}")
endfunction()
#! mo2_deploy_qt : add commands to deploy Qt from the given binaries
#
# this function attach install() entries that deploy Qt for the given binaries
#
# \param:NOPLUGINS do not deploy Qt plugins
# \param:BINARIES names of the binaries (in the install path) to deploy from
#
function(mo2_deploy_qt)
cmake_parse_arguments(DEPLOY "NOPLUGINS" "" "BINARIES" ${ARGN})
# find_program() does not work for whatever reason, just going for the whole
# name
set(windeployqt ${QT_ROOT}/bin/windeployqt.exe)
set(args
"--no-translations \
--verbose 0 \
--webenginewidgets \
--websockets \
--openglwidgets \
--libdir dlls \
--no-compiler-runtime")
if(${DEPLOY_NOPLUGINS})
set(args "${args} --no-plugins")
else()
set(args "${args} --plugindir qtplugins")
endif()
set(bin "${CMAKE_INSTALL_PREFIX}/bin")
set(deploys "")
foreach(binary ${DEPLOY_BINARIES})
set(deploys "${deploys}
EXECUTE_PROCESS(
COMMAND ${windeployqt} ${args} ${binary}
WORKING_DIRECTORY \"${bin}\")")
endforeach()
install(CODE "
${deploys}
file(REMOVE_RECURSE \"${bin}/platforms\")
file(REMOVE_RECURSE \"${bin}/styles\")
file(REMOVE_RECURSE \"${bin}/dlls/imageformats\")
file(REMOVE_RECURSE \"${bin}/dlls/tls\")
")
if(NOT ${DEPLOY_NOPLUGINS})
install(CODE "
file(RENAME \"${bin}/qtplugins/platforms\" \"${bin}/platforms\")
file(RENAME \"${bin}/qtplugins/styles\" \"${bin}/styles\")
file(RENAME \"${bin}/qtplugins/imageformats\" \"${bin}/dlls/imageformats\")
file(RENAME \"${bin}/qtplugins/tls\" \"${bin}/dlls/tls\")
file(REMOVE_RECURSE \"${bin}/qtplugins\")
")
endif()
endfunction()
#! generate .ts files from the given sources
#
# this function adds a ${TARGET}_lupdate target
#
# \param:TARGET target to generate releases for
# \param:TS_FILE .ts file to generate
# \param:SOURCES source folders to generate .ts file from
#
function(mo2_add_lupdate TARGET)
cmake_parse_arguments(MO2 "" "TS_FILE" "SOURCES" ${ARGN})
set(translation_files "")
set(ui_files "")
get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
if ("CXX" IN_LIST languages)
set(is_cpp True)
else()
set(is_cpp False)
endif()
foreach (SOURCE ${MO2_SOURCES})
if (${is_cpp})
file(GLOB_RECURSE source_sources CONFIGURE_DEPENDS
${SOURCE}/*.cpp
${SOURCE}/*.h)
else()
file(GLOB_RECURSE source_sources CONFIGURE_DEPENDS ${SOURCE}/*.py)
endif()
# ui files
file(GLOB_RECURSE source_ui_files CONFIGURE_DEPENDS ${SOURCE}/*.ui)
list(APPEND ui_files ${source_ui_files})
list(APPEND translation_files ${source_sources} ${source_ui_files})
endforeach()
# for Python, we need to remove the .py generated because these can be generated
# in the source folder
list(TRANSFORM ui_files REPLACE "[.]ui$" ".py")
list(REMOVE_ITEM translation_files ${ui_files})
message(TRACE "TS_FILE: ${MO2_TS_FILE}, SOURCES: ${MO2_SOURCES}, FILES: ${translation_files}")
if (${is_cpp})
set(lrelease_command ${QT_ROOT}/bin/lupdate)
set(lrelease_args ${MO2_SOURCES} -ts ${MO2_TS_FILE})
else()
endif()
add_custom_command(OUTPUT ${MO2_TS_FILE}
COMMAND ${lrelease_command} ARGS ${lrelease_args}
DEPENDS ${translation_files}
VERBATIM)
add_custom_target("${MO2_TARGET}_lupdate" DEPENDS ${MO2_TS_FILE})
# we need to set this property otherwise there is an issue with C# projects
# requiring nuget packages (e.g., installer_omod) that tries to resolve Nuget
# packages on these target but fails because there are obviously none
#
# we also "hide" the target by moving them to autogen
set_target_properties(${MO2_TARGET}_lupdate PROPERTIES
VS_GLOBAL_ResolveNugetPackages False
FOLDER autogen)
endfunction()
#! generate .ts files from the given sources
#
# this function adds a ${TARGET}_lrelease target
#
# \param:INSTALL if set, QM files will be installed to bin/translations
# \param:TARGET target to generate releases for
# \param:QM_FILE .qm file to generate
# \param:TS_FILES source ts
#
function(mo2_add_lrelease MO2_TARGET)
cmake_parse_arguments(MO2 "INSTALL" "QM_FILE" "TS_FILES" ${ARGN})
add_custom_command(OUTPUT ${MO2_QM_FILE}
COMMAND ${QT_ROOT}/bin/lrelease
ARGS ${MO2_TS_FILES} -qm ${MO2_QM_FILE}
DEPENDS "${MO2_TS_FILES}"
VERBATIM)
add_custom_target("${MO2_TARGET}_lrelease" DEPENDS ${MO2_QM_FILE})
# we need to set this property otherwise there is an issue with C# projects
# requiring nuget packages (e.g., installer_omod) that tries to resolve Nuget
# packages on these target but fails because there are obviously none
#
# we also "hide" the target by moving them to autogen
set_target_properties(${MO2_TARGET}_lrelease PROPERTIES
VS_GLOBAL_ResolveNugetPackages False
FOLDER autogen)
if (${MO2_INSTALL})
install(FILES ${MO2_QM_FILE} DESTINATION bin/translations)
endif()
endfunction()
function(mo2_add_translations TARGET)
cmake_parse_arguments(MO2 "RELEASE;INSTALL_RELEASE" "TS_FILE;QM_FILE" "SOURCES" ${ARGN})
if (NOT MO2_TS_FILE)
set(MO2_TS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}_en.ts)
endif()
if (NOT MO2_QM_FILE)
set(MO2_QM_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.qm)
endif()
# force release with install
if (${MO2_INSTALL_RELEASE})
set(MO2_RELEASE True)
endif()
mo2_add_lupdate(${TARGET} TS_FILE ${MO2_TS_FILE} SOURCES ${MO2_SOURCES})
if (${MO2_RELEASE})
mo2_add_lrelease(${TARGET}
INSTALL ${MO2_INSTALL_RELEASE}
TS_FILES ${MO2_TS_FILE}
QM_FILE ${MO2_QM_FILE})
add_dependencies(${TARGET}_lrelease ${TARGET}_lupdate)
add_dependencies(${TARGET} ${TARGET}_lrelease)
else()
add_dependencies(${TARGET} ${TARGET}_lupdate)
endif()
endfunction()
set(MO2_UTILS_DEFINED TRUE)