【问题标题】:How to avoid #include dependency to external library如何避免#include 对外部库的依赖
【发布时间】:2012-12-20 19:03:44
【问题描述】:

如果我正在创建一个带有如下头文件的静态库:

// Myfile.h

#include "SomeHeaderFile.h" // External library

Class MyClass
{

// My code

};

在我自己的项目中,我可以告诉编译器(在我的例子中是 Visual Studio)在哪里寻找 SomeHeaderFile.h。但是,我不希望我的用户关心这一点 - 他们应该能够包含我的标头,而无需通知 他们的 编译器 SomeHeaderFile.h 的位置。

这种情况一般是怎么处理的?

【问题讨论】:

  • 当用户使用你的库时,你有它在某个地方吗??
  • @g-makulik 不,我正在使用的外部库是仅标头库。我希望将外部库的所有声明/定义完全合并到我自己的库中,以便从用户的角度来看没有依赖性
  • 您可以将该标题的内容粘贴到您的文件中。
  • 嗯 ...,如果它只是标题,那么您的客户还需要找到它以及您的头文件,如果它是类型,则需要查看您界面中任何地方引用的类。
  • 转发声明你在头文件中使用的外部库的结构/类,并在你的源代码中包含头文件。

标签: c++ dependencies static-libraries header-files


【解决方案1】:

这是一个经典的“编译防火墙”场景。有两种简单的解决方案:

  1. 从外部库中向前声明您需要的任何类或函数。然后仅在您的 cpp 文件中包含外部库的头文件(当您实际需要使用您在标头中前向声明的类或函数时)。

  2. 使用 PImpl 习惯用法(或 Cheshire Cat),您可以在其中前向声明一个“实现”类,该类您仅私下声明和定义(在 cpp 文件中)。您使用该私有类来放置所有依赖于外部库的代码,以避免在您的公共类(在您的头文件中声明的那个)中留下任何痕迹。

这是使用第一个选项的示例:

#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H

class some_external_class;  // forward-declare external dependency.

class my_class {
  public:
    // ...
    void someFunction(some_external_class& aRef);  // declare members using the forward-declared incomplete type.
};

#endif

// in the cpp file:

#include "my_header.h"
#include "some_external_header.h"

void my_class::someFunction(some_external_class& aRef) {
  // here, you can use all that you want from some_external_class.
};

这是选项 2 的示例:

#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H

class my_class_impl;  // forward-declare private "implementation" class.

class my_class {
  private:
    std::unique_ptr<my_class_impl> pimpl; // a vanishing facade...
  public:
    // ...
};

#endif

// in the cpp file:

#include "my_header.h"
#include "some_external_header.h"

class my_class_impl {
  private:
    some_external_class obj;
    // ...
  public:
    // some functions ... 
};

my_class::my_class() : pimpl(new my_class_impl()) { };

【讨论】:

  • 警告:用户仍然需要扩充他们的库路径才能找到依赖项的库,前提是它不是一个只有头文件的库。
  • @matthieuM 除非您在用户收到的库中包含依赖项的库(或相关目标文件),对吧?
  • @JonBentley 有几个选项。如果您为您的库提供运行时库(.so 或 .dll),那么您可以将该库静态链接到外部库(将其包含到您提供的 .so 或 .dll 中),或者您可以提供您动态链接到您的库的外部库的运行时库(或要求用户将其安装在他的系统上)。如果您提供静态库(.a 或 .lib),则必须提供(或要求)必要的依赖库(或目标文件)。如果您分发资源,那么人们当然会需要一切。
【解决方案2】:

假设外部头文件包含以下内容:

外部.h

class foo
{
public:
   foo();
};

在你的库中你使用 foo:

myheader.h:

#include "external.h"

class bar
{
...
private:
   foo* _x;
};

要编译您的代码,您所要做的就是转发声明 foo 类(之后您可以删除包含):

class foo;

class bar
{
...
private:
   foo* _x;
};

然后您必须在源文件中包含 external.h。

【讨论】:

  • 如果头文件中没有完全提供实现,或者源代码集成在生成的库中,OP 的用户仍然需要提供到外部库的正确链接路径。
  • @g-makulik 我假设 OP 将静态链接他/她的库中的外部库。如果他/她这样做,那么客户就不会知道/关心 3rd 方库。
  • 这不只是共享库的一个选项吗?我认为静态库不能包含其他静态库,可以吗?
  • @g-makulik 我相信您可以指示您的编译器将一个静态库的全部内容包含到另一个静态库中(例如,使用 Visual Studio 中的 Librarian),并且有工具可以手动提取部分静态库一个静态库并将它们插入另一个库 - 这些是我读过但自己没有尝试过的东西。但是对于这个特殊问题,第三方库只有标题。
  • @Mustafa 谢谢,有帮助的答案。我接受 Mikael 只是因为他提供了除您之外的替代解决方案。
猜你喜欢
  • 2020-04-06
  • 2020-03-29
  • 2014-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-06
相关资源
最近更新 更多