Co oznacza „#define _GNU_SOURCE”?

152

Dzisiaj musiałem skorzystać z basename()funkcji, a man 3 basename( tutaj ) dał mi dziwną wiadomość:

Uwagi

Istnieją dwie różne wersje basename () - wersja POSIX opisana powyżej oraz wersja GNU , którą otrzymuje się po

#define _GNU_SOURCE
#include <string.h>

Zastanawiam się, co to #define _GNU_SOURCEoznacza: czy jest to skażenie kodu, który piszę, na licencji GNU? A może po prostu mówi kompilatorowi coś w stylu: „ Wiem, że ten zestaw funkcji nie jest POSIX-owy, więc nie jest przenośny, ale i tak chciałbym go użyć ”.

Jeśli tak, dlaczego nie dać ludziom różnych nagłówków, zamiast definiować jakieś niejasne makro, aby uzyskać jedną implementację funkcji lub inną?

Coś też mnie niepokoi: skąd kompilator wie, którą implementację funkcji połączyć z plikiem wykonywalnym? Czy to też używa #define?

Czy ktoś ma mi jakieś wskazówki?

Gui13
źródło

Odpowiedzi:

172

Definiowanie _GNU_SOURCEnie ma nic wspólnego z licencją, a wszystko z pisaniem (nie) przenośnego kodu. Jeśli zdefiniujesz _GNU_SOURCE, otrzymasz:

  1. dostęp do wielu niestandardowych funkcji rozszerzeń GNU / Linux
  2. dostęp do tradycyjnych funkcji, które zostały pominięte w standardzie POSIX (często z ważnych powodów, takich jak zastąpienie lepszymi alternatywami lub przywiązanie do konkretnych starszych implementacji)
  3. Dostęp do funkcji niskopoziomowych, które nie mogą być przenośne, ale czasami trzeba za wdrażanie narzędzi systemowych podoba mount, ifconfigitd
  4. zepsute zachowanie wielu funkcji określonych w POSIX, gdzie ludzie z GNU nie zgadzali się z komitetem normalizacyjnym co do tego, jak te funkcje powinny się zachowywać i postanowili zrobić swoje.

Dopóki jesteś świadomy tych rzeczy, nie powinno być problemu z ich zdefiniowaniem _GNU_SOURCE, ale powinieneś unikać ich definiowania i zamiast tego definiować _POSIX_C_SOURCE=200809Llub, _XOPEN_SOURCE=700jeśli to możliwe, zapewnić przenośność programów.

W szczególności rzeczy _GNU_SOURCE, których nigdy nie powinieneś używać, to punkty 2 i 4 powyżej.

R .. GitHub PRZESTAŃ POMÓC LODOWI
źródło
71
Oczywiście każdy wie, że prawdziwym powodem definiowania _GNU_SOURCEjest zdobycie strfryi memfrob.
user4815162342
5
Ten odnośnik do dokumentacji biblioteki GNU C dostarcza dodatkowych szczegółów (np. #define _GNU_SOURCEZaleca się, aby był „pierwszą rzeczą w pliku, poprzedzoną jedynie komentarzami”).
Alexander Pozdneev
Nie tak istotne, ale używane do rozszerzenia limitu rozmiaru pliku do 2 GB na 32-bitowe cele.
mckenzm
1
@mckenzm: Myślę, że masz na myśli _FILE_OFFSET_BITS, nie _GNU_SOURCE.
R .. GitHub STOP POMAGANIE LODOM
Chcę być płatnym programistą do przenoszenia strfry memfrob i podobnych udogodnień na inne platformy i łańcuchy narzędzi.
Massimo
6

Pozwól, że odpowiem na dwie dalsze kwestie:

Coś też mnie niepokoi: skąd kompilator wie, którą implementację funkcji połączyć z plikiem wykonywalnym? Czy używa również tego #define?

Typowym podejściem jest warunkowe #defineidentyfikowanie basenameróżnych nazw, w zależności od tego, czy _GNU_SOURCEsą zdefiniowane. Na przykład:

#ifdef _GNU_SOURCE
# define basename __basename_gnu
#else
# define basename __basename_nongnu
#endif

Teraz biblioteka musi po prostu zapewnić oba zachowania pod tymi nazwami.

Jeśli tak, dlaczego nie dać ludziom różnych nagłówków, zamiast definiować jakąś niejasną zmienną środowiskową, aby uzyskać jedną lub drugą implementację funkcji?

Często ten sam nagłówek miał nieco inną zawartość w różnych wersjach Uniksa, więc nie ma jednej właściwej treści dla, powiedzmy, <string.h>- istnieje wiele standardów ( xkcd ). Istnieje cały zestaw makr do wybrania swojego ulubionego, więc jeśli twój program oczekuje jednego standardu, biblioteka będzie się z nim zgadzać.

Blaisorblade
źródło
6

Aby uzyskać szczegółowe informacje na temat tego, co jest włączone _GNU_SOURCE, pomocna może być dokumentacja.

Z dokumentacji GNU:

Makro: _GNU_SOURCE

Jeśli zdefiniujesz to makro, wszystko zostanie uwzględnione: rozszerzenia ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X / Open, LFS i GNU. W przypadkach, gdy POSIX.1 koliduje z BSD, pierwszeństwo mają definicje POSIX.

Ze strony podręcznika Linux na temat makr testowania funkcji :

_GNU_SOURCE

Definiowanie tego makra (z dowolną wartością) niejawnie definiuje _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE z wartością 200809L (200112L w wersjach glibc 2.10 przed wersjami 2.10; 199b przed wersjami 2.10c; _XOPEN_SOURCE z wartością 700 (600 w wersjach glibc starszych niż 2.10; 500 w wersjach glibc starszych niż 2.2). Ponadto ujawniane są również różne rozszerzenia specyficzne dla GNU.

Od wersji 2.19 biblioteki glibc zdefiniowanie _GNU_SOURCE ma również wpływ na niejawne zdefiniowanie _DEFAULT_SOURCE. W wersjach glibc starszych niż 2.20 definiowanie _GNU_SOURCE miało również wpływ na niejawne definiowanie _BSD_SOURCE i _SVID_SOURCE.

Uwaga : _GNU_SOURCEnależy zdefiniować przed dołączeniem plików nagłówkowych, aby odpowiednie nagłówki włączały funkcje. Na przykład:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
...

_GNU_SOURCEmożna również włączyć na kompilację za pomocą -Dflagi:

$ gcc -D_GNU_SOURCE file.c

( -Dnie jest specyficzne dla, _GNU_SOURCEale każde makro jest zdefiniowane w ten sposób).

PP
źródło
4

Z jakiejś listy mailingowej przez Google:

Spójrz na include / features.h glibc:

_GNU_SOURCE Wszystkie powyższe, plus rozszerzenia GNU.

Co oznacza, że ​​umożliwia to wszystko:

STRICT_ANSI , _ISOC99_SOURCE , _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, _LARGEFILE_SOURCE, _LARGEFILE64_SOURCE, _FILE_OFFSET_BITSVID =

Więc umożliwia kompilację wielu flag dla gcc

Chris
źródło
21
Nie wpływa na zachowanie kompilatora, tylko to, jakie prototypy i rzeczy są widoczne z nagłówków.
Spudd86,