Linux下动态库的打包方法以及CMakeLists常用命令

​ 在我的项目里面会经常用到比如各种版本的ndt算法库,ndt_cpu/ndt_gpu_ndt_omp,无可避免得会涉及到一些动态库的打包及饮用方法,这里记录一下,并给出打包好的ndt lib库,库的源码来源为Autoware以及开源项目ndt_omp。

​ CMake 全称是Cross platform Make的简写,是基于Make来实现相关的内容的,换句话说,CMake就是在Make的基础上抽象出来的更高级的框架。这里也总结以下常用的CMake命令。

​ 我们知道,在LInux中,库文件分成静态库和共享库两种,静态库以.a作为后缀,共享库则是以.so结尾,所有库都是函数打包后的集合,区别就在于静态库每次被调用都会生成一个副本,而共享库则只有一个副本。这里以ndt_omp库为例,来进行生成.so库及引用。

打包ndt_omp动态库

打包

其项目源码地址:

https://github.com/koide3/ndt_omp.git

这个项目结构稍微浏览一下,可以看到ndt_omp库函数及头文件在src/pclomp以及include目录下,apps/align.cpp是作者给出的测试函数,有main。所以打包的时候我们直接考虑src目录下源文件即可。

​ 打开cmakelist.txt文件,可以看到

1
2
3
4
add_library(ndt_omp  //库名称为libndt_omp,可修改
src/pclomp/voxel_grid_covariance_omp.cpp
src/pclomp/ndt_omp.cpp
src/pclomp/gicp_omp.cpp)

这里直接修改为

1
2
3
4
add_library(ndt_omp  SHARED //库名称为libndt_omp,可修改
src/pclomp/voxel_grid_covariance_omp.cpp
src/pclomp/ndt_omp.cpp
src/pclomp/gicp_omp.cpp)

这样编译项目,即可在/build/devel/lib下面看到生成的libndt_omp.so文件。

引用

新建一个test_omp项目,

  1. 将ndt_omp/include文件夹复制过来,里面包含了要用到的头文件。

  2. 新建lib文件夹,将打包好的libndt_omp.so文件丢进去,

  3. 修改cmakelist.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
find_package(PCL 1.7 REQUIRED) #要用到pcl

find_package(OpenMP) #ndt_omp用到了openMP库
if (OPENMP_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()

include_directories(${PCL_INCLUDE_DIRS}) #pcl
link_directories(${PCL_LIBRARY_DIRS})

include_directories(include) #头文件加进去
link_directories(lib) #lib.so文件

add_executable(test_omp src/align.cpp )
target_link_libraries(test_omp
${PCL_LIBRARIES}
ndt_omp #这里链接.so库,库的名字是ndt_omp
)
  1. 然后我们写main函数测试是否能正常引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/registration/ndt.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>

#include <pclomp/ndt_omp.h> //头文件保证能找到
#include <iostream>

int main(int argc, char** argv) {
std::cout << "--- pcl::NDT ---" << std::endl;

//这里不报错,openMp顺利引用
std::vector<int> num_threads = {1, omp_get_max_threads()};

//这里顺利引用ndt_omp相关的函数
std::vector<std::pair<std::string, pclomp::NeighborSearchMethod>> search_methods = {
{"KDTREE", pclomp::KDTREE},
{"DIRECT7", pclomp::DIRECT7},
{"DIRECT1", pclomp::DIRECT1}
};
pclomp::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>::Ptr ndt_omp(new pclomp::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>());
ndt_omp->setResolution(1.0);
}

如果编译链接不出错,即正常引用。按这种方式在项目中使用即可。

最后我打包了ndt_cpu/ndt_gpu/ndt_omp/omp_ndt(autoware中提供的),项目地址如下,可直接使用。

CMake常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cmake_minimum_required(VERSION xxx) #cmake最小版本需求,新版本的cmake改了很多东西,提升了便利性,也可能让你自己挖坑了
project(xxx) #设置此项目的名称

add_executable(target target_source_codes) #生成可执行文件target ,后面填写的是生成此可执行文件所依赖的源文件列表。

SET(var_name var_value)# 设置一个名字var_name 的变量,同时给此变量赋值为var_value

MESSAGE("MSG") #类比echo 打印消息

option(var_name "comment" var_value) #给变量var_name赋值为var_value,comment是此变量的注释,和SET 有类似的功效,用于给某变量设置默认值

include_directories(xxx) #添加include路径,也就是 gcc -I xxx 的意思,或者vs ide中添加头文件包含目录

add_subdirectory(xxx) #调用xxx子目录的CMakeLists.txt执行

#给编译器添加xxx参数,但是貌似没有什么用,一般不这样添加参数,不直接
add_compile_options(xxx)

#给编译器添加库目录,也就是 gcc -L xxx 的意思,或者vs ide中添加库的包含目录
link_directories(xxx)

#和add_executable类似,生成库文件,SHARED代表动态库,STATIC代表静态库, 最后一个参数代表此库的源文件列表,此指令只有三个参数
add_library(lib_name SHARED or STATIC lib_source_code)

#给目标添加依赖库,类似与gcc -l lib_name,此指令有两个用处,一个是给可执行target_name 添加库依赖,二是给库target_name 添加库依赖。
target_link_libraries(target_name lib_name ...)

流程控制和循环指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(xxx)
...
elseif(xx)
...
else()
...
endif()

#常见条件语句用法为:
# if (va) va为bool型
# if (va MATCHES xxx) va 是string类型,如果va包含了xxx,则此句为真


#循环指令
foreach(va va_lists)
...
endforeach()

install指令

1
2
3
4
5
6
7
install(FILES flie DESTINATION dir_path) #执行make install时,把file拷贝到dir_path
install(PROGRAMS file DESTINATION dir_path) #执行make install时,把file拷贝到dir_path,并给予file可执行权限
INSTALL(TARGETS ylib ylib_s
#RUNTIME DESTINATION xxx
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)# 安装libylib.so到lib目录,安装libylib_s.a到lib目录,RUNTIME 是安装可执行文件到xxx目录,注意这个指令有个坑,我后面会说明这个问题。

内置变量

1
2
3
4
5
6
CMAKE_INSTALL_PREFIX  #make install 的安装路径
CMAKE_BUILD_TYPE #生成的目标为debug或者release
CMAKE_C_FLAGS #gcc 的编译参数指定,这个非常好用,一般通过set 修改其值
CMAKE_CXX_FLAGS #g++ 和上面CMAKE_C_FLAGS 类似
CMAKE_CURRENT_SOURCE_DIR # 当前CMakeLists.txt所在的目录,主要用来定位某文件
CMAKE_CURRENT_BINARY_DIR # 当前CMakeLists.txt对应的编译时的目录
-------------    本文结束  感谢您的阅读    -------------
胡想成 wechat
欢迎关注个人公众号!
您的支持,是我装逼的最大动力!

本文标题:Linux下动态库的打包方法以及CMakeLists常用命令

文章作者:胡想成

发布时间:2020年03月20日 - 17:03

最后更新:2020年04月06日 - 19:04

原始链接:xchu.net/2020/03/20/45cmake/

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0许可协议,转载请注明出处!