ΔΗΜΙΟΥΡΓΙΑ & ΧΡΗΣΗ ΒΙΒΛΙΟΘΗΚΩΝ Γεώργιος Παπαϊωάννου (2017-18) gepap@aueb.gr
Περιγραφή: Τι είναι οι βιβλιοθήκες Δημιουργία βιβλιοθηκών Σύνδεση βιβλιοθηκών Τελευταία ενημέρωση: Οκτώβριος 2017 2
Compilation Unit: Μονάδα μεταγλώττισης Είναι οτιδήποτε μπορεί ο compiler να μεταγλωττίσει ανεξάρτητα και αυτοτελώς Ταυτίζεται με αρχεία που περιέχουν υλοποιήσεις και δεν ενσωματώνονται σε άλλες μονάδες μεταγλώττισης (π.χ. το τυπικό cpp αρχείο) 3
Είναι αρχεία που περιέχουν μεταγλωττισμένο κώδικα και σύμβολα για τη σύνδεσή του και το debugging Έχουν προέλθει από τη μεταγλώττιση αρχείων υλοποίησης C/C++: Δικού μας κώδικα Κώδικα τρίτων Υλοποιούν συνήθως αυτοτελή και επαναχρησιμοποιήσιμη λειτουργικότητα Αποτελούνται από: Ένα ή περισσότερα αρχεία κεφαλίδας Ένα αρχείο lib (υπερβολικά πολλές) λεπτομέρειες για τα αρχεία βιβλιοθηκών θα βρείτε στο http://www.sco.com/developers/devspecs/gabi41.pdf 4
Έστω ότι έχουμε αρχεία C++ που υλοποιούν μαθηματικές πράξεις: vec.h και vec.cpp : Δηλώσεις και πράξεις διανυσμάτων complex.h και complex.cpp : Δηλώσεις και πράξεις μιγαδικών trig.h, trig.cpp και fast_trig.cpp: τριγωνομετρικές πράξεις και 2 διαφορετικές υλοποιήσεις τους (απλή, γρήγορη/προσεγγιστική) Μπορούμε να φτιάξουμε μια βιβλιοθήκη mymath.lib που να ενσωματώνει όλο το δυαδικό κώδικα των cpp αρχείων (δηλαδή των μονάδων μεταγλώττισης) 5
Header files της C++ Header files του project μας trig.h math.h limits.h Εξωτερικές εξαρτήσεις Εσωτερικές εξαρτήσεις complex.h vec.h Τα cpp αρχεία μας trig.cpp fast_trig.cpp complex.cpp vec.cpp Μεταγλώττιση Βιβλιοθήκη mymath.lib 6
Στη Visual C++, μια βιβλιοθήκη σχετίζεται με ένα ολόκληρο Project Μέσα σε ένα νέο ή υπάρχον Solution φτιάχνουμε ένα καινούριο Project 7
Στις αρχικές επιλογές δηλώνουμε ότι θέλουμε Win32 Console Application Όνομα Project 8
Προσέχουμε το μονοπάτι που θα δημιουργηθεί το project να είναι το επιθυμητό To μονοπάτι που δηλώνουμε είναι αυτό στο οποίο θα δημιουργήσει το Visual Studio το νέο κατάλογο με το όνομα του project μας Σε υπάρχον solution, συνήθως το μονοπάτι του επιπρόσθετου project πρέπει να είναι μέσα στον κατάλογο του solution 9
Δεν πατάμε Finish, καθώς θέλουμε να προσδιορίσουμε επιπλέον παραμέτρους: Πρέπει να δηλώσουμε ότι το project αφορά static library: 10
Επιλέγουμε Static Library Απενεργοποιούμε τις επιλογές για Precompiled header και SDL checks 11
Σε υπάρχον Solution, για να προσθέσουμε νέο Project, από το Solution Explorer επιλέγουμε Solution Add New Project Ακολουθούμε τα βήματα που είδαμε 12
Όταν έχουμε πολλαπλά projects μέσα σε ένα solution, ένα είναι το πρωτεύον (start up) Είναι αυτό που θα επιχειρήσει το IDE να εκτελέσει όταν του ζητήσουμε να μας τρέξει την εφαρμογή Σε ένα solution με ένα κύριο πρόγραμμα και μία ή περισσότερες βιβλιοθήκες, μόνο το project με το κύριο πρόγραμμα έχει νόημα να είναι startup Για να ορίσουμε ποιο Project είναι πρωτεύον, επιλέγουμε Set as StartuUp Project από το Pop-up menu του project 13
Κάθε project διαθέτει επιλογές, μεταξύ άλλων για: Το πού θα αποθηκευτεί το τελικό προϊόν του project (εδώ το.lib αρχείο) και ποιο θα είναι το όνομά του Που να ψάξει να βρει άλλα αρχεία που πρέπει είτε να ενσωματώσει (Include) στον κώδικα είτε να συνδέσει (Link) με αυτόν Οι επιλογές αυτές είναι χωριστές για κάθε Configuration (π.χ. Debug/Release) 14
Προσδιορισμός ονόματος βιβλιοθήκης και μονοπατιού αποθήκευσης Καλό είναι οι βιβλιοθήκες που δημιουργούμε να είναι συγκεντρωμένες σε έναν κατάλογο του solution για να μπορούμε εύκολα να τις εντοπίζουμε Πρέπει να δίνουμε διαφορετικό όνομα στη βιβλιοθήκη, ανάλογα με το configuration από το οποίο έχει προέλθει για να μην υπάρχει σύγχυση και να μην επικαλύπτονται τα αρχεία Συνήθως, σώζουμε τις βιβλιοθήκες: Είτε σε έναν κατάλογο /lib μέσα στο Solution Είτε σε έναν κατάλογο με το όνομα της βιβλιοθήκης μαζί με τα σχετικά header files της ΔΕΝ είναι οι προκαθορισμένοι κατάλογοι που επιλέγει το Visual Studio, άρα πρέπει να τον επαναπροσδιορίσουμε! 15
Προσδιορισμός ονόματος βιβλιοθήκης και μονοπατιού αποθήκευσης Από το διάλογο Properties του Project της βιβλιοθήκης: 16
Επιλογή configuration για το οποίο μεταβάλλουμε ρυθμίσεις: Προσδιορισμός καταλόγου που θα αποθηκευτεί το παραγόμενο lib αρχείο: Το δεσμευμένο αναγνωριστικό $(SolutionDir) αντιστοιχεί στον κατάλογο που είναι η βάση του solution μας (Περιλαμβάνεται το τερματικό / ) Διαλέγουμε ίδιο κατάλογο ΚΑΙ για τα 2 configurations 17
Προσδιορισμός του ονόματος της βιβλιοθήκης Για Release configuration: Και για Debug, φροντίζουμε να δώσουμε ένα διαφορετικό όνομα: Μετά το build για κάθε ένα configuration, έχουν δημιουργηθεί στον κατάλογο που ζητήσαμε οι 2 βιβλιοθήκες (Debug/Release) 18
Για να χρησιμοποιήσει η εφαρμογή μας μια βιβλιοθήκη (είτε από το ίδιο είτε από διαφορετικό Solution), χρειάζεται να: Ζητήσουμε την ενσωμάτωση ενός συγκεκριμένου lib αρχείου Να προσδιορίσουμε το μονοπάτι στο οποίο θα αναζητήσει το visual studio το (τα) lib αρχείο(α) μας Να προσδιορίσουμε το μονοπάτι στο οποίο ψάχνει ο compiler για τα αντίστοιχα header files που περιέχουν τις δηλώσεις της βιβλιοθήκης 19
Στις επιλογές του Project που θα χρησιμοποιήσει τη βιβλιοθήκη, ζητάμε να συμπεριληφθεί το συγκεκριμένο lib αρχείο στις εξαρτήσεις του project (Dependencies): 20
Προσθέτουμε το μονοπάτι στο οποίο το Project ψάχνει για την βιβλιοθήκη: Σχετικό μονοπάτι προς το lib αρχείο 21
Τοποθετούμε ή δημιουργούμε τα αρχεία του Project σε καταλόγους που να έχουν λογική και να είναι εύκολα προσβάσιμα από άλλα του solution μας. Κατάλογος της βιβλιοθήκης Αρχεία.h και.cpp της βιβλιοθήκης Κατάλογος του Solution Αρχεία.h και.cpp της κύριας εφαρμογής 22
Στην προηγούμενη εικόνα, τα αρχεία είναι οργανωμένα πρώτα κατά project με σημείο αναφοράς το Solution Εναλλακτικός τρόπος: Χωρίζουμε τα αρχεία σε headers, libraries και source files: 23
Για να ολοκληρώσουμε τη σύνδεση της εφαρμογής με τη βιβλιοθήκη, προσθέτουμε το μονοπάτι στο οποίο το Project ψάχνει για τα αρχεία κεφαλίδας της βιβλιοθήκης, στις επιλογές του compiler Ενσωματώνουμε τα κατάλληλα σχετικά μονοπάτια στις δηλώσεις #include στα αρχεία της εφαρμογής
Εδώ κενό (δε χρειάζεται), καθώς το header file βρίσκεται σε εσωτερικό φάκελο σε σχέση με τα αρχεία που το κάνουν #include και το μονοπάτι αυτό δίνεται κατά την ενσωμάτωση: 25
Σε ένα Solution που έχει πολλαπλά projects, ορισμένα από αυτά ενδέχεται να εξαρτώνται από τα αποτελέσματα άλλων π.χ. ένα εκτελέσιμο χρειάζεται να έχει προηγηθεί η δημιουργία μια βιβλιοθήκης που ενσωματώνει Στο Visual Studio μπορούμε να δηλώσουμε ποιες είναι οι εξαρτήσεις, ώστε να χτίζονται με τη σωστή σειρά τα Projects 26
27
Όσοι χρησιμοποιείτε τα εργαλεία ανάπτυξης της GNU (π.χ. με το πακέτο SIGWIN), μπορείτε να χτίσετε τη βιβλιοθήκη και την εφαρμογή που τη χρησιμοποιεί από τη γραμμή εντολών με τα εργαλεία: g++ : C++ compiler (καλεί και το Linker ld, ανάλογα με τα ορίσματα) ar : πρόγραμμα δημιουργίας βιβλιοθηκών (archives) ld : ανεξάρτητος Linker (δε χρειάζεται να τον καλέσετε μόνο του, καθώς απαιτεί παραμετροποίηση για τις βιβλιοθήκες της C++. Χρησιμοποιείστε τον g++ για την τελική σύνδεση, ο οποίος δηλώνει τις σωστές βιβλιοθήκες της C++) 28
Για να φτιάξετε μια βιβλιοθήκη, πρέπει: Να μεταγλωττίσετε τα cpp αρχεία της Π.χ., αν στο φάκελο vec έχω τα vec2.h vec2.cpp vec3.h vec3.cpp: g++ -c vec\vec2.cpp -o vec\vec2.o - std=c++11 g++ -c vec\vec3.cpp -o vec\vec3.o - std=c++11 ο [outfile]: δηλώνουμε ακριβώς σε ποιόν κατάλογο και με τι όνομα θα σωθεί το.ο αρχείο -std=c++11: ζητάμε να χρησιμοποιήσει ο compiler το πρότυπο C++11 (δεν είναι default στον GNU C++ compiler) 29
Να συμπεριλάβουμε τα.ο αρχεία σε μια βιβλιοθήκη (archive): ar rcs vec\libvec.a vec\vec2.o vec\vec3.o r: replace archive content cs: παράμετροι εντολής. c: suppress warnings, s: δημιουργία ευρετηρίου συμβόλων μέσα στη βιβλιοθήκη Σημείωση: η standard σύμβαση ονομάτων του g++ linker για τις βιβλιοθήκες είναι: lib[onoma].a Όταν θα ενσωματώσουμε μια βιβλιοθήκη, τη δηλώνουμε μόνο με το ΟΝΟΜΑ: -lonoma 30
Eνσωμάτωση της βιβλιοθήκης στο εκτελέσιμό μας: Π.χ: Φτιάχνουμε μια εφαρμογή demo.exe που χρησιμοποιεί τη βιβλιοθήκη libvec.a και χρειάζεται τις δηλώσεις που βρίσκονται στο αρχείο vec\vec2.h Παρατήρηση: Στο παράδειγμα αυτό ο κατάλογος vec είναι σχετικός με το τρέχον μονοπάτι της κύριας εφαρμογής Είτε κάνουμε στο καλόν αρχείο #include vec\vec2.h και δε χρειάζεται να δηλώσουμε επιπρόσθετα μονοπάτια αναζήτησης για τα header files στον compiler (αφού τα δίνουμε στην παράμετρο του include) Είτε κάνουμε στο καλόν αρχείο #include vec2.h και προσθέτουμε το μονοπάτι «vec» στα include paths κατά τη μεταγλώττιση και σύνδεση: -Ιvec 31
Επιπρόσθετο μονοπάτι αναζήτησης για include files σε περίπτωση που δεν υπάρχει ο σχετικός κατάλογος στο όρισμα του #include. Χρησιμοποιείται κατά τη μεταγλώττιση g++ main.cpp -o demo.exe I vec -L vec -l vec -std=c++11 Mονοπάτι αναζήτησης για βιβλιοθήκη. Χρησιμοποιείται κατά τη σύνδεση Το όνομα της βιβλιοθήκης που θέλουμε να συνδεθεί (libvec.a) 32