Yliopiston etusivulle Suomeksi På svenska In English
Helsingin yliopisto Tietojenkäsittelytieteen laitos
 

Tietojenkäsittelytieteen laitos

GCC:n komentorivisyntaksi

GCC:n ja muiden UNIXin C-kääntäjien komentorivisyntaksi on hieman normaalista UNIX-käytännöstä poikkeava. Optioiden ei nimittäin välttämättä tarvitse olla komennon alussa, ennen tiedostonimiä. Tähän on hyvä syy: joidenkin optioiden ja tiedostonimien järjestyksellä on merkitystä.

Optiot alkavat aivan normaalisti '-'-merkillä. Kaikki muut parametrit ovat tiedostonimiä. Käyttöliittymäohjelma päättelee tiedoston tyypin sen nimen loppuosasta, alla olevan taulukon mukaan. (C++:lle on useita perinteisiä tapoja nimetä lähdekooditiedostot.)

.c      C-lähdekoodia
.C      C++-lähdekoodia
.cc     C++-lähdekoodia
.cxx    C++-lähdekoodia
.s      symbolista konekieltä
.S      symbolista konekieltä
.o      objektitiedosto
.h      otsikkotiedosto (ei käännetä eikä linkitetä)
.a      objektitiedostokirjasto

Käyttöliittymäohjelma käsittelee komentorivillä olevia tiedostonimiä seuraavasti. Lähdekooditiedostot (.c, .C, .cc, .cxx, .s, .S) käännetään objektitiedostoiksi. Objektitiedoston nimi muodostetaan vaihtamalla nimen loppuosaksi .o. Tämän jälkeen juuri saadut objektitiedostot ja komentorivillä mainitut objektitiedostot ja kirjastot annetaan linkkerille, joka muodostaa niistä ajettavan ohjelman.

Osa optioista ohjaa käyttöliittymäohjelman toimintaa, esimerkiksi käskee sitä vain kääntämään annetut lähdekooditiedostot ilman linkitystä tai kertoo mikä on tulostiedoston nimi, osa on tarkoitettu välitettäväksi eteenpäin käyttöliittymän käynnistämille ohjelmille.

GCC tuntee lukuisia optioita. Monet ovat kuitenkin hyödyllisiä vain erikoistilanteissa, hyvin selviää tuntemalla vain muutaman tärkeimmän. Nämä on selvitetty tässä ohjeessa, muihin voi tutustua GCC-dokumentaation (manuaalisivu ja Texinfo-kirja) avulla.

Optio -c keskeyttää käännösprosessin kun kaikki lähdekooditiedostot on käännetty objektitiedostoiksi. Ohjelmaa ei siis linkata. Tästä on hyötyä, kun monesta modulista koostuva ohjelma halutaan kääntää: jokainen moduli voidaan kääntää erikseen ja lopuksi kaikki käännetyt modulit linkataan yhteen ajettavaksi ohjelmaksi. Moduleista foo.c ja bar.c koostuva ohjelma käännettäisiin siis seuraavasti:

gcc -c foo.c      käännä foo.c objektitiedostoksi foo.o
gcc -c bar.c      käännä bar.c objektitiedostoksi bar.o
gcc foo.o bar.o   linkitä foo.o ja bar.o ajettavaksi ohjelmaksi

Ongelmana on vain se, että GCC antaa ajettavalle ohjelmalle nimeksi a.out, jollei sitä aseteta optiolla -o. Mikäli haluaa ohjelman nimeksi esimerkiksi foo, on yllä viimeinen komento annettava muodossa

gcc foo.o bar.o -o foo

Optiota -o voi käyttää missä tahansa komentorivillä, sen paikka ei vaikuta toimintaan.

Kirjoitusvaivan säästämiseksi yksimoduliset ohjelmat käännetään ja linkataan yleensä yhtenä askeleena. Monimodulisissa ohjelmissa tämä ei ole järkevää, koska usein ei ole tarpeen kääntää koko ohjelmaa, vaan vain ne modulit, joita on muutettu.

Objektitiedostokirjastoja voi linkata mukaan ohjelmaa antamalla niiden nimet komentorivillä. Järjestys on tärkeää. Linkkeri käy läpi saamansa tiedostonimet järjestyksessä vasemmalta oikealle, lisää objektitiedostot mukaan ohjelmaan ja kirjastoista kaikki ne kirjastossa olevat objektitiedostot joihin on siihen mennessä viitattu jostakin ohjelmaan jo lisätystä objektitiedostosta. Jos siis esimerkiksi kirjastoon foo.a viitataan objektitiedostosta bar.o ja linkkauksessa käytetty komentorivi on

gcc foo.a bar.o

niin linkkaus epäonnistuu, koska kirjastoon foo.a ei ole sitä käsiteltäessä vielä viitattu joten se sivuutetaan kokonaan. Kun bar.o myöhemmin viittaa kirjastoon, ei linkkeri enää mene takaisin käsittelemään sitä uudestaan, vaan valittaa, ettei se löydä bar.o:n viittaamaa aliohjelmaa, esimerkiksi näin:

bar.o: Undefined symbol _foo referenced from text segment

(Tässä siis bar.c:ssä kutsuttiin funktiota foo; C-kääntäjä lisää automaattisesti alaviivan kaikkien globaalien tunnusten eteen, minkä takia linkkeri -- joka yllä olevan virheilmoituksen tulosti -- valittaa ettei se löydä funktiota _foo.)

Kirjastoja luodaan komennolla ar, katso tarkemmat ohjeet manuaalisivulta.

Tärkeimmät valmiiksi asennetut, kaikkien käytettäviksi tarkoitetut kirjastot ovat matemaattisia aliohjelmia sisältävä libm.a sekä näytön ja näppäimistön käsittelyyn tarkoitetut libcurses.a ja libtermcap.a. Nämä sijaitsevat UNIX-järjestelmissä yleensä hakemistossa /usr/lib, mutta paikka voi vaihdella järjestelmästä toiseen. Lisäksi pitkien tiedostonimien kirjoittaminen on hankalaa. Siksi järjestelmän kirjastoihin viitataan komentorivillä yleensä optiolla -l, jonka perään tulee heti kirjaston nimen lyhennys. Lyhennys muodostetaan poistamalla sen tiedostonimestä alusta lib ja lopusta .a. Näin esimerkiksi matematiikkakirjastoon viitataan optiolla -lm.

Optio -l siis on vain lyhennysmerkintä järjestelmäkirjastojen täydellisille tiedostonimille. GCC ja muut kääntäjät tietävät missä nämä järjestelmäkirjastot ovat (koska paikka on niille asennusvaiheessa kerrottu), joten ne osaavat muodostaa täydelliset tiedostonimet. Käyttäjän omat kirjastot yleensä kerrotaan komentorivillä tiedostonimien avulla.

Myös optiolla -l nimettyjen kirjastojen järjestys komentorivillä on tärkeää. Eräs yleisimpiä ongelmia aloitteleville C-ohjelmoijille UNIXin alla on, ettei matemaattisia aliohjelmia löydy, vaikka lähdekoodissa on sanottu

#include <math.h>

ja komentorivillä on mainittu myös -lm:

gcc -lm ohjelma.c

Virhe lienee tässä vaiheessa selvä.

Varoituksia voi kytkeä päälle optiolla -Wall (tämä on GCC:n erityispiirre). GCC:ssä on lukuisia varoituksia, -Wall kytkee päälle kaikki, joita on yleensä järkevä käyttää. (Osa varoituksista on järkeviä vain joissakin tilanteissa, esimerkiksi -Waggregate-return vain kun halutaan säilyttää yhteensopivuus ikivanhojen C-kääntäjien kanssa.) Lista -Wall:in päällekytkemistä varoituksista löytyy GCC:n manuaalisivulta.

Yleensä on järkevää kirjoittaa koodinsa siten, ettei mitään varoituksia tule. Joskus tämä on mahdotonta. Esimerkiksi joissakin koneissa ovat standardikirjastojen otsikkotiedostot niin vanhaa perua, ettei niissä ole prototyyppejä kaikille kirjastofunktioille. Tämän takia GCC valittaa joka kerran kun tälläistä funktiota kutsutaan. Näistä varoituksista joko ei kannata välittää tai sitten kannattaa tehdä oma otsikkotiedosto, jossa nuo puuttuvat prototyypit ovat.

Oletusarvoisesti GCC laajentaa C-kieltä monin eri tavoin. Mikäli ei halua vahingossa käyttää näitä laajennuksia, ne voi kieltää optioilla -ansi ja -pedantic. -ansi sulkee pois kaikki standardin kanssa ristiriitaiset laajennukset (esimerkiksi varatut sanat asm ja inline), -pedantic varoittaa kaikesta, mikä on standardin kireimmän tulkinnan mukaan kyseenalaista. Kumpaakin on yleensä syytä käyttää, jollei laajennusten käyttäminen ole perusteltua.

Optimoinnin voi kääntää päälle optiolla -O. Tämä parantaa kääntäjän tuottaman konekielen laatua, mutta hidastaa käännöstä. Lisäksi, mikäli varoitukset on käännetty päälle, kääntäjä voi myös varoittaa ohjelmanosista joihin ei ikinä voi päätyä. Optimointia on useamman tasoista, kukin taso tuottaa alempia tasoja parempaa koodia ja vie enemmän aikaa. Taso ilmaistaan numerolla -O:n jäljessä, esimerkiksi -O2.

Virheenjäljittimen (engl. debugger) käyttämiseksi on niin käännöksessä kuin linkkauksessa käytettävä optiota -g. Se käskee kääntäjää lisäämään objektitiedostoon muuttujista ja aliohjelmista tietoa, jota tarvitaan symbolista jäljitystä varten ja linkkeriä lisäämään muuta samankaltaista tietoa ohjelmaan. Jäljitintä voi käyttää vaikka optiota -g ei olisikaan käytetty, mutta jäljitys on tällöin vähemmän symbolista ja enemmän konekielen tasolla.

tietotekniikkaryhma@cs.helsinki.fi