上一个cmake生成exe的博客已经说明了怎么在 linux cmake-gui 和 visual studio 下怎么编译CMake工程。这篇文章会直接在 visual studio 下构建目标。
下面主要对CMake生成的两种方式进行相关的生成
1.总CMakeLists.txt生成所有目标
2.含有subject CMake 生成所有目标
为什么提上面两种方式?这里牵扯到lib构建顺序依赖的问题(这里将在本文的 sub模块分离式生成目标 下进行详细的解释)
顶层CMakeLists.txt生成所有目标。
工程结构
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.0)
# 最低版本要求 cmake 构建工具小于2.8.0将报错
project(genExeLinkLib)
# 工程项目名称
#set(MOD_CLASS_PATH "${CMAKE_SOURCE_DIR}/class")
set(MOD_CLASS_PATH ${CMAKE_SOURCE_DIR}/class)
# 设置一个变量标记路径 以上两种写法都是可行的 为了更好的适应各种CMake工程 推荐写第二种方式
# ${CMAKE_SOURCE_DIR} 这个取CMake自带宏里面的路径 就是这个CMakeLists.txt所在的路径
aux_source_directory(${MOD_CLASS_PATH} MOD_CLASS_SRC)
# ${} 固定的范式,取变量 MOD_CLASS_PATH 里面的值,这里为 ${CMAKE_SOURCE_DIR}/class
# MOD_CLASS_SRC 自定义的一个变量
# 整条语句将对 ${CMAKE_SOURCE_DIR}/class 的源码*.cpp 和*.c 文件 输出到变量 MOD_CLASS_SRC
#add_library(class_sayHello ${MOD_CLASS_SRC})# 默认构建静态库
#add_library(class_sayHello STATIC ${MOD_CLASS_SRC}) #和上面语句是一样的
add_library(class_sayHello SHARED ${MOD_CLASS_SRC}) # 构建动态库
# 将所有的源文件归档成lib 这一句将会在build下生成lib
# 设置生成目录这里暂时先不做编写 如果生成静态库的话直接注释打开然后注释 SHARED 这一句
# --------------上面的语句就已经能够生成动态库------------------
aux_source_directory(${CMAKE_SOURCE_DIR} RP_ALL_SRC)
# 这里对 ${CMAKE_SOURCE_DIR} 也就是当前CMakeList.txt 目录下的*.cpp输出到变量
# RP_ALL_SRC (ROOTPATH_ALL_SRC 意为顶层目录所有源码)
add_executable(HelloExecute ${RP_ALL_SRC})
# --------------这里很明显还没有引用lib 这是至少百分之八十友友遇到的错误----------
# error:link 多半就是目录问题 引用未定义的函数一般都是 宏 或者你忘记写函数实现
target_link_libraries(HelloExecute class_sayHello)
#为生成目标添加一个库 可以是多个 比如 target_link_libraries(HelloExecute lib1 lib2)
#这里因为是在同一个CMakeLists.txt中 所以lib会被识别并找到,这里默认构建了其生成的依赖关系
#为了屏蔽平台差异 我们直接省略后缀 .lib 因为gcc生成的库 .a .so
Hello.h
#ifndef HELLO_H
#define HELLO_H
#include <iostream>
class _declspec(dllexport) Hello
{
public:
Hello();
~Hello();
void sayHello();
};
#endif // !HELLO_H
Hello.cpp
#include "Hello.h"
Hello::Hello()
{
}
Hello::~Hello()
{
}
void Hello::sayHello()
{
std::cout << __FUNCTION__ << std::endl;
}
main.cpp
#include "class/Hello.h"
#include <iostream>
int main(int argc, char* argv[])
{
Hello helloUnit;
helloUnit.sayHello();
int a;
std::cin >> a;
}
运行结果
add_subdirectory生成目标
上图对整个目录结构进行梳理,每一个存在CMakeLists.txt 都可以称之为模块。为了更好的实现上图的结构应当避免模块间的耦合度(当然这不是硬性的规定)。具体的模块间的引用问题这里暂时留在下一篇博客中去说明。比如在其他子项的目录中我存在一种顺序依赖的关系、包括后面在 CMakeLists.txt中的 package_find() 语法命令。其实上面的目录结构是存在问题的,这里为了适应本博文和读者理解,循序渐进吧。
工程结构:
genExeLinkLib/class/CMakeLists.txt
cmake_minimum_required(VERSION 2.8.0) #cmake的 最低版本
project(class)#尽量和目录同名,为了方便区分
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} class_ALL_SRC)
# 遍历当前cmake下的所有*.c和*.cpp文件 输入到变量 class_ALL_SRC
# CMAKE_CURRENT_SOURCE_DIR 是当前的CMakeLists.txt的路径,如果存在疑问你可以打开下面的语句论证
# message(STATUS "CMAKE_CURRENT_SOURCE_DIR >>${CMAKE_CURRENT_SOURCE_DIR}")
add_library(${CMAKE_PROJECT_NAME} ${class_ALL_SRC})
#引用当前所有c和cpp文件 生成一个 class.lib
#CMAKE_PROJECT_NAME 为cmake自带变量 获取当前project()设置的变量,主要作用于当前CMakeLists.txt文件
genExeLinkLib/CMakeLists.txt
cmake_minimum_required(VERSION 2.8.0)
project(genExeLinkLib) #工程名称
aux_source_directory(${CMAKE_CURRENT_LIST_DIR} genXX_ALL_SRC) #遍历当前CMakeLists.txt所有*.c和*.cpp 输出到 genXX_ALL_SRC 变量
add_subdirectory(class) #添加子项
add_executable(genExeLinkLib ${genXX_ALL_SRC}) # 生成可执行目标 genExeLinkLib
target_link_libraries(genExeLinkLib class) # 添加lib依赖
install(TARGETS genExeLinkLib
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/dll
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
)#安装目录
运行结果:
如果大家在使用CMakeLists.txt工程上遇到了问题可以加我的 CMake技术交流Q群 870836798