繁体   English   中英

静态库和共享库,符号共享吗?

[英]Static libraries and shared objects, are symbols shared?

我正在创建一个帮助程序,以在C ++类和Lua对象之间创建多个继承。 因为Lua将C / C ++用户对象存储为void *,所以在检索对象时很难进行安全的强制转换。

例如,

如果你有

class A { }
class B { }
class C : public A, public B { }

然后将C类型的对象传递给Lua,传递C实例的地址,当需要将其强制转换为B时,C ++编译器会自动将指针对准B在C中的位置,因此这是不安全的直接将void *指针从C强制转换为B。

为避免此问题,我使用了一种转换器。 在Lua中,对象包含其名称作为字符串,因此,当您需要将对象从类型转换为其他类型时,它使用如下转换器:

converters [“ B”] [“ C”](mypointer,myresultpointer);

这是帮助创建这些转换器的类:

// Common.h

#include <functional>
#include <memory>
#include <unordered_map>
#include <string>

typedef std::function<void (void *, void *)> LuaConverter;

typedef std::unordered_map<
        std::string,
        std::unordered_map<
            std::string,
            LuaConverter
        >
    > LuaConverters;

class LuaeClass {
public:
    static LuaConverters converters;

public:
    template <class From, class To>
    static void createConverter(const std::string &fromName,
                    const std::string &toName)
    {
        converters[toName][fromName] = [&] (void *ptr, void *result) -> void {
            std::shared_ptr<From> *from = static_cast<std::shared_ptr<From> *>(ptr);
            *((std::shared_ptr<To> *)result) = std::static_pointer_cast<To>(*from);
        };
    }
};

此类被编译为静态库,以在项目中多次使用。

对象需要作为shared_ptr传递(它还解决了所有权和删除问题)。 它运作良好,但是当用作静态库时会出现段错误。

然后,我有一个简单的模块Battery,被编译为共享对象并链接到公共库。

在示例的范围内,它没有太多功能,但实际上使用了LuaeClass:

// Battery.cpp

#include <lua.hpp>

#include "Common.h"

class Battery {
public:
    int getPercent() {
        return 100;
    }
};

extern "C" int luaopen_battery(lua_State *L)
{
    LuaeClass::createConverter<Battery, Battery>("Battery", "Battery");

    return 0;
}

这被编译为名为Battery.so的共享对象,Lua将使用dlopen()和dlcose()进行加载。

最后,主要。 它还链接到common并使用它来创建对象。

// main.cpp

#include <iostream>
#include <memory>
#include <string>

#include <lua.hpp>

#include "Common.h"

using namespace std;

class LuaDeleter {
public:
    void operator()(lua_State *L) {
        lua_close(L);
    }
};

typedef unique_ptr<lua_State, LuaDeleter> LuaState;

int main(void)
{
    LuaState L(luaL_newstate());

    luaL_requiref(L.get(), "_G", luaopen_base, 1);
    luaL_requiref(L.get(), "package", luaopen_package, 1);

    // This will dlopen() and dlclose()
    string code = "local battery = require \"battery\"";

    LuaeClass::createConverter<int, int>("Int", "Int");

    if (luaL_dostring(L.get(), code.c_str()) != LUA_OK) {
        cerr << lua_tostring(L.get(), -1) << endl;
    }

    return 0;
}

总结一下:

  • Common.cpp,Common.h被编译为简单的静态库(libcommon.a)
  • Main.cpp,已编译并链接到libcommon.a
  • Battery.cpp,编译为共享库并链接到libcommon.a

出口处的主要段错误,核心文件说它在std :: function <>的析构函数中,所以我猜它在同一指针上被多次调用,对吗?

静态库数据是否在所有代码中共享? 如何避免这个问题?

核心的开始

#0  0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1  0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()

下一个跟踪是不可读和不可用的。

静态库的代码和全局/静态数据将注入到链接它的每个模块中。 因此,对于您的情况,项目中存在多个LuaeClass::converters实例。 并且您需要在每个链接静态库的模块中调用luaopen_battery()

我不确定您的崩溃是否与静态链接有关,但是我很确定您使用了复杂的实现。

您要解决的第一个问题是将void*安全地转换为A*, B*, C* 您要导出到Lua的哪个类/接口? 如果是class C ,则可以在C类中定义以下方法:

void pushThis(lua_State *L);
static C* getThis(lua_State *L, int idx);

两种方法都使用C* ,因此您不需要转换函数。 您可以使用元表将指针与其他用户数据区分开 如果您需要B* ,只需:

B* b = (B*)C::getThis(L, idx);

而且,您可能不一定需要shared_ptr。 当GC收集您的Lua对象时,shared_ptr不能帮助您删除C ++对象(因为shared_ptr仍然存在于堆中)。 相反,您必须在元表中实现__gc回调才能删除对象

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM