c++ - ¿Qué hace exactamente la opción de GCC-Wpsabi? ¿Cuáles son las implicaciones de suprimirlo?
linux gcc-warning (1)
Solo debe preocuparse por las ABI cuando cruce los límites de la biblioteca. Dentro de sus propias aplicaciones / bibliotecas, la ABI no importa realmente, ya que presumiblemente todos sus archivos de objetos están compilados con la misma versión de compilador y los mismos switches.
Si tiene una biblioteca compilada con ABI1 y una aplicación compilada con ABI2, la aplicación se bloqueará cuando intente llamar a funciones de la biblioteca ya que no pasará los argumentos correctamente. Para solucionar el fallo, necesitaría volver a compilar la biblioteca (y cualquier otra biblioteca de la que dependa) con ABI2.
En su caso específico, siempre que compile nlohmann con la misma versión del compilador que su aplicación (o simplemente esté utilizando nlohmann como encabezado), no necesita preocuparse por el cambio de ABI.
Suprimir globalmente la advertencia parece ser una opción peligrosa, ya que evitará que veas futuros problemas de ABI.
Una mejor opción sería utilizar
#pragma
para deshabilitar la advertencia solo para las funciones en cuestión, por ejemplo:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop
Fondo
El año pasado usé la biblioteca nlohmann json
[1]
y compilé de forma cruzada en x86_64 usando GCC 5.x
arm-linux-gnueabi-*
sin advertencias.
Cuando actualicé GCC a una versión más nueva, GCC generaría páginas de notas de diagnóstico crípticas.
Por ejemplo, aquí está una de las notas.
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)...);
~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fue fácil encontrar una solución, a saber, agregando
-Wno-psabi
a las opciones del compilador.
De hecho, esa fue la solución implementada en la biblioteca.
[2]
Entiendo los conceptos básicos de las interfaces binarias de aplicación (ABI) y las ABI específicas del procesador (psABI). Para referencia, esta respuesta [11] ofrece una visión general rápida de las ABI:
Un ABI ( Application Binary Interface ) es un estándar que define una asignación entre conceptos de bajo nivel en lenguajes de alto nivel y las capacidades de un código de máquina de una plataforma de hardware / SO específica. Eso incluye cosas como:
- cómo se disponen en la memoria los tipos de datos C / C ++ / Fortran / ... (tamaños de datos / alineaciones)
- cómo funcionan las llamadas de funciones anidadas (dónde y cómo se almacena la información sobre cómo volver al llamante de una función, dónde se pasan los registros de la CPU y / o en la función de memoria)
- cómo funciona el inicio / inicialización del programa (qué formato de datos tiene un "ejecutable", cómo se carga el código / los datos desde allí, cómo funcionan los DLL ...)
Las respuestas a estas son:
- específico del idioma (por lo tanto, tiene un ABI de C, un ABI de C ++, un ABI de Fortran, un ABI de Pascal, ... incluso la especificación del código de bytes de Java, aunque está dirigido a un procesador "virtual" en lugar de hardware real, es un ABI),
- específico del sistema operativo (MS Windows y Linux en el mismo hardware usan un ABI diferente),
- hardware / CPU-específico (las ABI de ARM y x86 son diferentes).
- evolucionando en el tiempo (largo) (las ABI existentes a menudo se han actualizado / revisado para que las nuevas funciones de la CPU se puedan utilizar, como, por ejemplo, especificar cómo los registros SSE x86 deben ser utilizados por las aplicaciones, por supuesto, solo fue posible una vez Las CPU tenían estos registros, por lo tanto, las ABI existentes debían ser aclaradas).
Por lo tanto, ABI es el componente principal y uno de sus componentes (los detalles "específicos del hardware / CPU") es el psABI.
Mi problema
El problema que estoy teniendo es
- No me gustan las advertencias de desactivación universal sin entender las implicaciones.
-
El consejo "use
-Wno-psabi
para hacer que las notas desaparezcan" parece ser un consejo bastante común para este tipo de notas de diagnóstico que "aparecen repentinamente" después de una actualización del compilador. [2] [3] [4] Incluso uno de los desarrolladores de GCC sugiere hacer esto. [5] -
Ni
-Wpsabi
ni-Wno-psabi
están documentados [6] en el manual de GCC. [7]
Como resultado, no estoy realmente seguro de qué exactamente
-Wno-psabi
afectará y no afectará.
Una opción relacionada
-Wabi
está
documentada:
[8]
-Wabi (C, Objective-C, C++ and Objective-C++ only)
Avise cuando G ++ genere código que probablemente no sea compatible con el ABI de C ++ neutral del proveedor ...
También advierte sobre los cambios relacionados con psABI. Los cambios conocidos de psABI en este punto incluyen:
- Para SysV / x86-64, las uniones con miembros dobles largos se pasan en la memoria como se especifica en psABI. Por ejemplo:
union U {
long double ld;
int i;
};
union U
siempre se pasa en la memoria.
Mi comprensión de todo esto es
-
-Wabi
generará advertencias cuando haya un cambio de psABI. -
GCC 7 corrigió un error ABI
[9]
introducido en GCC 5 que afecta a los objetivos ARM.
- En las notas de la versión se indica "este es un cambio ABI". [10]
-
Por alguna razón, las notas de la versión indican que las notas de diagnóstico relacionadas se generan cuando se utiliza el documento
-Wpsabi
no documentado, no el-Wabi
documentado. - Este cambio ABI no se menciona en el manual.
-
Reuniendo "esto es un cambio ABI" y "usar
-Wpsabi
", me parece que esto es específicamente un cambio psABI, no un tipo diferente de cambio ABI. (En realidad, es un cambio en la implementación de GAB de la psABI, no de la psABI en sí)
Sé que la documentación no siempre está actualizada, especialmente para algo que es una opción conocida e indocumentada.
Pero mi preocupación es que "use
-Wno-psabi
" parece ser la respuesta estándar para varios tipos diferentes de estas notas diagnósticas crípticas.
Pero, en mi comprensión básica de los ABI, ¿no es un cambio de ABI un gran problema?
¿No debería preocuparme por un cambio de ABI, en lugar de simplemente hacer que el mensaje desaparezca?
Entre las cosas indocumentadas y algunos de los detalles más finos de ABI vs psABI, no estoy realmente seguro ...
Por ejemplo, si agrego
-Wno-psabi
a mi makefile para que esas notas desaparezcan, ¿qué
sucede
si hay otro cambio de ABI en el futuro que afecte mi proyecto?
¿He silenciado efectivamente las advertencias o notas futuras que pueden ser importantes?
Además, a pesar de que nos dicen "si recompila todo el código, no hay nada de qué preocuparse", [5] ¿qué es exactamente "todo el código"? ¿Es ese mi código fuente? glibc? ¿Alguna otra biblioteca compartida de todo el sistema que pueda estar usando?
Referencias
- https://github.com/nlohmann/json
- https://github.com/nlohmann/json/issues/658
- https://stackoverflow.com/a/48149400
- https://stackoverflow.com/a/13915796/10270632
- 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
- https://stackoverflow.com/a/8063350