CMake

(注:CMake 支持大写、小写和混合大小写命令,但首选小写命令)

当多个⼈⽤不同的语⾔或者编译器开发⼀个项⽬,最终要输出⼀个可执⾏⽂件或者共享库(dll,so等等)

编译器是翻译代码为计算机语言的一个工具,我们平时写的代码如果想在某个特定的计算机上执行(计算机的cpu构架不同),就需要编译器来对代码进行编译汇编链接,而汇编和链接的过程对于每个不同的平台上过程都不一样。

gcc和clang是两个不同的编译器,而make和cmake是搭配编译器来方便用户进行多文件编译而发明的工具。

cmake工具,可以更加方便地生成makefile文件给make用。cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,无需自己根据每个平台的不同特性去修改。而cmake根据什么生成makefile,它需要根据CMakeLists.txt文件去生成makefile。

同一目录下main.cpp和CMakeLists.txt两个文件

main.cpp

#include <iostream>

int main(){
std::cout << "hello word" << std::endl;
}

CMakeLists.txt

PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

使用命令:cmake .. 后生成如下文件

⽬录下⽣成了这些⽂件-CMakeFiles, CMakeCache.txt, cmake_install.cmake 等⽂件,并且⽣成了Makefile。

使用命令:make

root@localhost cmake]# make
Scanning dependencies of target hello
[100%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
Linking CXX executable hello
[100%] Built target hello

最终⽣成了Hello的可执⾏程序

——————————————————————————————————————————

PROJECT关键字

可以⽤来指定⼯程的名字和⽀持的语⾔,默认⽀持所有语⾔

PROJECT (HELLO) 指定了⼯程的名字,并且⽀持所有语⾔—建议

PROJECT (HELLO CXX) 指定了⼯程的名字,并且⽀持语⾔是C++

PROJECT (HELLO C CXX) 指定了⼯程的名字,并且⽀持语⾔是C和C++

该指定隐式定义了两个CMAKE的变量

xx_BINARY_DIR,本例中是 HELLO_BINARY_DIR

xx_SOURCE_DIR,本例中是 HELLO_SOURCE_DIR

MESSAGE关键字就可以直接使⽤者两个变量,当前都指向当前的⼯作⽬录,后⾯会讲外部编译

问题:如果改了⼯程名,这两个变量名也会改变

解决:⼜定义两个预定义变量:PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,这两个变量和

HELLO_BINARY_DIR,HELLO_SOURCE_DIR是⼀致的。所以改了⼯程名也没有关系

——————————————————————————————————————————

SET关键字

⽤来设置变量

SET(SRC_LIST xx)

  • set指令不加PARENT_SCOPE 则修改的是当前CMakeLists的变量的值;

  • set指令加PARENT_SCOPE 则修改的是上一级目录中CMakeLists的变量的值,而当前CMakeLists中该变量的值不变。

——————————————————————————————————————————

MESSAGE关键字

向终端输出⽤户⾃定义的信息

主要包含三种信息:

  1. SEND_ERROR,产⽣错误,⽣成过程被跳过。

  1. SATUS,输出前缀为—的信息。

  1. FATAL_ERROR,⽴即终⽌所有 cmake 过程

include()

.cmake 文件是模块文件,可以被include到CMakeList.txt中

——————————————————————————————————————————

ADD_EXECUTABLE关键字

⽣成可执⾏⽂件

ADD_EXECUTABLE(hello ${SRC_LIST}) ⽣成的可执⾏⽂件名是hello,源⽂件读取变量SRC_LIST中的内容

也可以直接写 ADD_EXECUTABLE(hello main.cpp)

上述例⼦可以简化的写成

PROJECT(HELLO)

ADD_EXECUTABLE(hello main.cpp)

注意:⼯程名的 HELLO 和⽣成的可执⾏⽂件 hello 是没有任何关系的

语法的基本原则

变量使⽤${}⽅式取值


内部构建和外部构建

上述例⼦就是内部构建,他⽣产的临时⽂件特别多,不⽅便清理

外部构建,就会把⽣成的临时⽂件放在build⽬录下,不会对源⽂件有任何影响强烈使⽤外部构建⽅式

外部构建方式举例

1、当前⽬录下建⽴⼀个build⽬录

2、进⼊build,运⾏cmake .. ,当然..表示上⼀级⽬录,你可以写CMakeLists.txt所在的绝对路径,⽣产的⽂件都在build⽬录下了

3、在build⽬录下,运⾏make来构建⼯程

注意外部构建的两个变量

1、HELLO_SOURCE_DIR 还是⼯程路径

2、HELLO_BINARY_DIR 编译路径 也就是 /root/cmake/bulid

让Hello World看起来更像⼀个⼯程

为⼯程添加⼀个⼦⽬录 src,⽤来放置⼯程源代码

添加⼀个⼦⽬录 doc,⽤来放置这个⼯程的⽂档 hello.txt

在⼯程⽬录添加⽂本⽂件 COPYRIGHT, README

在⼯程⽬录添加⼀个 runhello.sh 脚本,⽤来调⽤ hello ⼆进制

将构建后的⽬标⽂件放⼊构建⽬录的 bin ⼦⽬录

将 doc ⽬录 的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/

将⽬标⽂件放⼊构建⽬录的 bin ⼦⽬录

每个⽬录下都要有⼀个CMakeLists.txt说明

[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
└── src
  ├── CMakeLists.txt
  └── main.cpp

外层CMakeLists.txt

PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)

src下的CMakeLists.txt

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY 指令

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令⽤于向当前⼯程添加存放源⽂件的⼦⽬录,并可以指定中间⼆进制和⽬标⼆进制存放的位置

EXCLUDE_FROM_ALL函数是将写的⽬录从编译中排除,如程序中的example

ADD_SUBDIRECTORY(src bin)

将 src ⼦⽬录加⼊⼯程并指定编译输出(包含编译中间结果)路径为bin ⽬录

如果不进⾏ bin ⽬录的指定,那么编译结果(包括中间结果)都将存放在build/src ⽬录

静态库和动态库的构建

任务:

1,建⽴⼀个静态库和动态库,提供 HelloFunc 函数供其他程序编程使⽤,HelloFunc 向终端输出 Hello World 字

符串。

2,安装头⽂件与共享库。

静态库和动态库的区别

静态库的扩展名⼀般为“.a”或“.lib”;动态库的扩展名⼀般为“.so”或“.dll”。

静态库在编译时会直接整合到⽬标程序中,编译成功的可执⾏⽂件可独⽴运⾏

动态库在编译时不会放到连接的⽬标程序中,即可执⾏⽂件⽆法单独运⾏。

wenet例子

cmake_minimum_required(VERSION 3.4.1)
set(TARGET wenet)
project(${TARGET} CXX)
set(CMAKE_CXX_STANDARD 14)
include(ExternalProject)

option(TORCH "whether to build with Torch" ON)
option(ONNX "whether to build with ONNX" OFF)
set(CMAKE_VERBOSE_MAKEFILE on)
set(build_DIR ${CMAKE_SOURCE_DIR}/../../../build)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
string(REPLACE "-Wl,--exclude-libs,libgcc_real.a" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")

#include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
#将指定目录添加到编译器的头文件搜索路径之下,指定目录被解释为当前源码路径的相对路径。
#[AFTER|BEFORE]定义了追加指定目录的方式在头还是尾。[SYSTEM]告诉编译器在一些平台上指定目录被当作系统头文件目录。


#include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>] [NO_POLICY_SCOPE])
#从指定的文件加载、运行CMake代码。如果指定文件,则直接处理。
#如果指定module,则寻找module.cmake文件,首先在${CMAKE_MODULE_PATH}中寻找,然后在CMake的module目录中查找。
include(libtorch)
include(openfst)

include_directories(
  ${CMAKE_SOURCE_DIR}
  ${CMAKE_SOURCE_DIR}/kaldi
)

#将子目录添加到构建系统中。source_dir指定一个目录,其中存放CMakeLists.txt文件和代码文件。
#binary_dir指定的目录存放输出文件,如果没有指定则使用source_dir。
add_subdirectory(utils)
add_subdirectory(frontend)
add_subdirectory(post_processor)
add_subdirectory(kaldi)  # kaldi: wfst based decoder
add_subdirectory(decoder)

link_libraries(frontend decoder android)

#add_library根据源码来生成一个库供他人使用。${TARGET}是个逻辑名称,在项目中必须唯一。
#STATIC指静态库,SHARED指动态库,wenet.cc(MODULE)指在运行期通过函数动态加载。
add_library(${TARGET} SHARED wenet.cc)

add_executable(decoder_main bin/decoder_main.cc)

#为目标文件链接依赖的库。PUBLIC修饰的库或目标会被链接,并成为链接接口的一部分。
#PRIVATE修饰的目标或库会被链接,但不是链接接口的一部分。INTERFACE修饰的库会追加到链接接口中,但不会用来链接目标文件<target>。
target_link_libraries(decoder_main PUBLIC libc++_shared.so)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值