最近在学cmake的书写和使用,搞了一个简单的项目记录一下
目录结构
目录结构如下:
| buildTest.bat
| CMakeLists.txt
|
+---bin
| \---Debug
| pj1.exe
| pj1.ilk
| pj1.pdb
| test1.dll
| test2.dll
| test3.dll
|
+---build
|
+---cmake
| createModule.cmake
| setupModule.cmake
|
+---include
| +---test1
| | test1.h
| | test1_export.h
| |
| +---test2
| | test2.h
| | test2_export.h
| |
| \---test3
| test3.h
| test3_export.h
|
+---lib
| +---test1
| | test1.lib
| |
| +---test2
| | test2.lib
| |
| \---test3
| test3.lib
|
\---src
| CMakeLists.txt
| main.cpp
|
+---test1
| CMakeLists.txt
| test1.cpp
| test1.h
| test1_export.h
|
+---test2
| CMakeLists.txt
| test2.cpp
| test2.h
| test2_export.h
|
\---test3
CMakeLists.txt
test3.cpp
test3.h
test3_export.h
bin:存放生成的exe执行文件和需要使用的dll文件
build:生成vs工程的目录
cmake:存放模块化的cmke操作函数和宏定义
include:放所有子工程的.h头文件
lib:放所有子工程的lib库
src:放源码
其中include和lib是用于方便移植和模块调用的,在CMakeLists.txt中链接这两个目录即可找到对应库和头文件,方便使用
buildTest.bat
用于快速在Windows平台生成Visual Studio 2017的64位调试版项目
cmake -S . -B build/ -G "Visual Studio 15 2017" -A x64 -DCMAKE_BUILD_TYPE:STRING=Debug -DTARGET_CPU:STRING=x64
pause
参数解释:
-S .
指定源代码根目录为当前目录(.
)
-B build/
指定构建输出目录为build/
子目录(自动创建)
-G "Visual Studio 15 2017"
指定生成器为VS2017(版本15)
-A x64
强制生成64位平台解决方案
-DCMAKE_BUILD_TYPE:STRING=Debug
设置构建类型为调试模式(启用调试符号)
-DTARGET_CPU:STRING=x64
自定义变量声明目标CPU架构为x64
pause
命令执行后暂停(防止cmd窗口自动关闭)
cmake模块文件
cmake文件用于标准化C++模块的构建和安装配置
参数解析:
头文件路径管理
target_include_directories
配置双模式包含路径:构建时:
${CMAKE_CURRENT_SOURCE_DIR}/include
安装后:
include
(相对安装前缀路径)
PUBLIC
属性使依赖该模块的其他目标自动继承头文件路径
库文件路径管理
target_link_directories
类似地处理库搜索路径:构建时:
${CMAKE_CURRENT_SOURCE_DIR}/lib
安装后:
lib
避免硬编码绝对路径,保证开发/部署环境一致性
安装规则
目标文件安装:
静态库(.a/.lib) →
lib/
动态库(.so/.dll) →
lib/
可执行文件 →
bin/Debug/
或bin/Release/
(按构建类型分类)资源文件安装:
include/
目录递归安装到系统include路径
lib/
目录内容安装到系统lib路径
函数代码:
createModule.cmake↓
# 模块化构建函数
macro(create_module MODULE_NAME)
# 基本项目设置
project(${MODULE_NAME})
message(STATUS "Building module: ${MODULE_NAME}")
# 源文件收集
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.h *.hpp)
# 创建共享库
add_library(${MODULE_NAME} SHARED ${SOURCES})
target_sources(${MODULE_NAME} PUBLIC ${HEADERS})
# 导出头文件生成
configure_export_header(${MODULE_NAME})
# Qt模块处理
setup_qt_modules(${MODULE_NAME})
# 输出目录设置
setup_output_directories(${MODULE_NAME})
endmacro()
# 配置导出头文件
macro(configure_export_header TARGET)
set(EXPORT_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}_export.h")
if(NOT EXISTS ${EXPORT_HEADER})
file(WRITE ${EXPORT_HEADER}
"#ifndef ${TARGET}_EXPORT_H\n"
"#define ${TARGET}_EXPORT_H\n\n"
"#ifdef ${TARGET}_EXPORTS\n"
"#define ${TARGET}_API __declspec(dllexport)\n"
"#else\n"
"#define ${TARGET}_API __declspec(dllimport)\n"
"#endif\n\n"
"#endif\n"
)
endif()
target_compile_definitions(${TARGET} PRIVATE ${TARGET}_EXPORTS)
endmacro()
# 设置Qt模块
macro(setup_qt_modules TARGET)
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.2/5.12.2/msvc2017_64")
set(QT_MODULES Core Gui Widgets AxContainer PrintSupport Sql Xml Concurrent OpenGL Network)
foreach(module ${QT_MODULES})
find_package(Qt5 REQUIRED COMPONENTS ${module})
target_link_libraries(${TARGET} PUBLIC Qt5::${module})
endforeach()
endmacro()
# 设置输出目录
macro(setup_output_directories TARGET)
set(BIN_DIR "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}")
set(LIB_DIR "${CMAKE_SOURCE_DIR}/lib/${TARGET}")
set(INC_DIR "${CMAKE_SOURCE_DIR}/include/${TARGET}")
# 创建目录
foreach(dir ${BIN_DIR} ${LIB_DIR} ${INC_DIR})
if(NOT EXISTS ${dir})
file(MAKE_DIRECTORY ${dir})
endif()
endforeach()
# 后构建复制
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${TARGET}> ${BIN_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:${TARGET}> ${LIB_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy ${HEADERS} ${INC_DIR}/
COMMENT "Copying build artifacts for ${TARGET}"
)
endmacro()
# 处理依赖项
macro(handle_dependencies TARGET)
target_include_directories(${TARGET} PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_link_directories(${TARGET} PRIVATE ${CMAKE_SOURCE_DIR}/lib)
# 处理依赖库列表(参数从ARGN获取),写法:handle_dependencies(my_target test1 test2 qtcore)
foreach(LIB_NAME ${ARGN})
# 查找库文件(支持debug/release版本)
find_library(${LIB_NAME}_LIBRARY
NAMES ${LIB_NAME} lib${LIB_NAME} ${LIB_NAME}d
PATHS ${CMAKE_SOURCE_DIR}/lib/${LIB_NAME}
NO_DEFAULT_PATH
)
# 如果找到则链接
if(${LIB_NAME}_LIBRARY)
message(STATUS "Linking ${LIB_NAME} to ${TARGET}")
target_link_libraries(${TARGET} PRIVATE ${${LIB_NAME}_LIBRARY})
else()
message(WARNING "Dependency ${LIB_NAME} not found in ${CMAKE_SOURCE_DIR}/lib/${LIB_NAME}")
endif()
endforeach()
endmacro()
setupModule.cmake↓
# 定义函数:自动配置模块的导出和安装规则
function(setup_module_target target_name)
# 包含头文件目录(PUBLIC 确保依赖者自动包含)
target_include_directories(${target_name} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# 添加构建时的库搜索路径
target_link_directories(${target_name} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib>
$<INSTALL_INTERFACE:lib>
)
# 安装规则(库文件、头文件)
install(TARGETS ${target_name}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin/${CMAKE_BUILD_TYPE}
)
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY lib/ DESTINATION lib)
endfunction()
关于使用function还是mcor,我这里的需求是:只在构建vs工程时使用,构建完成后完全使用vs进行开发和编译,所以使用mcor。
对于两者的区别,我查了一下,贴在下面:
特性 | function | macro |
---|---|---|
作用域 | 创建新作用域(局部变量) | 直接展开代码(无新作用域) |
变量传递 | 参数按值传递 | 参数按文本替换(类似C宏) |
返回值 | 通过set(var PARENT_SCOPE) 传递 | 直接修改调用者变量 |
调试 | 更容易跟踪(独立作用域) | 可能因变量污染难以调试 |
适用场景 | 复杂逻辑、需要隔离变量 | 简单代码模板、需直接修改变量 |
结合ai给出的使用场景,在以下情况需要使用function:
- 需要递归处理(如遍历文件树)
- 操作临时变量且不希望污染调用者作用域
- 跨平台项目(未来可能需要在Linux/Mac生成Makefile)
对于跨平台:
场景 | macro 风险点 | function 优势 |
---|---|---|
跨平台路径处理 | 文本替换可能导致Linux路径格式错误 | 作用域隔离,路径处理更安全 |
变量污染 | 可能意外修改调用者作用域的变量 | 局部变量不影响外部环境 |
动态逻辑需求 | 难以实现条件分支/循环等复杂逻辑 | 支持if() /foreach() 等控制流 |
目前我暂时使用的macro,仅作为在windows中的练习,若项目需要国产化则需要使用function。
源码
根据目录结构贴出对应代码,在写test3之前CMakeLists.txt都是摸索着写的,比较冗长,在写test3是把子工程目录的各操作提取成了.cmake模块进行使用,我会在其中贴出区别。
根目录
pj1/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pj1)
include(${CMAKE_SOURCE_DIR}/cmake/SetupModule.cmake)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
aux_source_directory(src bin)
add_executable(pj1 src/main.cpp)
# 设置Qt安装路径(Windows需手动指定)
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.2/5.12.2/msvc2017_64")
message(STATUS "QT库路径: ${CMAKE_PREFIX_PATH}")
# 设置Qt模块
set(QT_MODULES Core Gui Widgets AxContainer PrintSupport Sql Xml Concurrent OpenGL Network)
# 自动展开模块列表(关键技巧)
foreach(module ${QT_MODULES})
find_package(Qt5 REQUIRED COMPONENTS ${module})
target_link_libraries(pj1 PUBLIC Qt5::${module})
endforeach()
# 添加 Qt 模块的包含路径(自动包含 QtWidgets 等子目录)
target_include_directories(pj1 PUBLIC ${Qt5Widgets_INCLUDE_DIRS})
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakePredefinedTargets")
add_subdirectory(src)
# 设置输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
# 自动查找头文件和库
#target_include_directories(pj1 PRIVATE ${PROJECT_SOURCE_DIR}/include)
#target_link_directories(pj1 PRIVATE ${PROJECT_SOURCE_DIR}/lib)
add_definitions(-DTESTUSER)
find_library(TEST3_LIB
NAMES test3 libtest3 test3d
PATHS ${CMAKE_SOURCE_DIR}/lib/test3)
target_link_libraries(${PROJECT_NAME} PRIVATE ${TEST3_LIB})
main中使用到了子工程test3,需要链接库,于是大家可以看到我使用了find_library和target_link_librarie进行链接,如果不使用find_library,而直接使用target_link_libraries的话,会让该项目的所有.h文件添加到main.cpp的工程中。
在CMake中,
target_link_libraries
会自动传递依赖项的头文件搜索路径到当前目标。
使用find_library和target_link_libraries,可以解决该问题。
其实我也可以把这一段放到src/CMakeLists.txt中。
src目录
main.cpp
#include <QtWidgets/QApplication>
#include <QMainWindow>
#include <QObject>
#include "test3/test3.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QMainWindow w;
#ifdef TESTUSER
test3 *tmp = new test3;
w.setCentralWidget(tmp);
#endif // TESTUSER
w.show();
return a.exec();
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pj1)
add_subdirectory(test1)
add_subdirectory(test2)
add_subdirectory(test3)
src/test1
test1.h
#pragma once
#include <QWidget>
#include "test1_export.h"
class test1_API test1 : public QWidget
{
Q_OBJECT
public:
test1(QWidget *parent = nullptr);
~test1();
};
test1_export.h
(所有的子工程_export.h都类似,这里只贴出来一次,这里我设计的是有子目录文件夹,则生成时自动生成_export.h文件,不用自己写)
#ifndef test1_EXPORT_H
#define test1_EXPORT_H
#ifdef test1_EXPORTS
#define test1_API __declspec(dllexport)
#else
#define test1_API __declspec(dllimport)
#endif
#endif
test1.cpp
#include "test1.h"
#include <QLabel>
#include <QHBoxLayout>
test1::test1(QWidget *parent)
: QWidget(parent)
{
QLabel *pLabel = new QLabel(this);
pLabel->setText(u8"你好!test1");
QHBoxLayout *pLayout = new QHBoxLayout;
pLayout->addWidget(pLabel);
setLayout(pLayout);
}
test1::~test1()
{}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(test1)
message(STATUS "test1_test now")
include(${CMAKE_SOURCE_DIR}/cmake/SetupModule.cmake)
set(test1_dll_path ${PROJECT_SOURCE_DIR}/)
file(GLOB SOURCES *.cpp )
file(GLOB HEADERS *.h *.hpp)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
target_sources(${PROJECT_NAME} PUBLIC ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/test1/)
#target_compile_definitions(-D TESTUSER)
# 设置Qt安装路径(Windows需手动指定)
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.2/5.12.2/msvc2017_64")
message(STATUS "QT库路径: ${CMAKE_PREFIX_PATH}")
# 设置Qt模块
set(QT_MODULES Core Gui Widgets AxContainer PrintSupport Sql Xml Concurrent OpenGL Network)
# 自动展开模块列表(关键技巧)
foreach(module ${QT_MODULES})
find_package(Qt5 REQUIRED COMPONENTS ${module})
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::${module})
endforeach()
# 添加 Qt 模块的包含路径(自动包含 QtWidgets 等子目录)
target_include_directories(${PROJECT_NAME} PUBLIC ${Qt5Widgets_INCLUDE_DIRS})
message(STATUS "Qt5Gui库路径: ${Qt5Gui_LIBRARIES}")
# 创建模板头文件
if(NOT EXISTS "${test1_dll_path}/${PROJECT_NAME}_export.h")
file(WRITE ${test1_dll_path}/${PROJECT_NAME}_export.h
"#ifndef ${PROJECT_NAME}_EXPORT_H
#define ${PROJECT_NAME}_EXPORT_H
#ifdef ${PROJECT_NAME}_EXPORTS
#define ${PROJECT_NAME}_API __declspec(dllexport)
#else
#define ${PROJECT_NAME}_API __declspec(dllimport)
#endif
#endif
")
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_EXPORTS)
# 定义输出目录
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}/bin")
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}")
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
endif()
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME}")
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME})
endif()
set(BIN_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
set(LIB_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME})
set(HEADERS_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME})
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME}")
file(MAKE_DIRECTORY ${HEADERS_OUTPUT_DIR})
endif()
message(STATUS "path 4: $<TARGET_FILE:${PROJECT_NAME}")
message(STATUS "path 5: $<TARGET_LINKER_FILE:${PROJECT_NAME}")
#复制.dll/.lib/.h文件分别到bin/lib/include中
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:${PROJECT_NAME}>
${BIN_OUTPUT_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_LINKER_FILE:${PROJECT_NAME}>
${LIB_OUTPUT_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy
${HEADERS}
${HEADERS_OUTPUT_DIR}/
COMMENT "Copying build artifacts to output directories"
)
setup_module_target(${PROJECT_NAME})
# 仅添加include路径
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include
)
# 如果需要链接库路径
target_link_directories(${PROJECT_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/lib
)
${PROJECT_NAME}_export.h就是通过以下命令自动生成的,不用每次创建子工程都重新手写。
src/test2
test2.h
#pragma once
#include <QWidget>
#include "test2_export.h"
#include "test1/test1.h"
class test1;
class test2_API test2 : public QWidget
{
Q_OBJECT
public:
test2(QWidget *parent = nullptr);
~test2();
private:
test1 *m_pTest1;
};
test2.cpp
#include "test2.h"
#include <QLabel>
#include <QVBoxLayout>
test2::test2(QWidget *parent)
: QWidget(parent)
{
m_pTest1 = new test1;
QLabel *pLabel = new QLabel(this);
pLabel->setText(u8"你好! test2");
QVBoxLayout *ptmp = new QVBoxLayout;
ptmp->addWidget(m_pTest1);
ptmp->addWidget(pLabel);
setLayout(ptmp);
setStyleSheet(u8"QWidget{border: 2px solid red}");
}
test2::~test2()
{}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(test2)
message(STATUS "test2_test now")
include(${CMAKE_SOURCE_DIR}/cmake/SetupModule.cmake)
set(test2_dll_path ${PROJECT_SOURCE_DIR}/)
file(GLOB SOURCES *.cpp )
file(GLOB HEADERS *.h *.hpp)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
target_sources(${PROJECT_NAME} PUBLIC ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/test2/)
#target_compile_definitions(-D TESTUSER)
# 设置Qt安装路径(Windows需手动指定)
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.2/5.12.2/msvc2017_64")
message(STATUS "QT库路径: ${CMAKE_PREFIX_PATH}")
# 设置Qt模块
set(QT_MODULES Core Gui Widgets AxContainer PrintSupport Sql Xml Concurrent OpenGL Network)
# 自动展开模块列表(关键技巧)
foreach(module ${QT_MODULES})
find_package(Qt5 REQUIRED COMPONENTS ${module})
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::${module})
endforeach()
# 添加 Qt 模块的包含路径(自动包含 QtWidgets 等子目录)
target_include_directories(${PROJECT_NAME} PUBLIC ${Qt5Widgets_INCLUDE_DIRS})
message(STATUS "Qt5Gui库路径: ${Qt5Gui_LIBRARIES}")
# 创建模板头文件
if(NOT EXISTS "${test1_dll_path}/${PROJECT_NAME}_export.h")
file(WRITE ${test1_dll_path}/${PROJECT_NAME}_export.h
"#ifndef ${PROJECT_NAME}_EXPORT_H
#define ${PROJECT_NAME}_EXPORT_H
#ifdef ${PROJECT_NAME}_EXPORTS
#define ${PROJECT_NAME}_API __declspec(dllexport)
#else
#define ${PROJECT_NAME}_API __declspec(dllimport)
#endif
#endif
")
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_EXPORTS)
# 定义输出目录
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}/bin")
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}")
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
endif()
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME}")
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME})
endif()
set(BIN_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
set(LIB_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/lib/${PROJECT_NAME})
set(HEADERS_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME})
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME}")
file(MAKE_DIRECTORY ${HEADERS_OUTPUT_DIR})
endif()
message(STATUS "path 4: $<TARGET_FILE:${PROJECT_NAME}")
message(STATUS "path 5: $<TARGET_LINKER_FILE:${PROJECT_NAME}")
#复制.dll/.lib/.h文件分别到bin/lib/include中
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:${PROJECT_NAME}>
${BIN_OUTPUT_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_LINKER_FILE:${PROJECT_NAME}>
${LIB_OUTPUT_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy
${HEADERS}
${HEADERS_OUTPUT_DIR}/
COMMENT "Copying build artifacts to output directories"
)
setup_module_target(${PROJECT_NAME})
#禁用自动文件扫描
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# 仅添加test1的include路径而不传播
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include
)
# 如果需要链接库路径
target_link_directories(${PROJECT_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/lib
)
#其他模块使用
message(STATUS "path 6 : ${CMAKE_SOURCE_DIR}/lib/test1")
find_library(TEST1_LIB
NAMES test1 libtest1 test1d
PATHS ${CMAKE_SOURCE_DIR}/lib/test1)
target_link_libraries(${PROJECT_NAME} PRIVATE ${TEST1_LIB})
其实test1和test2的CMakeLists.txt内容基本一致,但是由于test2需要使用到test1,链接了test1的库,可以看看两者差异:
所以在写test3的时候把命令根据功能提取出来为了一个.cmake
src/test3
test3.h
#pragma once
#include <QWidget>
#include "test3_export.h"
#include "test1/test1.h"
#include "test2/test2.h"
class test3_API test3 : public QWidget
{
Q_OBJECT
public:
test3(QWidget *parent = nullptr);
~test3();
private:
test1 *p1;
test2 *p2;
};
test3.cpp
#include "test3.h"
#include <QLabel>
#include <QVBoxLayout>
test3::test3(QWidget * parent)
{
QLabel *pLabel = new QLabel(this);
pLabel->setText(u8"这里是test3");
p1 = new test1;
p2 = new test2;
QVBoxLayout *pLayout = new QVBoxLayout;
pLayout->addWidget(p1);
pLayout->addWidget(p2);
pLayout->addWidget(pLabel);
setLayout(pLayout);
}
test3::~test3()
{
}
CMakeLists.txt
可以看到使用.cmake进行模块调用后,子工程的CMakeLists.txt就变得清晰明了了
cmake_minimum_required(VERSION 3.15)
project(test3)
#引入宏
include(${CMAKE_SOURCE_DIR}/cmake/SetupModule.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/createModule.cmake)
create_module(${PROJECT_NAME})
setup_module_target(${PROJECT_NAME})
# 依赖处理
handle_dependencies(${PROJECT_NAME} test1 test2)