GNU Compiler Collection
Z Wikipedii
GNU Compiler Collection | |
![]() |
|
Rodzaj | Kompilator |
Aktualna wersja | 4.1.2 13 Luty 2007 |
Producent | The GNU Project |
Licencja | GPL |
http://gcc.gnu.org | |
![]() |
GCC (ang. GNU Compiler Collection) to zestaw kompilatorów do różnych języków programowania rozwijany w ramach projektu GNU i udostępniany na licencji GPL oraz LGPL. GCC jest podstawowym kompilatorem w systemach uniksopodobnych przy czym szczególnie ważną rolę odgrywa w procesie budowy jądra Linuksa. Początkowo skrótowiec GCC oznaczał GNU C Compiler, ponieważ był to kompilator wyłącznie do języka C.
Pierwsza wersja kompilatora o numerze 1.0 została opublikowana 23 maja 1987 roku przez Richarda Stallmana. Znaczącym wydarzeniem w historii rozwoju GCC było wydanie wersji 2.95 w lipcu 1999 roku - pierwszej po zintegrowaniu z projektem EGCS.
Spis treści |
[edytuj] Kompilatory dostępne w GCC
W skład GCC wchodzą kompilatory następujących języków programowania:
a także eksperymentalnie
[edytuj] Środowisko pracy
Kompilatory wchodzące w skład GCC mogą być uruchamiane na wielu różnych platformach sprzętowych jak i systemowych. Za ich pomocą można generować kod wynikowy przeznaczony dla różnych procesorów i systemów operacyjnych oraz dokonywać tzw. kompilacji skrośnej. Poniżej znajduje się lista kilku najważniejszych architekur sprzętowych, na których uruchomiono GCC.
- procesory firmy Intel i kompatybilne
- IA-64
- Alpha
- ARM
- Motorola M68000 i wiele innych układów tej firmy
- MIPS
- PowerPC
- SPARC/SPARC64
Poniżej zestawiono systemy operacyjne umożliwiające uruchomienie GCC
[edytuj] Budowa i działanie GCC
Program gcc (wywoływany podczas kompilacji np. z linii poleceń) odpowiada za przetworzenie argumentów, uruchomienie odpowiedniego kompilatora właściwego dla języka programowania w jakim zakodowano plik z kodem źródłowym, wykonanie programu assemblera dla tak otrzymanego wyniku oraz uruchomienie konsolidatora (linkera) w celu uzyskania pliku wykonywalnego. Przykładowo dla pliku napisanego w C zostaną wykonane następujące programy: preprocesor cpp, kompilator cc1, assembler as oraz konsolidator collect2 (dostępny zazwyczaj jako program ld). Należy przy tym zwrócić uwagę, iż program as wchodzi w skład pakietu oprogramowania binutils. Również pliki nagłówkowe biblioteki 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.
[edytuj] front end
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 zakodowanego parsera. W efekcie tego działania powstaje reprezentacja programu zwana AST (ang. abstract syntax tree), która jest następnie przetwarzana do postaci w pełni niezależnej od pierwotnie użytego języka programowania GENERIC lub GIMPLE.
[edytuj] middle end
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 postaci GIMPLE do innej zwanej RTL (ang. Register Transfer Language).
[edytuj] back end
Ta część GCC odpowiada za wygenerowanie kodu assemblera 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.
[edytuj] Rozszerzenia języka C
GCC zawiera wiele rozszerzeń ponad to, co określają standardy ANSI i ISO.
Są to m.in.:
- zmienne etykietowe
- etykiety lokalne
- traktowanie dowolnych fragmentów kodu (statement) jako wyrażeń (expression)
- zagnieżdżane definicje funkcji
- heksadecymalne deklarowanie zmiennych zmiennoprzecinkowych
- makra o zmiennej liczbie argumentów
- konstrukcja case z przedziałami
[edytuj] Zmienne etykietowe
#include <stdio.h> void foo (int nr) { static void * labels [] = {&&label0, &&label1}; goto *labels [nr]; label0: printf("Code 0\n"); return; label1: printf("Code 1\n"); return; } int main() { foo(0); foo(1); return 0; }
[edytuj] Inline Assembler w C/C++
GCC umożliwia użycie asemblera w kodzie. Nie są to jednak pojedyncze instrukcje, tylko całe bloki razem ze zdefiniowanymi specjalnym systemem interfejsem między asemblerem a C/C++. Dzięki temu GCC może o wiele lepiej optymalizować kod.
W poniższym przykładzie program drukuje najpierw i=1, później i=2. GCC sam dokonuje alokacji rejestrów oraz przeniesienia między rejestrami a zmienną i na stosie.
#include <stdio.h> int main() { int i=0; asm("movl $1, %0" : "=g" (i)); printf("i = %d\n", i); asm("addl $1, %0" : "+g" (i)); printf("i = %d\n", i); return 0; }