GNU Compiler Collection

GNU Compiler Collection (GCC) – zestaw kompilatorów o otwartym kodzie źródłowym rozwijany w ramach Projektu GNU. Rozpowszechniany jest 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.

Historia 
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 przez Richarda Stallmana.

Znaczącym wydarzeniem w historii rozwoju GCC było wydanie wersji 2.95 w lipcu 1999 – pierwszej po zintegrowaniu z projektem EGCS.

Kompilatory dostępne w GCC 
W skład GCC wchodzą kompilatory następujących języków programowania:
 C – gcc
 C++ – g++
 Objective-C – gobjc
 Fortran – g77 oraz nowa implementacja Fortranu 95 o nazwie GFortran
 Java – gcj
 Ada – gnat

a także eksperymentalnie
 Pascal – gpc
 Mercury
 VHDL
 PL/I

Istnieje również frontend języka D dla GCC – gdc.

Środowisko pracy 
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 i systemów operacyjnych oraz dokonywać tzw. kompilacji skrośnej.

Lista kilku najważniejszych architektur sprzętowych, na których uruchomiono GCC:
 Alpha
 ARM
 AVR
 IA-64
 MIPS
 Motorola M68000 i wiele innych układów tej firmy
 PowerPC
 SPARC/SPARC64
 x86/x86-64

Poniżej zestawiono systemy operacyjne umożliwiające uruchomienie GCC:
 AIX
 BeOS/Zeta
 *BSD
 DOS
 Haiku
 GNU/Linux
 OS X
 MorphOS
 Windows
 OS/2
 SunOS

Kompilatory GCC (w szczególności kompilator C) służą do kompilacji wielu jąder systemów operacyjnych, takich jak Linux, Hurd, jądro FreeBSD oraz wielu systemów eksperymentalnych.

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 asemblera 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, asembler 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.

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.

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).

back end 
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.

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żanie definicji funkcji
 heksadecymalne deklarowanie zmiennych zmiennoprzecinkowych
 makra o zmiennej liczbie argumentów
 konstrukcja case z przedziałami

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;
}

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;
}

Makra o zmiennej liczbie argumentów 
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:

Jednak, jak widać, jeśli makru printf podamy zero argumentów, po drugim argumencie funkcji fprintf 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.

Zobacz też 
 GNU Debugger
 MinGW
 Make

Przypisy

Linki zewnętrzne 

 Oficjalna strona GCC
 Wiki GCC
 Dokumentacja GCC
 Mingw-w64 – port GCC dla systemu Windows

Kompilatory
GNU