cmake 使用(八)

本文是 cmake 使用的第八篇,主要介绍如何使用 cmake 导入已经编译好的第三方库。

上一篇的链接为:https://blog.youkuaiyun.com/QCZL_CC/article/details/119826435,主要介绍如何设置编译标志,以便于在代码中使用预编译宏。

目录结构如下:

qczl@DESKTOP-HP-ZHAN:~$ tree httpTool
httpTool
├── CMakeLists.txt
├── cJSON
│   ├── cJSON.c
│   └── cJSON.h
├── src
│   ├── common.h
│   ├── debug.h
│   ├── http.c
│   ├── http.h
│   ├── mtime.c
│   ├── mtime.h
│   ├── pstring.c
│   ├── pstring.h
│   ├── safe.c
│   ├── safe.h
│   ├── url_parse.c
│   ├── url_parse.h
│   ├── util.c
│   └── util.h
└── tests
    ├── get_mac_info.c
    ├── get_mac_info.h
    └── main.c

以上是我写的一个小工具。httpTool/cJSON/ 中的代码我准备编译一个静态库。然后这套代码还依赖第三方库(openssl),接下来我将演示如何用 cmake 语法引入 openssl 库。我将 openssl 安装在了 /home/qczl/openSourceCode/install 目录。

CMakeLists.txt 规则如下:

# cmake 最低版本号
cmake_minimum_required(VERSION 3.14)

# CMake 提供的默认构建类型不包含用于优化的编译器标志。
# 对于某些项目,您可能希望设置默认构建类型,这样您就不必记住设置它。
# cmake 提供的级别有:
# Release        - 添加 -O3 -DNDEBUG 标志
# Debug          - 添加 -g 标志
# MinSizeRel     - 添加 -Os -DNDEBUG
# RelWithDebInfo - 添加 -O2 -g -DNDEBUG 标志
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    message("Setting build type to 'RelWithDebInfo' as none was specified.")
    set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
    # Set the possible values of build type for cmake-gui
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
        "MinSizeRel" "RelWithDebInfo")
endif()

# 项目名称
project(http_tools)

################################################
# 导入第三方库信息
################################################

# 自定义一个库,名称为 openssl
add_library(openssl INTERFACE IMPORTED)

# 为 openssl 设置其库文件的所在目录(.so 文件目录)
target_link_directories(openssl
   INTERFACE
       /home/qczl/openSourceCode/install/lib
)

# 为 openssl 设置其头文件的所在目录(.h 文件目录)
target_include_directories(openssl
    INTERFACE
        /home/qczl/openSourceCode/install/include
)

# 为 openssl 设置依赖。openssl 有 libssl.so 和 libcrtypto.so 2个动态库文件
target_link_libraries(openssl
    INTERFACE
        crypto
        ssl
)


################################################
# 创建 cSJON 静态库
################################################

# 从库源生成静态库
add_library(cJSON STATIC
    cJSON/cJSON.c
)

# 为 cJSON 库添加 -lm
target_link_libraries(cJSON
    PUBLIC
        m
)

# 为库添加头文件
target_include_directories(cJSON
    PUBLIC
        ${PROJECT_SOURCE_DIR}/cJSON
)

# 创建可执行文件
add_executable(tool
    src/http.c
    src/mtime.c
    src/pstring.c
    src/safe.c
    src/url_parse.c
    src/util.c
    tests/get_mac_info.c
    tests/main.c
)

# 为可执行文件添加头文件
target_include_directories(tool
    PRIVATE
        ${PROJECT_SOURCE_DIR}/src
        ${PROJECT_SOURCE_DIR}/tests
)

# 可执行文件链接库
target_link_libraries(tool
    PUBLIC
        cJSON
        openssl            # 上面我们自定义的库名称,此处将引入 openssl 依赖的 libssl.so 和 libcrypto.so
)

构建过程:

        1:mkdir build        创建该目录的目的是为了将编译产物和源文件分离

        2:cd build && cmake ..        cmake 后面第一个参数应该是 CMakeLists.txt 文件所在目录。此实例中 CMakeLists.txt 在 build 目录的上一级,所以使用 cmake ..

        3:make VERBOSE=1        加上 VERBOSE=1 可以看到编译的详细过程

可以看到最终生成可执行文件时链接了我们设置的第三方库:

我的实验环境是  ubuntu-20.04(WSL) 加 cmake 3.16

然后我遇到了问题。最终生成的可执行文件运行时报错。错误日志如下:提示找不到符号 EVP_idea_cbc 

./tool: symbol lookup error: /home/qczl/openSourceCode/install/lib/libssl.so.1.1: undefined symbol: EVP_idea_cbc, version OPENSSL_1_1_0

而我编译出的 openssl 库中是有这个符号的:

然后我 ldd tool 查看我的可执行文件,发现 libcrypto.so.1.1 还是使用的系统目录中的,而不是我在CMakeLists.txt 规则中指定 /home/qczl/openSourceCode/install/lib/ 目录中的。

然后我又在 ubuntu-16.04 和 cmake 3.14 的环境下试了一下,发现是正常的。

 如下图所示,在 ubuntu-16.04 和 cmake 3.14 的环境下 libssl 和 libcrypto 都正确的指向了我的自定义目录(/home/qczl/openSourceCode/install/lib/)

 再然后我又在 ubuntu-20.04(WSL) 加 cmake 3.14 的环境下 测试了下,现象和 ubuntu-20.04(WSL) 加 cmake 3.16 环境一样。所以和难道是 ubuntu-20.04(WSL) 的问题。

好的,下面为您介绍 CMake 中的 macro 和 function。 ## 1. macro macro 是一种 CMake 的宏定义机制,可以将一组 CMake 命令封装起来,用一个名字来调用,从而简化 CMakeLists.txt 中的代码量。 macro 的定义格式如下: ``` macro(macro_name [arg1 [arg2 [arg3 ...]]) # command1 # command2 # ... endmacro() ``` 其中,macro_name 是宏的名称,arg1、arg2、arg3...是宏的参数列表,可以有 0 至多个参数。 下面是一个简单的例子,定义了一个名为 print_info 的宏,该宏接受两个参数,分别是 name 和 age,然后输出一条信息: ``` macro(print_info name age) message("Name: ${name}, Age: ${age}") endmacro() print_info("Alice" 18) ``` 执行上述代码后,输出结果为: ``` Name: Alice, Age: 18 ``` ## 2. function function 与 macro 的作用类似,也是将一组 CMake 命令封装起来,用一个名字来调用,但 function 有明确的返回值。function 的定义格式如下: ``` function(func_name [arg1 [arg2 [arg3 ...]]) # command1 # command2 # ... return(value) endfunction() ``` 其中,func_name 是函数的名称,arg1、arg2、arg3...是函数的参数列表,可以有 0 至多个参数。value 是函数的返回值。 下面是一个简单的例子,定义了一个名为 add 的函数,该函数接受两个参数,分别是 a 和 b,然后返回它们的和: ``` function(add a b) set(result ${a}+${b}) return(${result}) endfunction() set(sum 0) math(EXPR sum "${sum} + $(add(1 2))") message("Sum: ${sum}") ``` 执行上述代码后,输出结果为: ``` Sum: 3 ``` 在 function 中,我们使用 set 命令定义了一个变量 result,然后用 return 返回了这个变量的值。在调用 add 函数时,我们使用了 $() 将函数调用结果作为表达式的一部分,然后再用 math 命令计算出 sum 的值。 以上就是 CMake 中 macro 和 function 的介绍,希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值