914 lines
27 KiB
CMake
914 lines
27 KiB
CMake
cmake_minimum_required(VERSION 3.19)
|
|
|
|
#[[
|
|
NOTICE
|
|
--------
|
|
Since Qt official CMake modules sets private header directory variables when you call `find_package(Qt)`
|
|
only if the Qt targets hasn't been defined, if we place `find_package(Qt)` in a function, the variable
|
|
will be cleared while the target remains after the function returns, as a result, we can never get the
|
|
private header directory variables again.
|
|
|
|
Therefore, never wrap `find_package(Qt)` in a function, use macro instead, any macros that wraps it also
|
|
shouldn't be wrapped in any function.
|
|
]] #
|
|
set(QMSETUP_MODULES_DIR ${CMAKE_CURRENT_LIST_DIR})
|
|
|
|
if(WIN32)
|
|
set(QMSETUP_SHARED_LIBRARY_CATEGORY bin)
|
|
set(QMSETUP_NULL_FILE "NUL")
|
|
set(QMSETUP_REGEX_ABSOLUTE_PATH "^[a-zA-Z]:|\\\\")
|
|
else()
|
|
set(QMSETUP_SHARED_LIBRARY_CATEGORY lib)
|
|
set(QMSETUP_NULL_FILE "/dev/null")
|
|
set(QMSETUP_REGEX_ABSOLUTE_PATH "^/")
|
|
endif()
|
|
|
|
set(QMSETUP_IGNORE_STDOUT > ${QMSETUP_NULL_FILE})
|
|
set(QMSETUP_IGNORE_STDERR 2> ${QMSETUP_NULL_FILE})
|
|
set(QMSETUP_IGNORE_STDOUT_STDERR > ${QMSETUP_NULL_FILE} 2>&1)
|
|
|
|
if(TARGET qmsetup::corecmd)
|
|
get_target_property(QMSETUP_CORECMD_EXECUTABLE qmsetup::corecmd LOCATION)
|
|
else()
|
|
set(QMSETUP_CORECMD_EXECUTABLE)
|
|
endif()
|
|
|
|
if(NOT DEFINED QMSETUP_FIND_QT_ORDER)
|
|
set(QMSETUP_FIND_QT_ORDER Qt6 Qt5)
|
|
endif()
|
|
|
|
include_guard(DIRECTORY)
|
|
|
|
#[[
|
|
Include modules of this library.
|
|
|
|
qm_import(<module...>)
|
|
]] #
|
|
macro(qm_import)
|
|
foreach(_module ${ARGN})
|
|
if(NOT _module MATCHES "(.+)\\.cmake")
|
|
set(_module "${_module}.cmake")
|
|
endif()
|
|
|
|
set(_module_path "${QMSETUP_MODULES_DIR}/modules/${_module}")
|
|
|
|
if(NOT EXISTS "${_module_path}")
|
|
message(FATAL_ERROR "qm_import: module \"${_module}\" not found.")
|
|
endif()
|
|
|
|
include("${_module_path}")
|
|
endforeach()
|
|
endmacro()
|
|
|
|
#[[
|
|
Include all modules of this library.
|
|
|
|
qm_import_all()
|
|
]] #
|
|
macro(qm_import_all)
|
|
file(GLOB _tmp_modules "${QMSETUP_MODULES_DIR}/modules/*")
|
|
|
|
foreach(_module IN LISTS _tmp_modules)
|
|
include("${_module}")
|
|
endforeach()
|
|
|
|
unset(_tmp_modules)
|
|
endmacro()
|
|
|
|
#[[
|
|
Parse version and create seq vars with specified prefix.
|
|
|
|
qm_parse_version(<prefix> <version>)
|
|
]] #
|
|
function(qm_parse_version _prefix _version)
|
|
string(REPLACE "." ";" _version_list ${_version})
|
|
list(LENGTH _version_list _version_count)
|
|
list(PREPEND _version_list 0) # Add placeholder
|
|
|
|
foreach(_i RANGE 1 4)
|
|
if(_i LESS_EQUAL _version_count)
|
|
list(GET _version_list ${_i} _item)
|
|
else()
|
|
set(_item 0)
|
|
endif()
|
|
|
|
set(${_prefix}_${_i} ${_item} PARENT_SCOPE)
|
|
endforeach()
|
|
endfunction()
|
|
|
|
#[[
|
|
Get shorter version number.
|
|
|
|
qm_crop_version(<VAR> <version> <count>)
|
|
]] #
|
|
function(qm_crop_version _var _version _count)
|
|
qm_parse_version(FUNC ${_version})
|
|
|
|
set(_list)
|
|
|
|
foreach(_i RANGE 1 ${_count})
|
|
list(APPEND _list ${FUNC_${_i}})
|
|
endforeach()
|
|
|
|
string(JOIN "." _short_version ${_list})
|
|
set(${_var} ${_short_version} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#[[
|
|
Tell if there are any generator expressions in the string.
|
|
|
|
qm_has_genex(<VAR> <string>)
|
|
]] #
|
|
function(qm_has_genex _out _str)
|
|
string(GENEX_STRIP "${_str}" _no_genex)
|
|
|
|
if(_str STREQUAL _no_genex)
|
|
set(_res off)
|
|
else()
|
|
set(_res on)
|
|
endif()
|
|
|
|
set(${_out} ${_res} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#[[
|
|
Tell if the given paths are same in canonical form.
|
|
|
|
qm_paths_equal(<VAR> <path1> <path2>)
|
|
]] #
|
|
function(qm_paths_equal _out _path1 _path2)
|
|
# cmake_path(NORMAL_PATH) is introduced in CMake 3.20, we don't use it
|
|
# We call `get_filename_component` twice to normalize the paths
|
|
get_filename_component(_path1 ${_path1} ABSOLUTE)
|
|
get_filename_component(_path1 ${_path1} REALPATH)
|
|
|
|
get_filename_component(_path2 ${_path2} ABSOLUTE)
|
|
get_filename_component(_path2 ${_path2} REALPATH)
|
|
|
|
if(_path1 STREQUAL _path2)
|
|
set(${_out} on PARENT_SCOPE)
|
|
else()
|
|
set(${_out} off PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
#[[
|
|
Set value if valid, otherwise use default.
|
|
|
|
qm_set_value(<key> <maybe_value...> <default>)
|
|
]] #
|
|
function(qm_set_value _key)
|
|
set(_args "${ARGN}")
|
|
list(POP_BACK _args _default)
|
|
|
|
foreach(_item IN LISTS _args)
|
|
if(${_item})
|
|
set(${_key} ${${_item}} PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${_key} ${_default} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#[[
|
|
Skip CMAKE_AUTOMOC for sources files or ones in directories.
|
|
|
|
qm_skip_automoc(<file/dir...>)
|
|
]] #
|
|
function(qm_skip_automoc)
|
|
foreach(_item ${ARGN})
|
|
get_filename_component(_item ${_item} ABSOLUTE)
|
|
|
|
if(IS_DIRECTORY ${_item})
|
|
file(GLOB _src
|
|
${_item}/*.h ${_item}/*.hpp
|
|
${_item}/*.hh ${_item}/*.hxx
|
|
${_item}/*.cpp ${_item}/*.cxx
|
|
${_item}/*.c ${_item}/*.cc
|
|
${_item}/*.m ${_item}/*.mm
|
|
)
|
|
set_source_files_properties(
|
|
${_src} PROPERTIES SKIP_AUTOMOC ON
|
|
)
|
|
elseif(EXISTS ${_item})
|
|
set_source_files_properties(
|
|
${_item} PROPERTIES SKIP_AUTOMOC ON
|
|
)
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
#[[
|
|
Find Qt libraries. Don't wrap it in any functions.
|
|
|
|
qm_find_qt(<modules...>)
|
|
#]]
|
|
macro(qm_find_qt)
|
|
foreach(_module ${ARGN})
|
|
if(NOT QT_VERSION_MAJOR)
|
|
find_package(QT NAMES ${QMSETUP_FIND_QT_ORDER} COMPONENTS ${_module} REQUIRED)
|
|
endif()
|
|
|
|
if(NOT TARGET Qt${QT_VERSION_MAJOR}::${_module})
|
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${_module} REQUIRED)
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
#[[
|
|
Link Qt libraries. Don't wrap it in any functions.
|
|
|
|
qm_link_qt(<target> <scope> <modules...>)
|
|
#]]
|
|
macro(qm_link_qt _target _scope)
|
|
foreach(_module ${ARGN})
|
|
qm_find_qt(${_module})
|
|
target_link_libraries(${_target} ${_scope} Qt${QT_VERSION_MAJOR}::${_module})
|
|
endforeach()
|
|
endmacro()
|
|
|
|
#[[
|
|
Include Qt private header directories. Don't wrap it in any functions.
|
|
|
|
qm_include_qt_private(<target> <scope> <modules...>)
|
|
#]]
|
|
macro(qm_include_qt_private _target _scope)
|
|
foreach(_module ${ARGN})
|
|
qm_find_qt(${_module})
|
|
target_include_directories(${_target} ${_scope} ${Qt${QT_VERSION_MAJOR}${_module}_PRIVATE_INCLUDE_DIRS})
|
|
endforeach()
|
|
endmacro()
|
|
|
|
#[[
|
|
Helper to set or append all kinds of attributes to a target. Don't wrap it in any functions.
|
|
|
|
qm_configure_target(<target>
|
|
[SOURCES <files>]
|
|
|
|
[LINKS <libs>]
|
|
[LINKS_PRIVATE <libs>]
|
|
|
|
[INCLUDE <dirs>]
|
|
[INCLUDE_PRIVATE <dirs>]
|
|
|
|
[LINKDIR <dirs>]
|
|
[LINKDIR_PRIVATE <dirs>]
|
|
|
|
[DEFINES <defs>]
|
|
[DEFINES_PRIVATE <defs>]
|
|
|
|
[FEATURES <features>]
|
|
[FEATURES_PRIVATE <features>]
|
|
|
|
[CCFLAGS <flags>]
|
|
[CCFLAGS_PUBLIC <flags>]
|
|
|
|
[LDFLAGS <flags>]
|
|
[LDFLAGS_PUBLIC <flags>]
|
|
|
|
[QT_LINKS <modules>]
|
|
[QT_LINKS_PRIVATE <modules>]
|
|
[QT_INCLUDE_PRIVATE <modules>]
|
|
|
|
[SKIP_AUTOMOC <dir/file...>]
|
|
)
|
|
|
|
INCLUDE/LINKDIR: `dir/*` will be expanded to all subdirectories
|
|
`dir/**` will be expanded to all descendent directories recursively
|
|
]] #
|
|
macro(qm_configure_target _target)
|
|
set(options)
|
|
set(oneValueArgs)
|
|
set(multiValueArgs
|
|
SOURCES
|
|
LINKS LINKS_PRIVATE
|
|
INCLUDE INCLUDE_PRIVATE
|
|
LINKDIR LINKDIR_PRIVATE
|
|
DEFINES DEFINES_PRIVATE
|
|
FEATURES FEATURES_PRIVATE
|
|
CCFLAGS CCFLAGS_PUBLIC
|
|
LDFLAGS LDFLAGS_PUBLIC
|
|
QT_LINKS QT_LINKS_PRIVATE QT_INCLUDE_PRIVATE
|
|
SKIP_AUTOMOC
|
|
)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
macro(_resolve_dir_helper _dirs _out)
|
|
set(${_out})
|
|
|
|
foreach(_item IN LISTS ${_dirs})
|
|
if(_item STREQUAL "*")
|
|
set(_cur_dir ".")
|
|
file(GLOB _subdirs LIST_DIRECTORIES true "*")
|
|
elseif(_item STREQUAL "**")
|
|
set(_cur_dir ".")
|
|
file(GLOB_RECURSE _subdirs LIST_DIRECTORIES true "*")
|
|
elseif(_item MATCHES "(.+)/\\*$")
|
|
set(_cur_dir ${CMAKE_MATCH_1})
|
|
file(GLOB _subdirs LIST_DIRECTORIES true "${_cur_dir}/*")
|
|
elseif(_item MATCHES "(.+)/\\*\\*$")
|
|
set(_cur_dir ${CMAKE_MATCH_1})
|
|
file(GLOB_RECURSE _subdirs LIST_DIRECTORIES true "${_cur_dir}/*")
|
|
else()
|
|
list(APPEND ${_out} ${_item})
|
|
continue()
|
|
endif()
|
|
|
|
list(APPEND ${_out} ${_cur_dir})
|
|
|
|
foreach(_subdir IN LISTS _subdirs)
|
|
if(IS_DIRECTORY ${_subdir})
|
|
get_filename_component(_subdir ${_subdir} ABSOLUTE)
|
|
list(APPEND ${_out} ${_subdir})
|
|
endif()
|
|
endforeach()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
target_sources(${_target} PRIVATE ${FUNC_SOURCES})
|
|
|
|
target_link_libraries(${_target} PUBLIC ${FUNC_LINKS})
|
|
target_link_libraries(${_target} PRIVATE ${FUNC_LINKS_PRIVATE})
|
|
|
|
if(FUNC_INCLUDE)
|
|
_resolve_dir_helper(FUNC_INCLUDE _temp_dirs)
|
|
target_include_directories(${_target} PUBLIC ${_temp_dirs})
|
|
unset(_temp_dirs)
|
|
endif()
|
|
|
|
if(FUNC_INCLUDE_PRIVATE)
|
|
_resolve_dir_helper(FUNC_INCLUDE_PRIVATE _temp_dirs)
|
|
target_include_directories(${_target} PRIVATE ${_temp_dirs})
|
|
unset(_temp_dirs)
|
|
endif()
|
|
|
|
if(FUNC_LINKDIR)
|
|
_resolve_dir_helper(FUNC_LINKDIR _temp_dirs)
|
|
target_link_directories(${_target} PUBLIC ${_temp_dirs})
|
|
unset(_temp_dirs)
|
|
endif()
|
|
|
|
if(FUNC_LINKDIR_PRIVATE)
|
|
_resolve_dir_helper(FUNC_LINKDIR_PRIVATE _temp_dirs)
|
|
target_link_directories(${_target} PRIVATE ${_temp_dirs})
|
|
unset(_temp_dirs)
|
|
endif()
|
|
|
|
target_compile_definitions(${_target} PUBLIC ${FUNC_DEFINES})
|
|
target_compile_definitions(${_target} PRIVATE ${FUNC_DEFINES_PRIVATE})
|
|
|
|
target_compile_features(${_target} PUBLIC ${FUNC_FEATURES})
|
|
target_compile_features(${_target} PRIVATE ${FUNC_FEATURES_PRIVATE})
|
|
|
|
target_compile_options(${_target} PUBLIC ${FUNC_CCFLAGS_PUBLIC})
|
|
target_compile_options(${_target} PRIVATE ${FUNC_CCFLAGS})
|
|
|
|
target_link_options(${_target} PUBLIC ${FUNC_LDFLAGS_PUBLIC})
|
|
target_link_options(${_target} PRIVATE ${FUNC_LDFLAGS})
|
|
|
|
qm_link_qt(${_target} PUBLIC ${FUNC_QT_LINKS})
|
|
qm_link_qt(${_target} PRIVATE ${FUNC_QT_LINKS_PRIVATE})
|
|
|
|
qm_include_qt_private(${_target} PRIVATE ${FUNC_QT_INCLUDE_PRIVATE})
|
|
|
|
if(FUNC_SKIP_AUTOMOC)
|
|
_resolve_dir_helper(FUNC_SKIP_AUTOMOC _temp_files)
|
|
qm_skip_automoc(${_temp_files})
|
|
unset(_temp_files)
|
|
endif()
|
|
endmacro()
|
|
|
|
#[[
|
|
Helper to define export macros.
|
|
|
|
qm_export_defines(<target>
|
|
[PREFIX <prefix>]
|
|
[STATIC <token>]
|
|
[LIBRARY <token>]
|
|
)
|
|
]] #
|
|
function(qm_export_defines _target)
|
|
set(options)
|
|
set(oneValueArgs PREFIX STATIC LIBRARY)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
if(NOT FUNC_PREFIX)
|
|
string(TOUPPER ${_target} _prefix)
|
|
else()
|
|
set(_prefix ${FUNC_PREFIX})
|
|
endif()
|
|
|
|
qm_set_value(_static_macro FUNC_STATIC ${_prefix}_STATIC)
|
|
qm_set_value(_library_macro FUNC_LIBRARY ${_prefix}_LIBRARY)
|
|
|
|
get_target_property(_type ${_target} TYPE)
|
|
|
|
if(_type STREQUAL "INTERFACE_LIBRARY")
|
|
return()
|
|
endif()
|
|
|
|
if(_type STREQUAL "STATIC_LIBRARY")
|
|
target_compile_definitions(${_target} PUBLIC ${_static_macro})
|
|
endif()
|
|
|
|
target_compile_definitions(${_target} PRIVATE ${_library_macro})
|
|
endfunction()
|
|
|
|
#[[
|
|
Attach windows RC file to a target.
|
|
|
|
qm_add_win_rc(<target>
|
|
[NAME name]
|
|
[VERSION version]
|
|
[DESCRIPTION desc]
|
|
[COPYRIGHT copyright]
|
|
[ICON ico]
|
|
[OUTPUT output]
|
|
)
|
|
]] #
|
|
function(qm_add_win_rc _target)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
_qm_check_target_type_helper(${_target} _ "EXECUTABLE" "SHARED_LIBRARY")
|
|
|
|
set(options)
|
|
set(oneValueArgs NAME VERSION DESCRIPTION COPYRIGHT ICON OUTPUT)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
qm_set_value(_name FUNC_NAME ${_target})
|
|
qm_set_value(_version FUNC_VERSION PROJECT_VERSION "0.0.0.0")
|
|
qm_set_value(_desc FUNC_DESCRIPTION ${_name})
|
|
qm_set_value(_copyright FUNC_COPYRIGHT ${_name})
|
|
|
|
qm_parse_version(_ver ${_version})
|
|
set(RC_VERSION ${_ver_1},${_ver_2},${_ver_3},${_ver_4})
|
|
|
|
set(RC_APPLICATION_NAME ${_name})
|
|
set(RC_VERSION_STRING ${_version})
|
|
set(RC_DESCRIPTION ${_desc})
|
|
set(RC_COPYRIGHT ${_copyright})
|
|
|
|
if(NOT FUNC_ICON)
|
|
set(RC_ICON_COMMENT "//")
|
|
set(RC_ICON_PATH)
|
|
else()
|
|
get_filename_component(RC_ICON_PATH ${FUNC_ICON} ABSOLUTE)
|
|
endif()
|
|
|
|
qm_set_value(_out_path FUNC_OUTOUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}_res.rc")
|
|
configure_file("${QMSETUP_MODULES_DIR}/windows/WinResource.rc.in" ${_out_path} @ONLY)
|
|
target_sources(${_target} PRIVATE ${_out_path})
|
|
endfunction()
|
|
|
|
#[[
|
|
Attach windows RC file to a target, enhanced edition.
|
|
|
|
qm_add_win_rc_enhanced(<target>
|
|
[NAME name]
|
|
[VERSION version]
|
|
[DESCRIPTION description]
|
|
[COPYRIGHT copyright]
|
|
[COMMENTS comments]
|
|
[COMPANY company]
|
|
[INTERNAL_NAME internal name]
|
|
[TRADEMARK trademark]
|
|
[ORIGINAL_FILENAME original filename]
|
|
[ICONS icon file paths]
|
|
[OUTPUT output]
|
|
)
|
|
]] #
|
|
function(qm_add_win_rc_enhanced _target)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
_qm_check_target_type_helper(${_target} _type "EXECUTABLE" "SHARED_LIBRARY")
|
|
|
|
set(options)
|
|
set(oneValueArgs
|
|
NAME VERSION DESCRIPTION COPYRIGHT COMMENTS COMPANY
|
|
INTERNAL_NAME TRADEMARK ORIGINAL_FILENAME OUTPUT
|
|
)
|
|
set(multiValueArgs ICONS)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
qm_set_value(_name FUNC_NAME ${_target})
|
|
qm_set_value(_version FUNC_VERSION PROJECT_VERSION "0.0.0.0")
|
|
qm_set_value(_desc FUNC_DESCRIPTION ${_name})
|
|
qm_set_value(_copyright FUNC_COPYRIGHT ${_name})
|
|
qm_set_value(_comments FUNC_COMMENTS "")
|
|
qm_set_value(_company FUNC_COMPANY "")
|
|
qm_set_value(_internal_name FUNC_INTERNAL_NAME "")
|
|
qm_set_value(_trademark FUNC_TRADEMARK "")
|
|
qm_set_value(_original_filename FUNC_ORIGINAL_FILENAME "")
|
|
|
|
qm_parse_version(_ver ${_version})
|
|
set(RC_VERSION ${_ver_1},${_ver_2},${_ver_3},${_ver_4})
|
|
|
|
set(RC_APPLICATION_NAME ${_name})
|
|
set(RC_VERSION_STRING ${_version})
|
|
set(RC_DESCRIPTION ${_desc})
|
|
set(RC_COPYRIGHT ${_copyright})
|
|
set(RC_COMMENTS ${_comments})
|
|
set(RC_COMPANY ${_company})
|
|
set(RC_INTERNAL_NAME ${_internal_name})
|
|
set(RC_TRADEMARK ${_trademark})
|
|
set(RC_ORIGINAL_FILENAME ${_original_filename})
|
|
|
|
set(_file_type)
|
|
|
|
if(_type STREQUAL "EXECUTABLE")
|
|
set(_file_type "VFT_APP")
|
|
else()
|
|
set(_file_type "VFT_DLL")
|
|
endif()
|
|
|
|
set(RC_FILE_TYPE ${_file_type})
|
|
|
|
set(_icons)
|
|
|
|
if(FUNC_ICONS)
|
|
set(_index 1)
|
|
|
|
foreach(_icon IN LISTS FUNC_ICONS)
|
|
get_filename_component(_icon_path ${_icon} ABSOLUTE)
|
|
string(APPEND _icons "IDI_ICON${_index} ICON \"${_icon_path}\"\n")
|
|
math(EXPR _index "${_index} +1")
|
|
endforeach()
|
|
endif()
|
|
|
|
set(RC_ICONS ${_icons})
|
|
|
|
qm_set_value(_out_path FUNC_OUTOUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}_res.rc")
|
|
configure_file("${QMSETUP_MODULES_DIR}/windows/WinResource2.rc.in" ${_out_path} @ONLY)
|
|
target_sources(${_target} PRIVATE ${_out_path})
|
|
endfunction()
|
|
|
|
#[[
|
|
Attach windows manifest file to a target.
|
|
|
|
qm_add_win_manifest(<target>
|
|
[NAME name]
|
|
[VERSION version]
|
|
[DESCRIPTION desc]
|
|
[OUTPUT output]
|
|
[UTF8]
|
|
[ADMIN]
|
|
)
|
|
]] #
|
|
function(qm_add_win_manifest _target)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
_qm_check_target_type_helper(${_target} _ "EXECUTABLE")
|
|
|
|
set(options UTF8 ADMIN)
|
|
set(oneValueArgs NAME VERSION DESCRIPTION OUTPUT)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
qm_set_value(_name FUNC_NAME ${_target})
|
|
qm_set_value(_version FUNC_VERSION PROJECT_VERSION "0.0.0.0")
|
|
qm_set_value(_desc FUNC_DESCRIPTION ${_name})
|
|
|
|
qm_crop_version(_version ${_version} 4)
|
|
|
|
set(MANIFEST_IDENTIFIER ${_name})
|
|
set(MANIFEST_VERSION ${_version})
|
|
set(MANIFEST_DESCRIPTION ${_desc})
|
|
|
|
set(MANIFEST_UTF8)
|
|
|
|
if(FUNC_UTF8)
|
|
set(MANIFEST_UTF8 "<activeCodePage xmlns=\"http://schemas.microsoft.com/SMI/2019/WindowsSettings\">UTF-8</activeCodePage>")
|
|
endif()
|
|
|
|
if(FUNC_ADMIN)
|
|
set(MANIFEST_PRIVILEGES "<requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"false\" />")
|
|
else()
|
|
set(MANIFEST_PRIVILEGES "<requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" />")
|
|
endif()
|
|
|
|
qm_set_value(_out_path FUNC_OUTOUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}_manifest.manifest")
|
|
configure_file("${QMSETUP_MODULES_DIR}/windows/WinManifest.manifest.in" ${_out_path} @ONLY)
|
|
target_sources(${_target} PRIVATE ${_out_path})
|
|
endfunction()
|
|
|
|
#[[
|
|
Add Mac bundle info.
|
|
|
|
qm_add_mac_bundle(<target>
|
|
[NAME <name>]
|
|
[VERSION <version>]
|
|
[DESCRIPTION <desc>]
|
|
[COPYRIGHT <copyright>]
|
|
[ICON <file>]
|
|
)
|
|
]] #
|
|
function(qm_add_mac_bundle _target)
|
|
if(NOT APPLE)
|
|
return()
|
|
endif()
|
|
|
|
_qm_check_target_type_helper(${_target} _ "EXECUTABLE")
|
|
|
|
set(options)
|
|
set(oneValueArgs NAME VERSION DESCRIPTION COPYRIGHT ICON)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
qm_set_value(_app_name FUNC_NAME ${_target})
|
|
qm_set_value(_app_version FUNC_VERSION PROJECT_VERSION "0.0.0.0")
|
|
qm_set_value(_app_desc FUNC_DESCRIPTION ${_app_name})
|
|
qm_set_value(_app_copyright FUNC_COPYRIGHT ${_app_name})
|
|
|
|
qm_parse_version(_app_version ${_app_version})
|
|
|
|
# configure mac plist
|
|
set_target_properties(${_target} PROPERTIES
|
|
MACOSX_BUNDLE TRUE
|
|
MACOSX_BUNDLE_BUNDLE_NAME ${_app_name}
|
|
MACOSX_BUNDLE_EXECUTABLE_NAME ${_app_name}
|
|
MACOSX_BUNDLE_INFO_STRING ${_app_desc}
|
|
MACOSX_BUNDLE_GUI_IDENTIFIER ${_app_name}
|
|
MACOSX_BUNDLE_BUNDLE_VERSION ${_app_version}
|
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${_app_version_1}.${_app_version_2}
|
|
MACOSX_BUNDLE_COPYRIGHT ${_app_copyright}
|
|
)
|
|
|
|
if(FUNC_ICON)
|
|
# And this part tells CMake where to find and install the file itself
|
|
set_source_files_properties(${FUNC_ICON} PROPERTIES
|
|
MACOSX_PACKAGE_LOCATION "Resources"
|
|
)
|
|
|
|
# NOTE: Don't include the path in MACOSX_BUNDLE_ICON_FILE -- this is
|
|
# the property added to Info.plist
|
|
get_filename_component(_icns_name ${FUNC_ICON} NAME)
|
|
|
|
# configure mac plist
|
|
set_target_properties(${_target} PROPERTIES
|
|
MACOSX_BUNDLE_ICON_FILE ${_icns_name}
|
|
)
|
|
|
|
# ICNS icon MUST be added to executable's sources list, for some reason
|
|
# Only apple can do
|
|
target_sources(${_target} PRIVATE ${FUNC_ICON})
|
|
endif()
|
|
endfunction()
|
|
|
|
#[[
|
|
Generate Windows shortcut after building target.
|
|
|
|
qm_create_win_shortcut(<target> <dir>
|
|
[OUTPUT_NAME <name]
|
|
)
|
|
]] #
|
|
function(qm_create_win_shortcut _target _dir)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
set(options)
|
|
set(oneValueArgs OUTPUT_NAME)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
qm_set_value(_output_name FUNC_OUTPUT_NAME $<TARGET_FILE_BASE_NAME:${_target}>)
|
|
|
|
set(_vbs_name ${CMAKE_CURRENT_BINARY_DIR}/${_target}_shortcut_$<CONFIG>.vbs)
|
|
set(_vbs_temp ${_vbs_name}.in)
|
|
|
|
set(_lnk_path "${_dir}/${_output_name}.lnk")
|
|
|
|
set(SHORTCUT_PATH ${_lnk_path})
|
|
set(SHORTCUT_TARGET_PATH $<TARGET_FILE:${_target}>)
|
|
set(SHORTCUT_WORKING_DIRECOTRY $<TARGET_FILE_DIR:${_target}>)
|
|
set(SHORTCUT_DESCRIPTION $<TARGET_FILE_BASE_NAME:${_target}>)
|
|
set(SHORTCUT_ICON_LOCATION $<TARGET_FILE:${_target}>)
|
|
|
|
configure_file(
|
|
"${QMSETUP_MODULES_DIR}/windows/WinCreateShortcut.vbs.in"
|
|
${_vbs_temp}
|
|
@ONLY
|
|
)
|
|
file(GENERATE OUTPUT ${_vbs_name} INPUT ${_vbs_temp})
|
|
|
|
add_custom_command(
|
|
TARGET ${_target} POST_BUILD
|
|
COMMAND cscript ${_vbs_name} ${QMSETUP_IGNORE_STDOUT}
|
|
BYPRODUCTS ${_lnk_path}
|
|
VERBATIM
|
|
)
|
|
endfunction()
|
|
|
|
#[[
|
|
Collect targets of given types recursively in a directory.
|
|
|
|
qm_collect_targets(<list> [DIRECTORY directory]
|
|
[EXECUTABLE] [SHARED] [STATIC] [INTERFACE] [UTILITY])
|
|
|
|
If one or more types are specified, return targets matching the types.
|
|
If no type is specified, return all targets.
|
|
]] #
|
|
function(qm_collect_targets _var)
|
|
set(options EXECUTABLE SHARED STATIC INTERFACE UTILITY)
|
|
set(oneValueArgs DIR)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
if(FUNC_DIRECTORY)
|
|
set(_dir ${FUNC_DIRECTORY})
|
|
else()
|
|
set(_dir ${CMAKE_CURRENT_SOURCE_DIR})
|
|
endif()
|
|
|
|
set(_tmp_targets)
|
|
|
|
macro(_get_targets_recursive _targets _dir)
|
|
get_property(_subdirs DIRECTORY ${_dir} PROPERTY SUBDIRECTORIES)
|
|
|
|
foreach(_subdir IN LISTS _subdirs)
|
|
_get_targets_recursive(${_targets} ${_subdir})
|
|
endforeach()
|
|
|
|
get_property(_current_targets DIRECTORY ${_dir} PROPERTY BUILDSYSTEM_TARGETS)
|
|
list(APPEND ${_targets} ${_current_targets})
|
|
endmacro()
|
|
|
|
# Get targets
|
|
_get_targets_recursive(_tmp_targets ${_dir})
|
|
set(_targets)
|
|
|
|
if(NOT FUNC_EXECUTABLE AND NOT FUNC_SHARED AND NOT FUNC_STATIC AND NOT FUNC_INTERFACE AND NOT FUNC_UTILITY)
|
|
set(_targets ${_tmp_targets})
|
|
else()
|
|
# Filter targets
|
|
foreach(_item IN LISTS _tmp_targets)
|
|
get_target_property(_type ${_item} TYPE)
|
|
|
|
if(_type STREQUAL "EXECUTABLE")
|
|
if(FUNC_EXECUTABLE)
|
|
list(APPEND _targets ${_item})
|
|
endif()
|
|
elseif(_type STREQUAL "SHARED_LIBRARY")
|
|
if(FUNC_SHARED)
|
|
list(APPEND _targets ${_item})
|
|
endif()
|
|
elseif(_type STREQUAL "STATIC_LIBRARY")
|
|
if(FUNC_STATIC)
|
|
list(APPEND _targets ${_item})
|
|
endif()
|
|
elseif(_type STREQUAL "INTERFACE_LIBRARY")
|
|
if(FUNC_INTERFACE)
|
|
list(APPEND _targets ${_item})
|
|
endif()
|
|
elseif(_type STREQUAL "UTILITY")
|
|
if(FUNC_UTILITY)
|
|
list(APPEND _targets ${_item})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
set(${_var} ${_targets} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#[[
|
|
Get subdirectories' names or paths.
|
|
|
|
qm_get_subdirs(<list>
|
|
[DIRECTORY dir]
|
|
[EXCLUDE names...]
|
|
[REGEX_INCLUDE exps...]
|
|
[REGEX_EXLCUDE exps...]
|
|
[RELATIVE path]
|
|
[ABSOLUTE]
|
|
)
|
|
|
|
If `DIRECTORY` is not specified, consider `CMAKE_CURRENT_SOURCE_DIR`.
|
|
If `RELATIVE` is specified, return paths evaluated as a relative path to it.
|
|
If `ABSOLUTE` is specified, return absolute paths.
|
|
If neither of them is specified, return names.
|
|
]] #
|
|
function(qm_get_subdirs _var)
|
|
set(options ABSOLUTE)
|
|
set(oneValueArgs DIRECTORY RELATIVE)
|
|
set(multiValueArgs EXCLUDE REGEX_EXLCUDE)
|
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
if(FUNC_DIRECTORY)
|
|
get_filename_component(_dir ${FUNC_DIRECTORY} ABSOLUTE)
|
|
else()
|
|
set(_dir ${CMAKE_CURRENT_SOURCE_DIR})
|
|
endif()
|
|
|
|
file(GLOB _subdirs LIST_DIRECTORIES true RELATIVE ${_dir} "${_dir}/*")
|
|
|
|
if(FUNC_EXCLUDE)
|
|
foreach(_exclude_dir IN LISTS FUNC_EXCLUDE)
|
|
list(REMOVE_ITEM _subdirs ${_exclude_dir})
|
|
endforeach()
|
|
endif()
|
|
|
|
if(FUNC_REGEX_INCLUDE)
|
|
foreach(_exp IN LISTS FUNC_REGEX_INCLUDE)
|
|
list(FILTER _subdirs INCLUDE REGEX ${_exp})
|
|
endforeach()
|
|
endif()
|
|
|
|
if(FUNC_REGEX_EXCLUDE)
|
|
foreach(_exp IN LISTS FUNC_REGEX_EXCLUDE)
|
|
list(FILTER _subdirs EXCLUDE REGEX ${_exp})
|
|
endforeach()
|
|
endif()
|
|
|
|
set(_res)
|
|
|
|
if(FUNC_RELATIVE)
|
|
get_filename_component(_relative ${FUNC_RELATIVE} ABSOLUTE)
|
|
else()
|
|
set(_relative)
|
|
endif()
|
|
|
|
foreach(_sub IN LISTS _subdirs)
|
|
if(IS_DIRECTORY ${_dir}/${_sub})
|
|
if(FUNC_ABSOLUTE)
|
|
list(APPEND _res ${_dir}/${_sub})
|
|
elseif(_relative)
|
|
file(RELATIVE_PATH _rel_path ${_relative} ${_dir}/${_sub})
|
|
list(APPEND _res ${_rel_path})
|
|
else()
|
|
list(APPEND _res ${_sub})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${_var} ${_res} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#[[
|
|
Create the names of output files preserving relative dirs. (Ported from MOC command)
|
|
|
|
qm_make_output_file(<infile> <prefix> <ext> <OUT>)
|
|
#]]
|
|
function(qm_make_output_file _infile _prefix _ext _out)
|
|
string(LENGTH ${CMAKE_CURRENT_BINARY_DIR} _binlength)
|
|
string(LENGTH ${_infile} _infileLength)
|
|
set(_checkinfile ${CMAKE_CURRENT_SOURCE_DIR})
|
|
|
|
if(_infileLength GREATER _binlength)
|
|
string(SUBSTRING "${_infile}" 0 ${_binlength} _checkinfile)
|
|
|
|
if(_checkinfile STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
|
file(RELATIVE_PATH _rel ${CMAKE_CURRENT_BINARY_DIR} ${_infile})
|
|
else()
|
|
file(RELATIVE_PATH _rel ${CMAKE_CURRENT_SOURCE_DIR} ${_infile})
|
|
endif()
|
|
else()
|
|
file(RELATIVE_PATH _rel ${CMAKE_CURRENT_SOURCE_DIR} ${_infile})
|
|
endif()
|
|
|
|
if(CMAKE_HOST_WIN32 AND _rel MATCHES "^([a-zA-Z]):(.*)$") # absolute path
|
|
set(_rel "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}")
|
|
endif()
|
|
|
|
set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${_rel}")
|
|
string(REPLACE ".." "__" _outfile ${_outfile})
|
|
get_filename_component(_outpath ${_outfile} PATH)
|
|
|
|
if(CMAKE_VERSION VERSION_LESS "3.14")
|
|
get_filename_component(_outfile_ext ${_outfile} EXT)
|
|
get_filename_component(_outfile_ext ${_outfile_ext} NAME_WE)
|
|
get_filename_component(_outfile ${_outfile} NAME_WE)
|
|
string(APPEND _outfile ${_outfile_ext})
|
|
else()
|
|
get_filename_component(_outfile ${_outfile} NAME_WLE)
|
|
endif()
|
|
|
|
file(MAKE_DIRECTORY ${_outpath})
|
|
set(${_out} ${_outpath}/${_prefix}${_outfile}.${_ext} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# ----------------------------------
|
|
# Private functions
|
|
# ----------------------------------
|
|
macro(_qm_check_target_type_helper _target _type)
|
|
set(_tmp_target_type_list ${ARGN})
|
|
get_target_property(_tmp_target_type ${_target} TYPE)
|
|
|
|
if(NOT "${_tmp_target_type}" IN_LIST _tmp_target_type_list)
|
|
return()
|
|
endif()
|
|
|
|
set(${_type} ${_tmp_target_type})
|
|
unset(_tmp_target_type)
|
|
unset(_tmp_target_type_list)
|
|
endmacro()
|