cmake学习实践:链接库和cmake模块化使用

最近在学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。

对于两者的区别,我查了一下,贴在下面:

特性functionmacro
作用域创建新作用域(局部变量)直接展开代码(无新作用域)
变量传递参数按值传递参数按文本替换(类似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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值