CMake3: CMake的嵌套使用与自定义库
文章目录
- 1. CMake嵌套使用
- 2.自定义库(该库依赖第三方库实现)
1. CMake嵌套使用
如果项目很大,或者项目中有很多的源码目录,在通过CMake管理项目的时候如果只使用一个CMakeLists.txt,那么这个文件相对会比较复杂,有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt文件(头文件目录不需要),这样每个文件都不会太复杂,而且更灵活,更容易维护。
当前文件的目录结构为:
.
├── bin
│ └── function_text
├── build
├── CMakeLists.txt
├── dataset
├── cmake_modules
├── include
│ ├── Frame.h
│ ├── ORBextractor.h
│ ├── ORBVocabulary.h
│ ├── system.h
│ ├── visual_odometry.h
│ └── visual_template.h
├── lib
│ └── libmyslam.so
├── src
│ ├── CMakeLists.txt
│ ├── Frame.cpp
│ ├── ORBextractor.cpp
│ ├── system.cpp
│ ├── visual_odometry.cpp
│ └── visual_template.cpp
├── test
│ ├── CMakeLists.txt
│ ├── function_text.cpp
│ └── main.cpp
└── ThirdParty└── DBoW2├── CMakeLists.txt├── DBoW2│ ├── BowVector.cpp│ ├── BowVector.h│ ├── FClass.h│ ├── FeatureVector.cpp│ ├── FeatureVector.h│ ├── FORB.cpp│ ├── FORB.h│ ├── ScoringObject.cpp│ ├── ScoringObject.h│ └── TemplatedVocabulary.h├── DUtils│ ├── Random.cpp│ ├── Random.h│ ├── Timestamp.cpp│ └── Timestamp.h├── lib│ └── libDBoW2.so├── LICENSE.txt└── README.txt
根目录包含的内容一般包含以下几个文件:
- bin : 存储生成的可执行二进制文件,可在CMakeLists.txt中指定路径
- build :存储查找链接库时生成的中间文件
- include:放置函数的头文件
- src : 放置函数的源文件
- lib : 放由函数文件所生成的静态库(.a)和动态库(.so)可在CMakeLists.txt中指定路径
- test : 存放主函数以及需要测试的文件(可撰写多个主函数,在CMakeLists.txt指定编译)
- cmake_modules :里边的文件以.cmake结尾,存放着库文件的路径,供find_package查询(文件名Find×××.cmake)
- dataset : 存放运行程序所需要的数据集
- CMakeLists.txt : 撰写该文件指导整个项目的编译,可存在于不同的目录下(上述在根目录,src以及text文件内均存在CMakeLists.txt)
- ThirdParty :存放一些修改过的第三方库
(1)编写顶层的CMakeLists.txt
Linux的目录是树状结构,所以嵌套的 CMake 也是一个树状结构,最顶层的 CMakeLists.txt 是根节点,其次都是子节点。
注意:CMakeLists.txt 文件变量作用域有如下关系
- 根节点CMakeLists.txt中的变量全局有效
- 父节点CMakeLists.txt中的变量可以在子节点中使用
- 子节点CMakeLists.txt中的变量只能在当前节点中使用
顶层,即根目录下的CMakeLists.txt内容为:
cmake_minimum_required(VERSION 2.8)
project(myslam)#设置编译方式
set(CMAKE_BUILD_TYPE Debug)#设置C++标准
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
#设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#设置库文件输出路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)############### dependencies ######################
find_package(OpenCV REQUIRED)#包含头文件的路径
include_directories(
${PROJECT_SOURCE_DIR}
${OpenCV_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/ThirdParty
"/usr/include/eigen3"
)#给定自定义的库文件的路径
link_directories(${PROJECT_SOURCE_DIR}/TirdParty/DBoW2/lib)set(THIRD_PARTY_LIBS${OpenCV_LIBS}libDBoW2.so)
add_subdirectory(src)
add_subdirectory(test)
(2)编写src下的CMakeLists.txt,用于编译库文件
#获取当前文件夹下的所有源文件
aux_source_directory( ./ SRC_LIST)
#添加库文件
add_library(myslam SHARED ${SRC_LIST})
#将生成的库文件与第三方库进行链接
target_link_libraries(myslam ${THIRD_PARTY_LIBS})
# 旧版本 CMake 中 target_link_libraries 默认是 PRIVATE 行为
(3)编写test下的CMakeLists.txt,用于编译主函数
add_executable(main_outcar main.cpp )
target_link_libraries(main_outcar myslam${THIRD_PARTY_LIBS})
#由前面注释知,(2)中的连接为 PRIVATE 行为,所以需要再连接一次add_executable(function_text function_text.cpp)
target_link_libraries(function_text myslam ${THIRD_PARTY_LIBS})
# 同上
2.自定义库(该库依赖第三方库实现)
将以上的文件修改,作为当前文件目录(不包含test文件夹):
.
├── build
├── CMakeLists.txt
├── include
│ ├── Frame.h
│ ├── ORBextractor.h
│ ├── ORBVocabulary.h
│ ├── system.h
│ ├── visual_odometry.h
│ └── visual_template.h
├── src
│ ├── CMakeLists.txt
│ ├── Frame.cpp
│ ├── ORBextractor.cpp
│ ├── system.cpp
│ ├── visual_odometry.cpp
│ └── visual_template.cpp
└── ThirdParty└── DBoW2├── CMakeLists.txt├── DBoW2│ ├── BowVector.cpp│ ├── BowVector.h│ ├── FClass.h│ ├── FeatureVector.cpp│ ├── FeatureVector.h│ ├── FORB.cpp│ ├── FORB.h│ ├── ScoringObject.cpp│ ├── ScoringObject.h│ └── TemplatedVocabulary.h├── DUtils│ ├── Random.cpp│ ├── Random.h│ ├── Timestamp.cpp│ └── Timestamp.h├── lib│ └── libDBoW2.so├── LICENSE.txt└── README.txt
(1)编写带安装命令的CMakeLists.txt
在根目录下编写CMakeLists.txt为:
cmake_minimum_required(VERSION 2.8)
project(myslam)
# 使用Debug或Release都可
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "-std=c++11 -O3 -fopenmp -pthread")############### dependencies ######################
# OpenCV
find_package(OpenCV REQUIRED)
include_directories(#opencv头文件路径${OpenCV_INCLUDE_DIRS}#自定义库的头文件路径${PROJECT_SOURCE_DIR}/include#第三方库的头文件路径(注:此处应与实际代码对应)#如:我的代码为#include "DBoW2/DBoW2/BowVector.h";因此上面加入的路径到ThirdParty就为止了${PROJECT_SOURCE_DIR}/ThirdParty#eigen库的头文件,该库全是头文件,无库文件,故后续无需链接"/usr/include/eigen3"
)#因为该库未安装到系统目录,也没有使用find_package指令进行查找,故在此处需要该库文件的路径
link_directories(${PROJECT_SOURCE_DIR}/TirdParty/DBoW2/lib)set(THIRD_PARTY_LIBS${OpenCV_LIBS}libDBoW2.so)#添加子文件夹,在子文件夹中编译库文件
add_subdirectory(src)
在src目录下编写CMakeLists.txt为:
# 将当前目录下的所有源文件添加到 SRC_LIST 变量中
aux_source_directory(./ SRC_LIST)# 创建名为 myslam 的共享库,使用 SRC_LIST 中的源文件进行编译
add_library(myslam SHARED ${SRC_LIST})# 将 myslam 库链接到 THIRD_PARTY_LIBS 中指定的第三方库
target_link_libraries(myslam ${THIRD_PARTY_LIBS})# 设置 myslam 库的版本为 PROJECT_NAME
set_target_properties(myslam PROPERTIES VERSION ${PROJECT_NAME})# 将 myslam 库安装到指定目录
install(TARGETS myslam#安装动态库使用这行指令 DESTINATION指定安装目录LIBRARY DESTINATION /usr/local/lib#安装静态库使用这行指令ARCHIVE DESTINATION /usr/local/lib
)# 将 include 目录下的所有头文件安装到指定目录
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include DESTINATION /usr/local/include/myslam# 匹配${PROJECT_SOURCE_DIR}/include 下的所有.h文件进行安装FILES_MATCHING PATTERN "*.h")# 还可加一些install命令,让其生成对应的Findmyslam.cmake或myslamConfig.cmake文件,这样就不用自己写配置文件了;具体指令目前尚未尝试
(2)生成带安装指令的库文件并安装的系统目录
在根目录build文件夹中,执行指令:
cmake ..
make#待成功编译后
sudo make install
生成的库文件名称为libmyslam.so
安装成功后显示:
注:第一行的libmyslam.so.myslam,最后一个myslam即为之前指定的版本号,用的是project_name
在相应的系统路径可查询为:
(3)新建一个工作空间,使用安装到系统的myslam库文件
新的工作空间为:
├── CMakeLists.txt
├── build
├── cmake_modules
│ └── Findmyslam.cmake
└── main.cpp
主函数main.cpp如下,该程序只使用了一个system.h的头文件:
#include <iostream>
#include <vector>
#include <string>
#include "system.h"void Loadimage(const string& Datafilepath,vector<string>& file_names);
int main(int argc, char **argv)
{vector<string> file_names;Loadimage(string(argv[1]),file_names); System SLAM;SLAM.TrackRGB(file_names);SLAM.SaveTrajectory(SLAM.GetExpTrajectory(),"./coordinate.csv");return 0;
}
新的工作空间下的CMakeLists.txt为:
cmake_minimum_required(VERSION 2.8)
project(Test_slam)# 设置 C++ 标准为 C++11
set(CMAKE_CXX_STANDARD 11)# 将自定义的模块路径添加到 CMake 模块路径中
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules ${CMAKE_MODULE_PATH})# 查找并加载名为 myslam 的 CMake 配置文件
find_package(myslam REQUIRED)# 将 myslam 的头文件路径添加到包含目录中
include_directories(${MYSLAM_INCLUDE_DIRS})# 添加可执行文件 main_outcar,使用 main.cpp 源文件
add_executable(main_outcar main.cpp )
# 将 myslam 库链接到 main_outcar 可执行文件中
target_link_libraries(main_outcar ${MYSLAM_LIBRARIES})
Findmyslam.cmake文件的编写如下:
注:这是固定格式的名称 Find库名.cmake;
# 检查是否已经找到 myslam 库
if(NOT MYSLAM_FOUND)
# 使用 find_path 查找指定的 .h 文件路径,并将结果存储到 MYSLAM_INCLUDE_DIRS 变量中# MYSLAM_INCLUDE_DIRS为变量,内存储的是路径find_path(MYSLAM_INCLUDE_DIRS#引入的头文件,此处不支持使用变量"system.h"#头文件的系统路径/usr/local/include/myslam/include)# 使用 find_library 查找指定的库文件,并将结果存储到 MYSLAM_LIBRARIES 变量中# MYSLAM_LIBRARIES为变量,内存储的是路径 + lib库名.sofind_library(MYSLAM_LIBRARIESmyslam/usr/local/lib)# 因为本库还依赖第三方库实现,需在此处引入连接find_package(OpenCV REQUIRED)# 添加需要的头文件include_directories(${OpenCV_INCLUDE_DIRS}"/usr/include/eigen3""/home/wheeltec-client/Desktop/Neuroslam/NeuroSlam_cpp/NeuroSLAM_MATLABtocpp-neuroslam_v2.0/TirdParty")# 添加链接目录,链接到指定的库文件目录link_directories(/home/wheeltec-client/Desktop/Neuroslam/NeuroSlam_cpp/NeuroSLAM_MATLABtocpp-neuroslam_v2.0/TirdParty/DBoW2/lib)# 设置 MYSLAM_LIBRARIES 变量,包含 myslam 库、libDBoW2.so、以及 OpenCV 的库文件set(MYSLAM_LIBRARIES${MYSLAM_LIBRARIES}libDBoW2.so${OpenCV_LIBS})# 设置库的找到标志为 TRUEset(MYSLAM_FOUND TRUE)
endif()
最后在build目录下编译:
cmake ..
make