Компиляция с -std = c ++ 11 на Cygwin скрывает доступные системные вызовы - PullRequest
0 голосов
/ 04 сентября 2018

Я занимался портированием некоторого кода со старого C ++ на более современную версию C ++ (например, C ++ 11 или выше). И затем я заметил, что сетевой код не компилируется, когда я добавил флаг компилятора -std=c++11

Простейший пример MVCE. Я на последнем Cygwin (буквально установлен сегодня). g++ --version обозначает версию 7.3.0.

Возьмите следующий исходный файл, урезанный практически до нуля, но достаточно, чтобы показать проблему, которую я собираюсь объяснить.

#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>

int some_networking_code()
{
   addrinfo* addr = NULL;
   int flags = AI_NUMERICHOST;
   return 0;
}

При новой установке Cygwin следующая команда работает отлично:

g++ foo.cpp -c

Но теперь перейдите к компиляции с C ++ 11.

g++ foo.cpp -c -std=c++11

И вывод компилятора будет таким:

foo.cpp: In function ‘int some_networking_code()’:
foo.cpp:8:4: error: ‘addrinfo’ was not declared in this scope
    addrinfo* addr = NULL;
    ^~~~~~~~
foo.cpp:8:4: note: suggested alternative: ‘addr_t’
    addrinfo* addr = NULL;
    ^~~~~~~~
    addr_t
foo.cpp:8:14: error: ‘addr’ was not declared in this scope
    addrinfo* addr = NULL;
              ^~~~
foo.cpp:8:14: note: suggested alternative: ‘addr_t’
    addrinfo* addr = NULL;
              ^~~~
              addr_t
foo.cpp:9:16: error: ‘AI_NUMERICHOST’ was not declared in this scope
    int flags = AI_NUMERICHOST;
                ^~~~~~~~~~~~~~

Отлаживая это, я смотрю на /usr/include/netdb.h и вижу, что определение для addrinfo предполагает, что макрос с именем __ POSIX_VISIBLE будет больше или равен 200112. Там определение для AI_NUMERICONLY заключено в аналогичный блок.

#if __POSIX_VISIBLE >= 200112 && !defined(__INSIDE_CYGWIN_NET__)
struct addrinfo {
  int             ai_flags;             /* input flags */
  … <deleted for brevity>
#endif

Используя переключатели -dM -E, мы можем спросить у компилятора, какие макросы он загружает и отфильтровать в POSIX_VISIBLE

$ g++ foo.cpp -c -dM -E | grep POSIX_VIS
#define __POSIX_VISIBLE 200809

Хорошо, это выглядит правильно для традиционного C ++. Давайте проверим, что для сборки C ++ 11:

$ g++ foo.cpp -c -std=c++11 -dM -E | grep POSIX_VIS
#define __POSIX_VISIBLE 0

__POSIX_VISIBLE определено равным 0. И это объясняет, почему у нас есть ошибки выше.

Похоже, что POSIX_VISIBLE определяется файлом заголовка в /usr/include/sys/features.h на основе других определенных макросов. Но вот тут я начинаю запутываться.

Это ошибка в дистрибутиве Cygwin или его заголовочных файлах? Как был построен компилятор? Или что-то другое? Какой подходящий обходной путь не повлияет на сборку в Linux, Mac, BSD и везде?

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Судя по https://cygwin.com/cygwin-ug-net/ov-new.html, Похоже, что cygwin стремится макробезопасность макроса совместимости с glibc. struct addrinfo используется getaddrinfo, что для glibc требует _POSIX_C_SOURCE >= 200112L.

Действительно, код компилируется, если вы определите соответствующий макрос:

g++ -D_POSIX_C_SOURCE=200112L foo.cpp -c -std=c++11

или, в качестве альтернативы, определите "дай мне все" _GNU_SOURCE.

g++ -D_GNU_SOURCE foo.cpp -c -std=c++11
0 голосов
/ 06 сентября 2018

Я обсуждал список рассылки Cygwin . Я предполагал, что отсутствие указания -std в командной строке ограничит мою сборку отсутствием доступа к современным функциям C ++. И это указание -std=c++11 или выше включит эти новые функции. Это на самом деле неверно. В новых версиях g ++ по умолчанию используется что-то более новое:

$ g++ -c foo.cpp -dM -E | grep cplus
#define __cplusplus 201402L

И использование -std не только ограничивает поведение функций компилятора, но и отключает встроенные определения GNU. А заголовки Cygwin будут скрывать несколько функций POSIX, когда GNU_SOURCE не определено, включая getaddrinfo. Я не уверен, согласен ли я с этой конфигурацией, но именно так она работает на Cygwin. Избегать -std лучше.

Обновление

Несмотря на то, что избегать использования -std - отличное решение, более ранние версии g ++ до 6.0 по умолчанию используют C ++ 98, если не используется -std. И все еще есть много людей, использующих версии до 6.0 g ++. Было много взломов Makefile, которые я исследовал, чтобы найти поддержку C ++ 11 или версию компилятора, так что -std=c++11 используется условно, и ни один из них не очень хорош. Обходной путь, который кажется универсальным для g ++, Cygwin и Clang, заключается в использовании -std=gnu++11.

То есть:

g++ foo.cpp -c -std=gnu++11
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...