CMake常用语法+包含常用库+工程目录组织

命令不区分大小写,变量名区分大小写,参数之间使用空格进行分隔

内置变量的使用:

•在CMakeLists.txt中指定,使用set
•cmake命令中使用,如cmake -DBUILD_SHARED_LIBS=OFF

ADD_DEFINITIONS
向 C/C++编译器添加-D 定义,比如:
ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割。

如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。
如果要添加其他的编译器开关,可以通过 CMAKE_C_FLAGS 变量和 CMAKE_CXX_FLAGS 变量设置。

ADD_DEPENDENCIES
定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。
ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

CMAKE_C(XX)_FLAGS

变量 CMAKE_C_FLAGS 存放的内容会被传给 C 编译器,作用在所有的编译组态上。如果希望只针对特定一种组态有效,可以设定 CMAKE_C_FLAGS_<编译组态>,例如 CMAKE_C_FLAGS_RELEASE、CMAKE_C_FLAGS_DEBUG。
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wall -O3 -march=native -Wno-reorder")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native -Wno-reorder")

编译选项为-Wall O3的优化

debug 版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而 release 版的不需要调试信息但需要优化。这些特性在 gcc/g++ 中是通过编译时的参数来决定的,如果将优化程度调到最高需要设置参数-O3,最低是 -O0 即不做优化;添加调试信息的参数是 -g -ggdb ,如果不添加这个参数,调试信息就不会被包含在生成的二进制文件中。

CMake 中有一个变量CMAKE_BUILD_TYPE ,可以的取值是 Debug、Release、RelWithDebInfo 和 MinSizeRel。当这个变量值为 Debug 的时候,CMake 会使用变量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG中的字符串作为编译选项生成Makefile ,当这个变量值为 Release 的时候,工程会使用变量 CMAKE_CXX_FLAGS_RELEASE 和CMAKE_C_FLAGS_RELEASE 选项生成 Makefile。

SET(CMAKE_CXX_FLAGS_DEBUG"$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")

SET(CMAKE_CXX_FLAGS_RELEASE"$ENV{CXXFLAGS} -O3 -Wall")

设置了两个变量 CMAKE_CXX_FLAGS_DEBUG 和CMAKE_CXX_FLAGS_RELEASE, 这两个变量是分别用于 debug 和 release 的编译选项。

多源文件目录的处理方式

我们在每一个源码目录中都会放置一个 CMakeLists.txt 文件。我们现在假定有这么一个工程:

HelloWorld

|

+------- Main.cpp

|

+------- CMakeLists.txt

|

+------- Lib

        |

        +------- Lib.cpp

        |

        +------- Lib.h

        |

        +------- CMakeLists.txt

这里 Lib 目录下的文件将被编译为一个库。首先,我们看一下 Lib 目录下的 CMakeLists.txt 文件:

aux_source_directory(. DIR_SRCS)

add_library(Lib ${DIR_SRCS})

然后,看一下 HelloWorld 目录下的 CMakeLists.txt 文件:

project(Main)

cmake_minimum_required(VERSION 2.8)

add_subdirectory(Lib)

aux_source_directory(. DIR_SRCS)

add_executable(Main ${DIR_SRCS})

target_link_libraries(Main Lib)

这里使用了 add_subdirectory 指定了需要进行构建的子目录,并且使用了 target_link_libraries 命令,表示 Main 可执行文件需要链接 Lib库。我们执行 CMake . 命令,首先会执行 HelloWorld 目录下的 CMakeLists.txt 中的命令,当执行到 add_subdirectory(Lib) 命令的时候会进入 Lib 子目录并执行其中的CMakeLists.txt 文件。

例子:

 CMakeLists.txt(放在工程顶层目录下)

# 声明要求的 cmake 最低版本
cmake_minimum_required( VERSION 2.8 )

# 声明一个 cmake 工程
# PROJECT指令会隐式定义<projectname>_BINARY_DIR和<projectname>_SOURCE_DIR两个变量
project( HelloSLAM )
# message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message todisplay”…)
message(${PROJECT_NAME})
MESSAGE(STATUS "HOME dir: $ENV{HOME}")#调用系统的环境变量
message($ENV{PATH})

set(FLAG ON)
if(NOT FLAG)#在控制语句条件中使用变量,不能用${}引用,而是直接应用变量名
message("FLAG false!!!")
elseif(UNIX)#WIN32
message("UNIX!!!")
else()
message(FATAL_ERROR "error!!!")
endif()

# 设置编译模式
# set( CMAKE_BUILD_TYPE "Debug" )
set( CMAKE_BUILD_TYPE "Release" )

# 编译标志相关变量,编译选项为-Wall O3的优化
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native -Wno-reorder")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native -Wno-reorder")

# CHECK_CXX_COMPILER_FLAG(<flag> <var>)检查CXX编译器是否支持给定的flag,赋值给的var是个bool型
# 检查当前编译器是否支持c++11
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
   add_definitions(-DCOMPILEDWITHC11)
   message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
   add_definitions(-DCOMPILEDWITHC0X)
   message(STATUS "Using flag -std=c++0x.")
else()
   message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

#最终生成的库文件存放在工程顶层目录下的lib文件夹
#PROJECT_SOURCE_DIR、CMAKE_SOURCE_DIR、${PROJECT_NAME}_SOURCE_DIR都是指向工程顶层目录
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib)

#--------------------生成自己的库--------------------#
#aux_source_directory(<dir> <variable>)用于将dir目录下的所有源文件的名字保存在变量variable中
aux_source_directory(${PROJECT_SOURCE_DIR}/src/lib_src LIB_SRC)
FOREACH(F ${LIB_SRC})
    MESSAGE(${F})
ENDFOREACH(F)
#默认静态库(.a),若SET(BUILD_SHARED_LIBS ON)后,默认共享库
add_library( hello ${LIB_SRC})
# 共享库(.so)
add_library( hello_shared SHARED ${LIB_SRC})

#--------------------包含第三方库--------------------#
# 包含Eigen库
# 添加头文件
include_directories( "/usr/include/eigen3" )

include_directories( "${PROJECT_SOURCE_DIR}/include" )

# FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE][[REQUIRED|COMPONENTS] [componets...]])
# REQUIRED 参数,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这个链接库是必备库,如果找不到这个链接库,则工程不能编译
# QUIET 参数,如果不指定这个参数,就会执行:

# 包含Sophus库
# 寻找Sophus库
FIND_PACKAGE( Sophus REQUIRED )
# 添加头文件
include_directories( ${Sophus_INCLUDE_DIRS} )

# 包含OpenCV库
# 寻找OpenCV库
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
   find_package(OpenCV 2.4.3 QUIET)
   if(NOT OpenCV_FOUND)
      message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
   endif()
endif()
# 添加头文件
include_directories( ${OpenCV_INCLUDE_DIRS} )

#最终生成的可执行文件存放在工程顶层目录下的bin文件夹
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 添加一个可执行程序
# 语法:add_executable( 程序名 源代码文件 )
add_executable( useHello  ${PROJECT_SOURCE_DIR}/src/useHello.cpp)
# 将库文件链接到可执行程序上
target_link_libraries( useHello hello_shared
${Sophus_LIBRARIES}
${OpenCV_LIBS})

#最终生成的可执行文件分别放在不同文件夹下
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/bin1)

add_executable( useHello1  ${PROJECT_SOURCE_DIR}/src/useHello.cpp)
target_link_libraries( useHello1 hello_shared
${Sophus_LIBRARIES}
${OpenCV_LIBS})

libHelloSLAM.h(放在include目录下)

#ifndef LIBHELLOSLAM_H_
#define LIBHELLOSLAM_H_
// 上面的宏定义是为了防止重复引用这个头文件而引起的重定义错误

void printHello();

#endif

libHelloSLAM.cpp(放在src/lib_src目录下)

//这是一个库文件
#include <iostream>
using namespace std;

void printHello()
{
    cout<<"Hello SLAM"<<endl;
}

useHello.cpp(放在src目录下)

#include <iostream>
#include "libHelloSLAM.h"
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <sophus/so3.h>
#include <sophus/se3.h>

using namespace std;
using namespace cv;
 
int main( int argc, char** argv )
{
	if(argc<2)
	{
		cout<<"usage: useHello path_to_image"<<endl;
		return -1;
	}

	//使用C++11新特性
	vector<int> nums(10,1);
	for(auto &i : nums)
	{
		cout<<i<<" ";
	}
	cout<<endl;
	
	Mat img=imread(argv[1]);
	imshow("my_img",img);
	waitKey(0);

    printHello();//使用 libHelloSLAM.h 中的 printHello() 函数
    Eigen::Matrix3d Eigen_R = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d(0,0,1)).toRotationMatrix();
    cout<<"rotation from Eigen: "<<endl<<Eigen_R<<endl;
    Sophus::SO3 SO3_R(Eigen_R);
    cout<<"rotation from so3: "<<endl<<SO3_R<<endl;
    return 0;
}

参考:

linux CMakeLists.txt 语法

cmake 常用变量和常用环境变量查表手册

猜你喜欢

转载自blog.csdn.net/A_L_A_N/article/details/82966731