注:在Linux平台下,动态库和静态库的源码是完全一样的,只需要改变编译参数即可。 Windows平台上生成的动态库的源代码与静态库是不同的。
在Windows平台上,当我们导入动态库时,不仅会生成.dll动态库,还会生成.lib文件。 这个.lib文件与静态库的.lib文件不同。 它保存的不是代码生成的二补码文件,而是所有需要导入符号的符号表。 因此库文件编译源码,这个.lib文件会比编译静态库生成的.lib文件小很多。 而这个导入的符号表需要在源码中指定。 如果我们要导入一个符号(symbol)(这里的符号可以指类、函数等各种类型),我们需要在其后面添加__declspec(dllexport)标志。 这样,这个符号的相关信息就会被导入到.lib中的符号表中。 如果我们的源码中没有__declspec(dllexport),我们仍然可以成功编译动态库,并且不会生成保存符号表的.lib文件。 这也是Windows平台下编译动态库时的常见问题。 如果我们的源码是在Linux平台下编译的,很容易忘记改源码。
原文链接:
上面说了,在windows下实现动态库源码的跨平台特性会比较麻烦,不过好在cmake有自己的解决方案,只要知道原理是什么就可以了。
1.2 新建一个Library项目
1.3 CmakeLists.txt的设置
GenerateExportHeader—CMake3.24.0-rc3文档
cmake_minimum_required(VERSION 3.22)
set(CMAKE_CXX_STANDARD 14)
project(MyDLL)
# 导入 GenerateExportHeader 函数
include(GenerateExportHeader)
#set(CMAKE_CXX_VISIBILITY_PRESET hidden)
#set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
# 判断是否是debug模式,如果是debug,则后缀加‘d',比如 MyDLLd.dll MyDLLd.lib
set(DEBUG_SUFFIX)
if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
set(DEBUG_SUFFIX "d")
endif ()
# CMAKE_DEBUG_POSTFIX 全局变量用于附加 d对于调试库:
set(CMAKE_DEBUG_POSTFIX d)
# 定义目标名称变量
set(TargetName ${PROJECT_NAME})
message(${TargetName})
# 生成 动态的 MyDLL.dll 文件
add_library(${TargetName} SHARED library.cpp)
# MyDLL export宏定义, 生成的文件名为 mydll_export.h, 路径: ${PROJECT_BINARY_DIR}
GENERATE_EXPORT_HEADER(${TargetName})
INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
# 设置安装目录
SET(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_lib)
# 拷贝头文件 到 include 目录下
INSTALL(FILES library.h ${PROJECT_BINARY_DIR}/mydll_export.h DESTINATION include)
# 将 dll 和 lib 库文件 分别放到 lib 和 bin 目录下
INSTALL(TARGETS ${TargetName} LIBRARY DESTINATION lib)
ReloadCmakeProject后,在项目的补码目录下手动生成mydll_export.h
1.4 ABI文件导出mydll_export.h
导出头文件后,使用MYDLL_EXPORT声明各处的函数
1.5 创建项目
项目建立并执行后,会生成相关的库文件,如右图所示:
1.6 安装
点击安装后库文件编译源码,会手动将库文件放到对应的目录下
2.使用第三方动态库文件
动态库使用生成的MyDLL
2.1 新项目
2.2 将MyDLL库文件复制到源代码目录
2.3 CmakeLists.txt的设置
cmake_minimum_required(VERSION 3.22)
project(UseDLL)
set(CMAKE_CXX_STANDARD 14)
# 判断是否是debug模式,如果是debug,则后缀加‘d',比如 MyDLLd.dll MyDLLd.lib
set(DEBUG_SUFFIX)
if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
set(DEBUG_SUFFIX "d")
endif ()
# CMAKE_DEBUG_POSTFIX 全局变量用于附加 d对于调试库:
#set(CMAKE_DEBUG_POSTFIX d) # 这玩意在使用库文件的时候,似乎没有用处
add_executable(UseDLL main.cpp)
#INCLUDE_DIRECTORIES(MyDLL_lib/include) # 这种方式也可以导入库文件
# 为目标添加 include 目录
target_include_directories(UseDLL
PUBLIC
${PROJECT_SOURCE_DIR}/MyDLL_lib/include)
message(${PROJECT_SOURCE_DIR}/MyDLL_lib/lib/MyDLL${DEBUG_SUFFIX})
# 为目标 链接添加 lib文件
target_link_libraries(UseDLL
PRIVATE
${PROJECT_SOURCE_DIR}/MyDLL_lib/lib/MyDLL${DEBUG_SUFFIX}.lib)
# 这种用目录的方式处理的不是很好,需要明确指定到lib的文件名,应该有其他的方式
2.4 使用库中的头文件
2.5 编译运行
将dll文件复制到补码目录下,然后编译运行
成功复制“你好,世界!”