Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++:如果两个库使用相同的源代码,那么会发生什么?_C++_Design Patterns_Shared Libraries_Token Name Resolution - Fatal编程技术网

C++:如果两个库使用相同的源代码,那么会发生什么?

C++:如果两个库使用相同的源代码,那么会发生什么?,c++,design-patterns,shared-libraries,token-name-resolution,C++,Design Patterns,Shared Libraries,Token Name Resolution,我怀疑是否可能再次使用相同的源文件common.cpp构建lib1.so和lib2.so。现在我想用这两个库构建我的应用程序 我的问题是 是可能的还是会给我错误? 如果它将成功构建,那么如何解决命名问题? 假设foo是一个普通的类。foo_v1是lib1.so中foo的对象,foo_v2是lib2.so中foo的对象。现在在bulid的应用程序中会发生什么?也可以在应用程序中创建foo对象吗? 自然会建议你考虑建立共同的功能共享。 由lib1.so和lib2.so组成一个不同的共享库libcom

我怀疑是否可能再次使用相同的源文件common.cpp构建lib1.so和lib2.so。现在我想用这两个库构建我的应用程序

我的问题是

是可能的还是会给我错误? 如果它将成功构建,那么如何解决命名问题? 假设foo是一个普通的类。foo_v1是lib1.so中foo的对象,foo_v2是lib2.so中foo的对象。现在在bulid的应用程序中会发生什么?也可以在应用程序中创建foo对象吗?
自然会建议你考虑建立共同的功能共享。 由lib1.so和lib2.so组成一个不同的共享库libcommon.so

但是如果您仍然希望静态链接公共功能 同样地1 您可以将这两个共享库链接到lib1.so和lib2.so中 你的节目。链接器对此没有问题。这是一个 说明:

普通的

foo.cpp

酒吧

bar.cpp

现在我们将创建两个共享库,libfoo.so和libbar.so。这个 我们需要的源文件是foo.cpp、bar.cpp和common.cpp。第一 把它们都编译成 对象文件:

$ g++ -Wall -Wextra -fPIC -c foo.cpp bar.cpp common.cpp
以下是我们刚刚制作的对象文件:

$ ls *.o
bar.o  common.o  foo.o
现在使用foo.o和common.o链接libfoo.so:

然后使用bar.o和common.o链接libbar.so

我们可以看到共同点:。。。符号由libfoo.so定义和导出:

现在我们将制作一个与这些库链接的程序:

main.cpp

它叫福;它叫酒吧, 它调用common::print1

它的运行方式如下:

$ ./prog
void foo::i_am() const. (count = 0)
void bar::i_am() const. (count = 1)
int main(). (count = 2)
这很好。您可能担心静态类变量的两个副本 common::count将在程序中结束-一个来自libfoo.so,另一个来自libbar.so, foo会增加一个副本,bar会增加另一个副本。但那没有发生

链接器如何解析公共::。。。符号?好吧,看看我们需要找到他们破损的形状, 链接器看到它们时:

$ nm common.o | grep common
0000000000000140 t _GLOBAL__sub_I_common.cpp
0000000000000000 B _ZN6common5countE
0000000000000000 T _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
000000000000007c T _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
它们都在那里,我们可以通过c++filt判断哪一个是哪一个:

因此链接器告诉我们它从./libfoo.So链接了common::count的定义。同样地 公共::print1的定义。同样,common::print2的定义也是如此。它把所有的事情联系在一起 普通::。。。libfoo.so中的符号定义

它告诉我们main.o中对common::print1的引用已解析为libfoo.so中的定义。同样地 libbar.so中对common::count的引用。同样,对common::print1和 公共::libbar.so中的print2。所有的共同点::。。。程序中的符号引用已解析为 libfoo.so提供的定义

因此,没有多个定义错误,也不存在关于common的哪些副本或版本的不确定性:。。。使用符号 通过程序:它只使用libfoo.so中的定义

为什么??因为libfoo.so是链接中第一个提供定义的库 对于公共::…符号。如果我们以-lfoo和-lbar的相反顺序重新链接prog:

$ g++ -o prog main.o -L. -lbar -lfoo -Wl,-rpath=$PWD \
    -Wl,-trace-symbol=_ZN6common5countE \
    -Wl,-trace-symbol=_ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE \
    -Wl,-trace-symbol=_ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE        
main.o: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: definition of _ZN6common5countE
./libbar.so: definition of _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: definition of _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: reference to _ZN6common5countE
./libfoo.so: reference to _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
然后我们得到完全相反的答案。所有的共同点::。。。程序中的符号引用 现在解析为libbar.so提供的定义。因为libbar.so首先提供了它们。 仍然没有不确定性,这对程序没有影响,因为libfoo.so 和libbar.so链接公共::。。。来自同一对象文件common.o的定义

链接器不会尝试查找符号的多个定义。一旦它找到了一个 符号的定义,在输入对象文件或共享库中,它将引用绑定到 S到它已找到的定义,并已完成对S的解析 不在乎它以后找到的共享库是否可以提供S的另一个定义,相同或不同, 即使后来的共享库解析的符号不是S

导致多定义错误的唯一方法是强制链接器 静态链接多个定义,即强制其物理合并到输出二进制文件中 两个对象文件obj1.o和obj2.o都包含一个定义S。 如果这样做,则相互竞争的静态定义具有完全相同的状态,并且只有 程序可以使用一个定义,因此链接器必须使您失败。但它不需要注意任何错误 共享库提供的动态符号定义(如果已解析S,但未解析S)


[1] 当然,如果使用不同的预处理器、编译器或链接选项编译和链接lib1和lib2,可能会任意破坏公共功能。

为什么要这样做?最佳做法是创建一个lib3.so,其中包括common.cpp逻辑,并将两个库和应用程序链接到它。您可以毫无问题地构建两个动态库。你不应该得到任何名称resol
只要不导出公共函数,就会出现错误。了解所有内容,但不同预处理器的最后部分除外。@arunpal Hi。如果我用-Dcommon=unspecial为我的libfoo而不是libbar编译了所有内容,那么这两个库中就不会有common::symbol了。或者我可以使用linker选项-defsym来更改libbar中符号的名称,但不能更改libfoo中的符号名称。因此[1]意味着您不会对这两个库的源代码或目标代码进行不同的修改。
#include "bar.h"

void bar::i_am() const
{
    _c.print2(__PRETTY_FUNCTION__);
}
$ g++ -Wall -Wextra -fPIC -c foo.cpp bar.cpp common.cpp
$ ls *.o
bar.o  common.o  foo.o
$ g++ -shared -o libfoo.so foo.o common.o
$ g++ -shared -o libbar.so bar.o common.o
$ nm -DC libfoo.so | grep common
0000000000202094 B common::count
0000000000000e7e T common::print1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const
0000000000000efa T common::print2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const
$ nm -DC libbar.so | grep common
0000000000202094 B common::count
0000000000000e7e T common::print1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const
0000000000000efa T common::print2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const
#include "foo.h"
#include "bar.h"

int main()
{
    foo f;
    bar b;
    common c;

    f.i_am();
    b.i_am();
    c.print1(__PRETTY_FUNCTION__);
    return 0;
}
$ g++ -Wall -Wextra -c main.cpp
$ g++ -o prog main.o -L. -lfoo -lbar -Wl,-rpath=$PWD
$ ./prog
void foo::i_am() const. (count = 0)
void bar::i_am() const. (count = 1)
int main(). (count = 2)
$ nm common.o | grep common
0000000000000140 t _GLOBAL__sub_I_common.cpp
0000000000000000 B _ZN6common5countE
0000000000000000 T _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
000000000000007c T _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
$ c++filt _ZN6common5countE
common::count

$ c++filt _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
common::print1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const

$ c++filt _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
common::print2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const
$ g++ -o prog main.o -L. -lfoo -lbar -Wl,-rpath=$PWD \
    -Wl,-trace-symbol=_ZN6common5countE \
    -Wl,-trace-symbol=_ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE \
    -Wl,-trace-symbol=_ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE        
main.o: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: definition of _ZN6common5countE
./libfoo.so: definition of _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: definition of _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: reference to _ZN6common5countE
./libbar.so: reference to _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
$ g++ -o prog main.o -L. -lbar -lfoo -Wl,-rpath=$PWD \
    -Wl,-trace-symbol=_ZN6common5countE \
    -Wl,-trace-symbol=_ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE \
    -Wl,-trace-symbol=_ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE        
main.o: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: definition of _ZN6common5countE
./libbar.so: definition of _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libbar.so: definition of _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: reference to _ZN6common5countE
./libfoo.so: reference to _ZNK6common6print2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
./libfoo.so: reference to _ZNK6common6print1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE