针对修改的头文件进行编译 [英] compiling against a modified header file

查看:139
本文介绍了针对修改的头文件进行编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个头文件类定义和一些包括。该类包含一些公共函数和一些私有变量。该类被编译成可执行文件。

I have a header file with a class definition and some includes. The class contains some public functions and some private variables. The class gets compiled into an executable.

假设有人接受这个头文件并创建一个公共副本。他删除所有的包含和私有变量(使用未定义符号的前向声明)。然后,他编译自己的代码(它调用有问题的类的公共函数)对公共头文件,并创建一个.so文件。

Lets say that somebody takes this header file and creates a "public" copy. He removes all the includes and private variables (uses forward declarations for the undefined symbols). Then he compiles his own code (which calls the public functions of the class in question) against the "public" header file and creates an .so file.

如果与可执行文件链接,此库会正常工作吗

Would this library work properly


  • 如果是在运行时动态加载,

  • if it is linked with the executable?
  • if it is dynamically loaded during runtime?

推荐答案

p>正如在评论中所解释的,你字面上描述的内容不会工作,但目标是合理的。我的理解是,你想隐藏一个类的实现细节,同时为插件提供一个固定的接口,以便插件代码开发可以从程序的其余部分脱钩。

As explained in the comments, what you've literally described won't work but the goal is reasonable. My understanding is that you want to hide the implementation details of a class while providing a fixed interface for plugins so that plugin code development can be decoupled from the rest of the program.

你不能通过提供一个虚假的标题来直接隐藏私有成员数据和函数。首先,ODR违反Igor Tandetnik指出。这不只是一个任意的规则。私有数据影响存储对象所需的内存,因此代码应该如何处理该对象。公共和私有函数的相对地址必须在多态性的常见vtable实现中已知。

You can't just literally hide the private member data and functions by giving a false header. First of all, ODR violation as Igor Tandetnik points out. This isn't just an arbitrary rule. Private data affects the memory required to store an object and hence how code should handle that object. The relative addresses of both public and private functions must be known in the common vtable implementation of polymorphism.

我们需要间接。我们的接口将告诉客户端代码它的公共函数是什么,只是它需要空间来存储指向实现类的指针。实现类的细节不需要知道。这是 pimpl成语。下面是如何使用动态加载的概述。

We need indirection. Our interface will tell client code what its public functions are and simply that it needs space to store a pointer to an implementation class. The details of the implementation class need not be known. This is the pimpl idiom. Here's an outline of how it can be used with dynamic loading.

main.cpp

#include <iostream>
#include <dlfcn.h>

#include "interface.h"

typedef int (bar_type)(const Interface&);

int main() {
#ifndef EXE_INPUT
#define EXE_INPUT 5
    Interface interface(EXE_INPUT);
#endif

    void* plugin = dlopen("plugin.so", RTLD_LAZY);
    if (plugin == NULL) {
        std::cout << dlerror() << std::endl;
        return 1;
    }

    bar_type* bar_ptr = (bar_type*)dlsym(plugin, "bar");
    if (bar_ptr == NULL) {
        std::cout << dlerror() << std::endl;
        return 1;
    }

    const int ret = (*bar_ptr)(interface);

    std::cout << "The value from the plugin is " << ret << std::endl;
}

interface.h

interface.h

#ifndef INTERFACE_H
#define INTERFACE_H
class Implementation;

class Interface
{
public:
    Interface(const int);
    ~Interface();
    int foo(int) const;
private:
    Implementation* imp_ptr;
};
#endif

interface.cpp

interface.cpp

#include "interface.h"

struct Implementation {
    Implementation(const int v)
        :   v(v)
    {}

    int foo(const int w) {
        return v * w;
    }

    int v;
    /* this struct is not exposed, do whatever you want here */
};

Interface::Interface(const int v)
    :   imp_ptr(new Implementation(v))
{}

Interface::~Interface() {
    delete imp_ptr;
}

/* if this signature changes or other functions get added
 * to Interface, plugin must be recompiled */
int Interface::foo(const int w) const {
    return imp_ptr->foo(w);
}

plugin.cpp

plugin.cpp

#include "interface.h"
#include "plugin.h"

extern "C" int bar(const Interface& i)
{
#ifndef PLUGIN_INPUT
#define PLUGIN_INPUT 11
    return i.foo(PLUGIN_INPUT);
#endif
}

plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H
#include "interface.h"
extern "C" int bar(const Interface& i);
#endif

编译和链接。我碰巧运行操作系统X.对于Linux删除-undefined dynamic_lookup。

Compile and link. I happen to be running OS X. For Linux remove "-undefined dynamic_lookup".

g++-4.8 -o main main.cpp interface.cpp
g++-4.8 -shared -fpic -undefined dynamic_lookup -ldl -o plugin.so plugin.cpp 

请注意,我们单独编译和链接。具体来说,plugin.cpp不知道interface.cpp中有什么。

Note that we compile and link separately. Specifically, plugin.cpp has no idea what's in interface.cpp.

$ ./main
The value from the plugin is 55

您可以更改 interface.cpp 如你所愿,无需重新编译插件。动态加载在这里不是绝对必要的。它也将与动态链接一起工作。

You can change interface.cpp as you please without need to recompile plugin. The dynamic loading isn't absolutely necessary here. It would also work with dynamic linking.

Caveat:C ++标准对用户定义的类必须如何布局在内存中的需求很少。如果你尝试在插件和主程序之间传递用户类实例,你可能不会得到你的期望,特别是如果主程序和插件是用不同的编译器编译。

Caveat: The C++ Standard makes few demands of how user defined classes must be laid out in memory. If you try to pass user class instances between the plugin and the main program you might not get what you expect, especially if the main program and plugin were compiled with different compilers.

这篇关于针对修改的头文件进行编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆