Что означает "#define _GNU_SOURCE"?
Сегодня мне пришлось использовать функцию basename()
, а man 3 basename
(здесь) дал мне странное сообщение:
Примечания
Существуют две разные версии basename() - версия POSIX, описанная выше, и версия GNU, которую можно получить после
#define _GNU_SOURCE
#include <string.h>
Мне интересно, что означает этот #define _GNU_SOURCE
: это заражает код, который я пишу, с лицензией, связанной с GNU? Или это просто используется, чтобы сказать компилятору что-то вроде "Ну, я знаю, этот набор функций не POSIX, поэтому он не переносимый, но я бы все равно его использовал".
Если да, почему бы не дать людям разные заголовки, вместо того, чтобы определять какой-то неясный макрос, чтобы получить одну реализацию функции или другую?
Что-то меня также менячет: как компилятор знает, какая реализация функции связана с исполняемым файлом? Использует ли он этот #define
?
У кого-нибудь есть указатели, чтобы дать мне?
Ответы
Ответ 1
Определение _GNU_SOURCE
не имеет ничего общего с лицензией и все, что связано с записью (не) переносимым кодом. Если вы определяете _GNU_SOURCE
, вы получите:
- доступ к множеству нестандартных функций расширения GNU/Linux.
- доступ к традиционным функциям, которые были исключены из стандарта POSIX (часто по уважительной причине, например, заменяются лучшими альтернативами или привязаны к определенным унаследованным реализациям).
- доступ к низкоуровневым функциям, которые не могут быть переносимыми, но которые вам иногда нужны для реализации системных утилит, таких как
mount
, ifconfig
и т.д.
- Поврежденное поведение для множества функций, указанных в POSIX, где люди GNU не согласны с комитетом по стандартам о том, как должны функционировать функции и решили делать свое дело.
Пока вы знаете об этих вещах, не должно быть проблемой определить _GNU_SOURCE
, но вы должны избегать его определения и вместо этого определять _POSIX_C_SOURCE=200809L
или _XOPEN_SOURCE=700
, когда это возможно, чтобы ваши программы были переносимым.
В частности, вещи из _GNU_SOURCE
, которые вы никогда не должны использовать, - это # 2 и # 4 выше.
Ответ 2
Позвольте мне ответить еще на два момента:
Что-то меня также беспокоит: как компилятор узнает, какую реализацию функции связать с исполняемым файлом? Использует ли он также этот #define?
Обычный подход заключается в условном #define
идентификаторе basename
для разных имен, в зависимости от того, определен ли _GNU_SOURCE
. Например:
#ifdef _GNU_SOURCE
# define basename __basename_gnu
#else
# define basename __basename_nongnu
#endif
Теперь библиотеке просто нужно предоставить оба поведения под этими именами.
Если так, то почему бы не дать людям разные заголовки, вместо того, чтобы определять какую-то непонятную переменную среды, чтобы получить одну реализацию функции или другую?
Зачастую один и тот же заголовок имеет несколько разное содержимое в разных версиях Unix, поэтому нет единого правильного содержимого, скажем, для <string.h>
- существует много стандартов (xkcd). Существует целый набор макросов для выбора вашего любимого, так что, если ваша программа ожидает один стандарт, библиотека будет соответствовать этому.
Ответ 3
Точная информация о том, что все включено _GNU_SOURCE
, может помочь в документации.
Из документации GNU:
Макрос: _GNU_SOURCE
Если вы определите этот макрос, все будет включено: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, LFS и GNU. В случаях, когда POSIX.1 конфликтует с BSD, определения POSIX имеют приоритет.
Из справочной страницы Linux по макросам тестирования функций:
_GNU_SOURCE
Определение этого макроса (с любым значением) неявным образом определяет _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE со значением 200809L (200112L в версиях glibc версии 2000–150; glbl; версии 2000–250; версии 2000–210; версии 2000–210; _XOPEN_SOURCE со значением 700 (600 в версиях glibc до 2.10; 500 в версиях glibc до 2.2). Кроме того, различные специфичные для GNU расширения также доступны.
Начиная с glibc 2.19, определение _GNU_SOURCE также имеет эффект неявного определения _DEFAULT_SOURCE. В версиях glibc до 2.20 определение _GNU_SOURCE также неявно определяло _BSD_SOURCE и _SVID_SOURCE.
Примечание: _GNU_SOURCE
необходимо определить перед включением заголовочных файлов, чтобы соответствующие заголовки включали функции. Например:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
...
_GNU_SOURCE
также можно включить для каждой компиляции, используя флаг -D
:
$ gcc -D_GNU_SOURCE file.c
(-D
не является специфичным для _GNU_SOURCE
но любой макрос может быть определен таким образом).
Ответ 4
Из списка рассылки через google:
Посмотрите glibc include/features.h:
_GNU_SOURCE Все вышеперечисленное, плюс расширения GNU.
Это означает, что он позволяет все это:
STRICT_ANSI, _ISOC99_SOURCE, _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, _LARGEFILE_SOURCE, _LARGEFILE64_SOURCE, _FILE_OFFSET_BITS = N, _BSD_SOURCE, _SVID_SOURCE
Таким образом, он позволяет создавать множество флагов для gcc