Help/Programming/Compile

Οδηγός μεταγλώτ τισης πηγαίου κώδικα

Περιεχόμενα

Εισαγωγή

Oι υπολογιστές αυτό που κάνουν δεν είναι τίποτε άλλο από πρόσθεση, πολλαπλασιασμός και αποθήκευση και μεταφορά δεδομένων. Αυτό επιτυγχάνεται με ηλεκτρονικά κυκλώματα, τα οποία ανάλογα με την είσοδο που δέχονται επιτρέπουν ή όχι τη διέλευση του ρεύματος. Οι καταστάσεις αυτές μπορούν να αναπαρασταθούν στο δυαδικό σύστημα ως 0 "δεν περνά ρεύμα" ή 1 "περνά ρεύμα". Οι οδηγίες ή εντολές που καταλαβαίνει δηλαδή ο υπολογιστής είναι γραμμένες σε γλώσσα μηχανής (machine code). Κώδικας μηχανής ή γλώσσα μηχανής είναι ένα σύστημα οδηγιών και δεδομένων που μπορούν να εκτελεσθούν απευθείας από την κεντρική μονάδα επεξεργασίας του υπολογιστή. Η γλώσσα μηχανής είναι συνήθως δύσκολη στο χειρισμό από τον άνθρωπο, αν και στις πρώτες μέρες των υπολογιστών ήταν αρκετά απλά. Γιαυτό το λόγο δημιουργήθηκε μια άλλη γλώσσα, η assembly, πιο προσιτή στον άνθρωπο. Η assembly είναι μια χαμηλού επιπέδου γλώσσα για τον προγραμματισμό υπολογιστών. Aν και χρησιμοποιείται ακόμη και σήμερα σε κάποιες εφαρμογές, όπως μικροεπεξεργαστές ή plc, είναι αρκετά δύσχρηστη. Γιαυτό αναπτύχθηκαν υψηλότερου επιπέδου γλώσσες κατανοητές στον άνθρωπο. Οι γλώσσες προγραμματισμού μπορούν να χωριστούν σε δύο κατηγορίες, compiled και interpreted, ανάλογα με το αν μετατρέπουν τον πηγαίο κώδικα σε κώδικα μηχανής ή αν τον εκτελούν βήμα-βήμα. Μερικά παραδείγματα compiled γλωσσών προγραμματισμού είναι fortran, C, C++, ada, algol, cobol, delphi, pascal. Παραδείγματα interpreted γλωσσών προγραμματισμού, γνωστές και ως scripting γλώσσες, αποτελούν python, java, tcl, ruby. Στον παρών οδηγό θα ασχοληθούμε με τη μεταγλώττιση προγραμμάτων γραμμένα κυρίως σε C, και σε κάποιες περιπτώσεις fortran.

Για τη μεταγλώττιση προγραμμάτων είναι απαραίτητα, εκτός του μεταγλωττιστή, κάποια εργαλεία που διευκολύνουν και αυτοματοποιούν τη διαδικασία. Στο debian (και σε παράγωγά του όπως το ubuntu) η εγκατάσταση των απαραίτητων προγραμμάτων, γίνεται ως εξής:

sudo apt-get install build-essential

Για τους χρήστες FORTRAN το απαραίτητο πακέτο μπορεί να εγκατασταθεί:

sudo apt-get install gfortran

Mια άλλη δυνατότητα περιλαμβάνει τη χρήση του μεταγλωττιστή g95, ο οποίος πρέπει να εγκατασταθεί χειροκίνητα. Τα υπόλοιπα εργαλεία, ld, ar, nm, που θα χρειασθούν είναι εγκατεστημένα σε κάθε σύστημα linux. Σε διαφορετική περίπτωση μπορούν να εγκατασταθούν επίσης απλά με τη χρήση της εντολής apt-get, όπως παραπάνω. Άλλες διανομές έχουν διαφορετικό τρόπο εγκατάστασης των πακέτων, όπως το rpm της Red Hat, oι οποίοι δεν πρόκειται να συζητηθούν εδώ.

Ο μεταγλωττιστής gcc

Ο μεταγλωττιστής gcc (GNU Compiler Collection, παλιότερα γνωστός ως GNU C Compiler) είναι ένα πρόγραμμα για τη μεταγλώττιση πηγαίου κώδικα σε γλώσσα μηχανής γραμμένου στις γλώσσες C, C++, ή Objective-C (αντικειμενική-C). Ο gcc μεταγλωττίζει ένα ή περισσότερα αρχεία πηγαίου κώδικα, για παράδειγμα πηγαία αρχεία C (file.c), πηγαία αρχεία assemply (file.s) ή προ επεξεργασμένα πηγαία αρχεία C (file.i). Aν η κατάληξη του αρχείου δεν αναγνωρισθεί τότε θεωρείται ως αντικειμενικό αρχείο (object) ή βιβλιοθήκη. Ο gcc καλεί συνήθως έναν προ επεξεργαστή (preprocessor), μεταγλωττίζει τον προ επεξεργασμένο κώδικα σε γλώσσα assembly, τον συναρμολεί και μετά το συνδέει με το linker. H διαδικασία μπορεί να διακοπεί σε ένα από τα προηγούμενα στάδια χρησιμοποιώντας τις επιλογές -c, -S, ή -E. Τα βήματα μπορεί επίσης να διαφέρουν ανάλογα με τη γλώσσα που χρησιμοποιείται. Ως προεπιλογή η έξοδος αποθηκεύεται στο αρχείο a.out. Σε μερικές περιπτώσεις ο gcc δημιουργεί ένα αντικειμενικό αρχειό έχοντας την κατάληξη .o και το αντίστοιχο βασικό όνομα.

Οι επιλογές του προ επεξεργαστή και του linker που δίνονται στη γραμμή εντολών του gcc, μεταβιβάζονται σε αυτά τα εργαλεία όταν εκτελούνται. Στον παρών οδηγό θα σχολιασθούν μόνο οι βασικές επιλογές του gcc, ενώ για μια πλήρη αναφορά μπορείτε να ανατρέξετε στις σελίδες εγχειριδίου (man pages).

Ας ξεκινήσουμε όμως από ένα απλό παράδειγμα. Το αρχείο hallo.c περιλαμβάνει τα εξής:

/* hallo.c */
int main(){
   printf("Hallo world\n");}

H εντολή

gcc hallo.c

δέχεται ως αρχείο εισόδου το hallo.c, το μεταγλωττίζει και χωρίς να αποθηκεύει το ενδιάμεσο αντικείμενο, δημιουργεί το εκτελέσιμο με το προεπιλεγμένο όνομα a.out. H περιφραστική εκδοχή της παραπάνω εντολής θα ήταν:

gcc -c hallo.c
gcc -o a.out hallo.c

Η επιλογή -c δηλώνει μεταγλώττιση (compile), ενώ η -ο (οutput) δηλώνει το αρχείο εξόδου. Στην περιφραστική εκδοχή αποθηκεύεται και το ενδιάμεσο αντικείμενο hallo.o.

Αν υποθέσουμε ότι το αρχείο hallo.c περιέχει πολλούς βρόγχους (loops) τον ένα μέσα στον άλλο για τον υπολογισμό πινάκων. Τότε αυτό θα κάνει το πρόγραμμα αρκετά αργό. Σε τέτοιες περιπτώσεις είναι απαραίτητη η χρήση της επιλογής βελτιστοποίησης -Ο όπως στο παρακάτω παράδειγμα:

gcc -c -O3 hallo.c 

όπου το επίπεδο βελτιστοποίησης τίθεται στο μέγιστο. Υπάρχει περίπτωση, μόνο αν ο κώδικάς σας δεν είναι γραμμένος καθαρά, η έκδοση με βελτιστοποίηση και αυτή χωρίς βελτιστοποίηση να διαφέρουν ως προς τα αποτελέσματα. Αυτό συμβαίνει γιατί η βελτιστοποίηση που εφαρμόζεται τροποποιεί ουσιαστικά τον κώδικα. Το τι σημαίνει "καθαρά" δε θα το σχολιάσουμε εδώ, αλλά μπορείτε να ανατρέξετε σε διάφορα βιβλία προγραμματισμού.

Οι επιλογές προ επεξεργαστή μπορεί να χρησιμοποιηθεί για προγράμματα που πρέπει να λειτουργούν σε διάφορες αρχιτεκτονικές με διαφορετικές τιμές σε μια μεταβλητή. Ας θεωρήσουμε ότι έχουμε σε ένα πρόγραμμα την επιλογή 32-bit ή 64-bit, και ότι σε καθε περίπτωση πρέπει να συμβεί κάτι διαφορετικό. Αυτό δε σημαίνει ότι πρέπει να έχουμε και δύο εκδόσεις του προγράμματος. Μπορεί εύκολα να λυθεί με την επιλογή -D όπως στο παρακάτω παράδειγμα:

int main(){
   if (BIT==32){
      printf("%i\n", BIT);
      }
   else if (BIT==64){   
      printf("%i\n",BIT);
      }
   else {
      printf("%i\n",BIT);
      }
} 

To οποίο μεταγλωττίζεται με μία από τις επιλογές:

gcc -DBIT hallo.c

gcc -DBIT=32 hallo.c

gcc -DBIT=64 hallo.c

Aς υποθέσουμε τώρα το αρχείο mylib.h βρίσκεται στο φάκελο ~/include και ότι θέλουμε να το συμπεριλάβουμε στον κώδικά μας με την εντολή #include "mylib.h". Αυτό θα το κάναμε με την επιλογή -Ι κατά τη μεταγλώττιση, ή οποία δέχεται τόσο σχετική όσο και απόλυτη διαδρομή.

gcc -l~/include hallo.c

Η χρήση μιας βιβλιοθήκης, πχ. libast.a, η οποία βρίσκεται στο φάκελο ~/lib γίνεται με τις παρακάτω επιλογές:

gcc -L~/lib -last hallo.c

Πρέπει να σημειωθεί ότι η βιβλιοθήκη libast.a με το εργαλείο ar, που θα παρουσιαστεί παρακάτω.

Γενικές επιλογές

Κατά αλφαβητική σειρά

  • -ansi
    • Eπιβάλει πλήρη συμβατότητα με το πρότυπο ANSI.
  • -c
    • Δημιουργία ενός συνδέσιμου αρχείου αντικειμένου για κάθε αρχείο πηγαίου κώδικα, αλλά χωρίς κλήση του linker.
  • -E
    • Προ επεξεργάζεται τα πηγαία αρχεία αλλά δεν τα μεταγλωττίζει. Τυπώνει τα αποτελέσματα στην τυπική έξοδο. Αυτή η επιλογή είναι χρήσιμη για τη μεταβίβαση μερικών επιλογών cpp (C ?PreProcessor) που διαφορετικά θα σταματούσαν το gcc όπως η -C, -M, ή -P.

  • -g
    • Συμπεριλαμβάνει πληροφορίες αποσφαλμάτωσης (debugging) για χρήση με το gdb.
  • -glevel
    • Παρέχει πληροφορίες για την αποσφαλμάτωση. level πρέπει να είναι 1, 2, ή 3, με το 1 να παρέχει το ελάχιστο πλήθος πληροφοριών. Η προεπιλογή είναι το 2.
  • --help
    • Τυπώνει τις συνηθέστερες βασικές επιλόγες και τερματίζει.
  • -o file
    • Ορίζει το αρχείο εξόδου ως file. Προεπιλεγμένο είναι το a.out.
  • -O[level]
    • Βελτιστοποίηση. level πρέπει να είναι 1, 2, 3, ή 0 (προεπιλεγμένο είναι το 1). Το 0 απενεργοποιεί τη βελτιστοποίηση.
  • -p
    • Παρέχει πληροφορίες προφίλ για χρήση με prof.
  • -pedantic
    • Προειδοποιεί αμετροεπώς.
  • -pg
    • Παρέχει πληροφορίες προφίλ για χρήση με gprof.
  • -std=standard
    • Kαθορίζει το πρότυπο της C του αρχείου εισόδου. Αποδεκτές τιμές είναι:
    • iso9899:1990, c89 1990 ISO C πρότυπο.
    • iso9899:199409 1994 προσθήκη στο 1990 ISO C πρότυπο.
    • iso9899:1999, c99 1999 ISO C αναθεωρημένο πρότυπο.
    • iso9899:1999, c9x
    • gnu89 1990 C πρότυπο με GNU επεκτάσεις (η προεπιλεγμένη τιμή).
    • gnu99, gnu9x 1999 αναθεωρημένο ISO C πρότυπο με GNU επεκτάσεις.
  • -s
    • Μεταγλωττίζει τα πηγαία αρχεία σε κώδικα assembly, αλλά δεν τα συναρμολογεί.
  • -v
    • Τυπώνει πληροφορίες έκδοσης.
  • -V version
    • Προσπαθεί να εκτελέσει την gcc έκδοση version.
  • -w
    • Aποσιωπεί τις προειδοποιήσεις.
  • -W
    • Προειδοποιεί πιο αμετροεπώς από το κανονικό.
  • -Wall
    • Ενεργοποιεί όλες τις πιθανές προειδοποιήσεις.
  • -x language
    • Περιμένει το αρχείο εισόδου να είναι γραμμένο στη γλώσσα language, που μπορεί να είναι c, objective-c, c-header, c++, ada, f77, ratfor, assembler, java, cpp-output, c++-cpp-ouput, objc-cpp-output, f77-cpp-output, assembler-with-cpp, ή ada. Αν δεν ορισθεί τίποτε τότε μαντεύει τη γλώσσα από την κατάληξη του αρχείου.

Επιλογές προ επεξεργαστή

Ο gcc μεταβιβάζει τις παρακάτω επιλογές στον προ επεξεργαστή:

  • -Dname[=def]
    • Ορίζει το name με την τιμή def σαν να είχε οριστεί ως #define. Αν δε δοθεί =def, τότε το name ο=ρίζεται με την τιμή 1. -D έχει χαμηλότερη προτεραιότητα από -U.
  • -Idir
    • Περιλαμβάνει το dir στη λίστα με τους φακέλους για να ψαξει για αρχεία που πρέπει να συμπεριληφθούν.
  • -Uname
    • Aπομακρύνει τον ορισμό το συμβόλου name.

Eπιλογές linker

Ο gcc μεταβιβάζει τις παρακάτω επιλογές στο linker:

  • -llib
    • Συνδέει στη βιβλιοθήκη lib.
  • -Ldir
    • Ψάχνει στο dir εκτός από προεπιλεγμένους φακέλους για βιβλιοθήκες.
  • -u symbol
    • Αναγκάζει το linker να ψάξει στις βιβλιοθηκες για τον ορισμό του symbol, και να συνδέσει στις βιβλιοθήκες που βρήκε.

Bιβλιογραφία

Robbins, Arnold (2005), UNIX in a nutshell, O' Reilly.

Help/Programming/Compile (last edited 26-01-2009 13:46:28 by ?rizitis)