CMakeLists编译总结

CMakeLists编译原理

​CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:

1. cmake
2. make

cmake 指向CMakeLists.txt所在的目录,例如cmake … 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译,例如

mkdir build
cd build
cmake ..
make
// make根据生成makefile文件,编译程序。

案例

cmake_minimum_required(VERSION 3.2)
project(six_calibration)
set(CMAKE_BUILD_TYPE "RelWithDebInfo")

set(3RD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../3rd)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin/debug/)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG  ${PROJECT_SOURCE_DIR}/bin/debug/)


set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)


file(GLOB_RECURSE HEAD_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h ${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp)
file(GLOB_RECURSE SOURCES_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

set(SOURCE_FILE
${HEAD_LIST}
${SOURCES_LIST}
)

find_package(PCL 1.10.1)
add_definitions(${PCL_DEFINITIONS} -DGLOG_NO_ABBREVIATED_SEVERITIES)

link_directories(${PCL_LIBRARY_DIRS})
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src 
${3RD_PATH}/opencv3.4/include
${3RD_PATH}/cctag/include
${3RD_PATH}/spdlog/include
${3RD_PATH}/boost/include/boost-1_79/
${3RD_PATH}/eigen
${3RD_PATH}/nlohmann
${3RD_PATH}/ceres/include/
${3RD_PATH}/glog/include/
${3RD_PATH}/gflags/include/
${PCL_INCLUDE_DIRS}
)
if(WIN32)
	set(3RD_LIB 
	${3RD_PATH}/opencv3.4/lib/opencv_world340.lib
	${3RD_PATH}/cctag/lib/CCTag.lib
	${3RD_PATH}/spdlog/lib/spdlog.lib
	${3RD_PATH}/boost/lib/libboost_serialization-vc142-mt-x64-1_79.lib
	${3RD_PATH}/open3d/lib/Open3D.lib
	${3RD_PATH}/ceres/lib/ceres.lib
	${3RD_PATH}/glog/lib/glog.lib
	${3RD_PATH}/gflags/lib/gflags.lib
	${PCL_LIBRARIES}
	)
else()

endif()
add_compile_definitions(SIX_CALIBRATION_EXPORTS)
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILE})


target_link_libraries(${PROJECT_NAME} 
${3RD_LIB}
${WIN32LIB}
${LINUXLIB}
)

file(GLOB_RECURSE TEST_HEAD_LIST ${CMAKE_CURRENT_SOURCE_DIR}/test/*.h ${CMAKE_CURRENT_SOURCE_DIR}/test/*.hpp)
file(GLOB_RECURSE TEST_SOURCES_LIST ${CMAKE_CURRENT_SOURCE_DIR}/test/*.c ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp)

set(TEST_SOURCE_FILE
${TEST_HEAD_LIST}
${TEST_SOURCES_LIST}
)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10240000000")

add_executable(app_test  ${TEST_SOURCE_FILE})

target_link_libraries(app_test
${3RD_LIB}
${WIN32LIB}
${LINUXLIB}
)

指定 cmake 的最小版本

cmake_minimum_required(VERSION 3.2)

指定了项目所需的最低CMake版本为3.2。这是一个必须的声明,以确保CMake版本符合要求。

设置项目名称

project(six_calibration)

设置项目的名称为"six_calibration",这个名称将在生成的构建系统中使用。

set(CMAKE_BUILD_TYPE "RelWithDebInfo")

设置构建类型为"RelWithDebInfo",这通常用于发布构建,包括调试信息以便于调试。

CMake设置输出目录

set(3RD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../3rd)

定义了一个名为3RD_PATH的变量,用于指定第三方依赖库的路径。
CMAKE_CURRENT_SOURCE_DIR是CMake中的另一个预定义变量,它用于表示当前处理的CMakeLists.txt文件所在的目录。

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug)

设置可执行文件的输出路径为${PROJECT_SOURCE_DIR}/bin/debug。这将生成的可执行文件放在指定的目录下
PROJECT_SOURCE_DIR是CMake中的一个预定义变量,用于表示当前项目的根目录。CMake会自动设置这个变量,以指向包含CMakeLists.txt文件的目录,即你的项目根目录。

因此,如果你在CMakeLists.txt文件中使用了set(EXECUTABLE_OUTPUT_PATH P R O J E C T S O U R C E D I R / b i n / d e b u g ) ,那么 {PROJECT_SOURCE_DIR}/bin/debug),那么 PROJECTSOURCEDIR/bin/debug),那么{PROJECT_SOURCE_DIR}会被替换为你的项目根目录的路径,然后生成的可执行文件将会被放置在这个路径下的bin/debug目录中。

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug)

设置库文件的输出路径为${PROJECT_SOURCE_DIR}/bin/debug。这将生成的库文件放在指定的目录下
eg: app_test.lib

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin/debug/)

设置调试构建的运行时输出目录。

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin/debug/)

设置调试构建的存档文件输出目录。

set(CMAKE_INCLUDE_CURRENT_DIR ON)

允许CMake包含当前源目录,这对于处理头文件很有用。

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

启用位置独立的代码生成,通常用于生成共享库。

set(CMAKE_CXX_STANDARD 17) 
set(CMAKE_CXX_STANDARD_REQUIRED ON)

设置C++标准为C++17,并要求编译器使用此标准。

指定编译包含的源文件

file(GLOB_RECURSE HEAD_LIST ...) 
file(GLOB_RECURSE SOURCES_LIST ...)

查找指定的文件

使用Glob函数获取源文件和头文件的列表。

find_package(PCL 1.10.1)

查找PCL(Point Cloud Library)1.10.1版本。如果找到,将设置相关变量。

add_definitions(${PCL_DEFINITIONS} -DGLOG_NO_ABBREVIATED_SEVERITIES)

将PCL的定义添加到项目,并定义一个名为-DGLOG_NO_ABBREVIATED_SEVERITIES的宏。

设置链接库搜索目录

link_directories(${PCL_LIBRARY_DIRS})

添加PCL库目录到链接目录中。

设置包含的目录

include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src 
${3RD_PATH}/opencv3.4/include
${3RD_PATH}/cctag/include
${3RD_PATH}/spdlog/include
${3RD_PATH}/boost/include/boost-1_79/
${3RD_PATH}/eigen
${3RD_PATH}/nlohmann
${3RD_PATH}/ceres/include/
${3RD_PATH}/glog/include/
${3RD_PATH}/gflags/include/
${PCL_INCLUDE_DIRS}
)
if(WIN32)
	set(3RD_LIB 
	${3RD_PATH}/opencv3.4/lib/opencv_world340.lib
	${3RD_PATH}/cctag/lib/CCTag.lib
	${3RD_PATH}/spdlog/lib/spdlog.lib
	${3RD_PATH}/boost/lib/libboost_serialization-vc142-mt-x64-1_79.lib
	${3RD_PATH}/open3d/lib/Open3D.lib
	${3RD_PATH}/ceres/lib/ceres.lib
	${3RD_PATH}/glog/lib/glog.lib
	${3RD_PATH}/gflags/lib/gflags.lib
	${PCL_LIBRARIES}
	)
else()

include_directories(…):添加包含目录,以便CMake知道在哪里查找头文件。

if(WIN32) 和 else():条件语句,检查操作系统是否为Windows。如果是,会设置一些Windows特定的变量。
eg:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")

Linux 下还可以通过如下方式设置包含的目录

add_compile_definitions(SIX_CALIBRATION_EXPORTS)

添加一个编译宏,通常用于在代码中区分库的导出和导入。

指定编译包含的源文件

add_executable(demo demo.cpp) # 生成可执行文件
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILE})

创建一个共享库,库的名称是PROJECT_NAME,库的源文件是SOURCE_FILE。
SHARED: 生成动态库
STATIC:生成静态库

静态(函数)库
一般扩展名为(.a或.lib),这类的函数库通常扩展名为libxxx.a或xxx.lib 。
这类库在编译的时候会直接整合到目标程序中,所以利用静态函数库编译成的文件会比较大,这类函数库最大的优点就是编译成功的可执行文件可以独立运行,而不再需要向外部要求读取函数库的内容;但是从升级难易度来看明显没有优势,如果函数库更新,需要重新编译。
动态函数库
动态函数库的扩展名一般为(.so或.dll),这类函数库通常名为libxxx.so或xxx.dll 。
与静态函数库被整个捕捉到程序中不同,动态函数库在编译的时候,在程序里只有一个“指向”的位置而已,也就是说当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用;也就是说可执行文件无法单独运行。这样从产品功能升级角度方便升级,只要替换对应动态库即可,不必重新编译整个可执行文件。
总结:综上,不能看出:
从产品化的角度,发布的算法库或功能库尽量使动态库,这样方便更新和升级,不必重新编译整个可执行文件,只需新版本动态库替换掉旧动态库即可。
从函数库集成的角度,若要将发布的所有子库(不止一个)集成为一个动态库向外提供接口,那么就需要将所有子库编译为静态库,这样所有子库就可以全部编译进目标动态库中,由最终的一个集成库向外提供功能。


(1)在 Windows 下是:demo.exe,common.lib,common.dll
(2)在 Linux 下是:demo,libcommon.a,libcommon.so

target_link_libraries(${PROJECT_NAME} ...)

指定项目所依赖的库。

file(GLOB_RECURSE TEST_HEAD_LIST ...)file(GLOB_RECURSE TEST_SOURCES_LIST ...)

文件列表获取,用于测试代码的头文件和源文件。

add_executable(app_test ${TEST_SOURCE_FILE})

创建一个可执行文件,名为"app_test",使用${TEST_SOURCE_FILE}中的源文件构建。

设置 target 需要链接的库

target_link_libraries(app_test ...)

eg:

target_link_libraries( # 目标库
                       demo 
                       # 目标库需要链接的库
                       # log-lib 是上面 find_library 指定的变量名
                       ${log-lib} )

在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)。

target_link_libraries(demo libface.a) # 链接libface.a
target_link_libraries(demo libface.so) # 链接libface.so

指定链接动态库或静态库

target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)

指定全路径

target_link_libraries(demo
    ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a
    boost_system.a
    boost_thread
    pthread)

指定链接多个库

其他

指定测试程序所依赖的库。

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10240000000")

设置可执行文件的链接器标志,包括栈大小等。

文件路径

.
├── build
├── CMakeLists.txt
├── include
│   └── b.h
└── src
    ├── b.c
    └── main.c

编写CMakeLists.txt

 1 #1.cmake verson,指定cmake版本 
 2 cmake_minimum_required(VERSION 3.2)
 3 
 4 #2.project name,指定项目的名称,一般和项目的文件夹名称对应
 5 PROJECT(test_sqrt)
 6 
 7 #3.head file path,头文件目录
 8 INCLUDE_DIRECTORIES(
 9 include
10 )
11 
12 #4.source directory,源文件目录
13 AUX_SOURCE_DIRECTORY(src DIR_SRCS)
14 
15 #5.set environment variable,设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,但是执行的时候会出现各种问题,比如"symbol lookup error xxxxx , undefined symbol"
16 SET(TEST_MATH
17 ${DIR_SRCS}
18 )
19 
20 #6.add executable file,添加要编译的可执行文件
21 ADD_EXECUTABLE(${PROJECT_NAME} ${TEST_MATH})
22 
23 #7.add link library,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称
24 TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)

参考:

CMakeLists常用命令
CMakeLists文件的编译
通俗理解动态库与静态库区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用CMake时,如果需要添加多个子目录并同时编译,可以按照以下步骤进行操作。 首先,在主目录的CMakeLists.txt文件中使用add_subdirectory命令来添加各个子目录。例如,假设我们有两个子目录分别为"subdir1"和"subdir2",我们可以在主目录的CMakeLists.txt中添加以下代码: ``` add_subdirectory(subdir1) add_subdirectory(subdir2) ``` 然后,在各个子目录中的CMakeLists.txt文件中设置该子目录的编译规则和依赖。例如,在"subdir1"的CMakeLists.txt中,我们可以使用add_library或add_executable命令来定义库或可执行文件,并指定需要编译的源文件或依赖的其他库。类似地,在"subdir2"的CMakeLists.txt中也可以定义相应的规则和依赖。 最后,在主目录的CMakeLists.txt中使用target_link_libraries命令来指定各个目标之间的依赖关系。例如,如果"subdir2"中的目标依赖于"subdir1"中的目标,我们可以在主目录的CMakeLists.txt中添加以下代码: ``` target_link_libraries(target_in_subdir2 target_in_subdir1) ``` 这样,当我们使用CMake生成项目时,各个子目录中的CMakeLists.txt文件将被自动调用,它们的目标将会被编译,并且指定的依赖关系也会被处理。 总结起来,要在CMake中添加引用多个子目录并同时编译,我们需要在主目录的CMakeLists.txt文件中添加每个子目录的路径,并在各个子目录的CMakeLists.txt文件中定义相应的规则和依赖关系。这样做可以使整个项目的构建更加清晰和灵活。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值