当前位置: 首页 > news >正文

Windows平台用vistual studio 2017打包制作C++动态库

1. 创建库项目

  1. 打开 Visual Studio 2017,选择 文件新建项目
  2. 选择 Visual C++Windows 桌面动态链接库 (DLL)静态库 (LIB)
    • 动态库 (DLL):生成 .dll.lib(导出符号表)。
    • 静态库 (LIB):生成 .lib(直接包含代码)。
  3. 输入项目名称(如 MyLibrary),点击 确定

2. 编写类代码

2.1示例:动态库 (DLL)

  1. 添加头文件MyClass.h):

    #pragma once// 导出宏定义
    #ifdef MYLIBRARY_EXPORTS
    #define MYLIBRARY_API __declspec(dllexport)
    #else
    #define MYLIBRARY_API __declspec(dllimport)
    #endifclass MYLIBRARY_API MyClass {
    public:MyClass();int Add(int a, int b);
    };
    
  2. 添加源文件MyClass.cpp):

    #include "MyClass.h"MyClass::MyClass() {}int MyClass::Add(int a, int b) {return a + b;
    }
    

2.2示例:静态库 (LIB)

  • 静态库不需要导出宏(直接包含完整代码):

    // MyClass.h
    #pragma onceclass MyClass {
    public:MyClass();int Add(int a, int b);
    };
    

3. 配置项目属性

  1. 设置导出符号(仅动态库需要)
    • 右键项目 → 属性C/C++预处理器预处理器定义
    • 添加 MYLIBRARY_EXPORTS(确保动态库项目导出符号)。
  2. 调整输出目录(可选):
    • 右键项目 → 属性常规输出目录,设置为 $(SolutionDir)bin\$(Platform)\$(Configuration)\
  3. 确保生成目标类型
    • 检查 配置类型(属性 → 常规配置类型)应为 动态库 (.dll)静态库 (.lib)

4. 编译生成库

  1. 选择 生成生成解决方案(或按 F7)。
  2. 生成的库文件会在输出目录中:
    • 动态库:MyLibrary.dllMyLibrary.lib
    • 静态库:MyLibrary.lib

5. 使用库

5.1在另一个项目中调用动态库

  1. 包含头文件

    #include "MyClass.h"
    
  2. 链接库文件

    • 右键项目 → 属性链接器输入附加依赖项,添加 MyLibrary.lib
    • 链接器常规附加库目录 中指定 .lib 文件路径。
  3. .dll 文件放在可执行文件目录

    • MyLibrary.dll 复制到可执行文件(.exe)的同一目录。
  4. 调用代码示例

    #include "MyClass.h"
    #include <iostream>int main() {MyClass obj;std::cout << "Add: " << obj.Add(3, 5) << std::endl;return 0;
    }
    

6. 常见问题

  • 符号未导出:确保在动态库项目中定义了 MYLIBRARY_EXPORTS
  • 链接错误:检查 .lib 文件路径是否正确。
  • 缺少 .dll:确保 .dll 文件在可执行文件目录或系统路径中。
  • 平台不匹配:确保生成库的平台(x86/x64)与调用项目一致。

7.静态库 vs 动态库

类型特点
静态库代码直接编译到可执行文件中,无需额外依赖。
动态库运行时加载,减少可执行文件体积,支持模块化更新。

8.设置debug模式生成的*_d.dll和*_d.lib

在 Visual Studio 中,可以通过配置项目属性来区分 DebugRelease 模式生成的库文件名(例如 MyLibrary_d.dllMyLibrary_d.lib)。以下是具体步骤:


8.1修改输出文件名(添加 _d 后缀)

(1) 针对 Debug 配置
  1. 右键项目 → 属性 → 确保顶部配置为 Debug 和对应的平台(如 x64)。

  2. 进入 常规目标文件名

    • 默认值为 $(ProjectName)
    • 修改为 $(ProjectName)_d,这样生成的库文件会带 _d 后缀。
(2) 针对 Release 配置
  1. 切换顶部配置为 Release
  2. 确保 目标文件名$(ProjectName)(无后缀)。

8.2调整输出目录(可选)

为了区分 Debug 和 Release 的输出文件,可以设置不同的输出目录:

  1. 常规输出目录 中,修改为:

    • Debug$(SolutionDir)bin\$(Platform)\Debug\
    • Release$(SolutionDir)bin\$(Platform)\Release\

8.3链接器导入库名称(自动同步)

  • 无需手动修改:当修改 目标文件名 后,链接器生成的 .lib 文件名会自动同步(例如 MyLibrary_d.lib)。

8.4验证生成结果

编译项目后,检查输出目录:

  • Debug 模式:生成 MyLibrary_d.dllMyLibrary_d.lib
  • Release 模式:生成 MyLibrary.dllMyLibrary.lib

8.5调用方项目配置

如果其他项目要链接该库,需根据配置引用对应的文件:

  1. Debug 配置
    • 附加依赖项MyLibrary_d.lib
    • 库目录$(SolutionDir)bin\$(Platform)\Debug\
  2. Release 配置
    • 附加依赖项MyLibrary.lib
    • 库目录$(SolutionDir)bin\$(Platform)\Release\

8.6完整配置示例

(1) 项目属性(Debug)
配置项
目标文件名$(ProjectName)_d
输出目录$(SolutionDir)bin\$(Platform)\Debug\
运行时库MDd(多线程调试 DLL)
(2) 项目属性(Release)
配置项
目标文件名$(ProjectName)
输出目录$(SolutionDir)bin\$(Platform)\Release\
运行时库MD(多线程 DLL)

8.7自动化配置(使用宏)

若需更灵活的命名规则,可以通过编辑 .vcxproj 文件自定义生成逻辑:

<!-- 在 .vcxproj 文件中添加条件 -->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"><TargetName>$(ProjectName)_d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'"><TargetName>$(ProjectName)</TargetName>
</PropertyGroup>

运行 HTML


8.8注意事项

  1. 运行时库一致性
    • Debug 和 Release 配置的 代码生成运行时库 必须与调用方项目一致(如 MDdMTd)。
  2. 清理旧文件
    • 修改配置后,先清理解决方案(生成清理解决方案),再重新生成。
  3. 符号导出宏
    • 如果导出宏(如 JIEBASEGMENTER_API)依赖项目名称,确保名称修改不影响宏定义。

9.隐藏第三方库头文件

很多时候我们制作一个功能类,如果调用第三方库在头文件中有引用,那么在其他人调用的时候也要将第三方库链接到项目中。当第三方库比较多的时候,这样就比较麻烦。我们如何能将第三方库头文件完全隐藏在生成的二进制库文件中呢?下面让我们详细说明一下。
原来的类:

9.1 隐藏前的头文件

// MyLibrary.h
#pragma once
#include <third/third_lib.h>  // 引用 OpenCV 头文件#ifdef MYLIBRARY_EXPORTS
#define MYLIBRARY_API __declspec(dllexport)
#else
#define MYLIBRARY_API __declspec(dllimport)
#endifclass MYLIBRARY_API MyLibrary {
public:// 构造函数MyLibrary(const std::string& str);// 成员函数声明std::vector<std::string> getWords(const std::string& sentence);// ......private:ThirdLib* thirdLib;
};

9.2 隐藏前的源码文件

// MyLibrary.cpp
MyLibrary::MyLibrary(const std::string& str):
thirdLib(std::make_unique<ThirdLib>(str))
{// 逻辑
}std::vector<std::string> MyLibrary::getWords(const std::string& sentence)
{// 逻辑
}

9.3 隐藏后的头文件

// MyLibrary.h
#pragma once#ifdef MYLIBRARY_EXPORTS
#define MYLIBRARY_API __declspec(dllexport)
#else
#define MYLIBRARY_API __declspec(dllimport)
#endif// 前向声明实现类(完全隐藏 third)
class ThirdLibImpl;class MYLIBRARY_API MyLibrary {
public:// 构造函数MyLibrary(const std::string& str);// 析构函数~MyLibrary();// 禁用拷贝(避免浅拷贝问题)MyLibrary(const MyLibrary&) = delete;MyLibrary& operator=(const MyLibrary&) = delete;// 移动语义支持(可选)MyLibrary(MyLibrary&&) noexcept;MyLibrary& operator=(MyLibrary&&) noexcept;// 成员函数声明std::vector<std::string> MyLibrary::getWords(const std::string& sentence);// ......private:std::unique_ptr<ThirdLibImpl> thirdLibImpl;
};

9.4 隐藏后的源码文件

// MyLibrary.cpp
#include "pch.h"
#include "MyLibrary.h"//--------------------- 实现类定义(完全隐藏) ---------------------
class ThirdLibImpl{
public:ThirdLibImpl(const std::string& str) {// 逻辑}std::vector<std::string> getWords(const std::string& sentence){// 逻辑}
private:ThirdLib* thirdLib; // 实际持有的 cppjieba 实例
};//--------------------- 接口类实现 ---------------------
MyLibrary::MyLibrary(const std::string& str) : thirdLibImpl(std::make_unique<ThirdLib>(str)) {}MyLibrary::~MyLibrary() = default;// 移动构造函数
MyLibrary::MyLibrary(MyLibrary&& other) noexcept: thirdLibImpl(std::move(other.thirdLibImpl)) {}// 移动赋值运算符
MyLibrary& MyLibrary::operator=(MyLibrary&& other) noexcept {if (this != &other) {pimpl_ = std::move(other.thirdLibImpl);}return *this;
}// 成员函数转发到实现类
std::vector<std::string> MyLibrary::getWords(const std::string& sentence)
{return thirdLibImpl->getWords(sentence);
}

相关文章:

  • STL详解 - stack与queue的模拟实现
  • 《AI大模型应知应会100篇》第22篇:系统提示词(System Prompt)设计与优化
  • USART讲解
  • 深入理解类:ArkTS面向对象编程的核心概念
  • 批量操作的优点
  • idea mvn执行打包命令后控制台乱码
  • 【无标题】STM32CubeMX
  • 【SpringBoot+Vue自学笔记】003 SpringBoot Controll
  • Oracle DBMS_SCHEDULER 与 DBMS_JOB 的对比
  • 【音视频开发】第五章 FFmpeg基础
  • k8s调度器:如何控制Pod的分布
  • 【Android】 如何将 APK 内置为系统应用(适用于编辑设置属性)
  • vim编辑器
  • Android Compose Activity 页面跳转动画详解
  • 更换 CentOS 7.9 的系统源
  • 智能交响:EtherCAT转Profinet网关开启汽车自动化通信新纪元
  • Linux电源管理(三),CPUIdle 和 ARM的PSCI
  • VFlash的自动化和自定义动作
  • 深入理解Qt状态机的应用
  • C++23 新特性:std::size_t 字面量后缀 Z/z
  • 香港特区政府强烈谴责美参议员恐吓国安人员
  • 南宁一学校发生伤害案件,警方通报:嫌疑人死亡,2人受伤
  • 陕西省市监局通报5批次不合格食品,涉添加剂超标、微生物污染等问题
  • 白玉兰奖征片综述丨海外剧创作趋势观察:跨界·融变·共生
  • 定制基因编辑疗法治愈罕见遗传病患儿
  • 农行回应“病重老人被要求亲自取钱在银行去世”:全力配合公安机关调查