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})
目录
相关文章
|
1月前
|
人工智能 并行计算 安全
从零到一,打造专属AI王国!大模型私有化部署全攻略,手把手教你搭建、优化与安全设置
【10月更文挑战第24天】本文详细介绍从零开始的大模型私有化部署流程,涵盖需求分析、环境搭建、模型准备、模型部署、性能优化和安全设置六个关键步骤,并提供相应的示例代码,确保企业能够高效、安全地将大型AI模型部署在本地或私有云上。
386 7
|
1月前
|
人工智能 安全 网络安全
揭秘!大模型私有化部署的全方位安全攻略与优化秘籍,让你的AI项目稳如磐石,数据安全无忧!
【10月更文挑战第24天】本文探讨了大模型私有化部署的安全性考量与优化策略,涵盖数据安全、防火墙配置、性能优化、容器化部署、模型更新和数据备份等方面,提供了实用的示例代码,旨在为企业提供全面的技术参考。
94 6
|
2月前
|
人工智能 数据安全/隐私保护 UED
RAG让AI大模型更懂业务解决方案部署使用体验
根据指导文档,部署过程得到了详细步骤说明的支持,包括环境配置、依赖安装及代码示例,确保了部署顺利进行。建议优化知识库问题汇总,增加部署失败案例参考,以提升用户体验。整体解决方案阅读与部署体验良好,有助于大型语言模型在特定业务场景的应用,未来可加强行业适应性和用户隐私保护。
66 5
|
1月前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,企业越来越关注大模型的私有化部署。本文详细探讨了硬件资源需求、数据隐私保护、模型可解释性、模型更新和维护等方面的挑战及解决方案,并提供了示例代码,帮助企业高效、安全地实现大模型的内部部署。
84 1
|
1月前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,大模型在各领域的应用日益广泛。然而,将其私有化部署到企业内部面临诸多挑战,如硬件资源需求高、数据隐私保护、模型可解释性差、更新维护成本高等。本文探讨了这些挑战,并提出了优化硬件配置、数据加密、可视化工具、自动化更新机制等解决方案,帮助企业顺利实现大模型的私有化部署。
86 1
|
2月前
|
人工智能 IDE 开发工具
C++中的AI编程助手添加
【10月更文挑战第16天】AI 对我们来说就是一个可靠的编程助手,给我们提供了实时的建议和解决方案,无论是快速修复错误、提升代码质量,或者查找关键文档和资源,AI 作为编程助手都能让你事半功倍。
|
2月前
|
Serverless 数据安全/隐私保护 前端开发
大模型代码能力体验报告之贪吃蛇小游戏《一》:Claude.ai篇 - 生成、预览和快速部署的serverless一条龙
本文介绍了通过Claude.ai生成并优化Web版贪吃蛇游戏的过程,展示了其强大的代码生成功能及用户友好的界面设计。从初始版本的快速生成到根据用户反馈调整游戏速度,再到提供多种实用工具如文件管理、版本控制和一键部署,Claude.ai不仅是一个代码助手,更像是一个全面的serverless开发平台。文中还呼吁国内厂商关注此类技术的发展。
|
机器学习/深度学习 人工智能 自然语言处理
用AI实现C++、Java、Python代码互译,运行成功率最高达80.9%
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 还记得美国前一阵要招聘60岁的老程序员吗?都怪编程语言发展太快! 因为新冠疫情的缘故,美国一些地区的失业救济系统不堪重负,而这些系统都是上古语言COBOL写的。
用AI实现C++、Java、Python代码互译,运行成功率最高达80.9%
|
17天前
|
机器学习/深度学习 人工智能 算法
AI技术在医疗诊断中的应用及前景展望
本文旨在探讨人工智能(AI)技术在医疗诊断领域的应用现状、挑战与未来发展趋势。通过分析AI技术如何助力提高诊断准确率、缩短诊断时间以及降低医疗成本,揭示了其在现代医疗体系中的重要价值。同时,文章也指出了当前AI医疗面临的数据隐私、算法透明度等挑战,并对未来的发展方向进行了展望。
|
24天前
|
机器学习/深度学习 人工智能 自然语言处理
当前AI大模型在软件开发中的创新应用与挑战
2024年,AI大模型在软件开发领域的应用正重塑传统流程,从自动化编码、智能协作到代码审查和测试,显著提升了开发效率和代码质量。然而,技术挑战、伦理安全及模型可解释性等问题仍需解决。未来,AI将继续推动软件开发向更高效、智能化方向发展。