C/C++编译工具:cmake | AI工程化部署

简介: CMake 是一个跨平台的开源构建工具,用于管理软件构建流程。它使用一个名为 CMakeLists.txt 的文本文件来描述构建过程。【1月更文挑战第4天】

1.基本使用

CMake 是一个跨平台的开源构建工具,用于管理软件构建流程。它使用一个名为 CMakeLists.txt 的文本文件来描述构建过程。以下是一个简单的 CMakeLists.txt 文件的示例,用于构建一个简单的 C++ 程序:

# 指定 CMake 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 指定项目名称
project(MyProject)

# 指定生成可执行文件
add_executable(my_program main.cpp)

在这个示例中,我们指定了 CMake 的最低版本要求,并且指定了项目的名称。然后,我们使用 add_executable 命令来告诉 CMake 创建一个名为 my_program 的可执行文件,该可执行文件由 main.cpp 文件构建而成。

为了使用 CMake 构建项目,我们需要执行以下步骤:

  1. 创建一个 CMakeLists.txt 文件来描述构建过程。
  2. 在项目根目录下创建一个 build 文件夹,并进入该文件夹。
  3. 运行 cmake 命令来生成构建系统所需的文件。例如:cmake ..
  4. 运行生成的构建系统,例如使用 make 命令进行构建。

通过这些步骤,CMake 将会根据 CMakeLists.txt 文件生成相应的构建系统文件,并且帮助我们完成项目的构建过程。

2.基本语法

  command(arg1 arg2 ...) # 运行命令
  set(var_name var_value) # 定义变量,或者给已经存在的变量赋值
  command(arg1 ${var_name}) # 使用变量

  # 控制语句
  IF(expression) COMMAND1(ARGS)
  ELSE(expression) COMMAND2(ARGS)
  ENDIF(expression)

  # expression
  IF(var) # 不是空, 0, N, NO, OFF, FALSE, NOTFOUND 或 _NOTFOUND时,为真
  IF(NOT var) # 与上述条件相反。
  IF(var1 AND var2) # 当两个变量都为真是为真。
  IF(var1 OR var2) # 当两个变量其中一个为真时为真。
  IF(COMMAND cmd) # 当给定的cmd确实是命令并可以调用是为真
  IF(EXISTS dir) # 目录名存在
  IF(EXISTS file) # 文件名存在
  IF(IS_DIRECTORY dirname) # 当dirname是目录
  IF(file1 IS_NEWER_THAN file2) # 当file1比file2新,为真
  IF(variable MATCHES regex) # 符合正则

  # 循环
  WHILE(condition) COMMAND1(ARGS) // ...
  ENDWHILE(condition)

  AUX_SOURCE_DIRECTORY(. SRC_LIST)
  FOREACH(one_dir ${SRC_LIST}) MESSAGE(${one_dir})
  ENDFOREACH(onedir)

基本操作

  • add_library: 指定的源文件(CPP文件)生成链接文件,然后添加到工程中去。生成动态库或者静态库

    add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])
    
    add_library(mod1 SHARED mod1.c mod1_func.c) # 生成动态库 libmod1.so
    add_library(mod2 STATIC mod2.c) # 生成静态库 libmod2.a
    
  • add_subdirectory: 在子文件夹添加了library或者executable之后,在上层目录添加subdirectory, 也可以在同一个CMakeList.txt中使用
  • target_link_libraries: 设置要链接的库文件的名称 具体的动态链接库文件.so, 在生成的可执行文件或动态库中连接进去其他的库
    target_link_libraries(<target> [item1 [item2 [...]]]
                        [[debug|optimized|general] <item>] ...)
    target_link_libraries(main mod1)
    
  • include_directories: 添加头文件目录 g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用
  • link_directories 添加需要链接的库文件目录。 它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用
  • link_libraries 添加需要链接的库文件路径

下面是一个使用 CMake 构建的示例,其中包括了 target_link_libraries,link_directories,include_directories,add_executable 和 add_library 等关键部分,以生成一个可执行文件和一个动态库。

cmake_minimum_required(VERSION 3.5)

project(MyProject)

# 设置编译选项
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Ofast -Wfatal-errors -pthread -fPIC -O3 -mavx")

# 添加动态库的源文件
set(SOURCE_FILES_LIB mylib.cpp)
add_library(mylib SHARED ${SOURCE_FILES_LIB})

# 添加可执行文件的源文件
set(SOURCE_FILES main.cpp)

# 添加包含目录
include_directories(include)

# 添加链接目录
link_directories(${CMAKE_SOURCE_DIR}/lib)

# 添加可执行文件
add_executable(myapp ${SOURCE_FILES})

# 链接动态库
target_link_libraries(myapp mylib)

假设项目的目录结构如下所示:

MyProject/
├── CMakeLists.txt
├── include/
│   └── mylib.h
├── src/
│   ├── main.cpp
│   └── mylib.cpp
└── lib/
    └── libmylib.so

在项目根目录中执行以下命令来生成构建文件和编译项目:

mkdir build
cd build
cmake ..
make

这将生成一个名为 myapp 的可执行文件和一个名为 libmylib.so 的动态库。

3.指定安装目录

我们进行cmake命令,会执行make命令进行编译,最后如果有需要的话会执行make install将编译好的库或者头文件安装到指定的未知。

在CMake中,可以使用install命令来设置安装相关信息,包括安装目标、安装路径等。以下是一个详细的例子,展示了如何在CMake中设置安装相关信息:

cmake_minimum_required(VERSION 3.10)

project(MyProject)

# 添加可执行文件
add_executable(MyExecutable main.cpp)

# 设置安装路径
set(CMAKE_INSTALL_PREFIX /usr/local)  # 安装到/usr/local目录下

# 安装可执行文件
install(TARGETS MyExecutable
        DESTINATION bin)  # 将可执行文件安装到bin目录下

# 安装头文件
file(GLOB HEADER_FILES "*.h")
install(FILES ${HEADER_FILES}
        DESTINATION include/myproject)  # 将头文件安装到include/myproject目录下

# 安装额外文件
install(FILES README.md
        DESTINATION share/myproject)  # 将README.md文件安装到share/myproject目录下

在上面的例子中,我们首先使用add_executable命令添加了一个可执行文件MyExecutable。然后使用set命令设置了安装路径为/usr/local。接下来使用install命令分别安装了可执行文件、头文件和额外文件到指定的安装路径下。

需要注意的是,安装路径可以根据实际需要进行调整。在使用CMake时,可以根据具体的项目需求来设置不同的安装路径和安装目标。

4.区分开发版与发布版

在CMake中,可以通过MAKE_BUILD_TYPE在确定不通类型的棒棒,常用的构建类型包括Debug、Release、MinSizeRel和RelWithDebInfo。

举例来说,假设我们有一个CMakeLists.txt文件,其中需要根据不同的构建类型来设置编译选项。我们可以使用MAKE_BUILD_TYPE来指定构建类型,然后根据不同的构建类型来设置不同的编译选项。

cmake_minimum_required(VERSION 3.10)

project(MyProject)

# 根据构建类型设置编译选项
if (MAKE_BUILD_TYPE STREQUAL "Debug")
    add_definitions(-DDEBUG)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
elseif (MAKE_BUILD_TYPE STREQUAL "Release")
    add_definitions(-DNDEBUG)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif()

# 添加源文件
add_executable(MyExecutable main.cpp)

在上面的例子中,根据不同的构建类型,我们设置了不同的预处理宏和编译选项。当构建类型为Debug时,会定义DEBUG宏并启用调试信息;当构建类型为Release时,会定义NDEBUG宏并开启优化。

这样我们就可以main.cpp中,通过条件编译的方式,确定是哪些debug模型的需要编译的,而在release发布版本不需要编译,形如:

#ifndef NDEBUG 
    printf("author: %s, release_date: %s\n", AUTHOR, RELEASE_DATE ); // 只在开发版本编译
#endif
cmake -DMAKE_BUILD_TYPE=Debug ..
cmake -DMAKE_BUILD_TYPE=Release ..

5.大杀器find_package

find_package是CMake中用于查找和加载第三方库的命令。它用于在系统中查找指定的软件包,并将其路径或库的相关信息导入到CMake中,以便在项目中使用。

要配置find_package,你需要在CMakeLists.txt文件中使用find_package命令,并提供要查找的软件包的名称。通常情况下,你还需要指定软件包的版本号。

下面是一个使用find_package的简单例子:

假设你想在CMake项目中使用OpenCV,你需要在CMakeLists.txt文件中添加以下内容:

# 查找OpenCV包
find_package(OpenCV 4.0 REQUIRED)

# 如果找到OpenCV包,将其包含路径和链接库添加到项目中
if(OpenCV_FOUND)
    include_directories(${OpenCV_INCLUDE_DIRS})
    target_link_libraries(your_project_name ${OpenCV_LIBS})
endif()

find_package语法为:FIND_PACKAGE( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )

在这个例子中,find_package命令用于查找OpenCV 4.0,并将其导入到项目中。如果找到了OpenCV包,将其包含路径添加到项目的include路径中,并将其链接库添加到项目的链接库中。

请注意,在实际项目中,你可能还需要根据你的项目结构和依赖项的不同做一些适当的调整。

那find_package怎么知道从哪里去查找相关依赖库呢?
查找的目录路径:

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH

其中,PATH中的路径如果以bin或sbin结尾,则自动回退到上一级目录。
找到根目录后,cmake会检查这些目录下的

<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/          (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/                (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/  (U)
cmake找到这些目录后,会开始依次找<package>Config.cmake或Find<package>.cmake文件。找到后即可执行该文件并生成相关链接信息。

最重要的一个是PATH。由于/usr/bin/在PATH中,cmake会自动去/usr/(lib/<arch>|lib|share)/cmake/<name>*/寻找模块
另外一个比较重要的是<package>_DIR。我们可以在调用cmake时将这个目录传给cmake。由于其优先级最高,因此cmake会优先从该目录中寻找,这样我们就可以随心所欲的配置cmake使其找到我们希望它要找到的包。而且除上述指定路径外,cmake还会直接进入<package>_DIR下寻找。如我在3rd_parties目录下编译了一个OpenCV,那么执行cmake时可以使用

OpenCV_DIR=../../3rd-party/opencv-3.3.4/build/ cmake ..

6.多个CMakeLists.txt

在一个复杂的项目中,通常会以模块化的方式来组织项目的框架,统一一个如main.cpp做为入口程序(如ffmpeg)。那么如果所有的程序的编译信息都写在一个CMakeLists.txt会很难维护。cmake里运行多个CMakeLists.txt,每个模块有自己的CMakeList负责编译。如下面的结构

  .
  ├── build
  │   ├── CMakeCache.txt
  │   ├── CMakeFiles
  │   ├── cmake_install.cmake
  │   ├── lib
  │   │   ├── libmod1.so
  │   │   └── mo2_lib
  │   │       ├── libmod2.a
  │   │       └── Makefile
  │   └── Makefile
  ├── CMakeLists.txt
  ├── main.c
  └── mod1
      ├── CMakeLists.txt
      ├── mod1.c
      ├── mod1_func.c
      ├── mod1_func.h
      ├── mod1.h
      └── mod2
          ├── CMakeLists.txt
          ├── mod2.c
          └── mod2.h

具体的,当使用CMake构建一个项目时,add_subdirectory命令可以用来包含子目录中的CMakeLists.txt文件,从而将子目录中的源代码文件添加到主项目中。下面是一个使用add_subdirectory的简单示例:

假设我们有以下项目目录结构:

project/
    CMakeLists.txt
    main.cpp
    subdirectory/
        CMakeLists.txt
        helper.cpp
        helper.h

在主项目的 CMakeLists.txt 文件中,可以包含子目录的 CMakeLists.txt 文件使用 add_subdirectory 命令。示例如下:

# 主项目的 CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(MyProject)

add_executable(my_app main.cpp)

# 包含subdirectory中的CMakeLists.txt
add_subdirectory(subdirectory)

# 将子目录中的源文件添加到主项目中
target_sources(my_app PRIVATE subdirectory/helper.cpp)

在子目录的 CMakeLists.txt 文件中,可以定义子目录中的源文件,示例如下:

# 子目录的 CMakeLists.txt

# 将子目录中的源文件添加到一个库中
add_library(helper_lib helper.cpp helper.h)

在这个例子中,add_subdirectory命令被用来引入子目录中的CMakeLists.txt文件,并将子目录中的源文件添加到主项目中。

7.打印信息

cmake可以通过message来打印一些调试信息

    cmake_minimum_required(VERSION 2.8)
    project(find_package_learning)
    find_package(OpenCV 3 REQUIRED)

    message(STATUS "OpenCV_DIR = ${OpenCV_DIR}")
    message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
    message(STATUS "OpenCV_LIBS = ${OpenCV_LIBS}")

    include_directories(${OPENCV_INCLUDE_DIRS})  
    add_executable(opencv_test opencv_test.cpp)  
    target_link_libraries(opencv_test ${OpenCV_LIBS})
目录
相关文章
|
19天前
|
人工智能 弹性计算 JSON
AI大模型复习“搭子”—部署流程演示
本文主要介绍文档智能,介绍利用大模型构建知识库和AI学习助手的部署流程,主要包括以下几方面的内容: 1.什么是文档智能 2.文档智能 & RAG 3.基于文档智能和百炼平台的RAG应用案例
|
19天前
|
人工智能 安全 Java
AI 应用工程化专场
本次分享的主题是AI 应用工程化专场,由Spring AI Alibaba 开源项目负责人刘军分享。 1. 初识 Spring AI Alibaba开源项目 2. Spring AI Alibaba 深入讲解 3. Spring AI Alibaba RAG 开发实践 4. Spring AI Allbaba 未来规划 5. 数据 6. 问答
|
28天前
|
人工智能 物联网
如何将Together AI上基于Qwen2-7B训练的模型部署到ModelScope平台
如何将Together AI上基于Qwen2-7B训练的模型部署到ModelScope平台
64 10
|
2月前
|
人工智能 数据库连接 API
在部署《主动式智能导购 AI 助手构建》解决方案的过程中,整体体验还是相对顺畅的,但确实遇到了一些问题,文档提供的引导也有所不足,以下是详细的体验评估
在部署《主动式智能导购 AI 助手构建》解决方案的过程中,整体体验还是相对顺畅的,但确实遇到了一些问题,文档提供的引导也有所不足,以下是详细的体验评估
|
28天前
|
存储 人工智能 Serverless
7分钟玩转 AI 应用,函数计算一键部署 AI 生图大模型
人工智能生成图像(AI 生图)的领域中,Stable Diffusion WebUI 以其强大的算法和稳定的输出质量而闻名。它能够快速地从文本描述中生成高质量的图像,为用户提供了一个直观且高效的创作平台。而 ComfyUI 则以其用户友好的界面和高度定制化的选项所受到欢迎。ComfyUI 的灵活性和直观性使得即使是没有技术背景的用户也能轻松上手。本次技术解决方案通过函数计算一键部署热门 AI 生图大模型,凭借其按量付费、卓越弹性、快速交付能力的特点,完美实现低成本,免运维。
|
2月前
|
人工智能 缓存 异构计算
云原生AI加速生成式人工智能应用的部署构建
本文探讨了云原生技术背景下,尤其是Kubernetes和容器技术的发展,对模型推理服务带来的挑战与优化策略。文中详细介绍了Knative的弹性扩展机制,包括HPA和CronHPA,以及针对传统弹性扩展“滞后”问题提出的AHPA(高级弹性预测)。此外,文章重点介绍了Fluid项目,它通过分布式缓存优化了模型加载的I/O操作,显著缩短了推理服务的冷启动时间,特别是在处理大规模并发请求时表现出色。通过实际案例,展示了Fluid在vLLM和Qwen模型推理中的应用效果,证明了其在提高模型推理效率和响应速度方面的优势。
云原生AI加速生成式人工智能应用的部署构建
|
2月前
|
人工智能 API Windows
免费部署本地AI大语言模型聊天系统:Chatbox AI + 马斯克grok2.0大模型(简单5步实现,免费且比GPT4.0更好用)
本文介绍了如何部署本地AI大语言模型聊天系统,使用Chatbox AI客户端应用和Grok-beta大模型。通过获取API密钥、下载并安装Chatbox AI、配置模型,最终实现高效、智能的聊天体验。Grok 2大模型由马斯克X-AI发布,支持超长文本上下文理解,免费且易于使用。
450 0
|
19天前
|
人工智能 运维 物联网
云大使 X 函数计算 FC 专属活动上线!享返佣,一键打造 AI 应用
如今,AI 技术已经成为推动业务创新和增长的重要力量。但对于许多企业和开发者来说,如何高效、便捷地部署和管理 AI 应用仍然是一个挑战。阿里云函数计算 FC 以其免运维的特点,大大降低了 AI 应用部署的复杂性。用户无需担心底层资源的管理和运维问题,可以专注于应用的创新和开发,并且用户可以通过一键部署功能,迅速将 AI 大模型部署到云端,实现快速上线和迭代。函数计算目前推出了多种规格的云资源优惠套餐,用户可以根据实际需求灵活选择。
|
16天前
|
人工智能 算法 前端开发
OmAgent:轻松构建在终端设备上运行的 AI 应用,赋能手机、穿戴设备、摄像头等多种设备
OmAgent 是 Om AI 与浙江大学联合开源的多模态语言代理框架,支持多设备连接、高效模型集成,助力开发者快速构建复杂的多模态代理应用。
151 72
OmAgent:轻松构建在终端设备上运行的 AI 应用,赋能手机、穿戴设备、摄像头等多种设备

热门文章

最新文章