Ubuntu中用Cmake管理C++项目

本文介绍了Cmake如何作为跨平台项目管理工具,包括CMakeLists.txt的使用、项目结构组织、OpenCV集成以及编译设置,展示了如何创建动态库并管理依赖关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

Cmake是可以跨平台管理C++项目的一个工具,在不使用IDE的情况下,用Cmake可以方便的管理自己的项目。
Cmake在安装之后就可以使用,Ubuntu中安装命令如下:

sudo apt install cmake

cmake是基于一个叫做CMakeLists.txt的文本文件作为代码载体,所有的命令都写在文件中。同样,父目录中的CMakeLists.txt是可以管理子目录中的CMakeLists.txt的,这样就可以实现一条命令管理整个项目。

总体结构框架

按照习惯,需要将项目中的文件分类存放后,再编写不同的CMakeLists.txt进行管理。一般的,在项目根目录中将项目分为以下几个目录,src,用于存放cpp源文件,build,用于存放编译文件,inc,用于存放头文件h源文件,lib,用于存放静态库文件.a文件和动态库文件.so文件,pic,用于存放项目的图片文件。此外,还需要将顶级CMakeLists.txt文件放在这一层级,即根目录中,此CMakeLists.txt是控制整个项目的编译,依赖项,库文件、头文件路径加载,子目录中的CMakeLists.txt的功能以及位置定义。
先贴上我写的一个示例,这个示例中cmake管理的目的有三个,第一,将src中自己写的一个类CVisionDetect.cpp编译为动态库文件,再在src中的中main.cpp中调用该库文件,生成项目可执行文件。
首先将项目根目录中的CMakeLists.txt内容贴出如下:

cmake_minimum_required(VERSION 3.2)
project(prj2)
find_package(OpenCV REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC mylib)
#由于编译器的问题,当配置mylib这个库文件的CMakeLists.txt中链接OpenCV库文件的命令target_link_libraries中设置为PRIVATE,那么在mylib这个动态链接库文件里所依赖的链接库OpenCV还需要再链接一次才能编译通过,否则报错,如果设置为PUBLIC,则编译会通过
#target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS})
#同样情况下,头文件就不需要再链接一次了
target_include_directories(${PROJECT_NAME} PUBLIC inc)
add_subdirectory(src bin)
#设置install命令所需要的前缀,这条命令一定要在project命令之后,在install命令之前
set(CMAKE_INSTALL_PREFIX /home/rotga/testCmake/project2)
#install命令,第一个参数,指明作用的是TARGETS,即用add_executable或者add_library命令创建出的目标,包括可执行文件,动态库文件和静态库文件,除了TARGETS外,当然也可以是FILES(普通文件)PROGRAMS(非目标的可执行文件)DIRECTORY(目录),后面第二个参数是targets的具体名字,可以是多个,而且可以是多个不同类型的targets,第三个参数是说将第二个参数列出的其中为动态链接库文件的安装(即拷贝)到指定的目录,可以是相对路径也可以是绝对路径,如果是相对路径,比如说写的是abc,则指定目录为${CMAKE_INSTALL_PREFIX}/abc,如果是绝对路径,则${CMAKE_INSTALL_PREFIX}将不起作用
install(TARGETS mylib
		LIBRARY DESTINATION bin)

下面逐行解释这个文件的内容。
cmake_minimum_required 命令一般都是第一行中先写上。后面括号内跟VERSION 3.2表示需要运行此文件最低需要cmake版本为3.2。
project 命令是命名该项目,后面括号内跟要命名的名称,这里是prj2。这里在定义了Project后,自动会有一个PROJECT_NAME的变量生成,如果后面要引用项目名称的话,就可以通过变脸引用的方式,用 ${PROJECT_NAME} 来使用。
find_package 命令是查找包的命令,简单来说,括号内先写上需要查找的包的名称,如果再跟上REQUIRED这个参数的话,那么就是说在没有查找到对应包的情况下,程序会终止编译。在成功查找到包后,会自动生成一些变量,包的地址:XXX_DIR,XXX是包的名称,这里是OpenCV_DIR;包的头文件包含地址,XXX_INCLUDE_DIRS,这里是OpenCV_INCLUDE_DIRS,包的库地址:XXX_LIBS,这里是OpenCV_LIBS,同时会将变量XXX_FOUND,这里是OpenCV_FOUND设置为真。关于find_package命令的更多知识,参阅:find_package命令详解,以及CMAKE专辑:CMAKE专辑
add_executable 命令,是生成可执行文件,该命令有两个参数,第一个是生成的可执行文件的路径及名称,第二个是由哪些源文件生成该可执行文件,这里的源文件可以有多个,用空格分开。
target_link_libraries 命令是链接可执行文件和库文件的命令,第一个参数是可执行文件的路径和名称,第二个是链接方式,可以是PUBLIC,PRIVATE,由于是初学,就写成PUBLIC,这样问题最少,或者不写,默认是PUBLIC。
target_include_directories 命令是链接可执行文件和头文件的命令,参数与上面基本相同,唯一不一样的是第三个参数,这个是需要包含的头文件的文件夹,而不是具体的文件名。
add_subdirectory 命令是向CMAKE管理的项目中添加一个子目录,并且执行该目录中的 CMakeLists.txt 文件中的命令。该命令有三个参数,鉴于水平,只说前两个参数,第一个是需要添加的子目录,可以是相对路径也可以是绝对路径,这里的相对路径,指的是相对于add_subdirectory命令所在的 CMakeLists.txt 文件所在的目录而言,第二个是二进制目标输出目录,同样可以是相对路径也可以是绝对路径。所谓二进制目标,就是添加的子目录中的CMakeLists.txt最终生成的库文件(目前就用到了这个,不知道可执行文件是否也可以,待验证)。而这里的相对路径指的是相对于执行cmake指令时所在的目录,比如,在项目根目录下的build文件夹中执行cmake …命令,那么第二个参数的相对路径就是以build目录为起点的路径。第三个参数没有理解透彻,先不写了。具体可以参考Cmake命令之add_subdirectory以及CMake add_subdirectory()函数
install 命令相当于是一个复制粘贴命令,将一些制定的文件复制到制定的目录中去,具体来说,就是可以安装目标文件,普通文件和目录。在本例子中,是安装目标文件,所谓目标文件,就是通过 add_libraries 或者 add_executable 命令所生成的目标,也就是静态库文件或动态库文件或可执行文件。详细可参阅文章cmake使用教(二) install的使用以及其专栏cmake。值得注意的是,在执行了cmake指令后,再执行make指令,此时install部分的指令并不会被执行,而是继续执行make install 后才会执行。
下面继续看子目录src中的CMakeLists.txt中内容

#此文件是为了生成动态库mylib

project(mylib)
#先通过find_package命令找到需要链接的OpenCV包
find_package(OpenCV REQUIRED)
#下面三条指令是演示找到包后自动生成的三个变量,分别是包的地址,包的包含头文件地址,包的动态连接库地址
message(STATUS "OpenCV_DIR = ${OpenCV_DIR}")
message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS = ${OpenCV_LIBS}")
#制作动态链接库文件的命令,第一个参数是动态链接库文件的目标,也就是这个文件要为哪个名称服务,也可以理解为库文件的名称,第二个参数是要生成库文件的类型,是静态的(STATIC)还是动态的(SHARED),第三个参数是生成包的源文件路径
add_library(${PROJECT_NAME} SHARED CVisionDetect.cpp)
#为该目标添加头文件搜索地址
target_include_directories(${PROJECT_NAME} PRIVATE ../inc PRIVATE ${OpenCV_INCLUDE_DIRS})
#target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS})

#为该目标绑定要链接的库文件路径,此处如果设置为PUBLIC,则在调用mylib库文件的主文件同级的CMakeLists.txt中不需要再调用OpenCV库文件,若设置为PRIVATE,则需要再调用一次OpenCV库文件
target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS})

注意,由于父目录中的CMakeLists.txt中的find_package命令里面设置了PUBLIC,那么此时是不需要再在此子目录中的CMakeLists.txt再写一次find_package的。
add_library 命令是生成库文件的命令,具体看文件中的注释即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值