Apa yang disiratkan oleh "#define _GNU_SOURCE"?

152

Hari ini saya harus menggunakan basename()fungsi, dan man 3 basename(di sini ) memberi saya beberapa pesan aneh:

Catatan

Ada dua versi basename () yang berbeda - versi POSIX yang dijelaskan di atas, dan versi GNU , yang diperoleh setelahnya

#define _GNU_SOURCE
#include <string.h>

Saya bertanya-tanya apa #define _GNU_SOURCEartinya ini : apakah ini mencemari kode yang saya tulis dengan lisensi terkait GNU? Atau apakah itu hanya digunakan untuk memberi tahu kompiler sesuatu seperti " Yah, saya tahu, rangkaian fungsi ini bukan POSIX, jadi tidak portabel, tetapi saya tetap ingin menggunakannya ".

Jika demikian, mengapa tidak memberi orang header yang berbeda, daripada harus mendefinisikan beberapa makro yang tidak jelas untuk mendapatkan satu implementasi fungsi atau yang lainnya?

Sesuatu juga mengganggu saya: bagaimana kompiler mengetahui implementasi fungsi mana yang harus dihubungkan dengan yang dapat dieksekusi? Apakah ini menggunakan ini #definejuga?

Adakah yang punya beberapa petunjuk untuk memberi saya?

Gui13
sumber

Jawaban:

172

Mendefinisikan _GNU_SOURCEtidak ada hubungannya dengan lisensi dan segala sesuatu yang berkaitan dengan penulisan kode portabel (non-). Jika Anda mendefinisikan _GNU_SOURCE, Anda akan mendapatkan:

  1. akses ke banyak fungsi ekstensi GNU / Linux yang tidak standar
  2. akses ke fungsi tradisional yang dihilangkan dari standar POSIX (seringkali karena alasan yang baik, seperti digantikan dengan alternatif yang lebih baik, atau dikaitkan dengan implementasi warisan tertentu)
  3. akses ke fungsi tingkat rendah yang tidak dapat portabel, tetapi Anda kadang-kadang perlu untuk menerapkan sistem utilitas seperti mount, ifconfig, dll
  4. perilaku rusak untuk banyak fungsi yang ditentukan POSIX, di mana orang-orang GNU tidak setuju dengan komite standar tentang bagaimana fungsi harus berperilaku dan memutuskan untuk melakukan hal mereka sendiri.

Selama Anda mengetahui hal-hal ini, seharusnya tidak menjadi masalah untuk didefinisikan _GNU_SOURCE, tetapi Anda harus menghindari mendefinisikannya dan sebaliknya mendefinisikan _POSIX_C_SOURCE=200809Latau _XOPEN_SOURCE=700jika mungkin untuk memastikan bahwa program Anda portabel.

Secara khusus, hal-hal _GNU_SOURCEyang tidak boleh Anda gunakan adalah # 2 dan # 4 di atas.

R .. GitHub BERHENTI MEMBANTU ES
sumber
71
Tentu saja, semua orang tahu alasan sebenarnya untuk mendefinisikan _GNU_SOURCEadalah untuk mendapatkan strfrydan memfrob.
user4815162342
5
Tautan ini ke dokumentasi GNU C Library memberikan beberapa detail tambahan (mis., #define _GNU_SOURCEDirekomendasikan untuk menjadi "hal pertama dalam file, didahului hanya dengan komentar").
Alexander Pozdneev
Tidak relevan tetapi digunakan untuk memperpanjang batas ukuran file 2GB pada target 32 ​​bit.
mckenzm
1
@ mckenzm: Saya pikir Anda sedang memikirkan _FILE_OFFSET_BITS, tidak _GNU_SOURCE.
R .. GitHub BERHENTI MEMBANTU ICE
Saya ingin menjadi programmer berbayar untuk porting strfry memfrob dan fasilitas serupa ke platform lain dan rantai alat.
Massimo
6

Biarkan saya menjawab dua poin lebih lanjut:

Sesuatu juga mengganggu saya: bagaimana kompiler mengetahui implementasi fungsi mana yang harus dihubungkan dengan yang dapat dieksekusi? Apakah ini menggunakan #define ini juga?

Pendekatan umum adalah #definemengidentifikasi secara kondisional basenameuntuk nama yang berbeda, tergantung pada apakah _GNU_SOURCEdidefinisikan. Misalnya:

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

Sekarang perpustakaan hanya perlu menyediakan kedua perilaku di bawah nama-nama itu.

Jika demikian, mengapa tidak memberi orang header yang berbeda, daripada harus mendefinisikan beberapa variabel lingkungan yang tidak jelas untuk mendapatkan satu implementasi fungsi atau yang lainnya?

Seringkali header yang sama memiliki konten yang sedikit berbeda di versi Unix yang berbeda, jadi tidak ada konten yang tepat untuk, katakanlah, <string.h>- ada banyak standar ( xkcd ). Ada satu set makro untuk memilih yang favorit Anda, sehingga jika program Anda mengharapkan satu standar, perpustakaan akan sesuai dengan itu.

Blaisorblade
sumber
6

Untuk perincian yang pasti tentang semua yang diaktifkan _GNU_SOURCE, dokumentasi dapat membantu.

Dari dokumentasi GNU:

Makro: _GNU_SOURCE

Jika Anda mendefinisikan makro ini, semuanya termasuk: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X / Open, LFS, dan ekstensi GNU. Dalam kasus di mana POSIX.1 bertentangan dengan BSD, definisi POSIX diutamakan.

Dari halaman manual Linux pada makro uji fitur :

_GNU_SOURCE

Mendefinisikan makro ini (dengan nilai apa pun) secara implisit mendefinisikan _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE dengan nilai sebelum versi 2.009c sebelum versi 2.509c di 2.500c pada 2.500c sebelum versi 2.011 di 2.500c sebelum versi 2.011 di 2.500c sebelum versi 2.011 di 2.500c sebelum versi 2.011 di 2.500c sebelum versi 2.011 di versi sebelumnya; _XOPEN_SOURCE dengan nilai 700 (600 dalam versi glibc sebelum 2.10; 500 dalam versi glibc sebelum 2.2). Selain itu, berbagai ekstensi spesifik GNU juga diekspos.

Sejak glibc 2.19, mendefinisikan _GNU_SOURCE juga memiliki efek mendefinisikan _DEFAULT_SOURCE secara implisit. Dalam versi glibc sebelum 2.20, mendefinisikan _GNU_SOURCE juga memiliki efek mendefinisikan _BSD_SOURCE dan _SVID_SOURCE secara implisit.

Catatan : _GNU_SOURCEperlu ditentukan sebelum termasuk file header sehingga header masing-masing mengaktifkan fitur. Sebagai contoh:

#define _GNU_SOURCE

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

_GNU_SOURCEdapat juga diaktifkan per kompilasi menggunakan -Dflag:

$ gcc -D_GNU_SOURCE file.c

( -Dtidak spesifik untuk _GNU_SOURCEtetapi makro didefinisikan dengan cara ini).

PP
sumber
4

Dari beberapa milis via google:

Lihatlah glibc's include / features.h:

_GNU_SOURCE Semua hal di atas, ditambah ekstensi GNU.

Yang artinya memungkinkan semua ini:

STRICT_ANSI , _ISOC99_SOURCE, _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, _LARGEFILE_SOURCE, _LARGEFILE64_SOURCE, _SURUR _S_UR, _S_UR_SS_UR, _S_UR_SS_URS, _S_URS, _S_URSS_URS, _SOURCES, _SOURCES , _SOURSS, _SOURSS, _SOURCE, _SOURCES, _SOURCES, _SOURCES, _SOURSS, _SOURCES, _SOURCES, STRURT_ANSI.

Jadi itu memungkinkan banyak kompilasi flag untuk gcc

Chris
sumber
21
Itu tidak mempengaruhi perilaku kompiler, hanya apa prototipe dan hal-hal yang terlihat dari header.
Spudd86