[[oktatas:programozás:automatikus_fordítás|< Automatikus fordítás]] ====== make ====== * **Szerző:** Sallai András * Copyright (c) 2011, Sallai András * Szerkesztve: 2011, 2014, 2015, 2020 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== A make parancsról ===== A make egy **parancssoros program**, amely leegyszerűsíti, **automatizálja a fordítási** tevékenységet. A fordítási utasításokat egy **Makefile** nevű állományban írjuk le. A **make** parancs a Makefile alapján végez tevékenységeket. A make parancs képes függőségek feltérképezésére, a fordítási sorrend eldöntésére. Felismeri mely forrásokat kell lefordítani, és melyek nem változtak. ===== A make parancs beszerzése ===== Debian GNU/Linux, Ubuntu, Linux Mint rendszeren a make csomagban van. Telepítése: apt install make Win alapú rendszerekre a Source Forge webhelyről szerezhetjük be, vagy telepítsük a Cygwin vagy a MingW csomaggal. * http://gnuwin32.sourceforge.net/ * https://www.cygwin.com/ * http://www.mingw.org/ A make program eredeti oldala: * http://www.gnu.org/software/make/ * https://www.gnu.org/software/make/manual/html_node/ (Dokumentáció) ===== A make fájl tartalma ===== * megjegyzések * változók * célok * függőségek * parancssoros utasítások # megjegyzés1 # megjegyzés2 VALTOZO=érték cél1: függőség_1 függőség_2 ... parancs_1 $(VALTOZO) parancs_2 parancs_n cél2: függőség_3 függőség_4 ... parancs_1 parancs_2 parancs_n A Makefile-ban egysoros megjegyzéseket helyezhetünk el, a "#" karakter után. Változókat vehetünk fel, amelynek értéket adhatunk egyenlőség jellel. A változók felvétele nem kötelező, de célszerű. A fájlban bárhol felvehetünk változókat. Egy változó nevében ajánlott karakter a betű, a szám és az aláhúzás. A változókra a ${név} vagy $(név) formában hivatkozhatunk. Több célt is megadhatunk. A make parancs kiadásakor megadhatjuk, hogy melyik cél hajtódjon végre. Ha egyet sem adunk meg, akkor az első cél hajtódik végre. A cél lehet egy fájl neve, amit elő kell állítani, de lehet egyszerűen egy tetszőleges szó. Konkrét cél helyett megadható változó is. Ha egy cél nem egy létrehozandó állományt takar, akkor hamis célról beszélünk. A hamis célokat megadhatjuk a .PHONY: kulcsszó után felsorolva. Például: .PHONY: clean A függőségek megadása nem kötelező. Ha cél egy fájl, akkor a fájl valamilyen forrásállományokból fog elkészülni. Ezeket a forrásállományokat érdemes felsorolni függőségként. A fordítás így csak akkor történik meg, ha az szükséges. A függőségek helyett megadható változó is. A parancsok, az operációs rendszer szintjén végrehajtandó parancsok. A parancsokba is beágyazhatunk változókat. Egy parancs sikertelen végrehajtása megszakítja a make működését. Ha szeretnénk a megszakítást megakadályozni, akkor egy "-" karakterrel kezdjük a parancsot. Például: clean: -rm *.class ===== Használat C nyelvvel ===== A következőkben a GNU Make használatát nézzük meg. A Makefile tartalmazhat fájlfüggőségek leírását, shell parancsokat, változókat és megjegyzéseket. Írjunk egy helló világ nevű programot: #include main() { printf("Valami\n"); } all: main main: main.o gcc -o main main.o main.o: main.c gcc -c main.c clean: rm main.o main A gcc és az rm sorok előtt tabulátor legyen, a szóköz nem jó. A létrehozandó fájl: "main" (kiterjesztés nélkül). A parancs általános alakja: cél: függőség_1 függőség_2 ... parancs_1 parancs_2 parancs_n * A cél mindig egy fájl neve, amit elő kell állítani. * A függőség egy vagy több fájl, amelyből a célt előállítjuk. * A parancs egy olyan shell parancs, ami elvégzi cél előállítását. Fontos, hogy a parancsok előtt pontosan **egy tabulátor** legyen. A make parancs egy egész értékkel tér vissza. Sikeres végrehajtás esetén 0-val, sikertelenség esetén 1-nél nagyobb számmal. A Makefile-ban használhatunk változókat is. Például megadjuk a fordítót: CC=gcc Az értékükre két módon hivatkozhatunk: $(CC) vagy: ${CC} A Makefile-ban megadható egy fő cél. A fő cél megadása az all kulcsszóval történik: all: main Windowson: all: main.exe Ha nem határozzuk meg az all kulcsszóval a fő célt, akkor az elsőként megtalált cél lesz a fő cél. main: egy.o ketto.o gcc egy.o ketto.o -o main egy.o:egy.h egy.c gcc -c egy.c ketto.o:ketto.h ketto.c gcc -c ketto.c Ha egyszer kiadtuk a make parancsot és létrejöttek a célfájlok, akkor a make parancs újbóli kiadási nem csinál semmit, ha nem változtattunk semmit a forrásfájlokon, mivel a forrásfájlok időbélyege és a célfájlok időbélyege megegyezik. Ha mégis szeretnénk újrafordítani, akkor törölni kell a célfájlokat. A clean egy speciális cél, amely a létrejött célok törlését szokás megadni. ===== Használat C# nyelvvel ===== A mono rendszerrel készült két darab forrásfájllal rendelkezünk: main.cs sajatc.cs Ha két állományból bármelyik változik, akkor fordítani kell. A kimenet egy main.exe. A Mono 2.0 verzióját használjuk, melynek fordítója: gmcs Ezek után a Makefile tartalma a következő tartalommal rendelkezhet: main.exe: main.cs sajatc.cs gmcs main.cs sajat.cs A fenti Makefile-ban azt határoztuk meg, hogy a main.exe függ a main.cs és a sajatc.cs forrásfájloktól. Ha valamelyik változott, akkor futtatjuk a második sort. A második sor egy tabulátor karaktert tartalmaz a sor elején. Ha hordozhatóbbá akarjuk tenni a Makefile-t akkor a fájlneveket érdemes változókban megadni. A fordítás parancsa is változóba tehető. Ezeket a változókat a fájl elején határozzuk meg. Ha valami változik, akkor csak ott kell változtatnunk. FOFORRASFAJL=main EGYEBFORRASFAJL=sajat.cs FORDITO=gmcs $(FOFORRASFAJL).exe: $(FOFORRASFAJL).cs $(EGYEBFORRASFAJL) $(FORDITO) $(FOFORRASFAJL).cs $(EGYEBFORRASFAJL) ===== Implicit szabályok ===== Ha van egy valami.o kiterjesztésű fájl ennek fordítását így írhatjuk explicit: valami.o: valami.c gcc -c valami.c Látható egy általános elv, amely szerint ha van egy valami.o nevű állomány, azt biztosan egy ugyanilyen nevű .c kiterjesztésű fájlból lehet létrehozni. Ezért az implicit szabályok használatával megengedett a szabályok egyszerűsítése: %.o: %.c gcc -c -o $@ $< ===== Példa ===== ==== C ==== TARGET = program01 CC = gcc RM = rm CFLAGS = -Wall -g LDFLAGS = SOURCES = program01.c OBJECTS = program01.o HEADERS = program01.h ${TARGET} : ${OBJECTS} ${CC} ${LDFLAGS} -o ${TARGET} ${OBJECTS} ${OBJECTS}.o : ${SOURCES} ${HEADERS} ${CC} ${CFLAGS} -c ${SOURCES} clean : ${RM} ${OBJECTS} ${TARGET} TARGET = program01.exe CC = "c:\Program Files (x86)\CodeBlocks\MinGW\bin\gcc" CFLAGS = -Wall -g LDFLAGS = -lmysql SRCS = program01.c OBJS = program01.o MYSQLINCLUDE = -Ic:/Users/joska/mysql-connector-c-6.1.5-win32/include/ MYSQLLIB = -Lc:/Users/joska/mysql-connector-c-6.1.5-win32/lib/ STDINCLUDE = -I"c:/Program Files (x86)/CodeBlocks/MinGW/include/" STDLIB = -L"c:/Program Files (x86)/CodeBlocks/MinGW/lib/" INCLUDES = ${STDINCLUDE} ${MYSQLINCLUDE} LIBS = ${STDLIB} ${MYSQLLIB} ${TARGET}: ${OBJS} ${CC} ${LDFLAGS} ${LIBS} -o ${TARGET} ${OBJS} ${OBJS}: ${SRCS} ${CC} ${CFLAGS} ${INCLUDES} -c ${SRCS} clean: rm ${OBJS} ${TARGET} SHELL = /bin/sh OBJ = main.o factorial.o hello.o CFLAG = -Wall -g CC = gcc INCLUDE = LIB = -lm hello:${OBJ} ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS} clean: -rm -f *.o core *.core .c.o: ${CC} ${CFLAGS} ${INCLUDES} -c $< ==== C++ ==== TARGET = main CXX = g++ RM = rm CPPFLAGS = -Wall -g LDFLAGS = SRCS = main.cxx dolgozo.cxx HEADS = dolgozo.h OBJS = main.o dolgozo.o ${TARGET}: ${OBJS} ${CXX} ${LDFLAGS} -o ${TARGET} ${OBJS} ${OBJS}.o:${SRCS} ${HEADS} ${CXX} ${CPPFLAGS} -c ${SRCS} clean: ${RM} ${OBJS} ${TARGET} ==== Java konzolos ==== PROGRAM=Program01 JAVA = /usr/local/jdk1.6.0_21/bin/ JC = $(JAVA)javac JR = $(JAVA)java JFLAGS = -classpath .:sqlite-jdbc-3.7.2.jar SOURCES = $(PROGRAM).java CLASSES = $(PROGRAM).class all: $(SOURCES) $(JC) $(SOURCES) xterm -e "$(JR) $(JFLAGS) $(PROGRAM) ; (echo 'Folytatáshoz nyomj egy Entert' && read)" clean: rm $(CLASSES) ==== Java GUI ==== PROGRAM=jSajatProgram JAVA = /mnt/tartaly/usr/local/jdk1.6.0_21/bin/ JC = $(JAVA)javac JR = $(JAVA)java JFLAGS = -classpath .:sqlite-jdbc-3.7.2.jar SOURCES = \ MainFrame.java \ MasterPanel.java \ SecPanel.java \ $(PROGRAM).java CLASSES = \ MainFrame.class \ MasterPanel.class \ SecPanel.class \ $(PROGRAM).class all: $(SOURCES) $(JC) $(SOURCES) $(JR) $(JFLAGS) $(PROGRAM) clean: rm $(CLASSES) ===== Link ===== * https://www.gnu.org/software/make/manual/html_node/ * http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html * http://www.opussoftware.com/tutorial/TutMakefile.htm * http://mrbook.org/tutorials/make/ * http://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html * http://jwrr.com/content/Gnu-Makefile-Examples/ (Java példák)