c++ - Что именно делает опция GCC-Wpsabi? Каковы последствия подавления этого?



linux gcc-warning (1)

Фон

В прошлом году я использовал библиотеку nlohmann json [1] и выполнял кросс-компиляцию на x86_64, используя GCC 5.x 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:

ABI ( двоичный интерфейс приложения ) - это стандарт, который определяет соответствие между концепциями низкого уровня в языках высокого уровня и возможностями машинного кода конкретной аппаратной / операционной системы. Это включает в себя такие вещи, как:

  • как типы данных C / C ++ / Fortran / ... размещаются в памяти (размеры данных / выравнивания)
  • как работают вызовы вложенных функций (где и как хранится информация о том, как вернуться к вызывающей функции, где передаются аргументы функций в регистрах ЦП и / или в памяти)
  • как работает запуск / инициализация программы (какой формат данных имеет «исполняемый файл», как код / ​​данные загружаются оттуда, как работают библиотеки DLL ...)

Ответы на них:

  • зависящий от языка (следовательно, у вас есть C ABI, C ++ ABI, Fortran ABI, Pascal ABI, ... даже спецификация Java-байт-кода, хотя и предназначенная для «виртуального» процессора вместо реального оборудования, является ABI),
  • в зависимости от операционной системы (MS Windows и Linux на одном и том же оборудовании используют разные ABI),
  • зависит от аппаратного / центрального процессора (разные интерфейсы ARM и x86).
  • развивались в течение (длительного) времени (существующие ABI часто обновлялись / обновлялись, так что новые функции ЦП могли использоваться, например, например, указание того, как регистры SSE x86 должны использоваться приложениями, конечно, возможно только один раз Процессоры имели эти правила, поэтому необходимо уточнить существующие ABI).

Таким образом, ABI является всеобъемлющим компонентом, а один из его компонентов («аппаратные / специфичные для процессора») - это psABI.

Мой вопрос

У меня проблема в том,

  1. Я не люблю повсеместно отключать предупреждения, не понимая их последствий.
  2. Совет «используйте -Wno-psabi для -Wno-psabi заметок» кажется довольно распространенным советом для этих типов диагностических заметок, которые «внезапно появляются» после обновления компилятора. [2] [3] [4] Даже один из разработчиков GCC предлагает сделать это. [5]
  3. Ни -Wpsabi ни -Wno-psabi не описаны [6] в руководстве GCC. [7]

В результате я не совсем уверен, что именно -Wno-psabi будет и не повлияет. Связанная опция -Wabi задокументирована: [8]

-Wabi (C, Objective-C, C++ and Objective-C++ only)

Предупреждать, когда G ++ генерирует код, который, вероятно, не совместим с независимым от поставщика C ++ ABI ...

Он также предупреждает об изменениях, связанных с psABI. Известные изменения psABI на этом этапе включают в себя:

  • Для SysV / x86-64 объединения с длинными двойными членами передаются в память, как указано в psABI. Например:

union U { long double ld; int i; };

union U всегда передается в память.

Мое понимание всего этого

  1. -Wabi будет генерировать предупреждения при изменении psABI.
  2. В GCC 7 исправлена ​​ошибка ABI [9], появившаяся в GCC 5, которая затрагивала цели ARM.
    • В примечаниях к выпуску указано «это изменение ABI». [10]
    • По некоторым причинам в примечаниях к выпуску говорится, что соответствующие диагностические примечания создаются при использовании недокументированного -Wpsabi , а не документированного -Wabi .
    • Это изменение ABI не упоминается в руководстве.
  3. -Wpsabi «это изменение ABI» и «используйте -Wpsabi », мне кажется, что это изменение psABI, а не изменение ABI другого типа. (На самом деле это изменение в реализации psABI в GCC, а не в самой psABI)

Я знаю, что документация не всегда актуальна, особенно для того, что является известным недокументированным вариантом. Но меня беспокоит то, что «use -Wno-psabi », по-видимому, является стандартным ответом для нескольких различных видов этих загадочных диагностических замечаний. Но, в моем базовом понимании ABI, разве ABI не меняет дело? Разве я не должен беспокоиться об изменении ABI, вместо того, чтобы просто пропустить сообщение? Между недокументированным материалом и некоторыми мелочами ABI против psABI я не совсем уверен ...

Например, если я добавлю -Wno-psabi в свой make-файл, чтобы эти заметки исчезли, что если в будущем произойдет другое изменение ABI, которое повлияет на мой проект? Эффективно ли я заставил замолчать будущие предупреждения или заметки, которые могут быть важными?

Кроме того, хотя нам говорят «если вы перекомпилируете весь код, вам не о чем беспокоиться» [5], что именно означает «весь код»? Это мой исходный код? GLibC? Любая другая общесистемная общая библиотека, которую я мог бы использовать?

Рекомендации

  1. https://github.com/nlohmann/json
  2. https://github.com/nlohmann/json/issues/658
  3. https://stackoverflow.com/a/48149400
  4. https://stackoverflow.com/a/13915796/10270632
  5. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html
  6. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831
  7. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc
  8. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html
  9. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
  10. https://gcc.gnu.org/gcc-7/changes.html
  11. https://stackoverflow.com/a/8063350

Вам нужно беспокоиться только о ABI, когда вы пересекаете границы библиотеки. В ваших собственных приложениях / библиотеках ABI на самом деле не имеет значения, так как предположительно все ваши объектные файлы скомпилированы с одинаковой версией компилятора и переключателями.

Если у вас есть библиотека, скомпилированная с помощью ABI1, и приложение, скомпилированное с помощью ABI2, то приложение будет аварийно завершать работу при попытке вызвать функции из библиотеки, поскольку оно не будет правильно передавать аргументы. Чтобы исправить ошибку, вам нужно перекомпилировать библиотеку (и любые другие библиотеки, от которых она зависит) с ABI2.

В вашем конкретном случае, пока вы компилируете nlohmann с той же версией компилятора, что и ваше приложение (или просто используете nlohmann в качестве заголовка), вам не нужно беспокоиться об изменении ABI.

Глобальное подавление предупреждения представляется опасным вариантом, поскольку оно не позволит вам увидеть какие-либо будущие проблемы с ABI. Лучшим вариантом было бы использовать #pragma для отключения предупреждения только для рассматриваемых функций, например:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop




abi