Proszę nie wskrzeszać antycznych wątków tylko zakładać nowe.To sprawa na dłuższego posta. A więc:
== KOMPILACJA ==Kompilator w najprostszym wypadku wywołujesz tak:
gcc [opcjonalne flagi] -o nazwa_pliku_wykonywalnego_do_utworzenia kod_źródłowy1.c kod_źródłowy2.c ...
g++ [opcjonalne flagi] -o nazwa_pliku_wykonywalnego_do_utworzenia kod_źródłowy1.cpp kod_źródłowy2.cpp ...
Wywołanie powyżej tak naprawdę uruchamia dwa różne programy:
1. Kompilator c/c++ kompiluje wszystkie pliki kod_źródłowyX.c/kod_źródłowyX.cpp do tzw. plików obiektu (*) kod_źródłowyX.o (niezależnie od języka źródłowego)
2. Linker łączy twoje pliki obiektu i bibliotekę standardową do pliku wykonywalnego (jeżeli ominiesz -o nazwapliku to ze względów historycznych plik wykonywalny będzie się nazywał a.out). Z ciekawostek, linker na ogół odpala się taką samą nazwą jak kompilator
aby było łatwiej.
Czyli jeżeli mamy pliki s1.c s2.c i s3.c a chcemy uzyskać plik program (parametr -c kompilatora instruuje go, aby tylko skompilował, bez linkowania)
/* Plik s1.c */
#include
extern int fs2(); /* Aby móc korzystać z funkcji z innego pliku .o */
extern int fs3(); /* Tak samo */
int main(int argc, char ** argv)
{
int s2 = fs2();
int s3 = fs3();
printf("s2+s3 = %d\\n",s2+s3);
return 0;
}
/* Plik s2.c */
int fs2()
{
return 5;
}
/* Plik s3.c */
int fs3()
{
return 10;
}
$> gcc -c s1.c s2.c s3.c
$> ls -l
-rw-r--r-- 1 pawel pawel 183 10-27 15:20 s1.c
-rw-r--r-- 1 pawel pawel 1656 10-27 15:20 s1.o
-rw-r--r-- 1 pawel pawel 28 10-27 15:14 s2.c
-rw-r--r-- 1 pawel pawel 1224 10-27 15:20 s2.o
-rw-r--r-- 1 pawel pawel 29 10-27 15:15 s3.c
-rw-r--r-- 1 pawel pawel 1224 10-27 15:20 s3.o
$> gcc -o program s1.o s2.o s3.o
$> ls -l
-rwxr-xr-x 1 pawel pawel 8151 10-27 15:20 program
-rw-r--r-- 1 pawel pawel 183 10-27 15:20 s1.c
-rw-r--r-- 1 pawel pawel 1656 10-27 15:20 s1.o
-rw-r--r-- 1 pawel pawel 28 10-27 15:14 s2.c
-rw-r--r-- 1 pawel pawel 1224 10-27 15:20 s2.o
-rw-r--r-- 1 pawel pawel 29 10-27 15:15 s3.c
-rw-r--r-- 1 pawel pawel 1224 10-27 15:20 s3.o
$> ./program
s2+s3 = 15
$>
W punkcie 2 musisz też dorzucić wszystkie biblioteki, z których korzystasz, w tym np allegro.
Wadą powyższego rozwiązania jest to, że jeżeli program składa się np z 15 plików źródłowych a ty zmienisz tylko jeden, to i tak ponownie kompilowane są wszystkie. Dlatego w większych projektach fizycznie rozdziela się fazę kompilacji i linkowania za pomocą programu make (qmake, gmake, cmake, nmake, whatever). Program jest tak sprytny, że sprawdza czy kod źródłowy nie jest czasem starszy od pliko .o, i jeżeli tak jest to zakłada, że plik źródłowy nie był modyfikowany od ostatniej kompilacji i go pomija. W ten sposób kompilowane są tylko pliki zmienione od poprzedniej kompilacji.
(*) - plik obiektu nie ma niz wspólnego z programowaniem obiektowym! To, niefortunna nazwa, która powstała zanim w ogóle wymyślono programowanie obiektowe.
== BIBLIOTEKI ZEWNĘTRZNE ==Biblioteki użytkowe w Linuksach (i Windowsie zresztą też) rozprowadzane są w 2 częściach:
* Biblioteka czasu wykonania (.so w Linuksie, .DLL w Windows). Biblioteka ta jest potrzebna (i wystarczająca) do uruchomienia już skompilowanego programu z niej korzystającego.
* Nagłówki i biblioteki czasu kompilacji (.h w obu systemach oraz .lib w Windows bądź .a/.la w Linuksach). Te elementy potrzebne są do skompilowania (.h) programu do pliku obiektu .o oraz do późniejszego zlinkowania obiektu (.lib/.a/.la) do pliku wykonywalnego. Biblioteki czasu kompilacji mają w Linuksach przyrostek -dev i są NIEZBĘDNE aby pisać programy z wykorzystaniem danej biblioteki.
Bardzo często w czasie kompilacji dana biblioteka wymaga dziwnych opcji przekazywanych kompilatorowi i/lub linkerowi. Aby nie obciążać tym programisty często tworzy się sprytny skrypt generujący potrzebne opcje automatycznie w locie. Np dla biblioteki PNG jest to plik libpng-config. Odpalony bez parametrów wygląda tak:
#> libpng-config
Usage: /usr/bin/libpng-config [OPTION] ...
Known values for OPTION are:
--prefix print libpng prefix
--libdir print path to directory containing library
--libs print library linking information
--ccopts print compiler options
--cppflags print pre-processor flags
--cflags print preprocessor flags, I_opts, and compiler options
--I_opts print "-I" include options
--L_opts print linker "-L" flags for dynamic linking
--R_opts print dynamic linker "-R" or "-rpath" flags
--ldopts print linker options
--ldflags print linker flags (ldopts, L_opts, R_opts, and libs)
--static revise subsequent outputs for static linking
--help print this help and exit
--version print version information
Teraz, aby kompilować z libpng do kompilatora trzeba dodać takie opcje:
#> /usr/bin/libpng-config --cflags
-I/usr/include/libpng15
a do linkera takie:
#> /usr/bin/libpng-config --ldflags
-L/usr/lib64 -lpng15
Aby nie bawić się w przepisywanie, kompilator i linker wywołujesz tak:
$> gcc `libpng-config --cflags` -c program.c
$> gcc `libpng-config --ldlags` -o program program.o
Odwrócone ciapki (`) uruchamiają program w nich się znajdujący i w ich miejsce wstawiają wynik działania. Tak więc powyższe linijki są równoważne tym:
$> gcc -I/usr/include/libpng15 -c program.c
$> gcc -L/usr/lib64 -lpng15 -o program program.o
Co to daje? Jak pojawi się nowe libpng w werji 16 (libpng16) libpng-config będzie generowało nowe pocecenia a przy przepisaniu "na stałe" musisz poprawiać wszystkie pliki make korzystające z libpng. Duże ułatwienie i mniejsza podatność na błędy.
==============================Tak więc polecenie
$> g++ main.cpp `allegro-config --libs --shared`
Kompiluje i linkuje program main.cpp do pliku a.out z automatycznie wygenerowaną konfiguracją niezbędną do użycia biblioteki allegro[...].so (to ta część --shared). Dodatkowo według man, --shared zawiera w sobie --libs, więc wystarczy tylko
$> g++ main.cpp `allegro-config --shared`
ALE Problem z tym, że te instrukcje są dla allegro4. Allegro 5 korzysta z nowego, uniwersalnego mechanizmu pkg-config i wywołanie powinno wyglądać tak (--libs generuje domyślnie aplikację linkowaną dynamicznie):
$> g++ main.cpp `pkg-config allegro-5.0 --libs`