首页 > 其他分享 >CMake简单教程

CMake简单教程

时间:2023-01-07 22:56:43浏览次数:37  
标签:教程 include bar lib add 简单 cpp CMake foo

title: CMake学习
date: 2023-01-07T20:29:55Z
lastmod: 2023-01-07T22:33:31Z

CMake学习

主要就是学习如何写CMakeList.txt, 直接从项目实战

项目结构

图片名称
  • common: 制作动态库, 将整数数转为二进制形式的字符串, 生成dll给main调用
  • dependencies/lib_pow: 自定义幂函数
  • dependencies/lib_sqrt: 自定义开方函数
  • lib: 动态/静态库生成目录(.dll: 动态 .a: 静态(默认))

CMakeList书写

下面看看各个CmakeList怎么写的:

common:

  • LIBRARY_OUTPUT_PATH ​: 库的输出目录
  • PROJECT_SOURCE_DIR: 项目的根目录, 即到Tutorial目录
  • add_library: 制作库(动态SHARED , 静态STATIC)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)  # 设置库的输出目录

add_library(common SHARED num2Binary.cpp)
#add_library(common STATIC num2Binary.cpp) # 默认为static

lib_pow

lib_pow和lib_sqrt基本一样, 就制作了个静态库

  • target_include_directories: 包含依赖的头文件, 这个例子里没啥用)
add_library(pow mypow.cpp)

#target_include_directories(lib_pow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

dependencies

add_subdirectory增加编译子目录

add_subdirectory(lib_sqrt)
add_subdirectory(lib_pow)

Main

  • cmake_minimum_required: 设置Cmake版本
  • project: 项目名, 版本(一般不用设置)
  • set(CMAKE_CXX_STANDARD 11): 设置C++版本为11, 开始构建项目可以设置, 但这里设置更灵活
  • set(CMAKE_CXX_STANDARD_REQUIRED ON): 必须使用设置的C++11版本, 若为OFF, 则C++11版本为首选项, 不可用时会使用上一个版本
  • configure_file(Main/TutorialConfig.h.in TutorialConfig.h): 基于配置文件TutorialConfig.h.in构建头文件TutorialConfig.h, 其中TutorialConfig.h.in为:
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@  //项目的子版本号0
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ // 项目的主版本号1
#define  USE_MYMATH   // 这个是源代码中的一个开关
  • option: 设置当前CMakeList里的开关, 注意CLion中有bug, 需要删除cmake-build-release(debug)目录, 然后点击顶层CmakeList重新加载, 改变才生效.
  • PROJECT_BINARY_DIR: 工程输出目录, 如cmake-build-release, cmake-build-debug
cmake_minimum_required(VERSION 3.5)

# set the project name and version
project(Tutorial VERSION 1.0)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)    # 动态(静态)库输出目录
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) # 可执行文件输出目录

configure_file(Main/TutorialConfig.h.in TutorialConfig.h)

option(USE_MYMATH "use tutorial provided math implementations" ON)

if (USE_MYMATH)
    add_subdirectory(dependencies)
    list(APPEND EXTRA_LIBS pow)
    list(APPEND EXTRA_LIBS sqrt)
endif (USE_MYMATH)


include_directories(dependencies/lib_pow)
include_directories(dependencies/lib_sqrt)
include_directories(lib/include)

add_executable(Tutorial Main/main.cpp)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})


target_link_libraries(Tutorial PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib/libcommon.dll)


add_subdirectory(common)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
        "${PROJECT_BINARY_DIR}")

其中开关的内容:

if (USE_MYMATH) 
    add_subdirectory(dependencies)   # 添加子文件夹
    list(APPEND EXTRA_LIBS pow)     # 将子文件夹下的库文件pow和sqrt的名字保存为EXTRA_LIBS变量
    list(APPEND EXTRA_LIBS sqrt)
endif (USE_MYMATH)
  • include_directories: 添加项目头文件搜索路径, 那么项目中该目录下的头文件可以直接include​, 而不用写出完整的相对路径
  • add_executable(Tutorial Main/main.cpp):​ 添加可执行文件, 名字为Tutorial, 后面是其包含的头文件
  • target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}): 可执行文件链接依赖库, 之前依赖库已经保存在变量EXTRA_LIBS中

link时的选项PUBLIC, INTERFACE, PRIVATE区别

结论

先说结论, 以target_link_libraries(A xx B)​为例

  • PRIVATE: B仅链接到A, 若C链接到A, C不会链接依赖项B (即链接无传递性)
  • INTERFACE: B并不链接到A, 当C链接了A, C会链接项B
  • PUBLIC: B链接A, 若C链接A, C也会链接依赖项B

实操

以具体例子说明:

CMake_link_test
├── cmake-build-release
├── bar.cpp
├── bar.h
├── CMakeLists.txt
├── foo.cpp
├── foo.h
└── app.cpp

foo.h
int foo();

foo.cpp
#include "foo.h"
int foo(){
    return 3;
}

bar.h
#include "foo.h"
int bar();

bar.cpp
#include "bar.h"
int bar() {
    return 5;
    //return foo() + 3;
}

main.cpp
#include <iostream>
#include "bar.h"

int main() {
    std::cout << bar() << std::endl;
    std::cout << foo() << std::endl; 
    return 0;
}

CMakeList为:

cmake_minimum_required(VERSION 3.16)

project(foobar)
set(CMAKE_SKIP_RPATH TRUE)

include_directories(${CMAKE_SOURCE_DIR})

add_library(foo SHARED foo.cpp)

add_library(bar SHARED bar.cpp)
target_link_libraries(bar INTERFACE foo)

add_executable(app app.cpp)
target_link_libraries(app bar)

  • 链接方式为PRIVATE , 发现app报错: app.cpp:6: undefined reference to `foo()'
target_link_libraries(bar PRIVATE foo)
  • 链接方式为PRIVATE, app貌似可以正常执行
target_link_libraries(bar INTERFACE foo)

但修改bar的实现为:​ return foo() + 3;​, 即bar中使用了foo.h中定义的函数, 报错: bar.cpp:9: undefined reference to `foo()'

  • 链接方式为PUBLIC: 无论bar.cpp中是否引用foo.h中定义的符号, 都正常执行.

总结

假设库的依赖关系: linux下静态库为.so, windows下.a

flowchart LR app-->libbar.so libbar.so-->foo.so
  • PRIVATE: foo.so对app不可见
  • NTERFACE: foo.so对bar不可见, 但可将foo.h头文件传递给app, 换句话说foo只提供给bar接口, 而不提供具体实现. 故foo.so对app可见,对bar不可见
  • PUBLIC: 等于PRIVATE + INTERFACE, foo对bar和app都可见
图片名称

标签:教程,include,bar,lib,add,简单,cpp,CMake,foo
From: https://www.cnblogs.com/shmilyt/p/17033786.html

相关文章

  • powershell简单的使用gui
    powershell作为win的官方shell,可以调用.net对象。让它可以无所不能。例如给脚本加上图形界面更直观。而且这是win占用文件体积最小的图形程序。几行文本就能构建一个gui程......
  • gdb的使用教程以及gdbpwndbg 常用命令
    gdb的使用教程以及gdb/pwndbg常用命令1、基本使用(参考)#include<iostream>usingnamespacestd;intfunc(intn){ intsum=0; for(inti=0;i<n;i++){ sum+=i;......
  • gdb的使用教程以及gdbpwndbg 常用命令
    gdb的使用教程以及gdb/pwndbg常用命令1、基本使用(参考)#include<iostream>usingnamespacestd;intfunc(intn){intsum=0;for(inti=0;i<n;i++){......
  • Markdown语法教程
    二级标题三级标题四级标题快捷键ctrl+1,2,3,4,5,6加粗用**1**我是加粗的文字快捷键ctrl+B斜体用*1*我是斜体的文字斜体并加粗用***1****我是斜体并......
  • 虚拟机PVE安装教程
    1.ProXmoX-VE简介Proxmox虚拟环境(简称PVE)是用于操作来宾操作系统的基于Debian Linux和KVM的虚拟化平台。Proxmox免费提供 -可以通过制造商(维也纳的ProxmoxServerSolut......
  • java中String类型的相关知识的简单总结
    java中String类型的相关知识总结一、常用方法:1.构造方法:byte数组可指定offset和length可指定charsetchar数组可指定offset和count字符序列String......
  • k8s教程(pod篇)-总结
    文章目录​​01引言​​​​02总结​​​​2.1定义与基本用法​​​​2.2容器共享volume​​​​2.3配置管理​​​​2.4容器获取pod信息(DownwardAPI)​​​​......
  • 简单测试qt通过odbc方式连接mysql8数据库
    下载数据库mysql8.0.27,SQLyog,mysql-connector-odbc强烈推荐从镜像下载mysql-connector-odbc-8.0.27-winx64.msi​​​https://mirrors.tuna.tsinghua.edu.cn/mysql/do......
  • 简单文件的读写
    1.背景2023-01-07最近学习了文件流操作,简单记录一下2.用途百度百科:用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出。说人话就是......
  • 麒麟系统虚拟机安装教程
    作者:朱金灿1.首先得安装VMWare软件。2.打开VMWare,点击“文件”->“新建虚拟机”。3.进入新建虚拟机向导,点击下一步。如下图:4.安装来源选择安装程序光盘映像文件(ISO文件)......