[Megoldva] Makefile láma

Írok egy programot, ami sok osztályt definiál, és minden osztály egy-egy külön fájlban van, ráadásul mappákba szervezve.

Szeretnék írni egy Makefile-t mindehhez, hogy a fordító lefordíthassa.

A Makefile-ban a címke után fel kellene sorolnom az összes forrásfájlt, vagy van erre valami egyszerűbb megoldás is? Az lenne a legkényelmesebb, ha megadhatnék mappát/mappákat, és a mappán belül minden fájlt figyelne, hogy történt-e változás.

Vagy mi a kulturált módja a sokfájlos Makefile elkészítésének?

Egy megoldás:

FILES=$(shell find ./classes -type f -name '*.class')
main: $(FILES)

Hozzászólások

Szerintem Makefile-ból is lehet hierarchiát létrehozni (mappánként).

Húzz le valami komolyabb forrást (Postgres mondjuk) és nézz bele hogy csinálja.

zászló, zászló, szív

Úgy tűnik, egy járható út a következő:

FILES=$(shell find ./classes -type f -name '*.class')
main: $(FILES)

Nem tudom, ez a legszebb megoldás-e, de ezzel már működik, és elég egyszer elkészíteni a Makefile-t.

Szerkesztve: 2023. 06. 14., sze – 13:11
all:
        javac $$(find . -name '*.java')

Ez mindig lefut, mivel várhatólag egy "all" nevű fájl nem fog keletkezni. Ha meg véletlen mégis lesz egy "all", akkor meg nem fut le...

Ha ez nem gond (mármint az, hogy mindig lefut a parancs), akkor felesleges a make, hiszen sokkal egyszerűbb lenne egy szimpla kb. egysoros szkriptet írni, amiben ez a parancs fut le.

Joggal kérdezhetnénk, hogy miért nem követjük a függőségeket (jdeps?) és fordítjuk csak azt, amit tényleg kell. Azt érdemes tudni, hogy a javac (vagy bármilyen java alkalmazás) indulása lassú. Tényleg lassú. Végezhetünk mérést is, kis projekt, 121 /.java file-ban összesen 21240 sor:

 

time find . -name '*.java' javac {} \;
real    1m22.756s
user    2m59.546s
sys     0m10.769s

$ time javac $(find . -name '*.java')
real    0m2.307s
user    0m7.211s
sys     0m0.211s

Viszont GNU Make (és bmake) esetében ott a $?, ami visszatér azokkal a függőségekkel, amik újabbak, mint a cél, azaz pl.

target: java-fajl-list
    javac $?

clean:
    rm -rf target

.PHONY: clean target

És már ki is használtad a make előnyét a szkripthez képest.

Ezek a .java fájlok (illetve a generált .class fájlok) egymástól is függhetnek, akár körkörösen is.

A `javac` lefordítja a függőségeket, ha pl. látja, hogy `whatnot.java` fordításához `foo.class` kellene, de csak `foo.java` van, de ha van `foo.class` csak régebbi, mint a `foo.java`, azzal nem törődik, szóval a biztos módszer mégis az, ha mindent egyszerre fordítunk. (Mármint egy terméken belül, ahol nincsenek jól definiált határok (interface-ek) az egyes komponensek között.)

Hát márpedig az a normális megoldás, hogy az ember a Makefile-ban precízen leírja a függőségeket. Mármint szerintem.

.java.class.

\t javac $?

whatnot.class: foo.class

 

foo.class: whatnot.class

main.class: foo.class whatnot.class

(Vagy valami hasonló)

Tudom nem ez volt a kérdés..... de ha már java akkor miért nem gradle vagy maven (legrosszabb esetben ant)? mert habár mindent IS meg lehet csinálni make-kel, de a fentiek "valóak" a java-hoz....

##
# source directory
##
SRC_DIR := src

##
# output directory
##
OUT_DIR := out

##
# sources
##
SRCS := $(wildcard $(SRC_DIR)/*.java)

##
# classes
## 
CLS := $(SRCS:$(SRC_DIR)/%.java=$(OUT_DIR)/%.class)

##
# compiler and compiler flags
##
JC := javac
JCFLAGS := -d $(OUT_DIR)/ -cp $(SRC_DIR)/

##
# suffixes
##
.SUFFIXES: .java

##
# targets that do not produce output files
##
.PHONY: all clean

##
# default target(s)
##
all: $(CLS)

$(CLS): $(OUT_DIR)/%.class: $(SRC_DIR)/%.java
    $(JC) $(JCFLAGS) $<

##
# clean up any output files
##
clean:
    rm $(OUT_DIR)/*.class

de amúgy ne használj Jávát, hanem inkább valami értelmes program nyelvet tanulj meg!