Skip to content

Commit 6d967b6

Browse files
2 parents 696160d + 92a8656 commit 6d967b6

20 files changed

Lines changed: 494 additions & 81 deletions

File tree

CMakeLists.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,31 @@ log_info("Post Qt Setups" "Run Post Qt Dependencies check")
7979
include(cmake/custom_target_helper.cmake)
8080
log_info("Post Qt Setups" "Run Post Qt Dependencies OK")
8181

82+
# ============================================================
83+
# Output Directory Configuration
84+
# ============================================================
85+
# 配置分类输出目录:bin/, examples/, plugins/, runtimes/
86+
log_info("OutputConfig" "Configuring output directories")
87+
include(cmake/OutputDirectoryConfig.cmake)
88+
89+
# ============================================================
90+
# Example Launcher Generator (Windows)
91+
# ============================================================
92+
# 为每个 example 生成 Windows 启动脚本
93+
if(WIN32)
94+
log_info("Launcher" "Including Windows launcher generator")
95+
include(cmake/ExampleLauncher.cmake)
96+
endif()
97+
98+
# ============================================================
99+
# Qt Shared Deployment (Windows)
100+
# ============================================================
101+
# 共享 Qt DLLs 部署到 runtimes/ 目录
102+
if(WIN32)
103+
log_info("QtDeploy" "Including shared Qt deployment utilities")
104+
include(cmake/QtDeployUtils.cmake)
105+
endif()
106+
82107
# Include development helpers generation
83108
include(cmake/generate_develop_helpers.cmake)
84109

@@ -115,4 +140,20 @@ add_subdirectory(test)
115140
# Log test module end
116141
log_module_end("test")
117142

143+
# ============================================================
144+
# Post-Build Setup (必须在所有 add_subdirectory 之后)
145+
# ============================================================
146+
147+
# 生成 Windows 启动脚本 (如果使用 ExampleLauncher)
148+
if(WIN32)
149+
log_info("Launcher" "Generating Windows launcher scripts")
150+
cf_generate_all_launchers()
151+
endif()
152+
153+
# 设置共享 Qt 部署 (Windows)
154+
if(WIN32)
155+
log_info("QtDeploy" "Setting up shared Qt deployment")
156+
cf_setup_shared_qt_deployment()
157+
endif()
158+
118159
log_info("Final" "Configuration Ends! You can try to build now!")

cmake/ExampleLauncher.cmake

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# ============================================================
2+
# Windows Example Launcher Generator
3+
# ============================================================
4+
# 为每个 example 可执行文件生成 Windows 启动脚本 (.bat)
5+
#
6+
# 功能:
7+
# - 自动生成 .bat 启动脚本
8+
# - 设置 PATH 指向共享的 runtimes/ 目录
9+
# - 提供环境隔离保护
10+
# - Linux 下跳过
11+
# ============================================================
12+
13+
# 全局列表:收集需要生成启动脚本的可执行文件
14+
set(LAUNCHER_EXECUTABLES "" CACHE INTERNAL "List of executables needing launcher scripts")
15+
16+
# ============================================================
17+
# 函数: cf_register_example_launcher
18+
# ============================================================
19+
# 注册一个可执行文件,为其生成启动脚本
20+
#
21+
# 参数:
22+
# TARGET_NAME - 目标名称
23+
# CATEGORY - 分类 (base, ui, gui)
24+
#
25+
# 用法:
26+
# cf_register_example_launcher(button_example "ui")
27+
#
28+
function(cf_register_example_launcher TARGET_NAME CATEGORY)
29+
if(WIN32)
30+
list(APPEND LAUNCHER_EXECUTABLES "${TARGET_NAME}|${CATEGORY}")
31+
set(LAUNCHER_EXECUTABLES "${LAUNCHER_EXECUTABLES}" CACHE INTERNAL "List of executables needing launcher scripts")
32+
log_info("Launcher" "Registered launcher for '${TARGET_NAME}' (${CATEGORY})")
33+
endif()
34+
endfunction()
35+
36+
# ============================================================
37+
# 函数: cf_generate_launcher_script
38+
# ============================================================
39+
# 为单个可执行文件生成启动脚本
40+
#
41+
# 参数:
42+
# TARGET_NAME - 目标名称
43+
# CATEGORY - 分类
44+
# OUTPUT_DIR - 输出目录
45+
#
46+
function(cf_generate_launcher_script TARGET_NAME CATEGORY OUTPUT_DIR)
47+
if(NOT WIN32)
48+
return()
49+
endif()
50+
51+
# 获取可执行文件名 (带扩展名)
52+
set(EXE_NAME "${TARGET_NAME}.exe")
53+
set(BAT_NAME "${TARGET_NAME}.bat")
54+
55+
# 启动脚本内容
56+
set(LAUNCHER_CONTENT "@echo off
57+
REM Launcher for ${TARGET_NAME}
58+
REM This script sets up the PATH to find shared Qt DLLs in ../runtimes/
59+
60+
setlocal
61+
62+
REM Get the directory where this script is located
63+
set \"SCRIPT_DIR=%~dp0\"
64+
65+
REM Add runtimes directory to PATH (relative to script location)
66+
REM The runtimes/ directory is at the same level as examples/
67+
set \"PATH=%SCRIPT_DIR%..\\runtimes;%PATH%\"
68+
69+
REM Launch the executable
70+
REM %* passes all command line arguments to the executable
71+
start \"\" \"%SCRIPT_DIR%%EXE_NAME%\" %*\
72+
73+
endlocal")
74+
75+
# 写入 .bat 文件
76+
file(WRITE "${OUTPUT_DIR}/${BAT_NAME}" "${LAUNCHER_CONTENT}")
77+
78+
log_info("Launcher" "Generated: ${OUTPUT_DIR}/${BAT_NAME}")
79+
endfunction()
80+
81+
# ============================================================
82+
# 函数: cf_generate_all_launchers
83+
# ============================================================
84+
# 为所有注册的可执行文件生成启动脚本
85+
#
86+
# 必须在所有 add_subdirectory 之后调用
87+
#
88+
function(cf_generate_all_launchers)
89+
if(NOT WIN32 OR NOT LAUNCHER_EXECUTABLES)
90+
return()
91+
endif()
92+
93+
message(STATUS "Generating Windows launcher scripts...")
94+
95+
foreach(LAUNCHER_ENTRY ${LAUNCHER_EXECUTABLES})
96+
# 分割 "TARGET_NAME|CATEGORY" 格式
97+
string(REPLACE "|" ";" LAUNCHER_LIST "${LAUNCHER_ENTRY}")
98+
list(GET LAUNCHER_LIST 0 TARGET_NAME)
99+
list(GET LAUNCHER_LIST 1 CATEGORY)
100+
101+
# 获取输出目录
102+
set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/examples/${CATEGORY}")
103+
104+
# 生成启动脚本
105+
cf_generate_launcher_script("${TARGET_NAME}" "${CATEGORY}" "${OUTPUT_DIR}")
106+
endforeach()
107+
108+
message(STATUS "Generated ${CMAKE_MATCH_COUNT} launcher scripts")
109+
endfunction()
110+
111+
# ============================================================
112+
# 宏: cf_add_example_with_launcher
113+
# ============================================================
114+
# 便捷宏:创建 example 并自动注册启动脚本
115+
#
116+
# 参数:
117+
# TARGET_NAME - 目标名称
118+
# CATEGORY - 分类 (base, ui, gui)
119+
# SOURCES - 源文件列表
120+
#
121+
# 用法:
122+
# cf_add_example_with_launcher(my_example "ui" main.cpp widget.cpp)
123+
# target_link_libraries(my_example PRIVATE cfui Qt6::Widgets)
124+
#
125+
macro(cf_add_example_with_launcher TARGET_NAME CATEGORY)
126+
# 创建可执行文件
127+
add_executable(${TARGET_NAME} ${ARGN})
128+
129+
# 设置输出目录
130+
cf_set_example_output_dir(${TARGET_NAME} ${CATEGORY})
131+
132+
# 注册启动脚本
133+
cf_register_example_launcher(${TARGET_NAME} ${CATEGORY})
134+
135+
# Windows 特定设置
136+
if(WIN32)
137+
set_target_properties(${TARGET_NAME} PROPERTIES
138+
WIN32_EXECUTABLE TRUE
139+
)
140+
endif()
141+
endmacro()

cmake/OutputDirectoryConfig.cmake

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# ============================================================
2+
# Output Directory Configuration
3+
# ============================================================
4+
# 配置构建产物的输出目录,实现分类管理
5+
#
6+
# 目录结构:
7+
# bin/ - 主应用和共享库
8+
# examples/ - 示例程序 (按类型分类)
9+
# plugins/ - Qt 插件
10+
# resources/ - 资源文件
11+
# runtimes/ - Windows Qt 运行时 DLLs (共享)
12+
# ============================================================
13+
14+
# 设置全局输出目录 (默认,可被覆盖)
15+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
16+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
17+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
18+
19+
# ============================================================
20+
# 兼容性宏: cf_register_example_launcher
21+
# ============================================================
22+
# 在非 Windows 平台上定义为空操作
23+
# (在 Windows 上由 ExampleLauncher.cmake 提供实际实现)
24+
if(NOT WIN32)
25+
macro(cf_register_example_launcher TARGET_NAME CATEGORY)
26+
# Linux 下不需要启动脚本,空操作
27+
endmacro()
28+
endif()
29+
30+
# ============================================================
31+
# 函数: cf_set_example_output_dir
32+
# ============================================================
33+
# 为 example 可执行文件设置分类输出目录
34+
#
35+
# 参数:
36+
# TARGET_NAME - 目标名称
37+
# CATEGORY - 分类名称 (base, ui, gui)
38+
#
39+
# 用法:
40+
# cf_set_example_output_dir(my_example "ui")
41+
#
42+
function(cf_set_example_output_dir TARGET_NAME CATEGORY)
43+
if(NOT TARGET ${TARGET_NAME})
44+
message(WARNING "cf_set_example_output_dir: Target '${TARGET_NAME}' does not exist")
45+
return()
46+
endif()
47+
48+
# 设置输出目录为 examples/{category}/
49+
set_target_properties(${TARGET_NAME} PROPERTIES
50+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/examples/${CATEGORY}"
51+
)
52+
53+
# 确保输出目录存在
54+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/examples/${CATEGORY}")
55+
56+
log_info("OutputDir" "Target '${TARGET_NAME}' -> examples/${CATEGORY}")
57+
endfunction()
58+
59+
# ============================================================
60+
# 函数: cf_set_main_app_output_dir
61+
# ============================================================
62+
# 为主应用设置输出目录 (bin/)
63+
#
64+
# 参数:
65+
# TARGET_NAME - 主应用目标名称
66+
#
67+
function(cf_set_main_app_output_dir TARGET_NAME)
68+
if(NOT TARGET ${TARGET_NAME})
69+
message(WARNING "cf_set_main_app_output_dir: Target '${TARGET_NAME}' does not exist")
70+
return()
71+
endif()
72+
73+
set_target_properties(${TARGET_NAME} PROPERTIES
74+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
75+
)
76+
77+
log_info("OutputDir" "Main app '${TARGET_NAME}' -> bin/")
78+
endfunction()
79+
80+
# ============================================================
81+
# 函数: cf_get_runtime_output_dir
82+
# ============================================================
83+
# 获取运行时输出目录 (用于 Qt 部署)
84+
#
85+
# 输出变量:
86+
# CF_RUNTIME_OUTPUT_DIR - 运行时输出目录
87+
#
88+
function(cf_get_runtime_output_dir VAR_NAME)
89+
set(${VAR_NAME} "${CMAKE_BINARY_DIR}/bin" PARENT_SCOPE)
90+
endfunction()
91+
92+
# ============================================================
93+
# 函数: cf_get_examples_output_dir
94+
# ============================================================
95+
# 获取 examples 输出目录
96+
#
97+
# 参数:
98+
# CATEGORY - 分类名称 (可选)
99+
# 输出变量:
100+
# CF_EXAMPLES_OUTPUT_DIR - examples 输出目录
101+
#
102+
function(cf_get_examples_output_dir VAR_NAME CATEGORY)
103+
if(CATEGORY)
104+
set(${VAR_NAME} "${CMAKE_BINARY_DIR}/examples/${CATEGORY}" PARENT_SCOPE)
105+
else()
106+
set(${VAR_NAME} "${CMAKE_BINARY_DIR}/examples" PARENT_SCOPE)
107+
endif()
108+
endfunction()
109+
110+
# ============================================================
111+
# 函数: cf_get_runtimes_dir
112+
# ============================================================
113+
# 获取 runtimes 目录 (Windows Qt DLLs)
114+
#
115+
# 输出变量:
116+
# CF_RUNTIMES_DIR - runtimes 目录
117+
#
118+
function(cf_get_runtimes_dir VAR_NAME)
119+
set(${VAR_NAME} "${CMAKE_BINARY_DIR}/runtimes" PARENT_SCOPE)
120+
endfunction()
121+
122+
# ============================================================
123+
# 函数: cf_get_plugins_dir
124+
# ============================================================
125+
# 获取 plugins 目录 (Qt 插件)
126+
#
127+
# 输出变量:
128+
# CF_PLUGINS_DIR - plugins 目录
129+
#
130+
function(cf_get_plugins_dir VAR_NAME)
131+
set(${VAR_NAME} "${CMAKE_BINARY_DIR}/plugins" PARENT_SCOPE)
132+
endfunction()
133+
134+
# ============================================================
135+
# 函数: cf_configure_qt_plugin_paths
136+
# ============================================================
137+
# 配置 Qt 插件路径 (用于 windeployqt)
138+
#
139+
# 设置 QT_PLUGIN_PATH 环境变量,使 Qt 能找到插件
140+
#
141+
function(cf_configure_qt_plugin_paths)
142+
if(WIN32)
143+
# 设置 Qt 插件输出到 plugins/ 目录
144+
set(CMAKE_INSTALL_PLUGINSDIR "${CMAKE_BINARY_DIR}/plugins" CACHE PATH "")
145+
endif()
146+
endfunction()
147+
148+
# ============================================================
149+
# 函数: cf_setup_output_dirs
150+
# ============================================================
151+
# 创建所有输出目录
152+
#
153+
function(cf_setup_output_dirs)
154+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
155+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
156+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/examples/base")
157+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/examples/ui")
158+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/examples/gui")
159+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/plugins")
160+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/resources")
161+
162+
if(WIN32)
163+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/runtimes")
164+
endif()
165+
166+
log_info("OutputDir" "Output directories created")
167+
endfunction()
168+
169+
# 自动创建输出目录
170+
cf_setup_output_dirs()

0 commit comments

Comments
 (0)