【CMake】CMake创建、安装、使用静态库和动态库
一、CMake创建静态库/动态库
使用CMake
可以轻松生成对应程序编译好的静态库和动态库,用于打包发布,下面详细介绍如何实现
程序文件
首先我们有如下的程序,一些简单的数学运算,需要将它编译成静态库/动态库
mymath.h
#pragma onceint add(int x,int y);int sub(int x,int y);int multiply(int x,int y);int divide(int x,int y);
mymath.cpp
#include"mymath.h"int add(int x,int y){return x + y;
}int sub(int x,int y){return x - y;
}int mutiply(int x,int y){return x * y;
}int divide(int x,int y){return x - y;
}
项目的结构如下
编写CMakeLists.txt
动态库
这里需要编写src/
文件夹下的CMakeLists.txt
,具体如下
ADD_EXECUTABLE(main main.cpp)SET(LIBMYMATH_SRC mymath.cpp)
ADD_LIBRARY(mymath SHARED ${LIBMYMATH_SRC})
-
这里使用
SET(LIBMYMATH_SRC mymath.cpp)
定义了一个变量LIBMYMATH_SRC
,代表了这个动态库所需的源文件 -
然后使用
ADD_LIBRARY
关键字将动态库所需的源文件编译为动态库mymath
是库名,也就是我们编译出来的动态库,编译后会有前缀lib
以及后缀.so
,即libmymath.so
SHARED
关键字,声明编译为动态库,最后的${LIBMYMATH_SRC}
是上述定义的源文件的变量名,用于生成动态库
进入build
路径,执行构建 & 编译指令
cmake .. && make
最外层的CMakeLists.txt
如下,设置了库文件的生成路径为 ${PROJECT_BINARY_DIR}/lib
,即build/lib
下
PROJECT(HELLO)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)INSTALL(PROGRAMS runhello.sh DESTINATION /usr/bin)INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/)ADD_SUBDIRECTORY(src)
在build/lib
路径下,可以查看到我们编译生成的动态库libmymath.so
静态库
类似动态库,我们也可以生成静态库,只需要将SHARED
关键字修改为STATIC
关键字即可,因此不需要CMakeLists.txt
几乎没改变
ADD_EXECUTABLE(main main.cpp)SET(LIBMYMATH_SRC mymath.cpp)# ADD_LIBRARY(mymath SHARED ${LIBMYMATH_SRC})ADD_LIBRARY(mymath STATIC ${LIBMYMATH_SRC})
构建、编译后,同样在build/lib
下生成了静态库,前缀为lib
,后缀为.a
,即libmymath.a
同时创建静态库和动态库
如果同时生成静态库和动态库,如下的方法是不行的,只会生成动态库
ADD_EXECUTABLE(main main.cpp)SET(LIBMYMATH_SRC mymath.cpp)ADD_LIBRARY(mymath SHARED ${LIBMYMATH_SRC})ADD_LIBRARY(mymath STATIC ${LIBMYMATH_SRC})
构建、编译
cmake .. && make
发现build/lib
下只有动态库生成,显然这样不是我们需要的结果
SET_TARGET_PROPERTIES
关键字
-
我们需要使用到
SET_TARGET_PROPERTIES
关键字来帮助我们同时生成动态库和静态库 -
SET_TARGET_PROPERTIES
用于设置输出的名称,对于动态库,还可以用于指定动态库的版本和API
版本
需要修改的CMakeLists.txt
如下
ADD_EXECUTABLE(main main.cpp)SET(LIBMYMATH_SRC mymath.cpp)ADD_LIBRARY(mymath_static STATIC ${LIBMYMATH_SRC})#设置 mymath_static 输出为 mymath
SET_TARGET_PROPERTIES(mymath_static PROPERTIES OUTPUT_NAME "mymath")ADD_LIBRARY(mymath SHARED ${LIBMYMATH_SRC})
这样就不会冲突了,构建、编译后在build/lib
目录下同时可以找到静态库和动态库
二、安装动态库和头文件
配合INSTALL
关键字可以将静态库、动态库和头文件安装到指定路径,我们这里安装到:
usr/local/lib
usr/local/lib
usr/local/include/mymath
- 修改的是内层的
CMakeLists.txt
- 注意这里头文件使用的是
FILES
,静态库是ARCHIVE
,动态库是LIBRARY
,可执行文件是RUNTIME
- 这些都是目标文件,因此需要使用
TARGETS
ADD_EXECUTABLE(main main.cpp)SET(LIBMYMATH_SRC mymath.cpp)ADD_LIBRARY(mymath_static STATIC ${LIBMYMATH_SRC})#设置 mymath_static 输出为 mymath
SET_TARGET_PROPERTIES(mymath_static PROPERTIES OUTPUT_NAME "mymath")ADD_LIBRARY(mymath SHARED ${LIBMYMATH_SRC})INSTALL(FILES mymath.h DESTINATION include/mymath)INSTALL(TARGETS main mymath_static mymath
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
进入到安装目录,查看是否存在对应的头文件、库文件、可执行文件,符合预期
三、使用静态库、动态库
- 我们刚才已经成功编译好了库文件,并且将它们安装到了指定的位置,现在让我们看看如何使用它们吧
- 为了方便测试,我们这里先删除
mymath.cpp
源文件和mymath.h
头文件
rm mymath.cpp mymath.h
在main.cpp
中使用我们刚才编译的库的函数
#include<iostream>
#include"mymath.h"int main(){int x = 1, y = 1;int z = add(x,y);std::cout << "x + y = " << z << std::endl;return 0;
}
显然,这里找不到mymath.h
这个头文件
- 一种方法是,直接指定
usr/local/include/mymath
这个路径,但是这样比较死板,而且一般不会这样使用 - 这里因为头文件默认的搜索路径是从
/usr/local/include/
以及/usr/include/
开始,因此这里可以直接写mymath/mymath.h
#include<iostream>
#include"mymath/mymath.h"int main(){int x = 1, y = 1;int z = add(x,y);std::cout << "x + y = " << z << std::endl;return 0;
}
另一种方法,就是在src/CMakeLists.txt
中加入如下的头文件搜索路径,这样直接指定mymath.h
就可以找到了
INCLUDE_DIRECTORIES(/usr/local/include/mymath)
构建、编译
cmake && make
此时编译失败,因为找不到对应的函数,因为没有链接库
链接静态库
我们演示如何链接静态库,这里介绍一种方法:
- 使用
LINK_DIRECTORIES
命令指定链接的静态库的路径 - 使用
TARGET_LINK_LIBRARIES
命令添加指定路径下的库名,这里是libmymath.a
- 如果在
TARGET_LINK_LIBRARIES
前未指定路径,则使用默认的路径,如usr/lib
、usr/local/lib
等
修改CMakeLists.txt
ADD_EXECUTABLE(main main.cpp)INCLUDE_DIRECTORIES(/usr/local/include/mymath)LINK_DIRECTORIES(/usr/local/lib)
TARGET_LINK_LIBRARIES(main libmymath.a)
构建、编译、运行
cmake .. && make && ./bin/main
链接动态库
保留上面的CMakeLists.txt
,只需要将libmymath.a
改为libmymath.so
,然后正常构建、编译
ADD_EXECUTABLE(main main.cpp)INCLUDE_DIRECTORIES(/usr/local/include/mymath)LINK_DIRECTORIES(/usr/local/lib)TARGET_LINK_LIBRARIES(main libmymath.so)
但是这样,运行时找不到对应的动态库,我们可以使用ldd ./bin/main
查看是否找到了依赖的运行库
ldd ./bin/main
显然这里找不到,因此运行起来肯定不行
一种方法是,使用export
设置LD_LIBRARY_PATH
添加环境变量,但是这样关闭bash
后就会失效
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
另一种方法,修改/etc/ld.so.conf.d/mymath.conf
文件,添加上对应路径/usr/local/lib
sudo vim /etc/ld.so.conf.d/mymath.conf
添加上动态库路径
然后刷新缓存
sudo ldconifg
再次运行,成功找到了动态库
更多资料:https://github.com/0voice