cmake使用方法

1.安装cmake

下载cmake对应代码包,并解压
wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz
tar -zxvf cmake-3.21.3.tar.gz
编译及安装:
cd cmake-3.21.3/
./bootstrap --prefix=/usr/local/cmake     #apt-get install libssl-dev
make -j 16
sudo make install
配置:
sudo mv /usr/bin/cmake  /usr/bin/cmake-3.16  #原始的cmake
sudo ln -s /usr/local/cmake/bin/cmake /usr/bin/cmake  

2.基本使用方法:

1.编一个简单的onnxruntime_model.cpp

cmake_minimum_required(VERSION 3.16)
project(name)

# 设置编译器标志
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 设置 ONNX Runtime 的路径
set(ONNXRUNTIME_INCLUDE_PATH "onnxruntime-linux-x64-1.9.0/include")
set(ONNXRUNTIME_LIBRARY_PATH "onnxruntime-linux-x64-1.9.0/lib")

# 添加可执行文件
add_executable(runmodel  onnxruntime_model.cc)

# 添加包含头文件
target_include_directories(runmodel  PRIVATE ${ONNXRUNTIME_INCLUDE_PATH})

# 添加链接库
target_link_directories(runmodel  PRIVATE ${ONNXRUNTIME_LIBRARY_PATH})
target_link_libraries(runmodel  PRIVATE onnxruntime)

# 设置可执行文件的输出路径为 bin 文件夹
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 将构建类型设置为 Debug, Release
set(CMAKE_BUILD_TYPE Debug)

2.多个源文件打包

cmake_minimum_required(VERSION 3.16)
project(FBANK CXX C)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)


# 该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。这个目的是为了减少源文件引入头文件时候,路径太多的原因;
# 比如:如果不使用include_directories,则feature-fbank.cc引入头文件只能是src/feat/feature-fbank.h, 如果设置
# include_directories(${PROJECT_SOURCE_DIR}, src/feat),则 feature-fbank.cc引入头文件可以是feature-fbank.h
include_directories(${PROJECT_SOURCE_DIR})

####################添加源文件位置:选择其一#######################
# 方法一:使用set,将源文件添加到sources中,优点是可以选择性的添加源文件
set(sources
  src/feat/feature-fbank.cc
  src/feat/feature-functions.cc
  src/feat/feature-window.cc
  src/feat/fftsg.c
  src/feat/mel-computations.cc
  src/feat/online-feature.cc
  src/feat/rfft.cc
)
# 方法二:使用aux_source_directory,直接批量添加,使用aux_source_directory把src/feat/目录下的源文件存列表存放到变量sources里;
aux_source_directory(src/feat/ sources)

# 设置开关
option(KALDI_NATIVE_FBANK_ENABLE_CHECK "Enable check" ON)
# 添加新的源文件
if(KALDI_NATIVE_FBANK_ENABLE_CHECK)
  list(APPEND sources src/feat/log.cc)
endif()

# 设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

# 设置动态库输出路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

#####################生成可执行文件:两种方法选一个#########################
# 方法一:使用动态/静态库方式,打包一起
add_library(kaldi-native-fbank-core SHARED  ${sources})
add_executable(test-online-feature src/bin/test-online-feature.cc)  
target_link_libraries(test-online-feature kaldi-native-fbank-core)

# 方法二: 可以将多个源文件打包一起
add_executable(test-online-feature src/bin/test-online-feature.cc ${sources})  

3.1 进阶使用方法-add_subdirectory

在这里插入图片描述

CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project (demo)
add_subdirectory (src)

add_subdirectory:这个语句的作用是增加编译子目录。其基本语法格式是:

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

一共有三个参数,后两个是可选参数.

source_dir 源代码目录

指定一个包含CMakeLists.txt和代码文件所在的目录,该目录可以是绝对路径,也可以是相对路径,对于后者相对路径的起点是CMAKE_CURRENT_SOURCE_DIR。此外,如果子目录再次包含的CMakeLists.txt,则将继续处理里层的CMakeLists.txt,而不是继续处理当前源代码。

binary_dir 二进制代码目录

这个目录是可选的,如果指定,cmake命令执行后的输出文件将会存放在此处,若没有指定,默认情况等于source_dir没有进行相对路径计算前的路径,也就是CMAKE_BINARY_DIR。

EXCLUDE_FROM_ALL标记

这个标志是可选的,如果传递了该参数表示新增加的子目录将会排除在ALL目录之外(可能是make系统中的make all?),表示这个目录将从IDE的工程中排除。用户必须显式在子文件这个编译目标(手动cmake之类的)。指定了这个文件夹,表示这个文件夹是独立于源工程的,这些函数是有用但是不是必要的,比如说我们一系列的例子。

add_subdirectory 这个命令用于添加源文件子目录,同时还可以指定中间二进制和目标二进制的生成路径。EXCLUDE_FROM_ALL将会将这个目录从编译中排除,如工程的例子需要等待其他编译完成后再进行单独的编译。通常子目录应该包含自己的project()命令,这样以来整个编译命令将会产生各自的目标文件。如果把CMakeLists.txt与VS IDE比较,总的CMakeLists.txt就相当于解决方案,子CMakeLists.txt就相当于在解决方案下的工程文件。还有一个需要注意的是,如果编译父CMakeLists时依赖了子CMakeLists.txt中的源文件,那么该标志将会被覆盖(也就是也会处理),以满足编译任务。

这里指定src目录下存放了源文件,当执行cmake时,就会进入src目录下去找src目录下的CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt,内容如下:

src/CMakeLists.txt

aux_source_directory (. SRC_LIST)
include_directories (../include)
add_executable (main ${SRC_LIST})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

这里的set其实是和前面的一样,只是EXECUTABLE_OUTPUT_PATH是个系统自带的预定义变量,其意义如下:

EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置

PROJECT_SOURCE_DIR:工程的根目录

所以,这里set的意思是把存放可执行文件的位置设置为工程根目录下的bin目录。(cmake有很多预定义变量,详细的可以网上搜索一下)

添加好以上这2个CMakeLists.txt后,整体文件结构如下:

3.2 进阶用法-编译动态库和静态库

有时只需要编译出动态库和静态库,然后等着让其它程序去使用。让我们看下这种情况该如何使用cmake。

在这里插入图片描述

cmake_minimum_required(VERSION 3.16)
project (demo)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/testFunc/testFunc.c)
add_library (testFunc_shared SHARED ${SRC_LIST})
add_library (testFunc_static STATIC ${SRC_LIST})
set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

这里又出现了新的命令和预定义变量:

add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)

set_target_properties: 设置最终生成的库的名称,还有其它功能,如设置库的版本号等

LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录

PS:前面使用set_target_properties重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称,只是连续2次使用add_library指定库名称时(第一个参数),这个名称不能相同,而set_target_properties可以把名称设置为相同,只是最终生成的库文件后缀不同(一个是.so,一个是.a),这样相对来说会好看点。

# 运行查看
cd build/
cmake ..
make
cd ../lib/
ls

在这里插入图片描述

生成了库,进行链接测试下,新增main.c文件,该文件头文件会调用生成的库文件
在这里插入图片描述

cmake_minimum_required(VERSION 3.16)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
# find testFunc.h
include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc)
find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
add_executable (main ${SRC_LIST})
target_link_libraries (main ${TESTFUNC_LIB})

这里出现2个新的命令,

find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档

target_link_libraries: 把目标文件与库文件进行链接

使用find_library的好处是在执行cmake …时就会去查找库是否存在,这样可以提前发现错误,不用等到链接时。

ps:在lib目录下有testFunc的静态库和动态库,find_library(TESTFUNC_LIB testFunc

…默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成find_library(TESTFUNC_LIB

libtestFunc.so …或者find_library(TESTFUNC_LIB libtestFunc.a …

ps: 查看文件使用了哪些库,可以使用readelf -d ./xx来查看 例:readelf -d ./main 【ELF (Executable and Linkable Format)文件,也就是在 Linux 中的目标文件】

3.3进阶用法-条件编译

# 有时编译程序时想添加一些编译选项,如-Wall,-std=c++11等,就可以使用add_compile_options来进行操作。
add_compile_options(-std=c++11 -Wall)

添加编译选项

有时希望在编译代码时只编译一些指定的源码,可以使用cmake的option命令,主要遇到的情况分为2种:

本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件

对于同一个bin文件,只想编译其中部分代码(使用宏来控制)
在这里插入图片描述
假设我们现在的工程会生成2个bin文件,main1和main2,项目结构如下:

cmake_minimum_required(VERSION 3.16)
project(demo)
option(MYDEBUG "enable debug compilation" OFF)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_subdirectory(src)

这里使用了option命令,其第一个参数是这个option的名字,第二个参数是字符串,用来描述这个option是来干嘛的,第三个是option的值,ON或OFF,也可以不写,不写就是默认OFF。

然后编写src目录下的CMakeLists.txt,如下:

cmake_minimum_required(VERSION 3.16)
add_executable(main1 main1.c)
if (MYDEBUG)
    add_executable(main2 main2.c)
else()
    message(STATUS "Currently is not in debug mode")    
endif()

注意,这里使用了if-else来根据option来决定是否编译main2.c ;
然后cd到build目录下输入cmake … && make就可以只编译出main1,如果想编译出main2,就把MYDEBUG设置为ON,再次输入cmake … && make重新编译。

每次想改变MYDEBUG时都需要去修改CMakeLists.txt,有点麻烦,其实可以通过cmake的命令行去操作,例如我们想把MYDEBUG设置为OFF,先cd到build目录,然后输入cmake … -DMYDEBUG=ON,这样就可以编译出main1和main2 (在bin目录下)

编译部分代码

在这里插入图片描述

假设我们有个main.c,其内容如下:

#include <stdio.h>
int main(void)
{
#ifdef WWW1
    printf("hello world1\n");
#endif    
#ifdef WWW2     
    printf("hello world2\n");
#endif
    return 0;
}

可以通过定义宏来控制打印的信息,我们CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.16)
project(demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)
if (WWW1)
    add_definitions(-DWWW1)
endif()
if (WWW2)
    add_definitions(-DWWW2)
endif()
add_executable(main main.c)

这里把option的名字保持和main.c里的宏名称一致,这样更加直观,也可以选择不同的名字。通过与add_definitions()的配合,就可以控制单个bin文件的打印输出了。

cd到build目录下执行cmake … && make,然后到bin目录下执行./main,可以看到打印为空,

接着分别按照下面指令去执行,然后查看打印效果,

cmake … -DWWW1=ON -DWWW2=OFF && make

cmake … -DWWW1=OFF -DWWW2=ON && make

cmake … -DWWW1=ON -DWWW2=ON && make

这里有个小坑要注意下:假设有2个options叫A和B,先调用cmake设置了A,下次再调用cmake去设置B,如果没有删除上次执行cmake时产生的缓存文件,那么这次虽然没设置A,也会默认使用A上次的option值。

所以如果option有变化,要么删除上次执行cmake时产生的缓存文件,要么把所有的option都显式的指定其值。

3.3 进阶用法-FetchContent

功能:外部导入外部库。FetchContent 是 3.11.0 版本开始提供的功能,只需要一个 URL 或者 Git 仓库即可引入一个库。

使用方法

include(FetchContent) :表示引入 FetchContent。
FetchContent_Declare(第三方库) :获取第三方库,可以是一个 URL 或者一个 Git 仓库。
FetchContent_MakeAvailable(第三方库) :将这个第三方库引入项目。
target_link_libraries(主项目 PRIVATE 子模块::子模块) :链接这个第三方库。

cmake_minimum_required(VERSION 3.16)
project(my_project)

# GoogleTest requires at least C++11
set(CMAKE_CXX_STANDARD 11)

include(FetchContent)
FetchContent_Declare(
  googletest
  URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值