Quanti di voi programmatori Java hanno avuto problemi per la compilazione di programmi? librerie fuori da $CLASSPATH, parametri chilometrici da passare al compilatore Java. Anche usando ambienti di sviluppo per Java la situazione non migliora di molto. Spendiamo molto tempo a settare paramteri e ogni volta che lanciamo la compilazione manca sempre qualcosa! |
Potete evitare tutti questi problemi semplicemente organizzando i sorgenti Java e usando un Makefile scritto ad hoc.
Un makefile è un file che descrive i passi da efftuare per arrivare ai file che vorremmo ottenere e tutto l'albero delle sue dipendenze. È molto usato nelle piattaforme basate su Unix e può essere utilizzato per compilare ogni tipo di programma. L'utility make interpreta i makefile e compila il codice sorgente per ottenere programmi eseguibili e librerie.
Molti di voi saranno scettici nell'utilizzo di un makefile per ogni progetto Java per la semplice ragione che il makefile richiede di specificare tutte le dipendenze tra i files, che sicuramente cambia da progetto a progetto. Quindi dovremmo scrivere un makefile diverso per ogni nostro progetto. Questo limite può essere superato scrivendo un makefile generico e in grado di calcolarsi tutte le dipendenze per il progetto da compilare in modo da utilizzare lo stesso script per tutti i progetti senza bisogno di moficare niente all'interno del makefile.
Un vantaggio sicuramente non trascurabile è la capacità di make di compilare solo il necessario. Evita quindi di compiare ciò che è già compilato e non è stato modificato con un risparmio notevole di tempo.
Con un solo makefile si riesce a compilare tutti i sorgenti del progetto.
Il makefile che ho scritto per compilare progetti Java può può essere utilizzato senza alcuna modifica per progetti che hanno una certa struttura di directory. I sorgenti Java devono avere una directory per i .java, una per i file .class, e una per le librerie jar. Come ad esempio:
|-- src | `-- main | |-- java | | `-- com | | `-- example | | |-- ExampleA.java | | |-- ExampleB.java | | `-- ExampleC.java | `-- resources | `-- Res.java |-- classes |-- libs | |-- general | | |-- DataBase | | | |-- DB1.jar | | | `-- DB2.jar | `-- Logging | `-- log.jar |-- jars
Per usarlo quindi basta scrivere il codice quì sotto nel file Makefile nella directory root del progetto, verificare che il nome delle directory sia quello specificato nel file (classes per i .class; src per i .java e libs per i jar) e lanciare il comando
make
questo è tutto. Se vogliamo anche un jar contenente tutto il progetto basta lanciare
make && make jar
#
#
CLASS_DIR = classes SOURCE_DIR = src JARS_DIR = jars
SUBDIRS := $(shell find $(SOURCE_DIR) -name "*.java" -printf %h\\n | sort | uniq | sed 's/$(SOURCE_DIR)\/\?//')
JAVA_HOME=/usr/local/java/bin
JCC = $(JAVA_HOME)/javac
.PHONY: clean classes compile jar
all: @@for p in $(SUBDIRS); do \ echo 'compile ' $$p; \ export SUBDIR=$$p; \ make --no-print-directory compile; \ done
clean: -rm -f *~ *.class *.bak $(foreach dir,$(SUBDIRS),$(CLASS_DIR)/$(dir)/*.class)
LOCAL_CLASS_DIR=$(CLASS_DIR)/$(SUBDIR) LOCAL_SOURCE_DIR=$(SOURCE_DIR)/$(SUBDIR)
jar: cd $(CLASS_DIR); jar -cf ../$(JARS_DIR)/project.jar *
compile: classes
$(LOCAL_CLASS_DIR): mkdir -p $(LOCAL_CLASS_DIR)
.SUFFIXES: .SUFFIXES: .java .class
vpath %.class $(LOCAL_CLASS_DIR) vpath %.java $(LOCAL_SOURCE_DIR)
LIBCLASSPATH:=$(CLASS_DIR):$(SOURCE_DIR):$(subst .jar ,.jar:,$(wildcard libs/*.jar libs/*/*.jar libs/*/*/*.jar jars/*.jar))
.java.class: CLASSPATH=$(LIBCLASSPATH) $(JCC) -nowarn -d $(CLASS_DIR) $(JDEBUGFLAGS) $<
PATHFILES = $(wildcard $(LOCAL_SOURCE_DIR)/*.java) FILES = $(subst $(LOCAL_SOURCE_DIR)/,,$(PATHFILES)) classes: $(FILES:.java=.class)
Buona compilazione.