如何更改 cpp .o 文件中的符号出现(在参数列表等内)?

问题描述 投票:0回答:1

我正在为实现类似功能的多个静态库编写一个包装器。其中两个库共享相同的类名并且(由于它们的年龄)不使用名称空间。

这会导致我的程序出现编译器错误,因为该类有两种不同的实现。

我通过使用 #define 为其中一个库重新定义类名来解决编译器问题。看起来像这样:

#define foo lib_foo

#include "lib.h"

#undef foo

起初,这似乎有效。但现在,当为 lib_foo 的实例赋值时,我收到此错误:

undefined reference to `lib_foo::operator=(lib_foo const&)'

该类似乎覆盖了赋值运算符(并且显然还有其他以

lib_foo
作为输入参数的函数),并且链接器无法找到这些函数的相应实现,因为它们是在 .cpp 文件中定义的没有得到#define 处理。

我无法将命名空间引入原始库(这不是我的库,它会破坏与其他项目的兼容性)。

我的计划是在库的目标文件中将

foo
的出现更改为
lib_foo
,但我不知道该怎么做。 我发现这篇post可以处理此类问题,但对于 c 函数来说,并且以更简单的方式。

有人有这方面的经验吗?或者有更简单的方法来处理这个问题吗?

c++ gcc static-libraries symbols name-collision
1个回答
0
投票

为每个外部库编写一个单独的共享库包装器,并在其中给出可区分的名称。您还可以隐藏/删除除包装器之外的所有符号。这是一种干净的方法,不需要您修改现有的库。仅当您不想或不能使用共享库时,它才不起作用,例如在嵌入式裸机环境中。

您仍然可以重命名静态库中的损坏符号,其方式与您找到的答案类似。只需将

objcopy
--redefine-sym
选项一起使用即可。最糟糕的部分是需要正确处理损坏的符号。示例:

lib1.h

class foo {
    int value;
public:
    foo(int value_);
    foo & operator=(foo const & foo_);
};

lib1.cpp

#include "lib1.h"

foo::foo(int value_) : value{value_} {}

foo & foo::operator=(foo const & foo_) {
    value = foo_.value;
    return *this;
}

lib2.h

class foo {
    float value;
public:
    foo(float value_);
    foo & operator=(foo const & foo_);
};

lib2.cpp

#include "lib2.h"

foo::foo(float value_) : value{value_} {}

foo & foo::operator=(foo const & foo_) {
    value = foo_.value;
    return *this;
}

主.cpp

#include <cstdio>

#define foo lib1_foo
#include "lib1.h"
#undef foo

#define foo lib2_foo
#include "lib2.h"
#undef foo

int main() {
    lib1_foo int_object(1);
    lib2_foo float_object(1.5);
    lib1_foo other_int_object(-1);
    lib2_foo other_float_object(-1.5);
    other_int_object = int_object;
    other_float_object = float_object;
}

模拟构建和使用库的过程:

$ g++ -o lib1.cpp.o -c lib1.cpp -I$(pwd)
$ g++ -o lib2.cpp.o -c lib2.cpp -I$(pwd)
$ ar qc lib1.o lib1.cpp.o
$ ar qc lib2.o lib2.cpp.o
$ g++ main.cpp lib1.o lib2.o -I$(pwd)

未定义的引用出现在最终命令的链接阶段。我们需要知道新的受损符号来替换当前的受损符号,因此

objdump -t lib1.o
告诉我们我们有符号
_ZN3fooC2Ei
_ZN3fooC1Ei
_ZN3fooaSERKS_
,因此将每个
3foo
子串替换为
8lib1_foo
lib2
也一样。或者,我们可以编译
main.cpp
的目标文件并查看其中缺少的符号名称。

$ objcopy --redefine-sym _ZN3fooC1Ei=_ZN8lib1_fooC1Ei --redefine-sym _ZN3fooC2Ei=_ZN8lib1_fooC2Ei --redefine-sym _ZN3fooaSERKS_=_ZN8lib1_fooaSERKS_ lib1.o lib1c.o
$ objcopy --redefine-sym _ZN3fooC1Ef=_ZN8lib2_fooC1Ef --redefine-sym _ZN3fooC2Ef=_ZN8lib2_fooC2Ef --redefine-sym _ZN3fooaSERKS_=_ZN8lib2_fooaSERKS_ lib2.o lib2c.o
$ g++ main.cpp lib1c.o lib2c.o -I$(pwd)

这次没有链接错误。如果有很多符号需要重新定义,我们可以使用

--redefine-syms
代替文件。我不推荐任何修改现有库和标头的方法,因为很容易错过因重命名而引入的一些运行时失败,但如果您确实需要它,这是可能的。

© www.soinside.com 2019 - 2024. All rights reserved.