std::function 在 GCC-4 和 GCC-5/6/7/8/9 之间未记录的 ABI 更改,如何使 .so 与 devtoolset-4/6/7/8/9 一起工作?
Undocumented ABI changes of std::function between GCC-4 and GCC-5/6/7/8/9, how to make a .so working with devtoolset-4/6/7/8/9?
与 _GLIBCXX_USE_CXX11_ABI=0
std::function GCC-4 与 GCC-5 及以下版本不同。
下面的代码告诉你事实:
==> lib.cc <==
#include <functional>
std::function<int(const void*p)> holder;
int run_holder(const void *p)
{
return holder(p);
}
==> main.cc <==
#include <stdio.h>
#include <functional>
extern int run_holder(const void*p);
extern std::function<int(const void*p)> holder;
int foo(const void* p)
{
printf("p=%p\n", p);
return 0;
}
int main()
{
holder = foo;
foo((void*)0x12345678);
holder((void*)0x12345678);
run_holder((void*)0x12345678);
}
==> make.sh <==
#!/bin/bash
GCC4=/usr/bin/g++
GCCN="scl enable devtoolset-5 -- g++"
$GCC4 -std=c++11 -c -g lib.cc -shared -o libfoo.so &&
$GCCN -std=c++11 -L. -lfoo -g main.cc -o a.out &&
LD_LIBRARY_PATH=. ./a.out
预期结果,类似于:
p=0x12345678
p=0x12345678
p=0x12345678
实际结果:
p=0x12345678
./make.sh: line 6: 973 Segmentation fault LD_LIBRARY_PATH=. ./a.out
原因是 std::function 没有文档更改的实现。
gcc4:/usr/include/c++/4.8.2/功能:2430
typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);
gcc5:/opt/rh/devtoolset-4/root/usr/include/c++/5.3.1/functional:2226
gcc8: /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_function.h:609
using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
所以我不能使用由 gcc4 编译并由 gcc5/6/7/8 使用的 std::function 编写 .so。没有像 _GLIBCXX_USE_CXX11_ABI 这样的宏可以控制行为。
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8.
正确。 Red Hat 和 GCC 项目都没有声称这是可能的,恰恰相反。 GCC 4.x 中的 C++11 支持不完整且不稳定,并且受 ABI 更改和 API 更改的影响。从未支持您尝试执行的操作。
我已经在
中对此进行了更详细的解释
Developer Toolset 文档也涵盖了它(强调我的):
"C++11 或 C++14 模式下的编译器仅保证与另一个 C++11 或 C++14 模式下的编译器兼容,前提是它们来自相同的发布系列(例如来自 Red Hat Developer Toolset 6.x)。
...
"Using the C++14 language version is supported in Red Hat Developer Toolset when all C++ objects compiled with the respective flag have been built using Red Hat Developer Toolset 6 or later. Objects compiled by the system GCC in its default mode of C++98 are also compatible, but objects compiled with the system GCC in C++11 or C++14 mode are not compatible."
There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
我们不提供宏来控制不受支持且无法工作的东西。
如果您想将 C++11 与 GCC 版本混合使用,您需要使用对 C++11 具有稳定、非实验性支持的版本。所以不是 GCC 4.x.
与 _GLIBCXX_USE_CXX11_ABI=0 std::function GCC-4 与 GCC-5 及以下版本不同。
下面的代码告诉你事实:
==> lib.cc <==
#include <functional>
std::function<int(const void*p)> holder;
int run_holder(const void *p)
{
return holder(p);
}
==> main.cc <==
#include <stdio.h>
#include <functional>
extern int run_holder(const void*p);
extern std::function<int(const void*p)> holder;
int foo(const void* p)
{
printf("p=%p\n", p);
return 0;
}
int main()
{
holder = foo;
foo((void*)0x12345678);
holder((void*)0x12345678);
run_holder((void*)0x12345678);
}
==> make.sh <==
#!/bin/bash
GCC4=/usr/bin/g++
GCCN="scl enable devtoolset-5 -- g++"
$GCC4 -std=c++11 -c -g lib.cc -shared -o libfoo.so &&
$GCCN -std=c++11 -L. -lfoo -g main.cc -o a.out &&
LD_LIBRARY_PATH=. ./a.out
预期结果,类似于:
p=0x12345678
p=0x12345678
p=0x12345678
实际结果:
p=0x12345678
./make.sh: line 6: 973 Segmentation fault LD_LIBRARY_PATH=. ./a.out
原因是 std::function 没有文档更改的实现。
gcc4:/usr/include/c++/4.8.2/功能:2430
typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);
gcc5:/opt/rh/devtoolset-4/root/usr/include/c++/5.3.1/functional:2226 gcc8: /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_function.h:609
using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
所以我不能使用由 gcc4 编译并由 gcc5/6/7/8 使用的 std::function 编写 .so。没有像 _GLIBCXX_USE_CXX11_ABI 这样的宏可以控制行为。
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8.
正确。 Red Hat 和 GCC 项目都没有声称这是可能的,恰恰相反。 GCC 4.x 中的 C++11 支持不完整且不稳定,并且受 ABI 更改和 API 更改的影响。从未支持您尝试执行的操作。
我已经在
Developer Toolset 文档也涵盖了它(强调我的):
"C++11 或 C++14 模式下的编译器仅保证与另一个 C++11 或 C++14 模式下的编译器兼容,前提是它们来自相同的发布系列(例如来自 Red Hat Developer Toolset 6.x)。
...
"Using the C++14 language version is supported in Red Hat Developer Toolset when all C++ objects compiled with the respective flag have been built using Red Hat Developer Toolset 6 or later. Objects compiled by the system GCC in its default mode of C++98 are also compatible, but objects compiled with the system GCC in C++11 or C++14 mode are not compatible."
There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
我们不提供宏来控制不受支持且无法工作的东西。
如果您想将 C++11 与 GCC 版本混合使用,您需要使用对 C++11 具有稳定、非实验性支持的版本。所以不是 GCC 4.x.