结合CmakeList来更好地理解windows下的动态库和静态库

动态库和静态库的输出

 window下输出的静态库为.lib文件,用于包含所有的函数,以及函数的实现,以及其他的一些东西,所以文件较大;输出的动态库包含.lib文件和.dll文件,.lib文件主要包含接口函数,而.dll文件用于保存函数的实现;

因此设置静态库保存路径时要设置ARCHIVE_OUTPUT_DIRECTORY;而设置动态库输出路径时要设置ARCHIVE_OUTPUT_DIRECTORY用于设置输出的.lib文件的保存路径以及RUNTIME_OUTPUT_DIRECTORY用于设置输出的.dll文件的保存路径;

例如,输出想要输出某个库时可以做如下编辑: 

set(SOURCES a.cpp b.cpp)
add_library(mylibray_static STATIC ${SOURCES}) #为静态库添加文件
add_libray(mylibrary_shared SHARED ${SOURCES}) #为动态库添加文件
set_target_properties(mylibray_static PROPERTIES
                        OUTPUT_NAME "mylibray" #设置输出库的名字
                        CLEAN_DIRECT_OUTPUT 1
                        ARCHIVE_OUTPUT_DIRECTORY staticlib/x64 #设置静态库输出路径
                      )

set_target_properties(mylibrary_shared PROPERTIES
                      VERSION ${MY_LIBRARY_VERSION_STRING}
                      SOVERSION ${MY_LIBRARY_VERSION_EPOCH}.${MY_LIBRARY_VERSION_MAJOR} #设置库的版本号
                      OUTPUT_NAME "mylibrary" #设置输出库的名字
                      CLEAN_DIRECT_OUTPUT 1
                      RUNTIME_OUTPUT_DIRECTORY bin/x64 #设置.dll文件的保存路径
                      ARCHIVE_OUTPUT_DIRECTORY lib/x64) #设置.lib文件的保存路径

但是因为动态库的.lib文件主要保存接口函数,因此,能否输出该.lib文件还需要在库的源文件的头文件中进行如下的定义:

#if(defined WIN32||defined_WIN32|| defined WINCE)&& defined EFIMPL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif

主要是if defined EFIMPL 来控制,即如果EFIMPL被定义了,则 define EXPORT __declspec(dllexport), 即将__declspec(dllexport) 定义为EXPORT, 而__declspec(dllexport) 即表示用于对外的接口, 所有添加了EXPORT 关键字的函数都会被输出到动态库的.lib文件中作为接口函数;

如下: 

EXPORT bool SetBoardParams(MyHandle detector,
                           const int param1,
                           const int param2,
                           const int param3,
                           const int param4);

这里函数SetBoardParams()将回作为一个接口函数输出,调用库时即可调用该函数;

而EFIMPL的定义则出现在CMAKELISTS中,如下:

SET_TARGET_PROPERTIES(circular_detect_shared PROPERTIES
                      COMPILE_FLAGS "-DEFIMPL ${SHARED_FLAGS}"

 即只针对动态库设置 COMPILE_FLAGS 为-DEFIMPL ${SHARED_FLAGS}, -D 表示define;

因此上述CMakelist文件中,如果想要输出动态库的.lib文件,不仅要在Cmake文件中对动态库添加COMPILE_FLAGS的设置,同时也要在.h文件中确定想要输出的接口函数;

平常使用中如果觉得这样麻烦的话可以在cmake中直接链接静态库(具体是静态库还是动态库会以名字做区分),但是交接时是动态库更加方便;例如:

include_directories("D:/ProgramFiles/boost_1_65_1")
link_directories("D:/ProgramFiles/boost_1_65_1/lib64-msvc-14.0")
link_directories(${PROJECT_SOURCE_DIR}/3rdparty/ceres_solver/lib)
link_directories(${PROJECT_SOURCE_DIR}/3rdparty/glog/lib)
link_directories(${PROJECT_SOURCE_DIR}/3rdparty/gflags/lib)
add_executable(applicationapplication.cpp)
target_link_libraries(application
                    ${OpenCV_LIBS}
                    my_library_static//链接静态库
                    boost_filesystem-vc140-mt-1_65_1)

备注: 这里的静态库calibration_static因为是和可执行文件application在一个项目中生成,因此,不需要用法link_directories,工程中自己会有记录;

 

关于__declspec(dllexport) VS2017的官网上有一段解释,摘抄下来,方便理解:

 https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport?view=vs-2017

Microsoft introduced __export in the 16-bit compiler version of Visual C++ to allow the compiler to generate the export names automatically and place them in a .lib file. This .lib file can then be used just like a static .lib to link with a DLL.

In newer compiler versions, you can export data, functions, classes, or class member functions from a DLL using the __declspec(dllexport) keyword. __declspec(dllexport) adds the export directive to the object file so you do not need to use a .def file.

When building your DLL, you typically create a header file that contains the function prototypes and/or classes you are exporting and add __declspec(dllexport) to the declarations in the header file. To make your code more readable, define a macro for __declspec(dllexport) and use the macro with each symbol you are exporting:

如有疑问,欢迎交流: wx: baobaohaha_ 欢迎对SLAM有兴趣的小伙伴一起交流学习~~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值