Step10.选择静态库或共享库

news/2025/2/12 22:17:57/

Step10.选择静态库或共享库

在本节中,我们将展示如何使用BUILD_SHARED_LIBS变量来控制add_library()的默认行为,并允许控制如何构建没有显式类型(STATICSHAREDMODULEOBJECT)的库。

为了实现这一点,我们需要将BUILD_SHARED_LIBS添加到顶级CMakeLists中。
我们使用option()命令,因为它允许用户选择值是ON还是OFF

接下来,我们将重构MathFunctions,使其成为一个使用mysqrtsqrt封装的真正的库,而不是要求调用代码执行此逻辑。
这也意味着USE_MYMATH不会控制构建MathFunctions,而是控制这个库的行为。

更改顶层CMakeLists为下面这样:

cmake_minimum_required(VERSION 3.15)# set the project name and version
project(Tutorial VERSION 1.0)# specify the C++ standard
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)# add compiler warning flags just when building this project via
# the BUILD_INTERFACE genex
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
target_compile_options(tutorial_compiler_flags INTERFACE"$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>""$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")option(BUILD_SHARED_LIBS "Build using shared libraries" ON)# configure a header file to pass the version number only
configure_file(TutorialConfig.h.in TutorialConfig.h)# add the MathFunctions library
add_subdirectory(MathFunctions)# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)

既然我们已经使MathFunctions始终被使用,我们就需要更新该库的逻辑。
因此,在MathFunctions/CMakeLists.txt中,我们需要创建一个SqrtLibrary,当启用USE_MYMATH时,它将有条件地构建和安装。
现在,由于这是一个教程,我们将明确要求静态构建SqrtLibrary。

最终MathFunctions/CMakeLists.txt看起来像这个样子:

# add the library that runs
add_library(MathFunctions MathFunctions.cxx)# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(MathFunctionsINTERFACE ${CMAKE_CURRENT_SOURCE_DIR})# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if(USE_MYMATH)target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")# first we add the executable that generates the tableadd_executable(MakeTable MakeTable.cxx)target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)# add the command to generate the source codeadd_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.hCOMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.hDEPENDS MakeTable)# library that just does sqrtadd_library(SqrtLibrary STATICmysqrt.cxx${CMAKE_CURRENT_BINARY_DIR}/Table.h)# state that we depend on our binary dir to find Table.htarget_include_directories(SqrtLibrary PRIVATE${CMAKE_CURRENT_BINARY_DIR})target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)# define the symbol stating we are using the declspec(dllexport) when
# building on windows
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")# install libs
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs} DESTINATION lib)
# install include headers
install(FILES MathFunctions.h DESTINATION include)

接下来,更新MathFunctions/mysqrt.cxx以使用mathfunctionsdetail名称空间:

#include <iostream>#include "MathFunctions.h"// include the generated table
#include "Table.h"namespace mathfunctions {
namespace detail {
// a hack square root calculation using simple operations
double mysqrt(double x)
{if (x <= 0) {return 0;}// use the table to help find an initial valuedouble result = x;if (x >= 1 && x < 10) {std::cout << "Use the table to help find an initial value " << std::endl;result = sqrtTable[static_cast<int>(x)];}// do ten iterationsfor (int i = 0; i < 10; ++i) {if (result <= 0) {result = 0.1;}double delta = x - (result * result);result = result + 0.5 * delta / result;std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;}return result;
}
}
}

我们还需要在tutorial.cxx中进行一些更改,以便它不再使用USE_MYMATH

  1. 总是包含MathFunctions.h
  2. 总是使用mathfunctions::sqrt
  3. 不要包含cmath

最后,更新MathFunctions/MathFunctions.h使用DLL导出宏定义

#if defined(_WIN32)
#  if defined(EXPORTING_MYMATH)
#    define DECLSPEC __declspec(dllexport)
#  else
#    define DECLSPEC __declspec(dllimport)
#  endif
#else // non windows
#  define DECLSPEC
#endifnamespace mathfunctions {
double DECLSPEC sqrt(double x);
}

此时,如果您构建了所有内容,您可能会注意到链接失败,因为我们将一个没有位置无关代码的静态库与一个具有位置无关代码库组合在一起。
解决方案是将SqrtLibrary的POSITION_INDEPENDENT_CODE目标属性显式设置为True,无论生成类型如何。

  # state that SqrtLibrary need PIC when the default is shared librariesset_target_properties(SqrtLibrary PROPERTIESPOSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS})

练习:我们修改了MathFunctions.h以使用dll导出定义。使用CMake文档,您可以找到一个帮助模块来简化这个过程吗?

参考CSDN

使用GENERATE_EXPORT_HEADER宏,生成头文件


http://www.ppmy.cn/news/9489.html

相关文章

【C语言】volatile 关键字

目录一、前言二、C语言中变量的访问1. 读变量2. 写变量三、代码优化1. 硬件层面&#xff1a;2. 软件层面&#xff1a;四、volatile的定义五、volatile的应用场合1. 中断2. 多线程3. 硬件寄存器一、前言 volatile 是 C语言 中规定的一个关键字&#xff0c;C语言课程中很少会提及…

【BSP视频教程】BSP视频教程第25期:CAN/CANFD/CANopen专题,CAN知识点干货分享, 收发执行过程和错误帧处理(2023-01-03)

视频教程汇总帖&#xff1a;【学以致用&#xff0c;授人以渔】2023视频教程汇总&#xff0c;DSP第10期&#xff0c;ThreadX第5期&#xff0c;BSP驱动第25期&#xff0c;USB实战第5期&#xff0c;GUI实战第3期&#xff08;2023-01-03&#xff09; - STM32F429 - 硬汉嵌入式论坛 …

一些加速库Blas OpenMP等

一些加速库Blas OpenMP等 一、OpenMP1.1 多执行绪的概念1.2 多执行绪的程式1.3 OpenMP 的基本使用1.4 OpenMP使用详解二、MPI (Message Passing Interface)三、 CUDA3.1 CUDA发展历程3.2 CUDA体系结构3.3 CUDA工具包3.4 nvcc C语言编译器3.5 CUDA的运算3.6 GPU并行计算过程一、…

MATLAB APP 设计实践(一)UART通信(上篇)

引言UART通信属于异步串行通信&#xff0c;通信速率比较低&#xff0c;在一些速度要求不高的场合常用来作为多设备之间的控制与被控制方式。例如以UART串口通信作为上位机侧与运行设备之间的通信形式&#xff0c;实现上位机对设备的操控以及检测设备运行状态等。那么谈到了上位…

Selenium用法详解【键盘控制】【JAVA爬虫】

简介本文主要简介如何使用java代码利用Selenium 控制浏览器中需要用到的键盘操作。键盘控制webdriver 中 Keys 类几乎提供了键盘上的所有按键方法&#xff0c;我们可以使用 send_keys Keys 实现输出键盘上的组合按键如 “Ctrl C”、“Ctrl V” 等。import org.openqa.seleni…

5G NR标准 第14章 调度

第14章 调度 NR 本质上是一个调度系统&#xff0c;这意味着调度器决定何时以及向哪些设备分配时间、频率和空间资源&#xff0c;以及使用什么传输参数&#xff0c;包括数据速率。 调度可以是动态的或半静态的。 动态调度是基本的操作模式&#xff0c;其中调度程序针对每个时间…

一起快速了解单片机入门知识吧!

从事计算机和电子信息技术行业的都熟知单片机一词&#xff0c;但是你真的了解单片机吗&#xff1f;单片机的种类有哪些&#xff1f;单片机有什么特点&#xff1f;单片机的工作原理是什么&#xff1f;下面一起来了解单片机知识吧&#xff01;在学习单片机知识前&#xff0c;我们…

算法leetcode|28. 找出字符串中第一个匹配项的下标(rust重拳出击)

文章目录28. 找出字符串中第一个匹配项的下标&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a;分析&#xff1a;题解&#xff1a;rustgoccpythonjava28. 找出字符串中第一个匹配项的下标&#xff1a; 给你两个字符串 haystack 和 needle &#xff0c;请你在…