当在Linux系统下编写程序时候,不能用或者不用visual studio、vs code等IDE进行C/C++开发时,我们要如何编译、运行程序呢?一种方法是编写makefile文件,用makefile文件管理程序脚本之间的相互依赖关系,其语法相对比较复杂。还有另一种有效的方法就是利用cmake工具,自动生成makefile文件。
cmake是什么?
CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。Linux/Ubuntu上基本都预先安装好了cmake工具,如果没有安装则可用 sudo apt-get install cmake
来自动安装。要使用cmake必须在工程的每个文件夹中都编写CMakeLists.txt
,注意C、M、L是大写。
有两种文件管理编译方式,in source build
和 out-of-source build
,下面分别介绍:
in source build 编译
马上开始实操,下面给出利用cmake进行编译并运行程序的例子,并说明如何在程序源文件pengzhangfushi.cpp
中和CMakeLists.txt
文件中调用opencv库
。首先建立一个名为text1
的文件夹,在其中建立程序源文件pengzhangfushi.cpp
和CMakeLists.txt
,该程序是要实现使用opencv库
来对图像进行有关的处理:
test1
文件夹中(文档)结构如下:
├── pengzhangfushi.cpp
└── CMakeLists.txt
pengzhangfushi.cpp
程序源文件部分内容:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <vector>
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
const int min_Hue = 10;
const int max_Hue = 80;
const int min_Saturation = 100;
const int max_Saturation = 255;
const int min_Value = 100;
const int max_Value = 255;
void callback_demo(int ,void*);
int element_size = 1, max_size = 10;
string window_name = "dilate img";
Mat src ,dst;
int main()
{
src = imread("/home/xag/data/simu_crop/3.jpg");
if (!src.data){
printf("cannot load image ...");
return -1;
}
Mat hsvImage;
cvtColor(src, hsvImage, CV_BGR2HSV);
// split the channels
vector<Mat> hsvChannels;
split(hsvImage, hsvChannels);
// is the color within the lower hue range?
Mat hueMask;
Mat hueImg = hsvChannels[0];
inRange(hueImg, min_Hue, max_Hue, hueMask);
Mat saturationMask;
Mat saturationImg = hsvChannels[1];
inRange(saturationImg, min_Saturation, max_Saturation, saturationMask);
Mat valueMask;
Mat valueImg = hsvChannels[2];
inRange(valueImg, min_Value, max_Value, valueMask);
hueMask = hueMask & saturationMask & valueMask;
namedWindow("src img", CV_WINDOW_AUTOSIZE);
imshow("src img", src);
...
...
...
}
在CMakeLists.txt
文件中输入下面的内容:
# 指定cmake的最低版本
cmake_minimum_required(VERSION 3.2)
# 指生成一个名为crop_row的工程
project(crop_row)
# 添加OPENCV库
# 如果不需要指定OpenCV版本,如下
# find_package(OpenCV REQUIRED)会在系统中找到OpenCVConfig.cmake,该文件定义了OpenCV_INCLUDE_DIRS和OpenCV_LIBS 等变量。
find_package(OpenCV REQUIRED)
# 如果需要指定OpenCV版本,如下
find_package(OpenCV 3.3 REQUIRED)
# 添加OpenCV头文件
include_directories(${OpenCV_INCLUDE_DIRS})
# 显示OpenCV_INCLUDE_DIRS的值
message(${OpenCV_INCLUDE_DIRS})
# 添加一个可执行程序,基于`pengzhangfushi.cpp`生成名为`pengzhang`的可执行文件。
# 语法:add_executable( 程序名 源代码文件 )
add_executable(pengzhang pengzhangfushi.cpp)
# 将库文件(此处是opencv的库文件)链接到可执行程序上。
target_link_libraries(pengzhang ${OpenCV_LIBS})
注意cmake
的命令不区分大小写,cmake
的注释为#
。
在terminal
中,cd
进入到test1
当前文件夹目录下,先后运行:
$ cmake .
$ make
此时文件夹中,生成的文件中有一个pengzhang文件
,该文件是编译之后的输出文件,再输入以下命令即可运行编译链接好的程序,可看到程序有相应的输出内容。
$ ./pengzhang
out-of-source build 编译
上述编译方法有个很大的问题,原本文件中仅有源文件
和CMakeLists.txt
,但是编译之后,文件夹中的文件如下所示:
CMakeCache.txt,cmake_install.cmake,pengzhang,Makefile,CMakeFiles,CMakeLists.txt,pengzhangfushi.cpp
编译之后在该文件夹下多了很多编译过程文件和结果文件,这样的方式显然是不方便的。如果能够把编译的过程文件和结果文件放在另一个文件夹,那么文件结构就比较清晰,可以方便地编辑、修改源文件。
test2
文件夹中(文档)结构如下:
├── src
├── CMakeLists.txt
└── pengzhangfushi.cpp
├── build
└── CMakeLists.txt
重新建立一个test2
文件夹来编译,并且在test2
中建立src
文件夹,build
文件夹和一个CMakeLists.txt
文件。
首先,在test2
文件夹当前目录中,建立一个CMakeLists.txt
,添加如下两行内容,第一行是建立名为crop_row
的工程,第二行添加src
子文件夹:
project(crop_row)
add_subdirectory(src)
然后,进入src
文件夹,再新建立一个CMakeLists.txt
,在该CMakeLists.txt
文件中添加如下内容,内容与 in source build 编译
中CMakeLists.txt
里添加的内容类似:
cmake_minimum_required(VERSION 3.2)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
message(${OpenCV_INCLUDE_DIRS})
add_executable(pengzhang pengzhangfushi.cpp)
target_link_libraries(pengzhang ${OpenCV_LIBS})
同样在该src
文件夹下建立pengzhangfushi.cpp
文件,pengzhangfushi.cpp
文件的内容与之前的内容一样。
然后,进入test2/build
文件夹,在terminal
中运行如下两行命名:
$ cmake ..
$ make
对程序进行编译,编译完成后,在build
文件夹中生成了编译文件和src
文件,src
文件夹中有pengzhang
的结果文件,进入src
文件夹中,在terminal
中:
$ ./pengzhang
可以看到输出结果,说明编译我们的编译已经成功。