【问题标题】:How to include external library in your lib?如何在你的库中包含外部库?
【发布时间】:2020-04-04 04:56:45
【问题描述】:

我正在编写一个库,它本身使用一个只有标头的 3rd-party 库。

目前,即使我将其构建为静态库,客户端代码仍需要添加该第 3 方库,因为它在我的库的头文件中声明。

我该怎么做才能使我的代码使用的所有内容最终都保存在静态库中,并且客户端代码不必包含我在头文件中包含的内容?

有一个similar question,但答案似乎对我不起作用,因为我正在构建具有所有依赖项的静态库(即配置包含路径并且构建成功)。

为了给你更好的视角,我的Core.h 是这样的:

#ifndef CORE_H
#define CORE_H

#include <iostream>
#include <string>
#include <vector>
#include <functional>

#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>

namespace py = pybind11;
using namespace py::literals;

typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;

class Core
{
private:
    py::scoped_interpreter guard{};
    py::object cls;
    py::object obj;
    py::object startFunc;
    py::object stopFunc;
    py::object setCpuAffinityFunc;
    py::object addCallbackFunc;
    py::object removeCallbackFunc;
    py::object getCallbacksFunc;

    py::dict kwargs;
    py::list callbackList;

public:
    Core();
    Core(bool showFeed);
    ...

如您所见,这里的问题是我的代码中使用的 Pybind11 仅标头库。不幸的是,由于这些#include 语句包含在我的头文件中,因此客户端代码还需要将pybind11 添加到他们的项目中才能构建他们的项目。

除了将所有py::* 转换为void* 然后将头文件包含在Core.cpp 文件中之外,还有其他方法吗?

【问题讨论】:

  • 如果它们是指针,可以将py::* 替换为void*,但是您如何/如何使用类Core?
  • @shingo :我将不得不将它们重铸回 py:: 它们在实现方面的内容并继续。但这根本不理想,因为 pybind 在这个部门很头疼,因为我对它不是很熟悉。所以这是我考虑的最后手段
  • @Rika 问题:您必须只使用 .lib 吗?没有DLL?因为我认为 DLL 可以解决您的问题
  • @Landstalker 我也可以使用 DLL,实际上我应该同时实现这两种情况。但现在我遇到了静态库的问题。但是,我想我也会在 DLL 中遇到问题。如果您能详细解释如何在 dll 中避免这种情况,将不胜感激!

标签: c++


【解决方案1】:

我为您找到了解决方案。考虑您的情况:客户使用的库使用了第三个库。
这可以通过以下解决方案来吸收:

  • Client : .exe project是只知道Core project的客户
  • Core : .lib project 使用第三方(Header_lib project),可以被Client project 使用
  • Header_lib project 是第三方库

解决方案配置:
- Client Project 依赖于 Core project:

-Core project 依赖于Header_Lib project:

在代码中:

  1. Client 创建 CCore 对象的实例 cc。
  2. cc 调用 useCoreParty 函数。
  3. useCoreParty 函数使用ThirdParty

当我导出core.lib:

DUMPBIN /SYMBOLS   "G:\Core.lib" | findstr "useThirdParty"  

我明白了:

这意味着第三方部分包含在您的core.lib 中。因此,客户端不需要包含第三方库

【讨论】:

  • 非常感谢。但是你的core.h 怎么样?它是否有任何使用来自 3rd 方库的任何类型的方法?这就是我的情况。显然我要么必须使用前向声明或void*,以便我的core.h 没有任何第三方库的迹象,因此客户端可以轻松包含它,但我正在使用的库在演员阵容方面令人头疼我正在寻找是否有其他选择。我真的很感谢你的帮助
  • @Rika 我将代码移到了我的core.h 中以使其与您的情况相同,并且我更新了我的帖子(见第一张图)。如果代码在我的core.h 或core.cpp 中,它不会改变任何东西。图书馆的组成保持不变。希望对你有帮助
  • @Rika 是否有任何方法可以使用来自 3rd 方库的任何类型? 是的。它使用一个类对象CuseThirdParty ObjThirdParty; 和一个简单的函数useThirdParty ()
  • 就我而言,3dparty 库中有几个类和类型用作方法参数类型等,因此客户端需要包含 3rdparty 头文件。否则,方法类型等在尝试使用时将不知道。
  • @Rika 无论如何,你的项目似乎很感兴趣并且充满挑战
【解决方案2】:

我最终使用了前向声明,但不适用于 Pybind11 类。 这就是我最终做的:


//header file
#ifndef CORE_H
#define CORE_H

#include <iostream>
#include <string>
#include <vector>
#include <functional>

struct Wapper; 

class Core
{
private:

    Wapper* cls;
    Wapper* obj;
    Wapper* startFunc;
    Wapper* stopFunc;
    ...
public:
    Core();
    ...
};

在实现文件中:

#include <pybind11/pybind11.h>
...

namespace py = pybind11;
using namespace py::literals;

struct Wrapper
{
    py::object obj;
};

py::scoped_interpreter guard{};

Core::Core()
{
    this->cls = new PyWrapper();
    this->obj = new PyWrapper();
    ...
    auto serviceUtilsModule = py::module::import("Module");
    this->cls->obj = serviceUtilsModule.attr("SomeClass");
    ...
    this->obj->obj = this->cls->obj(**kwargs);
    ...
}

这从客户端代码中隐藏了 pybind11 依赖并实现了我所追求的!

基本上,我转发声明了一个新类型,从中创建了一个指针,并在 core.cpp 中定义了它。并且由于我在core.cpp 中定义,我有很多选择,其中之一是在其中添加一个 py::object 并改用它。

旁注:
我注意到客户端项目必须包含Python 的include 和library 文件夹,否则,它会抱怨找不到Pybind11!这真的很奇怪!但由于客户端代码将在必须安装 python 包的环境中运行,所以这不是问题! 不过,我也想知道为什么会这样!

【讨论】:

  • 您采用了正确的方法,但恕我直言,它仍然有点过于细化。我会看到一个 PIMPL 习惯用法更像这样:pastebin.com/EW0YRU7e - 即面向公众的Core 仅具有公共成员函数,以及指向前向声明的实现类的单个指针。所有Core的成员函数只是将参数转发给对应的实现函数,实现基本上就是Core原来的样子。
  • 非常感谢。非常感谢您的友善和出色的答案/观点:)
猜你喜欢
  • 2011-01-21
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
  • 2014-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多