GNU Compiler Collection (GCC) – zestawkompilatorów ootwartym kodzie źródłowym rozwijany w ramachProjektu GNU. Rozpowszechniany jest na licencjiGPL orazLGPL.
GCC jest podstawowym kompilatorem wsystemach uniksopodobnych, przy czym szczególnie ważną rolę odgrywa w procesie budowyjądra Linuksa.
Początkowo skrótowiec GCC oznaczał GNU C Compiler, ponieważ był to kompilator wyłącznie dojęzyka C.
Pierwsza wersja kompilatora o numerze 1.0 została opublikowana 23 maja1987 przezRicharda Stallmana.
Znaczącym wydarzeniem w historii rozwoju GCC było wydanie wersji 2.95 w lipcu 1999 – pierwszej po zintegrowaniu z projektemEGCS.
W skład GCC wchodzą kompilatory następującychjęzyków programowania:
a także eksperymentalnie
Istnieje również frontend językaD dla GCC – gdc[2].
Kompilatory wchodzące w skład GCC mogą być uruchamiane na wielu różnych platformach sprzętowych i systemowych. Za ich pomocą można generować kod wynikowy przeznaczony dla różnych procesorów isystemów operacyjnych oraz dokonywać tzw.kompilacji skrośnej.
Lista kilku najważniejszych architektur sprzętowych, na których uruchomiono GCC:
Poniżej zestawiono systemy operacyjne umożliwiające uruchomienie GCC:
Kompilatory GCC (w szczególności kompilator C) służą do kompilacji wielująder systemów operacyjnych, takich jakLinux,Hurd, jądroFreeBSD oraz wielu systemów eksperymentalnych.
Programgcc (wywoływany podczas kompilacji np. zlinii poleceń) odpowiada za przetworzenie argumentów, uruchomienie odpowiedniegokompilatora właściwego dlajęzyka programowania w jakim zakodowano plik zkodem źródłowym, wykonanie programuasemblera dla tak otrzymanego wyniku oraz uruchomieniekonsolidatora (linkera) w celu uzyskaniapliku wykonywalnego.
Przykładowo dla pliku napisanego wC zostaną wykonane następujące programy: preprocesorcpp, kompilatorcc1, asembleras orazkonsolidatorcollect2 (dostępny zazwyczaj jako programld). Należy przy tym zwrócić uwagę, iż programas wchodzi w skład pakietu oprogramowaniabinutils. Równieżpliki nagłówkowebiblioteki standardowej języka C nie są częścią GCC.
Kompilator GCC składa się z 3 głównych części: front endu, middle endu oraz back endu.
Dla każdego języka programowania obsługiwanego przez GCC istnieje oddzielny front end. Dzięki temu względnie łatwo można dodawać kompilatory do nowych języków. Plik z kodem źródłowym poddawany jest procesowi analizy składniowej za pomocą ręcznie zakodowanegoparsera. W efekcie tego działania powstaje reprezentacja programu zwanaAST (ang. abstract syntax tree), która jest następnie przetwarzana do postaci w pełni niezależnej od pierwotnie użytego języka programowaniaGENERIC lubGIMPLE.
Na tym etapie kompilator dokonuje optymalizacji kodu polegającej na:
- usunięciu "martwego" kodu, który się nigdy nie wykona
- obliczeniu stałych wartości i zastąpieniu nimi wyrażeń zawartych w programie
- wyeliminowaniu kodu nadmiarowego
- wykonaniu innych optymalizacji
Reprezentacja kodu zamieniana jest z postaciGIMPLE do innej zwanejRTL (ang. Register Transfer Language).
Ta część GCC odpowiada za wygenerowanie kodu asemblera przeznaczonego dla konkretnej architektury sprzętowej, a z niego kodu obiektowego. Ponieważ na tym etapie kompilator ma wiele informacji na temat docelowej platformy może dokonać kolejnych optymalizacji kodu np. uwzględniając budowę procesora, zestaw jego rozkazów czy specyficzne rozszerzenia.
GCC zawiera wiele rozszerzeń ponad to, co określają standardyANSI iISO.
Są to m.in.:
- zmienne etykietowe
- etykiety lokalne
- traktowanie dowolnych fragmentów kodu (statement) jako wyrażeń (expression)
- zagnieżdżanie definicji funkcji
- heksadecymalne deklarowanie zmiennych zmiennoprzecinkowych
- makra o zmiennej liczbieargumentów
- konstrukcja
case z przedziałami
#include<stdio.h>voidfoo(intnr){staticvoid*labels[]={&&label0,&&label1};goto*labels[nr];label0:printf("Code 0\n");return;label1:printf("Code 1\n");return;}intmain(){foo(0);foo(1);return0;}GCC umożliwia użycieasemblera wkodzie. Nie są to jednak pojedyncze instrukcje, tylko całe bloki razem ze zdefiniowanymi specjalnym systememinterfejsem między asemblerem a C/C++. Dzięki temu GCC może o wiele lepiej optymalizować kod.
W poniższym przykładzie program drukuje najpierwi=1, późnieji=2. GCC sam dokonujealokacjirejestrów oraz przeniesienia między rejestrami a zmiennąi nastosie.
#include<stdio.h>intmain(){inti=0;asm("movl $1, %0":"=g"(i));printf("i = %d\n",i);asm("addl $1, %0":"+g"(i));printf("i = %d\n",i);return0;}Oprócz funkcji o zmiennej liczbie argumentów, deklarowanych np.int printf (const char *, ...); (gdzie... oznacza zero lub więcej argumentów), GCC umożliwia tworzenie makr o zmiennej liczbie argumentów. Deklaruje je się tak samo jak funkcje:
# define printf(fmt, ...)
Aby użyć listy argumentów, należy użyć definiowanego wtedy makra__VA_ARGS__:
# define printf(fmt, ...) fprintf(stdout, fmt, __VA_ARGS__);
Zamiast__VA_ARGS__, zostaną wklejone argumenty, w formie:
| 0 argumentów | |
|---|
| 1 argument | arg1 |
|---|
| 2 lub więcej argumentów | arg1, arg2, arg3, arg4 |
|---|
Jednak, jak widać, jeśli makruprintf podamy zero argumentów, po drugim argumencie funkcjifprintf zostanie sam przecinek. Będzie to błędem składniowym. Aby tego uniknąć, wymyślono jeszcze jedno rozszerzenie
# define printf(fmt, ...) fprintf(stdout, fmt,##__VA_ARGS__);
Dzięki zastosowaniu operatora sklejania##, jeśli podane zostanie zero argumentów o zmiennej liczbie, nie będzie zbędnego przecinka.
| Historia | |
|---|
| Licencje | |
|---|
| Programy | |
|---|
| Postacie | |
|---|