notepad--/cmake/SparkMacrosConfig.cmake

417 lines
17 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

cmake_minimum_required(VERSION 3.5.1)
# 定义一些 macro 用于自动生成构建结构
# spark_aux_source_directory outvar invar [skip]
# 获取目录下的所有源代码
macro(spark_aux_source_directory OUTVAR INVAR)
# iv: internal_variable
set(iv_args ${ARGN})
list(LENGTH iv_args iv_arglen)
file(GLOB iv_SOURCE_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.c ${INVAR}/*.cpp ${INVAR}/*.cc)
file(GLOB iv_HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.h ${INVAR}/*.hpp)
file(GLOB iv_QT_UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.ui ${INVAR}/*.qrc)
if(iv_arglen EQUAL 1)
list(APPEND ${OUTVAR} ${iv_SOURCE_LIST} ${iv_HEADER_LIST} ${iv_QT_UI_LIST})
else()
set(${OUTVAR} ${iv_SOURCE_LIST} ${iv_HEADER_LIST} ${iv_QT_UI_LIST})
endif(iv_arglen EQUAL 1)
unset(iv_args)
unset(iv_arglen)
unset(iv_SOURCE_LIST)
unset(iv_HEADER_LIST)
unset(iv_QT_UI_LIST)
endmacro(spark_aux_source_directory OUTVAR INVAR)
# spark_aux_source_directories outvar invar [...]
# 获取目录列表下的所有源代码
# spark_aux_source_directory 的扩展,支持多个 invar 与追加参数
macro(spark_aux_source_directories OUTVAR INVAR)
set(iv_aux_directories ${ARGN})
spark_aux_source_directory(${OUTVAR} ${INVAR})
foreach(iv_directory IN LISTS iv_aux_directories)
spark_aux_source_directory(${OUTVAR} ${iv_directory} SKIP)
endforeach(iv_directory IN LISTS iv_aux_directories)
unset(iv_aux_directories)
endmacro(spark_aux_source_directories OUTVAR INVAR)
# spark_add_library <lib_name> [files]...
# 构建一个库,基于指定的源文件
# 并根据库名生成 target_link_<lib_name> 函数
macro(spark_add_library _lib_name)
spark_debug_message("================ ${_lib_name} Library ================")
add_library(${_lib_name} ${ARGN})
set(SRCS ${ARGN})
foreach(item IN LISTS SRCS)
spark_debug_message(" -> ${item}")
endforeach(item IN LISTS SRCS)
function(target_link_${_lib_name} TARGET)
spark_debug_message("${_lib_name}")
target_link_libraries(${TARGET} ${_lib_name})
endfunction(target_link_${_lib_name} TARGET)
endmacro(spark_add_library _lib_name)
# spark_add_library_path <lib_name> <lib_path>
# 构建一个库,基于指定的路径
# 并根据库名生成 target_link_<lib_name> 函数
# 函数内增加以 <lib_path> 头文件搜索路径
macro(spark_add_library_path _lib_name _lib_path)
# 0. 建立初始变量体系
set(${_lib_name}_TYPE)
set(${_lib_name}_TYPE_MESSAGE "STATIC(Default)")
set(${_lib_name}_ARGN ${ARGN})
# 1. 判断 _lib_path 是否是 SHARED 或 STATIC
if(${_lib_path} STREQUAL SHARED OR ${_lib_path} STREQUAL STATIC)
set(${_lib_name}_TYPE ${_lib_path})
set(${_lib_name}_TYPE_MESSAGE ${${_lib_name}_TYPE})
if(${ARGC} LESS 3)
message(FATAL_ERROR "Missing parameter, library path not specified.")
endif(${ARGC} LESS 3)
else()
# 如没有则将 _lib_path 加入到 ARGN
list(APPEND ${_lib_name}_ARGN ${_lib_path})
endif(${_lib_path} STREQUAL SHARED OR ${_lib_path} STREQUAL STATIC)
# 1. 处理由 spark_add_library_realpaths 构建转本构建时的清洗机制
spark_debug_message("> Building: ${_lib_name}, type: ${${_lib_name}_TYPE_MESSAGE}")
set(${_lib_name}_ARGN_REF ${${_lib_name}_ARGN})
unset(${_lib_name}_ARGN)
foreach(_old IN LISTS ${_lib_name}_ARGN_REF)
set(_new ${_old})
string(FIND "${_old}" "+" _plus_index)
if(${_plus_index} GREATER 0)
string(SUBSTRING "${_old}" 0 ${_plus_index} _new)
spark_debug_message(" [CONVERT] ${_new} <- ${_old}")
endif(${_plus_index} GREATER 0)
list(APPEND ${_lib_name}_ARGN ${_new})
endforeach(_old IN LISTS ${_lib_name}_ARGN_REF)
# 2.目标参数项分析出子项
# 拆分出源代码、路径、未知项等
set(${_lib_name}_ARGN_SOURCES)
set(${_lib_name}_ARGN_APPEND_PATHS)
set(${_lib_name}_ARGN_UNKNOW)
foreach(item IN LISTS ${_lib_name}_ARGN)
spark_debug_message(" [ARGN] check:" ${item})
if(NOT EXISTS ${item})
set(item ${CMAKE_CURRENT_LIST_DIR}/${item})
endif()
if(EXISTS ${item})
# spark_debug_message(" exists: true")
file(REAL_PATH ${item} ${_lib_name}_ARGN_item)
if(IS_DIRECTORY ${${_lib_name}_ARGN_item})
list(APPEND ${_lib_name}_ARGN_APPEND_PATHS ${item})
else()
list(APPEND ${_lib_name}_ARGN_SOURCES ${item})
endif(IS_DIRECTORY ${${_lib_name}_ARGN_item})
else()
list(APPEND ${_lib_name}_ARGN_UNKNOW ${item})
spark_debug_message(" exists: false")
endif()
endforeach()
list(LENGTH ${_lib_name}_ARGN_SOURCES ${_lib_name}_ARGN_SOURCES_LENGTH)
list(LENGTH ${_lib_name}_ARGN_APPEND_PATHS ${_lib_name}_ARGN_APPEND_PATHS_LENGTH)
list(LENGTH ${_lib_name}_ARGN_UNKNOW ${_lib_name}_ARGN_UNKNOW_LENGTH)
spark_debug_message(" result: files(${${_lib_name}_ARGN_SOURCES_LENGTH}), paths(${${_lib_name}_ARGN_APPEND_PATHS_LENGTH}), unknow(${${_lib_name}_ARGN_UNKNOW_LENGTH})" ${item})
# 3. 获取所以源代码为 any_files
spark_debug_message(" files:")
set(any_files ${${_lib_name}_ARGN_SOURCES})
foreach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
spark_aux_source_directory(item_files ${item})
list(APPEND any_files ${item_files})
foreach(item_file IN LISTS item_files)
spark_debug_message(" ${item_file}")
endforeach(item_file IN LISTS item_files)
endforeach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
# 3.1 转化 Qt5/6 的 ui 文件
set(${_lib_name}_SOURCE_UIS)
set(ui_wrap_files)
foreach(item IN LISTS ${_lib_name}_ARGN_SOURCES any_files)
get_filename_component(ex "${item}" LAST_EXT)
if("${ex}" STREQUAL ".ui")
list(APPEND ${_lib_name}_SOURCE_UIS ${item})
endif("${ex}" STREQUAL ".ui")
endforeach(item IN LISTS ${_lib_name}_ARGN_SOURCES any_files)
if(SPARK_FIND_QT6)
qt_wrap_ui(ui_wrap_files ${${_lib_name}_SOURCE_UIS})
elseif(SPARK_FIND_QT5)
qt5_wrap_ui(ui_wrap_files ${${_lib_name}_SOURCE_UIS})
endif(SPARK_FIND_QT6)
# 4. 构建目标库
add_library(${_lib_name} ${${_lib_name}_TYPE}
${${_lib_name}_ARGN_SOURCES}
${any_files} ${ui_wrap_files})
# 5. 建立引用点
# target_link_<_lib_name> 函数
# target_include_<_lib_name> 函数
# target_<_lib_name>_include 函数
# target_<_lib_name>_link 函数
function(target_${_lib_name}_include _include)
spark_debug_message("添加引用: ${_lib_name} <- ${_include} ${${_lib_name}_INCLUDE_ARGN}")
target_include_directories(${_lib_name} PRIVATE ${_include})
endfunction(target_${_lib_name}_include _include)
function(target_${_lib_name}_link _library)
spark_debug_message("添加链接: ${_lib_name} <- ${_library} ${${_lib_name}_LINK_ARGN}")
target_link_libraries(${_lib_name} ${_library})
endfunction(target_${_lib_name}_link _library)
function(target_link_${_lib_name} TARGET)
spark_debug_message("链接引用: ${TARGET} <- ${_lib_name}")
target_include_directories(${TARGET} PRIVATE
"${${_lib_name}_SOURCE_PATH}" ${${_lib_name}_ARGN_APPEND_PATHS})
target_link_libraries(${TARGET} ${_lib_name})
endfunction(target_link_${_lib_name} TARGET)
function(target_include_${_lib_name} TARGET)
spark_debug_message("引入引用: ${TARGET} <- ${_lib_name}")
target_include_directories(${TARGET} PUBLIC
"${${_lib_name}_SOURCE_PATH}" ${${_lib_name}_ARGN_APPEND_PATHS})
endfunction(target_include_${_lib_name} TARGET)
target_include_directories(${_lib_name} PRIVATE
"${${_lib_name}_ARGN_APPEND_PATHS}")
# 输出 includes
spark_debug_message(" ${_lib_name}_ARGN_APPEND_PATHS: ")
foreach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
string(REPLACE "${CMAKE_SOURCE_DIR}/" "" item_var "${item}")
spark_debug_message(" ${item_var}")
endforeach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
# 如果想用以下操作手动实现 target_link_include_directories
# 请注意对 LIST 类型使用 "" 进行包围
# target_link_include_directories 的 PUBLIC 将会填充(追加)目标的 INCLUDE_DIRECTORIES 属性
# target_link_include_directories 支持 cmake 生成大表达式,更容易操作,手动将无法实现此类能力
# target_link_include_directories 支持相对路径和绝对路径参数
# 手动操作将必须使用绝对路径,这是不好的地方
# get_target_property(_lib_include_directories ${_lib_name} INCLUDE_DIRECTORIES)
# list(APPEND _lib_include_directories "${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
# spark_debug_message("----> ${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
# spark_debug_message("----> ${_lib_include_directories}")
# set_target_properties(${_lib_name} PROPERTIES
# INCLUDE_DIRECTORIES "${_lib_include_directories}"
# INTERFACE_INCLUDE_DIRECTORIES "${_lib_include_directories}"
# )
endmacro(spark_add_library_path _lib_name _lib_path)
# spark_add_shared_library <target> [files ...]
# 构建一个共享库,基于指定的源代码
# 并根据库名生成 target_link_<lib_name> 函数
macro(spark_add_shared_library _lib_name)
spark_add_library(${_lib_name} SHARED ${ARGN})
endmacro(spark_add_shared_library _lib_name)
# spark_add_shared_library_path <target> [files ... paths]
# 构建一个共享库,基于指定的路径
# 并根据库名生成 target_link_<lib_name> 函数
macro(spark_add_shared_library_path _lib_name)
spark_add_library_path(${_lib_name} SHARED ${ARGN})
endmacro(spark_add_shared_library_path _lib_name)
# spark_add_executable <exec_name> [files]...
# 构建一个可执行文件,基于指定的源文件
# Qt编译时源文件包括很多类型需要指定 *.h/*.cpp/*.qrc/*.qm/... 等
macro(spark_add_executable _exec_name)
set(${_exec_name}_TYPE_MESSAGE "可执行程序")
spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
add_executable(${_exec_name} ${ARGN})
endmacro(spark_add_executable _exec_name)
# spark_add_executable_path <target> <path> [files ... paths]
# 构建一个可执行程序,基于指定的路径
macro(spark_add_executable_path _exec_name _exec_path)
spark_add_executable(${_exec_name})
# 0. 建立初始变量体系
# set(${_exec_name}_TYPE)
# set(${_exec_name}_TYPE_MESSAGE "可执行程序")
set(${_exec_name}_ARGN ${ARGN})
# 1. 处理由 spark_add_executable_realpaths 构建转本构建时的清洗机制
# spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
set(${_exec_name}_ARGN_REF ${${_exec_name}_ARGN})
unset(${_exec_name}_ARGN)
foreach(_old IN LISTS ${_exec_name}_ARGN_REF)
set(_new ${_old})
string(FIND "${_old}" "+" _plus_index)
if(${_plus_index} GREATER 0)
string(SUBSTRING "${_old}" 0 ${_plus_index} _new)
spark_debug_message(" [CONVERT] ${_new} <- ${_old}")
endif(${_plus_index} GREATER 0)
list(APPEND ${_exec_name}_ARGN ${_new})
endforeach(_old IN LISTS ${_exec_name}_ARGN_REF)
# 1.目标参数项分析出子项
# 拆分出源代码、路径、未知项等
# spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
set(${_exec_name}_ARGN_SOURCES)
set(${_exec_name}_ARGN_APPEND_PATHS ${_exec_path})
set(${_exec_name}_ARGN_UNKNOW)
foreach(item IN LISTS ${_exec_name}_ARGN)
spark_debug_message(" [ARGN] check:" ${item})
if(NOT EXISTS ${item})
set(item ${CMAKE_CURRENT_LIST_DIR}/${item})
endif()
if(EXISTS ${item})
# spark_debug_message(" exists: true")
file(REAL_PATH ${item} ${_exec_name}_ARGN_item)
if(IS_DIRECTORY ${${_exec_name}_ARGN_item})
list(APPEND ${_exec_name}_ARGN_APPEND_PATHS ${item})
else()
list(APPEND ${_exec_name}_ARGN_SOURCES ${item})
endif(IS_DIRECTORY ${${_exec_name}_ARGN_item})
else()
list(APPEND ${_exec_name}_ARGN_UNKNOW ${item})
spark_debug_message(" exists: false")
endif()
endforeach()
list(LENGTH ${_exec_name}_ARGN_SOURCES ${_exec_name}_ARGN_SOURCES_LENGTH)
list(LENGTH ${_exec_name}_ARGN_APPEND_PATHS ${_exec_name}_ARGN_APPEND_PATHS_LENGTH)
list(LENGTH ${_exec_name}_ARGN_UNKNOW ${_exec_name}_ARGN_UNKNOW_LENGTH)
spark_debug_message(" result: files(${${_exec_name}_ARGN_SOURCES_LENGTH}), paths(${${_exec_name}_ARGN_APPEND_PATHS_LENGTH}), unknow(${${_exec_name}_ARGN_UNKNOW_LENGTH})" ${item})
# 2. 获取所以源代码为 any_files
spark_debug_message(" files:")
set(any_files ${${_exec_name}_ARGN_SOURCES})
foreach(item IN LISTS ${_exec_name}_ARGN_APPEND_PATHS)
spark_aux_source_directory(item_files ${item})
list(APPEND any_files ${item_files})
foreach(item_file IN LISTS item_files)
spark_debug_message(" ${item_file}")
endforeach(item_file IN LISTS item_files)
endforeach(item IN LISTS ${_exec_name}_ARGN_APPEND_PATHS)
# 3.1 转化 Qt5/6 的 ui 文件
set(${_exec_name}_SOURCE_UIS)
set(ui_wrap_files)
foreach(item IN LISTS ${_exec_name}_ARGN_SOURCES any_files)
get_filename_component(ex "${item}" LAST_EXT)
if("${ex}" STREQUAL ".ui")
list(APPEND ${_exec_name}_SOURCE_UIS ${item})
endif("${ex}" STREQUAL ".ui")
endforeach(item IN LISTS ${_exec_name}_ARGN_SOURCES any_files)
if(SPARK_FIND_QT6)
qt_wrap_ui(ui_wrap_files ${${_exec_name}_SOURCE_UIS})
elseif(SPARK_FIND_QT5)
qt5_wrap_ui(ui_wrap_files ${${_exec_name}_SOURCE_UIS})
endif(SPARK_FIND_QT6)
# 3. 构建可执行目标所需要的文件
# add_executable(${_exec_name}
# ${${_exec_name}_ARGN_SOURCES}
# ${any_files})
target_sources(${_exec_name} PRIVATE
${${_exec_name}_ARGN_SOURCES}
${any_files} ${ui_wrap_files})
# 4. 建立引用点
# target_<_exec_name>_include 函数
# target_<_exec_name>_link 函数
function(target_${_exec_name}_include _include)
spark_debug_message("添加引用: ${_exec_name} <- ${_include} ${${_exec_name}_INCLUDE_ARGN}")
target_include_directories(${_exec_name} PRIVATE ${_include})
endfunction(target_${_exec_name}_include _include)
function(target_${_exec_name}_link _library)
spark_debug_message("添加链接: ${_exec_name} <- ${_library} ${${_exec_name}_LINK_ARGN}")
target_link_libraries(${_exec_name} ${_library})
endfunction(target_${_exec_name}_link _library)
target_include_directories(${_exec_name} PRIVATE
${_exec_path})
spark_debug_message(" include: ${_exec_path}\n")
endmacro(spark_add_executable_path _exec_name _exec_path)
# spark_find_library
# 搜索一个库,基于指定的库名,调用 pkg-config 搜索库
# 并根据库名生成一个 target_link_<prefix> 函数
macro(spark_find_library _prefix)
find_package(PkgConfig REQUIRED)
# libnotify
pkg_check_modules(${_prefix} ${ARGN})
function(target_link_${_prefix} TARGET)
target_include_directories(${TARGET} PUBLIC
${${_prefix}_INCLUDE_DIRS})
target_link_libraries(${TARGET}
${${_prefix}_LIBRARIES})
endfunction(target_link_${_prefix} TARGET)
endmacro(spark_find_library _prefix)
macro(target_link_qt)
if(SPARK_FIND_QT6)
target_link_qt6(${ARGN})
elseif(SPARK_FIND_QT5)
target_link_qt5(${ARGN})
endif(SPARK_FIND_QT6)
endmacro(target_link_qt)
# spark_add_executable_paths
# 自定义构建宏,基于指定的前缀名称,处理后续参数为子目录
# item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
# file: 为在目录中不以递归(GLOB_RECURSE)方式寻找 qrc 文件,需要将其参与编译才能被 rcc
# 并根据 prefix-<item> 生成构建目标,
macro(spark_add_executable_paths _prefix_path)
set(PATHS ${ARGN})
foreach(item IN LISTS PATHS)
file(GLOB QRCS "${item}/*.qrc")
spark_debug_message(">>> add_executable: " "${_prefix_path}-${item} ${item} + ${QRCS}")
string(REPLACE "/" "-" new_item "${item}")
spark_add_executable_path(${_prefix_path}-${new_item} ${item} ${QRCS})
target_link_qt(${_prefix_path}-${item})
endforeach(item IN LISTS PATHS)
endmacro(spark_add_executable_paths _prefix_path)
# spark_add_link
# 自定义宏以代替当前使用 fucntion 定义 target_link_<name> 结构
# _IN_NAME: 此宏生成 target_link_<name> 的要求参数
# ARGN: 此宏剩余的参数列表
# 在使用 target_link_<name> 时
# _NAME: 用于此 fucntion 中的要求参数: <_NAME>目标将要连接此库
macro(spark_add_link _name)
function(target_link_${_name} _link)
spark_debug_message("> Linking: ${_link}")
spark_debug_message(" <- ${ARGN}\n")
target_link_libraries(${_link}
${ARGN})
endfunction(target_link_${_name} _link)
endmacro(spark_add_link _name)