Το Debian στην Ελλάδα

Top Menu

  • Αρχική
  • Forum
  • Blogs
  • Wiki
  • Επικοινωνία
Αρχική σελίδα

Makefiles

Submitted by kegior on Σαβ, 13/06/2009 - 01:33.
  • Προγραμματισμός

Makefiles

Το Unix και σχεδόν όλα τα Unix-like λειτουργικά συστήματα, όπως το Linux, προσφέρουν στον προγραμματιστή ένα πoλύτιμο εργαλείο για πιο εύκολη μετάφραση ενός μεγάλου έργου σε c/c++: το make. Το εργαλείο make χρησιμοποιείται για τη διαχείριση μεγάλων εργασιών με πολλά αρχεία. Το make ελέγχει ποια αρχεία έχουν αλλάξει και τα μεταγλωττίζει αυτόματα χωρίς να χρειάζεται εμείς να μεταγλωττίζουμε κάθε αρχείο χωριστά.

Tα makefiles είναι text αρχεία που περιέχουν "στόχους" και συνταγές για την υλοποίηση των στόχων Στην ενότητα αυτή θα σας εξηγήσουμε τη χρήσιμότητα και τη λειτουργία των makefiles ώστε να γράφετε πιο ευανάγνωστο κώδικα.

 

ΕΙΣΑΓΩΓΗ

  • Τα makefiles ρυθμίζουν τον τρόπο με τον οποίο συνδέουμε πολλά αρχεία μεταξύ τους.
  • Όταν μεταφράζουμε τον πηγαίο (source) κώδικα, ο μεταγλωττιστής παράγει ένα αρχείο με τελικό (object [.o]) κώδικα.
  • Ο linker συνδέει τα αρχεία τελικού κώδικα με τον τελικό κώδικα από τις βιβλιοθήκες και παράγει το εκτελέσιμο.

Το αρχείο makefile (ή σχεδόν ισοδύναμα και Makefile) περιέχει εντολές για το πώς θα συνδέσουμε και θα μεταγλωττίσουμε τα αρχεία μας.
Μερικές οδηγίες (options ή directives):


# This is a comment
# Options for the compilation of C, C++ programs:
# -O Optimize object code
# -c Compile and assemble, but do not link
# -o <file> Place the output into <file>

Σημείωση: Ότι ακολουθεί το σύμβολο # αποτελεί σχόλιο και δε λαμβάνεται υπόψην.

 

Πως γίνεται η μεταγλώττιση

 

Έστω ότι τα περιεχόμενα του τρέχοντος directory είναι:


stack1.h, stack1.c, main.c, makefile
Η μεταγλώττιση γίνεται ως εξής:
make main

Τότε θα δημιουργηθεί μέσα στον τρέχον κατάλογο ένα αρχείο με δικαιώματα εκτέλεσης που θα ονομάζεται main.

Παράδειγμα
Έστω ότι τα περιεχόμενα του τρέχοντος directory είναι:


stack1.h, stack1.c, main.c, makefile
To makefile Έστω ότι τα περιεχόμενα του τρέχοντος directory είναι:
stack1.h, stack1.c, main.c, makefile

Το makefile μπορεί να έχει την παρακάτω μορφή:

# stack1.o DEPENDS on stack1.h and stack1.c
# Still, we create only the .o file and do not
# link it to an executable
# main DEPENDS on the stack1.o[bject] file and
# main.c
# We compile it and we produce the executable
# main
main: stack1.o main.c
gcc stack1.o -o main main.c
stack1.o: stack1.h stack1.c
gcc -O -c stack1.c

 

Επεξήγηση


main: stack1.o main.c
Το εκτελέσιμο πρόγραμμα main που θα παράγουμε εξαρτάται από τη σύνδεση του πηγαίου κώδικα του main.c με το αντικείμενο stack1.o. main: stack1.o
gcc stack1.o -o main main.c
Εδώ δηλώνουμε πως θα μεταγλωττιστεί το main.
stack1.o: stack1.h stack1.c
Το αντικείμενο stack1.ο εξαρτάται από το αρχείο βιβλιοθήκης stack1.h καθώς και από το αρχείο πηγαίου κώδικα stack1.c
gcc -O -c stack1.c
Εδώ δηλώνουμε πως θα μεταγλωττιστεί το stack1.o To -O δεν ειναι απαραίτητο. Το έχουμε βάλει για θέματα βελτιστοποίησης. Το -c δηλώνει ότι δε θα γίνει σύνδεση οπότε θα παραχτεί το αντικείμενο stack1.o και όχι το εκτελέσιμο stack1.

 

ΠΡΟΧΩΡΗΜΕΝΑ ΘΕΜΑΤΑ

 

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

 

Κανόνες

 

Οι κανόνες είναι ο κορμός του Makefile. Η μορφή κάθε κανόνα είναι η παρακάτω:
<target> : <dependencies>
<action1>
<action2>...

Ο κανόνας ορίζει τρία πράγματα. Το όνομα του αρχείου που πρέπει να ανανεωθεί (στόχος - target), πότε πρέπει να ανανεωθεί (εξαρτήσεις - dependencies) και πώς θα ανανεωθεί (ενέργειες - actions). Οι εξαρτήσεις (dependencies) είναι ονόματα αρχείων από τα οποία εξαρτάται ο στόχος (target) και μπορεί να είναι και ονόματα στόχων από άλλους κανόνες. Το make θα εκτελέσει τις ενέργειες (actions) με τη σειρά που ορίζονται όταν κάποιο από τα αρχεία που αναφέρονται στις εξαρτήσεις έχει νεότερη ημερομηνία από το στόχο. Οι ενέργειες (actions) μπορεί να είναι οποιεσδήποτε εντολές και πρέπει υποχρεωτικά να ξεκινούν με ΤΑΒ. Η παράλειψη του αρχικού TAB σε κάθε γραμμή ενέργειας είναι και το συνηθέστερο λάθος στην κατασκευή του Makefile.
Έστω για παράδειγμα ότι σε μια εργασία του μαθήματος έχουμε τα αρχεία list.C και list.h . Ένας κανόνας για να δημιουργούμε το list.o είναι:
list.o : list.C list.h
g++ -c list.C

Αν το εκτελέσιμο της εργασίας ονομάζεται test_data_structures και περιέχει ένα επιπλέον αρχείο main.C, τότε για να το δημιουργήσουμε αρκεί να προσθέσουμε στην αρχή του αρχείου Makefile τους κανόνες:
test_data_structures : list.o main.o
g++ -o test_data_structures list.o main.o

main.o : main.C
g++ -c main.C

Έτσι όταν δίνουμε την εντολή make, θα μεταγλωττίζεται μόνο όποιο αρχείο είναι νεότερο από το εκτελέσιμο.

 

Σχόλια

 

Τα σχόλια στο Makefile εισάγονται με τη χρήση του χαρακτήρα #: ο χαρακτήρας # και όλοι οι χαρακτήρες μέχρι το τέλος της γραμμής αγνοούνται. Τα σχόλια μπορούν να εμφανίζονται οπουδήποτε στο Makefile. Παράδειγμα:
LEDA_LIBS = -lL -lm # Link with the LEDA library of basic data types

Ειδικοί κανόνες και ορίσματα γραμμής εντολών

Το όνομα ενός στόχου (target) δεν είναι ανάγκη να είναι κάποιο αρχείο. Μπορούμε να ορίσουμε έναν ειδικό κανόνα που όταν κληθεί θα κάνει μια εργασία διαφορετική από μεταγλώττιση. Ο συνηθέστερος τέτοιος κανόνας είναι αυτός που ορίζουμε για να διαγραφούν ορισμένα αρχεία όταν δεν χρειάζονται:

clean :
rm -f *.o test_data_structures core

Ένας άλλος τέτοιος κανόνας μπορεί να δημιουργεί το κατάλληλο αρχείο για παραδοση μιας άσκησης:

submit :
mkdir exercise1
cp *.C *.h report exercise1
tar czvf exercise1.tar.gz exercise1
rm -rf exercise1

Τέτοιους κανόνες τους καλούμε δίνοντας το όνομα του στόχου σαν όρισμα στη γραμμή εντολών αμέσως μετά το make, π.χ.:
make clean

Το make δέχεται διάφορα ορίσματα στη γραμμή εντολών. Το πιο συνηθισμένο είναι να δοθεί σαν όρισμα το όνομα ενός στόχου (όπως το make clean που έχουμε δει παραπάνω). Αν δεν υπάρχει όνομα στόχου στη γραμμή εντολών το make επεξεργάζεται τον πρώτο στόχο του Makefile. Άλλο ένα σύνηθες όρισμα είναι το -f <Makefile> που λέει στο make να χρησιμοποιήσει κάποιο άλλο αρχείο σαν Makefile. Παράδειγμα:
make -f Makefile2


Μεταβλητές

 

Στην αρχή κάθε Makefile μπορούμε να ορίσουμε μεταβλητές για να αποφεύγουμε περιττές επαναλήψεις και να το κάνουμε πιο ευανάγνωστο. Οι ορισμοί των μεταβλητών είναι της μορφής:
<όνομα_μεταβλητής> = <κείμενο>

Αν υπάρχουν κενά στην αρχή του κειμένου αγνοούνται. Οι μεταβλητές μπορούν να χρησιμοποιηθούν οπουδήποτε (ακόμη και για τον ορισμό άλλων μεταβλητών). Στην τιμή μιας μεταβλητής αναφερόμαστε με τη σύνταξη:
$(<όνομα>) ή ${<όνομα>}

Έστω για παράδειγμα ότι έχουμε την εργασία που περιγράψαμε παραπάνω και έστω ότι θέλουμε να καλέσουμε τον μεταγλωττιστή με την επιλογή -g (για debugging). Μπορούμε στην αρχή του Makefile να ορίσουμε:
CXXFLAGS = -g

και να τροποποιήσουμε τους κανόνες ως εξής:
test_data_structures : list.o main.o
g++ -o $(CXXFLAGS) test_data_structures list.o main.o

list.o : list.C list.h
g++ -c ${CXXFLAGS} list.C

main.o : main.C
g++ -c $(CXXFLAGS) main.C

Έτσι αν θέλουμε να αλλάξουμε τα ορίσματα του compiler π.χ. από -g σε -O2 (για βελτιστοποίηση), αρκεί να αλλάξουμε μόνο τον ορισμό της CXXFLAGS σε:
CXXFLAGS = -O2

Η ίδια τακτική μπορεί να χρησιμοποιηθεί και για άλλα ορίσματα, π.χ. βιβλιοθήκες. Για παράδειγμα αν για την παραπάνω εργασία πρέπει να χρησιμοποιήσουμε και τη βιβλιοθήκη βασικών τύπων της LEDA θα προσθέσουμε στο Makefile:
LEDA_LIBS = -lL -lm

και θα τροποποιήσουμε τον κανόνα για το test_data_structures ως εξής:
test_data_structures : list.o main.o
g++ -o $(CFLAGS) test_data_structures list.o main.o $(LEDA_LIBS)

Ενσωματωμένοι κανόνες

Το make έχει ενσωματωμένους κανόνες για τις πιο συνηθισμένες λειτουργίες μεταγλώττισης (π.χ. παραγωγή object από αρχείο κώδικα C++). Σε αυτές τις περιπτώσεις δεν χρειάζεται να ορίσουμε εμείς τους κανόνες μεταγλώττισης. Αυτοί οι κανόνες χρησιμοποιούν ειδικές μεταβλητές τις οποίες μπορούμε να ορίσουμε ώστε να επηρεάσουμε τη συμπεριφορά του κανόνα.
Σχετικά με τα αρχεία C++ το make παράγει το αρχείο .o από το αντίστοιχο αρχείο .C με χρήση του κανόνα
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)

όπου η μεταβλητή CXX έχει προεπιλεγμένη τιμή g++, ενώ οι μεταβλητές CPPFLAGS και CXXFLAGS θεωρούνται ότι έχουν κενή προεπιλεγμένη τιμή.
Για να χρησιμοποιήσουμε έναν τέτοιο κανόνα πρέπει είτε να ορίσουμε έναν κανόνα χωρίς ενέργειες (actions) ή να μην ορίσουμε κανένα κανόνα για κάποιο αρχείο. Για παράδειγμα για την εργασία που έχουμε προαναφέρει ο κανόνας που δημιουργεί το main.o μπορεί να παραλειφθεί. Όταν το make χρειαστεί το main.o θα ελέγξει αν υπάρχει το main.C και αν ναι, θα χρησιμοποιήσει τον αντίστοιχο ενσωματωμένο κανόνα για C++. Οταν θέλουμε να ορίσουμε επιπλέον εξαρτήσεις (dependecies), τότε ορίζουμε ένα σχετικό κανόνα αλλά δεν ορίζουμε ενέργειες (actions). Στην παραπάνω εργασία ο κανόνας για το list.o μπορεί να τροποποιηθεί ως εξής:
list.o : list.h

Η συμπεριφορά των ενσωματωμένων κανόνων μπορεί να τροποποιηθεί με το να δώσουμε διαφορετικές τιμές στις μεταβλητές που χρησιμοποιούν. Έτσι αν θέλουμε, μπορούμε να προσθέσουμε στo Makefile:
CXXFLAGS = -g

για να τροποποιήσουμε τη συμπεριφορά του ενσωματωμένου κανόνα. (Φυσικά δεν είναι αναγκαίο να χρησιμοποιήσουμε τους ενσωματωμένους κανόνες). Στο τέλος του κειμένου υπάρχει ένα ολοκληρωμένο παράδειγμα.

 

Δημιουργία βιβλιοθηκών

 

Το make μπορεί να χρησιμοποιηθεί και για την αυτοματοποίηση της δημιουργίας βιβλιοθηκών. Μια βιβλιοθήκη δημιουργείται από αρχεία object (.o) με τη χρήση των εντολών ar και ranlib. Μπορούμε επομένως να ορίσουμε έναν κανόνα που θα εκτελεί τις παραπάνω εντολές. Για παράδειγμα έστω ότι στην εργασία που έχουμε αναφέρει υπάρχει και ένα τρίτο αρχείο, το stack.C, και θέλουμε πέρα από το εκτελέσιμο της εργασίας να δημιουργήσουμε μια βιβλιοθήκη my_lib.a για μελλοντική χρήση. Ορίζουμε τότε στο Makefile τον κανόνα:

my_lib : list.o stack.o
ar crv my_lib.a list.o stack.o
ranlib my_lib.a

(Τα ορίσματα της ar σημαίνουν τα εξής : c: να δημιουργήσει - create - το αρχείο my_lib.a, να προσθέσει - add with replacement - τα αρχεία list.o και stack.o και να αναφέρει αναλυτικά - verbose - τις ενέργειες καθώς εκτελείται). Για το stack.o δε χρειάζεται να ορίσουμε τίποτα αφού θα δημιουργηθεί από το stack.C με τη χρήση ενσωματωμένου κανόνα. Για να δημιουργήσουμε τη βιβλιοθήκη πρέπει να δώσουμε στη γραμμή εντολών το όνομα του σχετικού στόχου σαν όρισμα, δηλαδη:
make my_lib

 

Παράδειγμα

Έστω ότι έχουμε την παραπάνω εργασία που χρησιμοποιεί και τη βιβλιοθήκη LEDA που υποθέτουμε ότι βρίσκεται στο /usr/local/LEDA-5.2 (το path μπορεί στην πραγματικότητα να είναι λίγο διαφορετικό). Ένα Makefile για τη συγκεκριμένη εργασία είναι το παρακάτω:

CXX = g++ # use the g++ compiler

OBJS = main.o list.o stack.o # project files
LIB_OBJS = list.o stack.o # my_lib files

LEDA_PATH = /usr/local/LEDA-5.2 # directory where LEDA libraries are stored
LEDA_LIBS = -lL -lm # Link with the LEDA library of basic data types

CXXFLAGS = -g # for debugging; can be changed or omitted later
CPPFLAGS = -I$(LEDA_PATH)

all : test_data_structures my_lib # rule to create everything

test_data_structures : $(OBJS) # rule to create executable
$(CXX) -o test_data_structures $(OBJS) -L$(LEDA_PATH) $(LEDA_LIBS)

my_lib : $(LIB_OBJS) # rule to create my_lib.a from list.o and stack.o
ar crv my_lib.a list.o stack.o
ranlib my_lib.a

# we write this rule only to state the dependency of list.o from list.h
list.o : list.h

#rules for main.o and stack.o are not necessary

clean : # rule to delete unnecessary files
rm -f *.o test_data_structures core

4.5
Average: 4.5 (2 votes)
Your rating: None
  • Login or register to post comments

Επιλογές

  • Τι είναι το Debian
    • Ιστορία του Debian
    • Εκδόσεις του Debian
    • Άδεια χρήσης
    • Χορηγίες
  • Κατεβάστε το Debian
  • Tutorials
  • Ελληνικά στο Debian
  • Νέα - Ειδήσεις
  • Debian FAQ
  • Εγχειρίδια
  • Συνεντεύξεις
  • #debian.gr στο IRC
  • Software Directory
  • Λίστα Ελλήνων Χρηστών debian
  • Image galleries

Πλοήγηση

  • Create content
    • Issue

Σύνδεση χρήστη

  • Δημιουργία νέου λογαριασμού
  • Αίτηση νέου κωδικού

New forum topics

  • MSN Messenger Clone
  • Offline εγκατάσταση πακέτων
  • Fosscom 2010 Θεσσαλονίκη
  • Port forward για torrent client;
  • Δε μπορώ να στείλω αρχεία με το bluetooth
  • πρόβλημα εγκατάστασης nvidia driver GTS250.
  • ρυθμιση pidgin για χρηση στο windows live
  • Rapidshare download
  • Offline instalation;
  • Segfault σε lib6 2.7
περισσότερα

Νέοι χρήστες

  • credswerway
  • crow
  • Lochecillssa
  • viagrarxcheap
  • alexandrosorodios

Online χρήστες

Προς το παρόν υπάρχουν 0 users και 3 guests online.

Disclaimer

This is not an official website of the Debian Project. It is located at www.debian.org.

Active forum topics

  • Fosscom 2010 Θεσσαλονίκη
  • MSN Messenger Clone
  • Offline εγκατάσταση πακέτων
  • Δε μπορώ να στείλω αρχεία με το bluetooth
  • Port forward για torrent client;
  • Rapidshare download
  • ρυθμιση pidgin για χρηση στο windows live
  • πρόβλημα εγκατάστασης nvidia driver GTS250.
  • Offline instalation;
  • Segfault σε lib6 2.7
περισσότερα

Recent comments

  • Δευτέρα 8
    gekaklam
    08/03/2010 - 21:05
  • MSN on Linux
    johnp
    07/03/2010 - 23:18
  • κοιτα σαν
    crow
    05/03/2010 - 13:51
  • προς το παρών
    bermi
    05/03/2010 - 12:11
περισσότερα

Οι πιο πρόσφατες καταχωρίσεις blog.

  • Ο κύκλος ενός πακέτου
  • 2010
  • TasPython.eu
  • Downtime
  • καλορίζικο!!!
  • "burn baby burn, mailist infernooooooo, burn baby burn.... <guitar solo>"
  • Set the record straight...
  • 1η Συνέλευση φίλων ΕΛ/ΛΑΚ Χανίων 24/1/09
  • Iceweasel search-plugin
  • λίγες σκέψεις και ευχαριστίες
περισσότερα
Ελληνική Κοινότητα Debian  |   Κοινότητα ΦΛΑΚ