一、怎么写CMakeLists.txt
对之前单例模式的代码进行重写,来学习cmake的使用
单例模式的使用
-
第一种尝试:整个项目的所有设置都写在一个CMakeLists.txt中
不是所有预处理器都支持#program once,因此这里写成防卫式声明的样子-
将类单独写成.h和.cpp
//A.h #ifndef __A__ #define __A__ #include <iostream> #include <pthread.h> class A { public: static A &getinstance();//首先写一个静态成员函数用于获取静态单例对象 void otherfun(); private://4个函数放private A(); ~A(); A(const A &a)=delete; const A &operator=(const A &a)=delete; }; #endif
//A.cpp #include "A.h" A::A() { } A::~A() { } void A::otherfun(){ std::cout<<pthread_self()<<" : "<<this<<std::endl;//打印当前线程所使用的实例对象地址 }; A &A::getinstance() { static A a; return a; }
-
main
#include "A.h" #include "B/Sonfun.h" int main() { //1.创建线程 pthread_t t[3]; pthread_create(&t[0], NULL, sonfun, NULL); pthread_create(&t[1], NULL, sonfun, NULL); pthread_create(&t[2], NULL, sonfun, NULL); //2.等待结束 pthread_join(t[0], NULL); pthread_join(t[1], NULL); pthread_join(t[2], NULL); return 0; }
-
子线程的函数也同样拿出来单独写成.h和.cpp
//Sonfun.h #ifndef _SONFUN_ #define _SONFUN_ #include "../A/A.h" void *sonfun(void *); #endif
//Sonfun.cpp #include "Sonfun.h" void *sonfun(void *) { A& a = A::getinstance(); a.otherfun(); }
-
在build目录下写CMakeLists.txt
cmake_minimum_required(VERSION 3.15.5) project(testuse_single_bycmake) add_executable(main main.cpp A/A.cpp B/Sonfun.cpp) target_include_directories(main PUBLIC A B) target_link_libraries(main PUBLIC pthread)
-
生成makefile:cmake …
-
编译:make
-
-
第二种尝试:为每个模块(库)编写独立的CMakeLists.txt文件
├── A │ ├── A.cpp │ ├── A.h │ └── CMakeLists.txt ├── B │ ├── CMakeLists.txt │ ├── Sonfun.cpp │ └── Sonfun.h ├── CMakeLists.txt └── main.cpp
-
最外层CMakeLists.txt
cmake_minimum_required(VERSION 3.15.5) project(testuse_single_bycmake) #添加子目录 add_subdirectory(A) add_subdirectory(B) #生成可执行程序所需要的源文件只剩main.cpp了 add_executable(main main.cpp) target_include_directories(main PUBLIC A B) target_link_libraries(main PUBLIC pthread) #其余cpp文件通过动态库的形式在此添加进来 target_link_libraries(main PUBLIC alib) target_link_libraries(main PUBLIC blib)
-
那么在子模块中,是怎么生成动态库的呢
cmake_minimum_required(VERSION 3.15.5) project(a) set(A_SRC ./A.cpp) add_library(alib SHARED ${A_SRC})
-
B中基本一致,但B中的Sonfun.cpp依赖于A,需要为其指定依赖
即多写一行:target_link_libraries(blib PUBLIC alib)
-
二、一些语法
在使用target_include_directories为指定目标设置包含目录时,有3种修饰符:
PUBLIC:指定的目录/库对 目标本身以及链接该目标的其它目标,都有效
PRIVATE:只对当前目标有效
INTERFACE:对当前目标无效,对链接该目标的其它目标有效
如果是想设置对所有目标都起作用,那么使用include_directories即可
使用了target_include_directories后,该路径被视为与系统路径等价。代码里就可以直接引入该文件夹的头文件,甚至可以使用<>来引用其中的头文件。
当前目录:${CMAKE_CURRENT_SOURCE_DIR}
-
生成库文件:add_library
静态库:add_library(目标 STATIC source.cpp) 生成.a
动态库:add_library(目标 SHARED source.cpp) 生成.so -
在某可执行文件中使用该库
target_link_libraries(…) -
引用第三方库
- 纯头文件
- 子模块的形式:把项目克隆下来,使用add_subdirectory引入目录,再使用target_link_libraries使用该库
- 引用系统中预安装的第三方库fmt:
- 使用find_package(fmt REQUIRED)先找到该包
- 再使用target_link_libraries(目标 PUBLIC fmt::fmt) fmt::fmt表示fmt包下的fmt库
三、实战
-
目前编写了一个mysql线程池,使用到cJSON、mysqlclient、pthread
写如下CMakeLists.txtcmake_minimum_required(VERSION 3.10) set(CMAKE_BUILD_TYPE DEBUG) set(CMAKE_CXX_STANDARD 14) project(YX) include_directories(include "/usr/include/mysql" three) add_executable(yx main.cpp MysqlConn.cpp ConnectionPool.cpp three/cJSON.c) target_link_libraries(yx mysqlclient) target_link_libraries(yx pthread)
在build目录下执行cmake …生成makefile
然后执行cmake --build . 即可生成可执行文件yx
mysqlpool -
怎样调试
- 首先配置launch.json
主要是2行:
"program": "${workspaceFolder}/build/yx"
"preLaunchTask": "CMake Build"
第一行表示cmakeLists编译生成得到的可执行文件位置,注意,这里yx是生成可执行文件的名字
第二行就是调用lable为CMake Build的tasks.json - 配置tasks.json
{ "options": { "cwd": "${workspaceFolder}/build" }, "tasks": [ { "label": "cmake", "command": "cmake", "args": [ "-DCMAKE_BUILD_TYPE=Debug", ".." ] }, { "label": "make", "command": "make" }, { "label": "CMake Build", "dependsOn": [ "cmake", "make" ] } ], "version": "2.0.0" }
- 首先配置launch.json