本文链接 github.com/BeyondXinXin
记录几个之前存在疑惑的地方。
不管链接,都要给可执行程序添加导入库。静态库的导入库就存在他本身、动态库的导入库存在*.lib(这个lib并不是静态库)
所以程序封装给别人用,需要提供:
静态库和导入库名字相同,大小差异很多。导入库只有函数的符号,静态库有具体实现。
库文件中的函数并非全部导出,不同编译器会有不同效果。
所以使用msvc时候会出现,明明把文件和库都加载了却依旧找不到实现的符号。
可以想象到的是:
还没实际试过,抽空研究一下补上。
第二个问题说了,msvc动态库不会导出任何函数,那msvc应该怎么用?
类/函数在库内部使用:不做任何操作
类/函数在库外部给别人用:使用_declspec(dllexport)修饰类/函数
使用库内部的函数/类:声明的头文件使用_declspec(dllimport)修饰类/函数
只有msvc才有动态库封装部分接口给外部使用,其他的比如gcc会封装所有的函数给外部使用。
封装使用_declspec(dllexport)修饰函数/类、调用使用_declspec(dllimport)修饰函数/类
那其实问题就变成了用什么修饰函数/类的问题
// 动态库封装的cmakelist.txt if(WIN32) if(MSVC) add_definitions(-DUSE_SHARED) else() add_definitions(-DNO_MSVC) endif() endif()
// 静态库封装的cmakelist.txt if(WIN32) if(MSVC) add_definitions(-DUSE_STATIC) else() add_definitions(-DNO_MSVC) endif() endif()
// 可执行程序的cmakelist.txt // 啥也不用写
// Q_DECL_EXPORT 和 Q_DECL_IMPORT 是Qt封装好的,跟直接用__declspec(***)一样 #define Q_DECL_EXPORT __declspec(dllexport) #define Q_DECL_IMPORT __declspec(dllimport)
#ifdef _WIN32 #if defined(USE_SHARED) #define REGDLL_API Q_DECL_EXPORT #elif defined(USE_STATIC) #define REGDLL_API #elif defined(NO_MSVC) #define REGDLL_API #else #define REGDLL_API Q_DECL_IMPORT #endif #else #define REGDLL_API __attribute__ ((visibility ("default"))) #endif namespace RegFuncs { // 类被 REGDLL_API 修饰。所有的函数都可以载外部调用 class REGDLL_API PubRegFuncs { public: static void LoadMarkerData(const QString &fileName); }; // 被 REGDLL_API 修饰的函数才可以载外部调用 class MarkerRegistration { public: REGDLL_API static bool GetCoefficient(std::string filePath); }; }
GCC 4.0以后,提供visibility属性,可以应用到函数、变量、模板以及C++类。
#ifdef __GNUC__ >= 4 #ifdef FBC_EXPORT #define FBC_API_PUBLIC __attribute__((visibility ("default"))) #define FBC_API_LOCAL __attribute__((visibility("hidden"))) #else #define FBC_API_PUBLIC #define FBC_API_LOCAL #endif #else #error "------ requires gcc version >= 4.0 ------" #endif
使用(MSVC)
gcc 可以直接 -fvisibility=hidden
MSVC该怎么操作?没找到合适的办法
每天cpp文件是一个编译单元,单元有三个符号:
编译阶段:只要声明就可以
链接阶段:链接器就是把这些符号相互链接,少了那个都会链接失败。
静态库 <-- 静态库
MSVC只需链接静态库,gcc需要链接两个静态库
静态库 <-- 动态库
动态库依旧被动态调用
MSVC只需链接静态库,gcc需要链接静态和动态库
如果你写的静态库引入其他库,还是改成动态库吧。
动态库 <-- 静态库
MSVC、gcc 只需链接动态库
试了下可行,限制挺多
动态库 <-- 动态库
MSVC、gcc 只需链接动态库
静态库没有链接这个步骤,静态库如果用了其他静态库或者动态库需要手动链接
动态库有链接步骤,链接静态库则把静态库全部放进来,链接动态库则只放入符号再程序启动时候链接。
动态库可以由多个程序共享, 节省内存,易于升级。静态库外部依赖少, 更易于部署。
目前个人理解是这样,有错误请指正。