GCC 的 -Wpsabi 选项究竟有什么作用?压制它有什么影响?
What exactly does GCC's -Wpsabi option do? What are the implications of supressing it?
背景
去年我使用了 nlohmann json 库 [1] 并使用 GCC [=158= 在 x86_64 上进行了交叉编译] arm-linux-gnueabi-*
没有警告。当我将 GCC 更新到新版本时,GCC 会生成几页神秘的诊断说明。例如,这里是其中一个注释
In file included from /usr/arm-linux-gnueabi/include/c++/7/vector:69:0,
from include/json.hpp:58,
from src/write_hsi.cpp:23:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long int, long long unsigned int, double, std::allocator, nlohmann::adl_serializer>}; _Tp = nlohmann::basic_json<>; _Alloc = std::allocator<nlohmann::basic_json<> >]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:394:7: note: parameter passing for argument of type ‘std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > >::iterator {aka __gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >}’ changed in GCC 7.1
vector<_Tp, _Alloc>::
^~~~~~~~~~~~~~~~~~~
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer> nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::parser::parse_internal(bool) [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:105:21: note: parameter passing for argument of type ‘__gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >’ changed in GCC 7.1
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
很容易找到解决方案,即在编译器选项中添加 -Wno-psabi
。事实上,这是库中实施的修复。[2]
我了解应用程序二进制接口 (ABI) 和特定于处理器的 ABI (psABI) 的基础知识。作为参考,此答案[11] 提供了 ABI 的快速概述:
An ABI (Application Binary Interface) is a standard that defines a mapping between low-level concepts in high-level languages and the abilities of a specific hardware/OS platform's machine code. That includes things like:
- how C/C++/Fortran/... data types are laid out in memory (data sizes / alignments)
- how nested function calls work (where and how the information on how to return to a function's caller is stored, where in the CPU registers and/or in memory function arguments are passed)
- how program startup / initialization works (what data format an "executable" has, how the code / data is loaded from there, how DLLs work ...)
The answers to these are:
- language-specific (hence you've got a C ABI, C++ ABI, Fortran ABI, Pascal ABI, ... even the Java bytecode spec, although targeting a "virtual" processor instead of real hardware, is an ABI),
- operating-system specific (MS Windows and Linux on the same hardware use a different ABI),
- hardware/CPU-specific (the ARM and x86 ABIs are different).
- evolving over (long) time (existing ABIs have often been updated / rev'ed so that new CPU features could be made use of, like, say, specifying how the x86 SSE registers are to be used by apps was of course only possible once CPUs had these regs, therefore existing ABIs needed to be clarified).
因此 ABI 是首要组件,其组件之一("hardware/CPU-specific" 详细信息)是 psABI。
我的问题
我遇到的问题是
- 我不喜欢在不了解其含义的情况下普遍禁用警告。
- 建议 "use
-Wno-psabi
to make the notes go away" 似乎是这些类型的诊断说明的常见建议 "suddenly appear" 在编译器升级后。[2][3][4] 甚至其中一位 GCC 开发人员也建议这样做。[5]
- GCC 手册中
-Wpsabi
和 -Wno-psabi
均未记录[6]。[7]
因此,我不太确定 -Wno-psabi
究竟会影响什么,不会影响什么。一个相关的选项 -Wabi
是 记录的:[8]
-Wabi (C, Objective-C, C++ and Objective-C++ only)
Warn when G++ it generates code that is probably not compatible with the vendor-neutral C++ ABI...
It also warns about psABI-related changes. The known psABI changes at this point include:
- For SysV/x86-64, unions with long double members are passed in memory as specified in psABI. For example:
union U {
long double ld;
int i;
};
union U
is always passed in memory.
我对这一切的理解是
-Wabi
将在 psABI 更改时生成警告。
- GCC 7 修复了 GCC 5 中引入的影响 ARM 目标的 ABI 错误[9]。
- 发行说明中指出 "this is an ABI change."[10]
- 出于某种原因,发行说明指出相关的诊断说明是在使用未记录的
-Wpsabi
而不是记录的 -Wabi
. 时生成的
- 手册中没有提到此 ABI 更改。
- 将 "this is an ABI change" 和 "use
-Wpsabi
" 放在一起,在我看来这是 特别是 psABI 更改,而不是另一种 ABI 更改。 (实际上这是 GCC 对 psABI 的实现的改变,而不是 psABI 本身)
我知道文档并不总是最新的,尤其是对于已知未记录选项的内容。但我担心的是 "use -Wno-psabi
" 似乎是几种不同类型的这些神秘诊断说明的标准响应。但是,在我对 ABI 的基本理解中,ABI 的变化不是很大吗?我不应该关心 ABI 的变化,而不是让消息消失吗?在未记录的内容和 ABI 与 psABI 的一些更精细的细节之间,我不太确定...
例如,如果我将 -Wno-psabi
添加到我的 makefile 中以使这些注释消失,如果将来有另一个 ABI 更改确实 影响我怎么办?项目?我是否有效地消除了未来可能重要的警告或注意事项?
此外,即使我们被告知 "if you recompile all the code, there is nothing to worry about,"[5] "all the code" 究竟是什么?那是我的源代码吗? glibc?我可能正在使用的任何其他系统范围的共享库?
参考资料
- https://github.com/nlohmann/json
- https://github.com/nlohmann/json/issues/658
- https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831
- https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc
- https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
- https://gcc.gnu.org/gcc-7/changes.html
您只需要在跨越库边界时担心 ABI。在你自己的 applications/libraries 中,ABI 并不重要,因为你所有的 object 文件都是用相同的编译器版本和开关编译的。
如果您有一个使用 ABI1 编译的库和一个使用 ABI2 编译的应用程序,那么当应用程序尝试从库中调用函数时,它会崩溃,因为它不会正确传递参数。要修复崩溃,您需要使用 ABI2 重新编译库(以及它所依赖的任何其他库)。
在您的特定情况下,只要您使用与您的应用程序相同的编译器版本编译 nlohmann(或者只是将 nlohmann 用作 header),那么您无需担心 ABI 更改。
全局禁止警告似乎是一个危险的选择,因为它会阻止您看到任何未来的 ABI 问题。更好的选择是使用 #pragma
仅针对相关功能禁用警告,例如:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop
背景
去年我使用了 nlohmann json 库 [1] 并使用 GCC [=158= 在 x86_64 上进行了交叉编译] arm-linux-gnueabi-*
没有警告。当我将 GCC 更新到新版本时,GCC 会生成几页神秘的诊断说明。例如,这里是其中一个注释
In file included from /usr/arm-linux-gnueabi/include/c++/7/vector:69:0,
from include/json.hpp:58,
from src/write_hsi.cpp:23:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long int, long long unsigned int, double, std::allocator, nlohmann::adl_serializer>}; _Tp = nlohmann::basic_json<>; _Alloc = std::allocator<nlohmann::basic_json<> >]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:394:7: note: parameter passing for argument of type ‘std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > >::iterator {aka __gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >}’ changed in GCC 7.1
vector<_Tp, _Alloc>::
^~~~~~~~~~~~~~~~~~~
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer> nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::parser::parse_internal(bool) [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:105:21: note: parameter passing for argument of type ‘__gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >’ changed in GCC 7.1
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
很容易找到解决方案,即在编译器选项中添加 -Wno-psabi
。事实上,这是库中实施的修复。[2]
我了解应用程序二进制接口 (ABI) 和特定于处理器的 ABI (psABI) 的基础知识。作为参考,此答案[11] 提供了 ABI 的快速概述:
An ABI (Application Binary Interface) is a standard that defines a mapping between low-level concepts in high-level languages and the abilities of a specific hardware/OS platform's machine code. That includes things like:
- how C/C++/Fortran/... data types are laid out in memory (data sizes / alignments)
- how nested function calls work (where and how the information on how to return to a function's caller is stored, where in the CPU registers and/or in memory function arguments are passed)
- how program startup / initialization works (what data format an "executable" has, how the code / data is loaded from there, how DLLs work ...)
The answers to these are:
- language-specific (hence you've got a C ABI, C++ ABI, Fortran ABI, Pascal ABI, ... even the Java bytecode spec, although targeting a "virtual" processor instead of real hardware, is an ABI),
- operating-system specific (MS Windows and Linux on the same hardware use a different ABI),
- hardware/CPU-specific (the ARM and x86 ABIs are different).
- evolving over (long) time (existing ABIs have often been updated / rev'ed so that new CPU features could be made use of, like, say, specifying how the x86 SSE registers are to be used by apps was of course only possible once CPUs had these regs, therefore existing ABIs needed to be clarified).
因此 ABI 是首要组件,其组件之一("hardware/CPU-specific" 详细信息)是 psABI。
我的问题
我遇到的问题是
- 我不喜欢在不了解其含义的情况下普遍禁用警告。
- 建议 "use
-Wno-psabi
to make the notes go away" 似乎是这些类型的诊断说明的常见建议 "suddenly appear" 在编译器升级后。[2][3][4] 甚至其中一位 GCC 开发人员也建议这样做。[5] - GCC 手册中
-Wpsabi
和-Wno-psabi
均未记录[6]。[7]
因此,我不太确定 -Wno-psabi
究竟会影响什么,不会影响什么。一个相关的选项 -Wabi
是 记录的:[8]
-Wabi (C, Objective-C, C++ and Objective-C++ only)
Warn when G++ it generates code that is probably not compatible with the vendor-neutral C++ ABI...
It also warns about psABI-related changes. The known psABI changes at this point include:
- For SysV/x86-64, unions with long double members are passed in memory as specified in psABI. For example:
union U {
long double ld;
int i;
};
union U
is always passed in memory.
我对这一切的理解是
-Wabi
将在 psABI 更改时生成警告。- GCC 7 修复了 GCC 5 中引入的影响 ARM 目标的 ABI 错误[9]。
- 发行说明中指出 "this is an ABI change."[10]
- 出于某种原因,发行说明指出相关的诊断说明是在使用未记录的
-Wpsabi
而不是记录的-Wabi
. 时生成的
- 手册中没有提到此 ABI 更改。
- 将 "this is an ABI change" 和 "use
-Wpsabi
" 放在一起,在我看来这是 特别是 psABI 更改,而不是另一种 ABI 更改。 (实际上这是 GCC 对 psABI 的实现的改变,而不是 psABI 本身)
我知道文档并不总是最新的,尤其是对于已知未记录选项的内容。但我担心的是 "use -Wno-psabi
" 似乎是几种不同类型的这些神秘诊断说明的标准响应。但是,在我对 ABI 的基本理解中,ABI 的变化不是很大吗?我不应该关心 ABI 的变化,而不是让消息消失吗?在未记录的内容和 ABI 与 psABI 的一些更精细的细节之间,我不太确定...
例如,如果我将 -Wno-psabi
添加到我的 makefile 中以使这些注释消失,如果将来有另一个 ABI 更改确实 影响我怎么办?项目?我是否有效地消除了未来可能重要的警告或注意事项?
此外,即使我们被告知 "if you recompile all the code, there is nothing to worry about,"[5] "all the code" 究竟是什么?那是我的源代码吗? glibc?我可能正在使用的任何其他系统范围的共享库?
参考资料
- https://github.com/nlohmann/json
- https://github.com/nlohmann/json/issues/658
- https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831
- https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc
- https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
- https://gcc.gnu.org/gcc-7/changes.html
您只需要在跨越库边界时担心 ABI。在你自己的 applications/libraries 中,ABI 并不重要,因为你所有的 object 文件都是用相同的编译器版本和开关编译的。
如果您有一个使用 ABI1 编译的库和一个使用 ABI2 编译的应用程序,那么当应用程序尝试从库中调用函数时,它会崩溃,因为它不会正确传递参数。要修复崩溃,您需要使用 ABI2 重新编译库(以及它所依赖的任何其他库)。
在您的特定情况下,只要您使用与您的应用程序相同的编译器版本编译 nlohmann(或者只是将 nlohmann 用作 header),那么您无需担心 ABI 更改。
全局禁止警告似乎是一个危险的选择,因为它会阻止您看到任何未来的 ABI 问题。更好的选择是使用 #pragma
仅针对相关功能禁用警告,例如:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop