首页 > 其他分享 >cmake 笔记

cmake 笔记

时间:2024-06-20 18:59:20浏览次数:20  
标签:cmake target 笔记 PROJECT CMAKE curl HELLO DIR

一、 一个完整的工程

  给工程起个名字

加上这句:project(hello)

命令:project(<PROJECT-NAME> [LANGUAGES] [<language-name>...])

作用:定义工程名称, 设置几个变量的名字: PROJECT_NAME, PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR, PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR, 高级用法请见参考链接2:CMake命令

  告诉CMake我的构建目标

add_executable(${PROJECT_NAME} ${hello_src})

  让CMake找到我的头文件

target_include_directories(${project_name} PRIVATE
    ${CMAKE_SOURCE_DIR}/include
)

  让CMake找到我的源文件

target_sources(${project_name} PRIVATE
    ${SRC}
    ${QRC}
)

  让CMake找到我的库文件

target_link_directories(${project_name} PRIVATE
    ${Qt_LIBSDIR}
)

  告诉CMake我要链接哪个库文件

set(Qt_LIBS
    Qt5::Core
    Qt5::Gui
    Qt5::Widgets
)

target_link_libraries(${project_name} PRIVATE
    ${Qt_LIBS}
)

  设置编译、连接参数

target_compile_features(${project_name} PRIVATE cxx_std_11)
target_compile_options(${project_name} PRIVATE -g -Wall)
target_link_options(${project_name} PRIVATE -Wl, --warn-unresolved-symbol)

  开始构建

通过以上步骤, 最后,在文件头部添加CMake版本检查,以我的环境为例,我的CMake版本是3.0,那么我在脚本最开始加上:

cmake_minimum_required ( VERSION 3.0)

完整的CMakeLists.txt如下所示:

cmake_minimum_required ( VERSION 3.0)

project(hello)

include_directories(${CMAKE_CURRENT_LIST_DIR}/include)

link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)

aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src ${hello_src})

add_executable(${PROJECT_NAME} ${hello_src})

target_link_libraries(${PROJECT_NAME} util)

set(CMAKE_CXX_COMPILER      "clang++" )         # 显示指定使用的C++编译器

set(CMAKE_CXX_FLAGS   "-std=c++11")             # c++11
set(CMAKE_CXX_FLAGS   "-g")                     # 调试信息
set(CMAKE_CXX_FLAGS   "-Wall")                  # 开启所有警告

set(CMAKE_CXX_FLAGS_DEBUG   "-O0" )             # 调试包不优化
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG " )   # release包优化

  构建动态库、静态库

如果要构建动态库,将 add_executable(${PROJECT_NAME} ${hello_src}) 替换为 ADD_LIBRARY(${PROJECT_NAME} SHARED ${hello_src})  即可

如果要构建静态库,则为 ADD_LIBRARY(${PROJECT_NAME} STATIC ${hello_src}) 

可以将目标名称修改如下

  SET_TARGET_PROPERTIES (${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "hello")

也可以指定动态库版本

  SET_TARGET_PROPERTIES (${PROJECT_NAME}PROPERTIES VERSION 1.2 SOVERSION 1)

二、 其他

1. cmake help

CMake Reference Documentation — CMake 3.27.9 Documentation
CMAKE_SOURCE_DIR:根cmaek文件所在路径
CMAKE_CURRENT_SOURCE_DIR :当前cmake文件所在路径
PROJECT_SOURCE_DIR :当前cmake文件所在路径

现代CMake工具的设计理念和使用

  https://mp.weixin.qq.com/s/qIEsImvOWa3-nRx7Ik_R8g

全面的例子

  https://gitee.com/li736069609/qt_demo/blob/master/gui/CMakeLists.txt

2. cmake 中定义宏,代码中使用

# 新的语法
add_compile_definitions(OPENCV_VERSION="1.0.0") // 代码中可以直接使用 OPENCV_VERSION,值为 1.0.0
add_compile_definitions(WITH_OPENCV2) // 代码中可以直接使用 WITH_OPENCV2 进行条件编译
或者
add_compile_definitions(OPENCV_VERSION="1.0.0" WITH_OPENCV2)

# 旧的语法
add_definitions(-DSOURCE_DIR="aaa")  // 代码中的宏 SOURCE_DIR 就是字符串aaa
add_definitions(-DWITH_TEST)  // 代码中可以使用 WITH_TEST 进行条件编译

3. 静态库的连接顺序

工程在链接阶段静态库是有顺序要求的,如果懒得理这些顺序,就用  -Wl,--start-group  和 -Wl,--end-group 括起来即可

target_link_libraries(
    -Wl,--start-group
    libX3.a
    libX2.a
    libX1.a
    -Wl,--end-group
)

4. 大型工程中有用的几个设置

target_link_options(${project_name} PRIVATE -Wl, --no-undefined)
QMAKE_LFLAGS += -Wl,--no-undefined (qmake)

告诉链接器在链接过程中不允许有未定义的符号 (对动态库 so)

target_link_options(${project_name} PRIVATE -Wl, --warn-unresolved-symbol)

告诉链接器在链接过程中可以有未定义的符号 (对可执行程序)

target_link_options(${project_name} PRIVATE -Wl, --copy-dt-needed-entries)

当链接可执行文件时,依赖于libA.so,而libA.so又依赖于libB.so,而且可执行文件中还直接调用了libB.so中的函数,如果可执行文件没有显示声明连接libB.so,则会报错 DSO missing from command line,因为自从binutils 2.22版本以后,如果你在程序中使用了你依赖的动态库所依赖的动态库中的函数时,你就必须显式的指定你依赖的动态库所依赖的动态库,

5 Debug 与 Release 版本控制 

cmake .. -DCMAKE_BUILD_TYPE=Debug/Release

if (CMAKE_BUILD_TYPE)
    if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
        target_compile_options (${PROJECT_NAME}    PRIVATE -O0 -g -Wall)
    elseif (${CMAKE_BUILD_TYPE} STREQUAL "Release")
        target_compile_options (${PROJECT_NAME}    PRIVATE -O2 -g -Wall)
    else ()
        target_compile_options (${PROJECT_NAME}    PRIVATE -O2 -g -Wall)
    endif ()
else ()
    target_compile_options (${PROJECT_NAME}    PRIVATE -O2 -g -Wall)
endif ()    

6. find_package 使用

find_package( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )

用来调用预定义在 CMAKE_MODULE_PATH 下的 Find<name>.cmake 模块。

(1)查找引用使用第三方库,如使用 curl 库

在工程根目录中建立 src 文件夹,并在其下创建 main.c 文件,内容如下:

#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE *fp;
int write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main()
{
const char * path = “/tmp/curl-test”;
const char * mode = “w”;
fp = fopen(path,mode);
curl_global_init(CURL_GLOBAL_ALL);
CURLcode res;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, “http://www.linux-ren.org”);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}

在工程根目录下建立主工程文件 CMakeLists.txt,内容如下

PROJECT(CURLTEST)
ADD_SUBDIRECTORY(src)

在 src 下创建 CMakeLists.txt

ADD_EXECUTABLE(curltest main.c)

 现在自然是没办法编译的,我们需要添加 curl 的头文件路径和库文件。

方法 1:
直接通过 INCLUDE_DIRECTORIES 和 TARGET_LINK_LIBRARIES 指令添加:
我们可以直接在 src/CMakeLists.txt 中添加:
INCLUDE_DIRECTORIES(/usr/include)
TARGET_LINK_LIBRARIES(curltest curl)
然后建立 build 目录进行外部构建即可。

方法 2
使用 FindCURL 模块。
向src/CMakeLists.txt 中添加:
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
  INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
  TARGET_LINK_LIBRARIES(curltest ${CURL_LIBRARY})
ELSE(CURL_FOUND)
    MESSAGE(FATAL_ERROR ”CURL library not found”)
ENDIF(CURL_FOUND)
对于系统预定义的 Find<name>.cmake 模块,使用方法一般如上例所示:
每一个模块都会定义以下几个变量
    <name>_FOUND
    <name>_INCLUDE_DIR or <name>_INCLUDES
    <name>_LIBRARY or <name>_LIBRARIES
你可以通过<name>_FOUND 来判断模块是否被找到,如果没有找到,按照工程的需要关闭某些特性、给出提醒或者中止编译,上面的例子就是报出致命错误并终止构建。
如果<name>_FOUND 为真,则将<name>_INCLUDE_DIR 加入 INCLUDE_DIRECTORIES,将<name>_LIBRARY 加入 TARGET_LINK_LIBRARIES 中。

(2)自定义 cmake 模块,如编写属于自己的 FindHello 模块。

定义 cmake/FindHELLO.cmake 模块

FIND_PATH(HELLO_INCLUDE_DIR hello.h /usr/include/hello /usr/local/include/hello)
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATH /usr/lib /usr/local/lib)
IF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
  SET(HELLO_FOUND TRUE)
ENDIF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
IF (HELLO_FOUND) IF (NOT HELLO_FIND_QUIETLY) MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}") ENDIF (NOT HELLO_FIND_QUIETLY) ELSE (HELLO_FOUND) IF (HELLO_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find hello library") ENDIF (HELLO_FIND_REQUIRED) ENDIF (HELLO_FOUND)

可以看到在该模块中定义了 HELLO_FOUND、HELLO_INCLUDE_DIR、HELLO_LIBRARY变量

前面的 curl 例子中我们使用了最简单的 FIND_PACKAGE 指令,其实他可以使用多种参数

QUIET 参数,对应与我们编写的 FindHELLO 中的 HELLO_FIND_QUIETLY ,如果不指定这个参数,就会执行:
MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}")

REQUIRED 参数,对应于 FindHELLO.cmake 模块中的 HELLO_FIND_REQUIRED ,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这个链接库是必备库,如果找不到这个链接库,则工程不能编译。

使用自定义的 Hello 与使用 curl 的方法一致。

 设置动态库的版本号:

set_target_properties(${project_name} PROPERTIES VERSION 1.0.0 SOVERSION 1) 

 

------

 

标签:cmake,target,笔记,PROJECT,CMAKE,curl,HELLO,DIR
From: https://www.cnblogs.com/qcwh736/p/13533655.html

相关文章

  • 【Effective Python教程】(90个有效方法)笔记——第3章:函数——23:用关键字参数来传参(位
    文章目录第3章:函数第23条用关键字参数来传参位置传递参数关键字传递参数位置和关键字传递参数混合使用另外,关键字形式与位置形式也可以混用。下面这四种写法的效果相同:==如果混用,那么位置参数必须出现在关键字参数之前,否则就会出错。==每个参数只能指定一次,不能既通过位......
  • Living-Dream 系列笔记 第60期
    \(\mathcal{TRIE}\):用于存储和查询字符串的树形结构,相同前缀的字符串共用节点,每个节点存储一个字符。操作:insert:单次\(O(len)\)search:单次\(O(len)\)性质\(1\):若一个字符串\(T\)作为前缀,则包含\(T\)的所有字符串的“终止节点”一定在以\(T\)的“终止节点”为根......
  • Linux学习笔记(一)(以Ubuntu为例)
    Linux操作命令的笔记(一)(Ubuntu)其实Linux不同发行版的基础命令区别不大。Linux命令基础格式命令通用格式:command[-options][parameter][]表示可选的意思command:命令本身-options:[可选,非必填]命令的一些选项,可以通过选项控制命令的行为细节parameter:[可选,非必填]命令......
  • 行列式学习笔记
    行列式基础概念\(n\)阶行列式\[\begin{vmatrix}a_{11}&a_{12}&...&a_{1n}\\a_{21}&a_{22}&...&a_{2n}\\...&...&&...\\a_{n1}&a_{n2}&...&a_{nn}\\\end{vmatrix}\]完全展开式$\sum_{......
  • 学习笔记483—如何关闭 Mac Office 更新提示
    MacOffice总是弹出MicrosoftAutoUpdate更新提示怎么办? 问题:Mac电脑安装 Office2021Mac版后,老是弹出更新提示(MicrosoftAutoUpdate),关掉之后再开机又会弹出来,怎么办? 解决方法:用AppCleaner把MacOffice更新程序MicrosoftAutoUpdate直接卸载,这样就不会再弹出......
  • 学习笔记:计算机内存管理
    虚拟内存    单片机是没有操作系统的,所以每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。        单片机的CPU是直接操作内存的「物理地址」。        在这种情况下,要想在内存中同时运行两个程序是不可能的。如果第一个程序在20......
  • 阅读笔记6
    《现代软件工程构建之法》第九章讲述了项目经理在软件开发中的角色和职责,以及项目管理的一些基本原则和方法。在我的过去的软件开发经验中,我可能会集中在技术开发上,忽略项目管理和沟通方面的问题。这种方法往往会导致进度和质量等问题,缺乏项目的整体视野和沟通能力。通过本章的学......
  • 阅读笔记5
    《现代软件工程构建之法》第八章讲述了需求分析在软件开发中的重要性及方法。在我过去的软件开发中,我可能会只关注部分需求,而忽略其他因素,或者基于主观判断进行需求评估和分析。这种方法很容易导致软件的实际功能不符合用户的需求,因而影响软件的使用效果和用户体验。通过本章的学......
  • Openstack 部署笔记
    1、设置主机名hostnamectlset-hostnametemplate2、设置hostscat/etc/hosts127.0.0.1localhostlocalhost.localdomainlocalhost4localhost4.localdomain4openstack192.168.59.20controller192.168.59.31compute01192.168.59.32compute02cpeh-public192.168.5......
  • ROS机器人虚拟仿真挑战赛持续学习笔记-20240619
    cartographer需要全手工编译……比较麻烦。如果使用新版ceres-solver,版本2.x,需要修改源码,部分“接口代码”有改动。稳妥使用ceres-solver-1.13.0,且需要安装abseil-cpp。验证是否成功,使用roscd或roslaunch,查看一下是否有对于功能包:map只有room_mini和tianracer_racetr......