From cc5663fe96d6c19a99288d40cf1fe180c1b0affb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 2 May 2022 14:33:57 +0200 Subject: [PATCH] Documentation and cleaning. --- README.md | 94 ++++++++++++++++++++++++++++++++ mo2_cpp.cmake | 134 ++++++++++++++++++++++++++-------------------- mo2_python.cmake | 88 ++++++++++++++++++------------ mo2_targets.cmake | 47 +++++++--------- mo2_utils.cmake | 46 ++++++++++------ 5 files changed, 275 insertions(+), 134 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..062ede0 --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# MO2 CMake Common + +This repository contains CMake macro and functions that are used in most MO2 +repository to build uibase, modorganizer itself and plugins (C++/Python). + +## Getting Started + +To get started, simply include the `mo2.cmake` file in your project: + +```cmake +# this can safely be included multiple time +include(path_to_cmake_common/mo2.cmake) +``` + +This will set some (not too intrusive) variables and define many useful functions, +all prefixed with `mo2_`. + +The basic MO2 plugin/executable CMake will then look like this: + +```cmake +# this is for a C++ plugin +add_library(my_plugin SHARED) + +# configure the plugin - this will also set the sources of the plugin +# based on the file in the current directory (and subdirectory) +mo2_configure_plugin(my_plugin) + +# install the target to MO2 installation path, typically in the +# plugins/ folder +mo2_install_target(my_plugin) +``` + +## Configuring + +The main entry-points are the the configure functions: + +- C++ + - `mo2_configure_target` - this is the "base" configuration, + which should not be used most of the time (this one is called by + other functions), + - `mo2_configure_uibase` - specific for uibase, should not be used + elsewhere, + - `mo2_configure_plugin` - configuration for a C++ plugin, + - `mo2_configure_library` - configuration for static or shared libraries, + - `mo2_configure_executable` - configuration for executables, including the main + MO2 executable, + - `mo2_configure_tests` - configuration for tests. +- Python + - `mo2_configure_python`. + +The function are documented so you can look at the documentation to see what arguments +are available. + +### Dependencies + +You can add dependencies to the target by using the standard `target_link_libraries`, +but this might be difficult when looking for MO2 dependencies, such as other libraries +or Qt. + +The `mo2_configure_XXX` accept `PRIVATE_DEPENDS` and `PUBLIC_DEPENDS` parameters that +can be used to add dependencies to the target in an easier way. +These parameters accept 3 types of dependencies: + +- Qt dependencies, that should be specified as `Qt::COMPONENTS`, e.g., `Qt::Core` or + `Qt::Widgets`. Note that the `Qt::` is version-independent, MO2 will add the proper + version for you. +- Boost dependencies - For header only libraries, you can simply pass `boost`, for + non-header only libraries, you can pass `boost::COMPONENT`, e.g., `boost::threads`. +- MO2 dependencies - Those are either components available via the MO2 build system, + such as `zlib` or `libbsarch`, or other MO2 components such as `game_gamebryo`. + +## Installing + +For C++ plugin, you need to call `mo2_install_target` to install the plugins or +executable in MO2 installation directory. +Where the target should be installed is defined in the `mo2_configure_XXX` function +(which should be called before `mo2_install_target`). + +Installing Python plugins does not require extra call apart from `mo2_configure_python`. + +## Examples + +All MO2 repositories use these functions, so you can look at any repository to get +details on how to use them. +Here are entry points for the various type of plugins: + +- [`game_skyrimse`](https://github.com/ModOrganizer2/modorganizer-game_skyrimSE/) + for a plugin that depends on a static library built by MO2. +- [`game_gamebryo`](https://github.com/ModOrganizer2/modorganizer-game_gamebryo/) + for a static library example. +- [`installer_wizard`](https://github.com/ModOrganizer2/modorganizer-installer_wizard) + for a Python plugin (module). +- [`fnistool`](https://github.com/ModOrganizer2/modorganizer-fnistool/) for a Python + plugin (simple file). diff --git a/mo2_cpp.cmake b/mo2_cpp.cmake index 3aef5e8..eb5cec8 100644 --- a/mo2_cpp.cmake +++ b/mo2_cpp.cmake @@ -4,23 +4,26 @@ 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 +#! 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: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 +# \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 # -function(mo2_configure_target MO2_TARGET) +function(mo2_configure_target TARGET) cmake_parse_arguments(MO2 "SOURCE_TREE" "WARNINGS;PERMISSIVE;BIGOBJ;CLI;TRANSLATIONS;AUTOMOC" "EXTRA_TRANSLATIONS;PUBLIC_DEPENDS;PRIVATE_DEPENDS" @@ -39,11 +42,11 @@ function(mo2_configure_target MO2_TARGET) if (${MO2_AUTOMOC}) find_package(Qt6 COMPONENTS Widgets REQUIRED) - set_target_properties(${MO2_TARGET} + set_target_properties(${TARGET} PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON) endif() - target_compile_options(${MO2_TARGET} + target_compile_options(${TARGET} PRIVATE "/MP" $<$:/O2> ) @@ -52,25 +55,25 @@ function(mo2_configure_target MO2_TARGET) if (${MO2_CLI}) set(CXX_STANDARD 17) endif() - set_target_properties(${MO2_TARGET} PROPERTIES + set_target_properties(${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} + target_link_options(${TARGET} PRIVATE $<$:/LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF>) if(${MO2_WARNINGS}) - target_compile_options(${MO2_TARGET} PRIVATE "/Wall" "/wd4464") + target_compile_options(${TARGET} PRIVATE "/Wall" "/wd4464") endif() if(NOT ${MO2_PERMISSIVE}) - target_compile_options(${MO2_TARGET} PRIVATE "/permissive-") + target_compile_options(${TARGET} PRIVATE "/permissive-") endif() if(${MO2_BIGOBJ}) - target_compile_options(${MO2_TARGET} PRIVATE "/bigobj") + target_compile_options(${TARGET} PRIVATE "/bigobj") endif() # find source files @@ -104,11 +107,11 @@ function(mo2_configure_target MO2_TARGET) if(${MO2_TRANSLATIONS}) - mo2_add_translations(${MO2_TARGET} + mo2_add_translations(${TARGET} SOURCES ${CMAKE_CURRENT_SOURCE_DIR} ${MO2_EXTRA_TRANSLATIONS}) endif() - target_sources(${MO2_TARGET} + target_sources(${TARGET} PRIVATE ${source_files} ${header_files} @@ -127,7 +130,7 @@ function(mo2_configure_target MO2_TARGET) ) target_compile_definitions( - ${MO2_TARGET} + ${TARGET} PRIVATE _UNICODE UNICODE @@ -145,7 +148,7 @@ function(mo2_configure_target MO2_TARGET) if(${MO2_CLI}) if (CMAKE_GENERATOR MATCHES "Visual Studio") - set_target_properties(${MO2_TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "") + set_target_properties(${TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "") else() # can this really happen? set(COMPILE_FLAGS "${COMPILE_FLAGS} /clr") @@ -153,30 +156,33 @@ function(mo2_configure_target MO2_TARGET) endif() endif() - set_target_properties(${MO2_TARGET} PROPERTIES VS_STARTUP_PROJECT ${MO2_TARGET}) + set_target_properties(${TARGET} PROPERTIES VS_STARTUP_PROJECT ${TARGET}) - target_link_libraries(${MO2_TARGET} PRIVATE Version Dbghelp) + target_link_libraries(${TARGET} PRIVATE Version Dbghelp) if (MO2_PUBLIC_DEPENDS) - mo2_add_dependencies(${MO2_TARGET} PUBLIC ${MO2_PUBLIC_DEPENDS}) + mo2_add_dependencies(${TARGET} PUBLIC ${MO2_PUBLIC_DEPENDS}) endif() if (MO2_PRIVATE_DEPENDS) - mo2_add_dependencies(${MO2_TARGET} PRIVATE ${MO2_PRIVATE_DEPENDS}) + mo2_add_dependencies(${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}) + set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${TARGET}) endif() endfunction() #! mo2_configure_tests : configure a target as a MO2 C++ tests # -# extra arguments are given to mo2_configure_target +# this function creates a set of tests available in the ${TARET}_gtests variable +# +# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are +# OFF by default # function(mo2_configure_tests TARGET) mo2_configure_target(${TARGET} TRANSLATIONS OFF AUTOMOC OFF ${ARGN}) @@ -211,23 +217,25 @@ endfunction() # 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")) +function(mo2_configure_uibase TARGET) + if (NOT (${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") + mo2_configure_target(${TARGET} ${ARGN}) + set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "uibase") - target_include_directories(${MO2_TARGET} PUBLIC + target_include_directories(${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) + ${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe) 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) @@ -240,52 +248,54 @@ function(mo2_configure_plugin TARGET) ${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe) endfunction() -#! mo2_configure_library : configure a C++ library (NOT a plugin) +#! mo2_configure_library : configure a C++ library (NOT a plugin), can be a STATIC +# or SHARED library # -# extra arguments are given to mo2_configure_target +# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are +# OFF by default # -function(mo2_configure_library MO2_TARGET) - mo2_configure_target(${MO2_TARGET} AUTOMOC OFF TRANSLATIONS OFF ${ARGN}) +function(mo2_configure_library TARGET) + mo2_configure_target(${TARGET} AUTOMOC OFF TRANSLATIONS OFF ${ARGN}) - get_target_property(TARGET_TYPE ${MO2_TARGET} TYPE) + get_target_property(TARGET_TYPE ${TARGET} TYPE) - target_include_directories(${MO2_TARGET} + target_include_directories(${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") + set_target_properties(${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") + ${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe) + set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "library-shared") endif() endfunction() #! mo2_configure_executable : configure a target as MO2 C++ executable # +# \param:ELEVATED set flag on the executable to run as elevated by default +# # extra arguments are given to mo2_configure_target # -function(mo2_configure_executable MO2_TARGET) +function(mo2_configure_executable 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") + mo2_configure_target(${TARGET} ${ARGN}) + set_target_properties(${TARGET} + PROPERTIES WIN32_EXECUTABLE TRUE TARGET_TYPE "executable") - get_target_property(output_name ${MO2_TARGET} OUTPUT_NAME) + get_target_property(output_name ${TARGET} OUTPUT_NAME) if("${output_name}" STREQUAL "output_name-NOTFOUND") - set(output_name ${MO2_TARGET}) + set(output_name ${TARGET}) endif() mo2_set_project_to_run_from_install( - ${MO2_TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/${output_name}) + ${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 + set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"") endif() endfunction() @@ -294,39 +304,45 @@ endfunction() # # for this to work properly, the target must have been configured # -function(mo2_install_target MO2_TARGET) +# \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) cmake_parse_arguments(MO2 "FOLDER" "INSTALLDIR" "" ${ARGN}) - get_target_property(MO2_TARGET_TYPE ${MO2_TARGET} MO2_TARGET_TYPE) + get_target_property(MO2_TARGET_TYPE ${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) + mo2_set_if_not_defined(MO2_INSTALLDIR "bin") + install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR}) + install(TARGETS ${TARGET} ARCHIVE DESTINATION libs) elseif (${MO2_TARGET_TYPE} STREQUAL "plugin") if (${MO2_FOLDER}) - install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION bin/plugins/${MO2_TARGET}) + install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins/${TARGET}) else() - install(TARGETS ${MO2_TARGET} RUNTIME DESTINATION bin/plugins) + install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins) endif() - install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs) + install(TARGETS ${TARGET} ARCHIVE DESTINATION libs) elseif (${MO2_TARGET_TYPE} STREQUAL "library-static") - install(TARGETS ${MO2_TARGET} ARCHIVE DESTINATION libs) + install(TARGETS ${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) + install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR}) + install(TARGETS ${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}) + install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR}) else() - message(ERROR "unknown MO2 target type for target '${MO2_TARGET}', did you forget using mo2_configure_XXX?") + message(ERROR "unknown MO2 target type for target '${TARGET}', did you forget using mo2_configure_XXX?") endif() # install PDB if possible if (NOT (${MO2_TARGET_TYPE} STREQUAL "library-static")) - install(FILES $ DESTINATION pdb) + install(FILES $ DESTINATION pdb) endif() endfunction() diff --git a/mo2_python.cmake b/mo2_python.cmake index addaddf..0fbf9f4 100644 --- a/mo2_python.cmake +++ b/mo2_python.cmake @@ -4,11 +4,12 @@ include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake) #! mo2_python_uifiles : create .py files from .ui files for a python target # +# \param:TARGET target to generate .py files for # \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) +function(mo2_python_uifiles TARGET) cmake_parse_arguments(MO2 "INPLACE" "" "FILES" ${ARGN}) if (NOT MO2_FILES) @@ -46,20 +47,21 @@ function(mo2_python_uifiles MO2_TARGET) 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_custom_target("${TARGET}_uic" DEPENDS ${pyui_files}) + set_target_properties("${TARGET}_uic" PROPERTIES FOLDER autogen) - add_dependencies(${MO2_TARGET} "${MO2_TARGET}_uic") + add_dependencies(${TARGET} "${TARGET}_uic") endfunction() #! mo2_python_rcfiles : create .py files from .qrc files for a python target # +# \param:TARGET target to generate .py files for # \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) +function(mo2_python_rcfiles TARGET) cmake_parse_arguments(MO2 "" "INPLACE" "FILES" ${ARGN}) if (NOT MO2_FILES) @@ -99,14 +101,19 @@ function(mo2_python_rcfiles MO2_TARGET) 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") + add_custom_target("${TARGET}_qrc" DEPENDS ${pyrc_files}) + set_target_properties("${TARGET}_qrc" PROPERTIES FOLDER autogen) + add_dependencies(${TARGET} "${TARGET}_qrc") endfunction() #! mo2_python_pip_install : run "pip install ..." # +# \param:TARGET target to install Python package for +# \param:DIRECTORY directory to install libraries to, REQUIRED +# \param:PACKAGES packages to install, REQUIRED, can contain version constraints, e.g., +# "PyQt6==6.3.0" +# function(mo2_python_pip_install TARGET) cmake_parse_arguments(MO2 "" "DIRECTORY" "PACKAGES" ${ARGN}) @@ -136,12 +143,14 @@ function(mo2_python_pip_install TARGET) add_dependencies(${TARGET} ${pip_target_name}) - endfunction() #! mo2_python_requirements : install requirements for a python target # -function(mo2_python_requirements MO2_TARGET) +# \param:TARGET target to install requirements for +# \param:LIBDIR library to install requirements to +# +function(mo2_python_requirements TARGET) cmake_parse_arguments(MO2 "" "LIBDIR" "") add_custom_command( @@ -150,28 +159,34 @@ function(mo2_python_requirements MO2_TARGET) -I -m pip install --force --upgrade --disable-pip-version-check - --target="${lib_dir}" + --target="${MO2_LIBDIR}" --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" + add_custom_target("${TARGET}_libs" ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pip.log") - set_target_properties("${MO2_TARGET}_libs" PROPERTIES FOLDER autogen) + set_target_properties("${TARGET}_libs" PROPERTIES FOLDER autogen) - add_dependencies(${MO2_TARGET} "${MO2_TARGET}_libs") + add_dependencies(${TARGET} "${TARGET}_libs") - file(MAKE_DIRECTORY "${lib_dir}") + file(MAKE_DIRECTORY "${MO2_LIBDIR}") install( - DIRECTORY "${lib_dir}" - DESTINATION "${MO2_INSTALL_PATH}/bin/plugins/${MO2_TARGET}" + DIRECTORY "${MO2_LIBDIR}" + DESTINATION "${MO2_INSTALL_PATH}/bin/plugins/${TARGET}" ) endfunction() -function(mo2_configure_python_module MO2_TARGET) +#! mo2_configure_python_module : configure a Python plugin module +# +# \param:TARGET target for the Python plugin +# \param:LIBDIR directory to install requirements (if any) to, default is "lib" +# \param:RESDIR directory to install genereated resources (if any) to, default is "res" +# +function(mo2_configure_python_module TARGET) cmake_parse_arguments(MO2 "" "LIBDIR;RESDIR" "" ${ARGN}) mo2_set_if_not_defined(MO2_LIBDIR "lib") @@ -191,7 +206,7 @@ function(mo2_configure_python_module MO2_TARGET) set(lib_files ${all_src_files}) list(FILTER lib_files INCLUDE REGEX "${lib_dir}[/\\].*") - target_sources(${MO2_TARGET} PRIVATE ${src_files}) + target_sources(${TARGET} PRIVATE ${src_files}) source_group(cmake FILES CMakeLists.txt) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX src @@ -202,23 +217,23 @@ function(mo2_configure_python_module MO2_TARGET) # ui files file(GLOB_RECURSE ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui) - mo2_python_uifiles(${MO2_TARGET} INPLACE FILES ${ui_files}) + mo2_python_uifiles(${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}) + mo2_python_rcfiles(${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 + mo2_python_requirements(${TARGET} LIBDIR "${lib_dir}") + target_sources(${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}") + set(install_dir "${MO2_INSTALL_PATH}/bin/plugins/${TARGET}") # directories that go in bin/plugins/${name} install( @@ -238,7 +253,11 @@ function(mo2_configure_python_module MO2_TARGET) endfunction() -function(mo2_configure_python_simple MO2_TARGET) +#! mo2_configure_python_simple : configure a Python plugin (simple file) +# +# \param:TARGET target for the Python plugin +# +function(mo2_configure_python_simple TARGET) # this copies all the .py files that are directly in src/ into # ${install_dir}/ @@ -249,11 +268,11 @@ function(mo2_configure_python_simple MO2_TARGET) # ui files file(GLOB ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui) - mo2_python_uifiles(${MO2_TARGET} FILES ${ui_files}) + mo2_python_uifiles(${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}) + mo2_python_rcfiles(${TARGET} FILES ${qrc_files}) # .py files directly in the directory file(GLOB py_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.py) @@ -266,7 +285,7 @@ function(mo2_configure_python_simple MO2_TARGET) ${CMAKE_CURRENT_SOURCE_DIR}/**/*.py) set(src_files ${py_files} ${ui_files} ${json_files} ${extra_py_files}) - target_sources(${MO2_TARGET} PRIVATE ${src_files}) + target_sources(${TARGET} PRIVATE ${src_files}) source_group(cmake FILES CMakeLists.txt) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX src @@ -306,8 +325,11 @@ endfunction() #! mo2_configure_python : configure a MO2 python target # # \param:MODULE indicates if this is a Python module plugin or a file plugin +# \param:TRANSLATIONS ON to generate translations (default), OFF to not generate them +# \param:LIB only for Python module, see mo2_configure_python_module +# \param:RES only for Python module, see mo2_configure_python_module # -function(mo2_configure_python MO2_TARGET) +function(mo2_configure_python TARGET) cmake_parse_arguments(MO2 "MODULE;SIMPLE" "TRANSLATIONS;LIB;RES" "" ${ARGN}) mo2_set_if_not_defined(MO2_TRANSLATIONS ON) @@ -317,21 +339,21 @@ function(mo2_configure_python MO2_TARGET) endif() if (${MO2_MODULE}) - mo2_configure_python_module(${MO2_TARGET} ${ARGN}) + mo2_configure_python_module(${TARGET} ${ARGN}) else() - mo2_configure_python_simple(${MO2_TARGET} ${ARGN}) + mo2_configure_python_simple(${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}) + mo2_add_translations(${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} + target_sources(${TARGET} PRIVATE ${py_files} ${ui_files} ${rc_files} ${qm_files}) endfunction() diff --git a/mo2_targets.cmake b/mo2_targets.cmake index 07577cd..5ce1511 100644 --- a/mo2_targets.cmake +++ b/mo2_targets.cmake @@ -5,11 +5,13 @@ 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 +# the name of the dependencies should be: +# - valid mo2 "libraries", as per mo2_find_libraries, +# - boost (for header-only Boost libraries) or "boost::XXX" for specific Boost +# components +# - or Qt::XXX for Qt components # -function(mo2_add_dependencies MO2_TARGET PRIVATE_OR_PUBLIC) +function(mo2_add_dependencies TARGET PRIVATE_OR_PUBLIC) # remove everything boost related set(standard_deps ${ARGN}) @@ -30,7 +32,7 @@ function(mo2_add_dependencies MO2_TARGET PRIVATE_OR_PUBLIC) 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}) + target_link_libraries(${TARGET} ${PRIVATE_OR_PUBLIC} ${standard_deps}) # handle Qt dependencies if (qt_deps) @@ -40,14 +42,14 @@ function(mo2_add_dependencies MO2_TARGET PRIVATE_OR_PUBLIC) # 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}) + target_link_libraries(${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}) + ${TARGET} ${PRIVATE_OR_PUBLIC} ${Boost_INCLUDE_DIRS}) list(TRANSFORM boost_deps REPLACE "boost(::)?" "") list(FILTER boost_deps EXCLUDE REGEX "^$") @@ -56,13 +58,16 @@ function(mo2_add_dependencies MO2_TARGET PRIVATE_OR_PUBLIC) 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}) + target_link_libraries(${TARGET} ${PRIVATE_OR_PUBLIC} ${Boost_LIBRARIES}) endif() endif() endfunction() #! mo2_find_uibase : find and create a mo2::uibase target # +# if a 'uibase' target already exists, makes an alias as 'mo2::uibase', otherwise +# creates an imported target +# function(mo2_find_uibase) # target was already created @@ -95,6 +100,7 @@ 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}) @@ -406,30 +412,17 @@ function(mo2_find_usvfs) endfunction() -#! mo2_find_libraries : find and create library +#! mo2_find_libraries : find and create libraries to link to # -# this function find the given libraries and generate (if the libraries are found) -# targets mo2::LIBRARY_NAME +# this function tries to find the given libraries and generates (if the libraries are +# found) targets mo2::LIBRARY_NAME for each library found # -# example: mo2_find_libraries(uibase, loot) will create mo2::uibase and mo2::loot +# example: mo2_find_libraries(uibase loot) will create mo2::uibase and mo2::loot +# +# available libraries are the ones with mo2_find_XXX functions # 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() diff --git a/mo2_utils.cmake b/mo2_utils.cmake index 4266746..91aa05b 100644 --- a/mo2_utils.cmake +++ b/mo2_utils.cmake @@ -18,11 +18,11 @@ function (mo2_set_if_not_defined NAME VALUE) endif() endfunction() -#! mo2_set_project_to_run_from_install : set a PROJECT to run from a given executable +#! mo2_set_project_to_run_from_install : set a target to run from a given executable # -# this function only works for VS generator +# this function is only meaningful for VS generator # -# \param:PROJECT name of the project +# \param:TARGET name of the target # \param:EXECUTABLE full path to the executable # \param:WORKDIR working directory (optional, default is the directory of the executable) # @@ -34,7 +34,7 @@ function(mo2_set_project_to_run_from_install TARGET) get_filename_component(MO2_WORKDIR ${MO2_EXECUTABLE} DIRECTORY) endif() - set_target_properties(${MO2_TARGET} PROPERTIES + set_target_properties(${TARGET} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${MO2_WORKDIR}" VS_DEBUGGER_COMMAND "${MO2_EXECUTABLE}") endfunction() @@ -66,7 +66,7 @@ endmacro() # # \param:NAME name of the group # \param:FILES files to add -# \param:GROUPS files to add +# \param:GROUPS basename to add, e.g., "foo" will add "foo.cpp", "foo.h" and "foo.inc" # function(mo2_add_filter) cmake_parse_arguments(PARSE_ARGV 0 add_filter "" "NAME" "FILES;GROUPS") @@ -81,7 +81,11 @@ function(mo2_add_filter) source_group(${filter_name} FILES ${files}) endfunction() -#! mo2_find_qt_version : try to deduce Qt version from variables +#! mo2_find_qt_version : try to deduce Qt version from QT_ROOT variable +# +# this function caches the given variable +# +# \param:VAR name of the variable to store the version into # function(mo2_find_qt_version VAR) @@ -157,11 +161,11 @@ function(mo2_deploy_qt) endif() endfunction() -#! generate .ts files from the given sources +#! mo2_add_lupdate : generate .ts files from the given sources # # this function adds a ${TARGET}_lupdate target # -# \param:TARGET target to generate releases for +# \param:TARGET target to generate lupdate for # \param:TS_FILE .ts file to generate # \param:SOURCES source folders to generate .ts file from # @@ -214,29 +218,29 @@ function(mo2_add_lupdate TARGET) DEPENDS ${translation_files} VERBATIM) - add_custom_target("${MO2_TARGET}_lupdate" DEPENDS ${MO2_TS_FILE}) + add_custom_target("${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 + set_target_properties(${TARGET}_lupdate PROPERTIES VS_GLOBAL_ResolveNugetPackages False FOLDER autogen) endfunction() -#! generate .ts files from the given sources +#! mo2_add_lrelease : 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:INSTALL if set, QM files will be installed to bin/translations # \param:QM_FILE .qm file to generate # \param:TS_FILES source ts # -function(mo2_add_lrelease MO2_TARGET) +function(mo2_add_lrelease TARGET) cmake_parse_arguments(MO2 "INSTALL" "QM_FILE" "TS_FILES" ${ARGN}) add_custom_command(OUTPUT ${MO2_QM_FILE} @@ -245,14 +249,14 @@ function(mo2_add_lrelease MO2_TARGET) DEPENDS "${MO2_TS_FILES}" VERBATIM) - add_custom_target("${MO2_TARGET}_lrelease" DEPENDS ${MO2_QM_FILE}) + add_custom_target("${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 + set_target_properties(${TARGET}_lrelease PROPERTIES VS_GLOBAL_ResolveNugetPackages False FOLDER autogen) @@ -262,6 +266,18 @@ function(mo2_add_lrelease MO2_TARGET) endfunction() + +#! mo2_add_translations : generate translation files +# +# this function is a wrapper around mo2_add_lupdate and mo2_add_lrelease +# +# \param:TARGET target to generate translations for +# \param:RELEASE if set, will use mo2_add_lrelease to generate .qm files +# \param:INSTALL_RELEASE if true, will install generated .qm files (force RELEASE) +# \param:TS_FILE intermediate .ts file to generate +# \param:QM_FILE file .qm file to generate if RELEASE or INSTALL_RELEASE is set +# \param:SOURCES source directories to look for translations, send to mo2_add_lupdate +# function(mo2_add_translations TARGET) cmake_parse_arguments(MO2 "RELEASE;INSTALL_RELEASE" "TS_FILE;QM_FILE" "SOURCES" ${ARGN})