[[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)