以前在Linux上通过一套格式化的Makefile来构建Linux工程,生成库和可执行文件。
今天看了一下cmake这种跨平台构建方式来构建Linux下工程一样方便,可值钱格式化的Makefile没有什么不一样。下面进行展示:
我在虚拟机中的工作目录如图所示:
本文首先在prj_lib工程中生成动态库,然后再在prj_linux中生成目标程序时链接该动态库,这样比较符合日常实际开发。
放心这里的实例不会比别人从单文件到多文件再到链接库来得困难。
进入到prj_lib的目录下,有3个文件夹和一个txt文本文件:
在include文件夹中就是我们需要生成库的头文件,在source中就是库的源文件
简单看看这个库干了什么吧(其实也没必要看)
这个库实现的功能就是:基类提供打印一下当前函数所在文件,名字的能力,子类来完善一下功能,增加一个耗时的打印。
注意我在源文件中第二行写的#include “…/include/common.h”,这里直接去找到并展开上级目录中的include目录,因此我在之后介绍的CMakeList.txt中就没有添加子目录去增加访问include目录的功能。
然后来看prj_lib下面的CMakeList.txt:
看注释!
# 指定cmake最低版本要求 版本低了有些功能没有 #version require cmake_minimum_required(VERSION 3.1) # 工程名 #project project(comprt) # 将./source/目录下的所有源文件 一并赋值给LIB_SRC, 当然你可以任意指定一个变量名,比如SRC_LIST之类的 #source cpp path aux_source_directory(source LIB_SRC) # 生成库总得给个名字吧 第二个参数SHARED如果不写的话,就是默认是静态库 #target add_library(comprt SHARED ${LIB_SRC})
就此CMakeList.txt写完了,我是把它放在顶级目录下的,然后呢进入到build/里面去,当然你可以试试就在CMakeList.txt所在目录执行以下cmake .
意思是cmake + 路径,你会看到生成一对东西,这样是内部构建,它不好看,所以还是选择外部构建的方式
在build/中 cmake ..
会生成以下东西
看到生成了一个Makefile了没,这下子就可以编译你的库啦。
tip:我一般喜欢make clean all
看,生成动态库了吧
大功告成,这样这个库就可以丢给别人使用了。
假如我作为一个用户要使用这个libcomprt.so,我肯定要去包它的头文件,找到它在哪,然后链接它,接下来就开整:
我这个用户很简单,不包含其他的头文件,源文件,只有一个有main函数的cpp,但是呢接下来要写在这个工程里面的CMakeLists.txt包罗万象,把g++指令完全体现出来了:
先看看我文件结构吧:
再看看main.cpp干了啥,(其实也没必要)
主函数包含iostream
, string
以及 我们libcomprt的头文件common.h
,一般来说,使用者在代码里不用理会这个库头文件在哪(所以这个地方补足之前编库的时候说的#include里写路径的问题)
主函数干了什么呢,他用库提供的morePrint类型,来做一个函数进出和耗时的打印,你可以把这个类型放在任意函数中,他自己的生命周期就和函数进出栈的时机是一致的。
然后呀,主函数就打印一个hello world,用到了一个c++17的新类型std::string_view,这个不懂可以去我之前写的一个博客看看,或者找别人的来看看,蛮有用的(打给自己打个广告:string_view)
会makefile以及gcc/g++指令的同学,我们在编译这个程序是会执行类似于下面这串指令的吧(之前编库忘了写。。。)
默认你在main.cpp同级目录:
g++ -std=c++17 -Wall -O2 main.cpp -I../prj_lib/include -L../prj_lib/build -lcomprt -o demo
我将g++的参数拆分为以下几段:
# C++标准 -std=c++17
# g++ 参数 当然还有诸如-g -shared, 生成中间文件的-E -s -c等等 -Wall -O2
# 源文件们,本文就一个main.cpp,在其他目录记得带上路径哦 main.cpp
# 头文件们 -I path
# 库在哪 -L path
# 库叫啥 -l 库名(不加lib和.a/.so)
# 输出(不加的话给你一个a.out) -o target
好了。让我们来看看cmake怎样实现以上各段参数吧:
# 不用多说了,无视图里这版本不一样 cmake_minimum_required(VERSION 3.1) project(DEMO) #源文件们 # main.cpp set(FILE_MAIN main.cpp) # C++标准,这个代码里面用到17的东西,所以要加17 # param set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 给CMAKE_CXX_FLAG追加一堆参数 set(CMAKE_CXX_FLAG ${CMAKE_CXX_FLAG} "-O2 -Wall -g") # 头文件们,此处工程简单,没有除了库以外的头文件,你可是想上一行那样使用set追加 # -I set(LIB_INCLUDE ../prj_lib/include) include_directories(${LIB_INCLUDE}) # 库在哪 # -L set(LIB_DIR ../prj_lib/build) link_directories(${LIB_DIR}) # 输出目标文件名字和依赖上面的源文件们 # -o add_executable(test ${FILE_MAIN}) #库的名字 # -l set(LIB_NAME comprt) target_link_libraries(test ${LIB_NAME})
然后我们在build里构建:
看到了没,生成test了,执行下看个效果吧,这里还不需要添加环境变量,牛哔了
好就这样吧,文章永磁很粗糙,后面来改