# # Copyright (C) 2019 Michael Zucchi # # This is the copyright for java.make # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # General purpose modular java makefile that supports native library # compilation directly. Non-recrusve implementation. # # Uses metamake programming with some file conventions to implement # auto-make-like features. # Define modules # -------------- # java_MODULES list of java modules to compile. The sources must # exist in src//classes. Resource files are # stored in src//classes. Source-code # generators must exist in src//gen. Native # libraries must exist in src//jni. # Global variables # JAVA_HOME location of jdk. # JAVAC java compiler to use. Default is 'javac' on the path. # JAVACFLAGS javac flags applied to all invocations. # JAR jar command. # JARFLAGS jar flags # JMOD jmod command. # JMODFLAGS jmod flags. # Module specific variables # _JDEPMOD Lists modules which this one depends on. # _JAVACFLAGS Extra module-specific flags for each command. # _JARFLAGS # _JMODFLAGS # _JAVA Java sources. If not set it is found from src//classes/(*.java) # _RESOURCES .jar resources. If not set it is found from src//classes/(not *.java) # _JAVA_GENERATED Java generated sources. These must be relative to the package name. # Variables for use in fragments # gen.make and jni.make can additionally make use of these variables # _gendir Location for files used in Java generation process (per project). # _genjavadir Location where _JAVA_GENERATED .java files will be created (per project). # _jnidir Location for jni generated files (per target). # _objdir Location for c objects (per target). # _incdir Location for output includes, .jmod staging. # _libdir Location for output libraries, .jmod staging. May point to _bindir. # _bindir Location for output commands, .jmod staging. # Define libraries # ---------------- # Each module can define one or more native libraries. # These are compiled after the java sources have been compiled as that # process also generates any native binding headers. # _JNI_LIBRARIES list of libraries to build. # library names match System.loadLibrary(). # Global variables # _LDFLAGS # _LDLIBS # _CPPFLAGS # _CFLAGS # SO shared library suffix # LIB shared library prefix # Utility functions # # $(call library-path,,) will resolve to the library file name. # Per library variables. # _SOURCES .c, .cc, .C - source files for library. Paths are relative to src//jni. # _HEADERS header files for jmod # _COMMANDS commands/bin/scripts for jmod # _LDFLAGS link flags # _LIBADD extra objects to add to link line # _LDLIBS link libraries # _CPPFLAGS c pre-processor flags. "-Isrc//jni -Ibin/include/" is implicit. # _CCFLAGS c compiler flags # _DEPENDENCIES A list of other objects on which this library depends before linking. # _DEFS A list of .def files for nativez-gen. # _DEFSFLAGS Flags for nativez-gen invocation. # .c files have dependencies automatically generated # Targets # ------- # make gen only generate java sources # make clean rm -rf bin # make dist create dist tar in bin/ # make | make jar make all jars and jmods # make bin make everything but jars and mods # Outputs # ------- # All intermediate and output files are written to bin/ # This layout is enforced by javac # bin/include// .h files from javac -h # bin/modules// .class files from javac # This layout is convenient for netbeans # bin/gen//gen/ .c, exe files for generator free use # bin/gen//classes/ .java files from generator _JAVA_GENERATED # Working files # bin/status/ marker files for makefile # bin///lib .so librareies for jmod _LIBRARIES = libname # bin///obj .o, .d files for library _SOURCES # bin///include .h files for jmod _HEADERS # bin///.jmod .jmod module # Output files # bin//lib/ modular jar files and shared libraries for GNU/linux dev # bin//include/ header files for exported shared libraries # bin//bin/ shared libraries for microsoft dev # bin//jmods/ jmod files for 'jlink' use. # ###################################################################### E:= S:=$(E) $(E) # All modules with native code java_JMODS=$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/jni/jni.make),$(module))) # Only modules with no native code java_JARS=$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/jni/jni.make),,$(module))) # Modules with generated java source java_JGEN=$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/gen/gen.make),$(module))) # Define some useful variables before including fragments define java_variables= $(1)_gendir:=bin/gen/$(1)/gen $(1)_genjavadir:=bin/gen/$(1)/classes $(1)_jnidir:=bin/$(1)/$(TARGET)/jni $(1)_objdir:=bin/$(1)/$(TARGET)/obj $(1)_incdir:=bin/$(1)/$(TARGET)/include $(1)_libdir:=$$(if $$(filter windows-%,$(TARGET)),bin/$(1)/$(TARGET)/bin,bin/$(1)/$(TARGET)/lib) $(1)_bindir:=bin/$(1)/$(TARGET)/bin ifndef $(1)_JAVA $(1)_JAVA := $$(shell find src/$(1)/classes -type f -name '*.java') endif ifndef $(1)_RESOURCES $(1)_RESOURCES := $$(shell find src/$(1)/classes -type f \! -name '*.java') endif endef java_libdir:=$(if $(filter windows-%,$(TARGET)),bin/$(TARGET)/bin,bin/$(TARGET)/lib) java_bindir:=bin/$(TARGET)/bin java_jardir:=bin/$(TARGET)/lib java_incdir:=bin/$(TARGET)/include java_jmoddir:=bin/$(TARGET)/jmods $(foreach module,$(java_MODULES),$(eval $(call java_variables,$(module)))) # ###################################################################### all: jar bin: gen: .PHONY: all clean jar bin gen clean: rm -rf bin include $(patsubst %,src/%/gen/gen.make,$(java_JGEN)) include $(patsubst %,src/%/jni/jni.make,$(java_JMODS)) # ###################################################################### # Java # ###################################################################### define java_targets= # Rules for module $(1) $(1)_JAVA_generated = $$(addprefix $$($(1)_genjavadir)/,$$($(1)_JAVA_GENERATED)) bin/status/$(1).data: $$($(1)_RESOURCES) bin/status/$(1).classes: $(patsubst %,bin/status/%.classes,$($(1)_JDEPMOD)) $$($(1)_JAVA) $$($(1)_JAVA_generated) jar $(1): $(java_jardir)/$(1).jar $(java_jmoddir)/$(1).jmod bin: bin/status/$(1).classes bin/status/$(1).data sources: $(java_jardir)/$(1)-sources.zip gen: $$($(1)_JAVA_generated) # Create modular jar $(java_jardir)/$(1).jar: bin/status/$(1).classes bin/status/$(1).data @install -d $$(@D) $(JAR) cf $$@ \ $(JARFLAGS) $$($(1)_JARFLAGS) \ -C bin/modules/$(1) . # Create a jmod $(java_jmoddir)/$(1).jmod: bin/status/$(1).classes bin/status/$(1).data rm -f $$@ @install -d $$(@D) $$(JMOD) create \ $$(JMODFLAGS) $$($(1)_JMODFLAGS) \ --target-platform $(TARGET) \ --class-path bin/modules/$(1) \ $$(if $$(wildcard bin/$(1)/$(TARGET)/include),--header-files bin/$(1)/$(TARGET)/include) \ $$(if $$(wildcard src/$(1)/legal),--legal-notices src/$(1)/legal) \ $$(if $$(wildcard bin/$(1)/$(TARGET)/bin),--cmds bin/$(1)/$(TARGET)/bin) \ $$(if $$(wildcard bin/$(1)/$(TARGET)/lib),--libs bin/$(1)/$(TARGET)/lib) \ $$@ # Create an IDE source zip, paths have to match --module-source-path $(java_jardir)/$(1)-sources.zip: bin/status/$(1).classes @install -d $$(@D) jar -c -f $$@ -M \ $$(patsubst src/$(1)/classes/%,-C src/$(1)/classes %,$$(filter src/$(1)/classes/%,$$($(1)_JAVA))) \ $$(patsubst bin/gen/$(1)/classes/%,-C bin/gen/$(1)/classes %,$$(filter bin/gen/$(1)/classes/%,$$($(1)_JAVA))) endef #$(foreach module,$(java_MODULES),$(info $(call java_targets,$(module)))) $(foreach module,$(java_MODULES),$(eval $(call java_targets,$(module)))) # ###################################################################### # Global pattern rules # Stage resources bin/status/%.data: @install -d $(@D) for data in $(patsubst src/$*/classes/%,"%",$($*_RESOURCES)) ; do \ install -vDC "src/$*/classes/$$data" "bin/modules/$*/$$data" || exit 1 ; \ done touch $@ # Compile one module. This only updates (javac -h) headers if they changed. bin/status/%.classes: @install -d $(@D) $(JAVAC) \ --module-source-path "src/*/classes:bin/gen/*/classes" \ $(if $(JAVAMODPATH),--module-path $(subst $(S),:,$(JAVAMODPATH))) \ $(JAVACFLAGS) $($*_JAVACFLAGS) \ -h bin/inc \ -d bin/modules \ -m $* \ $($*_JAVA) $($*_JAVA_generated) if [ -d bin/inc/$* ] ; then \ install -DC -t bin/include/$* bin/inc/$*/*.h ; \ fi touch $@ # ###################################################################### # C stuff # ###################################################################### SUFFIXES=.c .C .cc SO=$($(TARGET)_SO) LIB=$($(TARGET)_LIB) # functions to find cross-module stuff $(call library-path,modname,libname) library-path=$($(1)_libdir)/$(LIB)$(2)$(SO) library-dir=$($(1)_libdir)/ define jni_library= # Rule for library $(2) in module $(1) $(2)_OBJS = $(foreach sx,$(SUFFIXES),$(patsubst %$(sx), $($(1)_objdir)/%.o, $(filter %$(sx),$($(2)_SOURCES)))) $(2)_SRCS = $(addprefix src/$(1)/jni/,$($(2)_SOURCES)) $(2)_SO = $($(1)_libdir)/$(LIB)$(2)$(SO) $($(1)_libdir)/$(LIB)$(2)$(SO): $$($(2)_OBJS) $($(2)_LIBADD) $($(2)_DEPENDENCIES) @install -d $$(@D) $($(TARGET)_CC) -o $$@ -shared \ $($(TARGET)_LDFLAGS) $($(2)_LDFLAGS) $$($(2)_OBJS) $($(2)_LIBADD) $($(TARGET)_LDLIBS) $($(2)_LDLIBS) $(java_libdir)/%: $($(1)_libdir)/% install -DC $$< $$@ $(java_bindir)/%: $($(1)_bindir)/% install -DC $$< $$@ $(java_incdir)/%: $($(1)_incdir)/% install -DC $$< $$@ $($(1)_objdir)/%.o: src/$(1)/jni/%.c @install -d $$(@D) $($(TARGET)_CC) -Isrc/$(1)/jni -Ibin/include/$(1) -I$($(1)_jnidir) \ $($(TARGET)_CPPFLAGS) $($(2)_CPPFLAGS) \ $($(TARGET)_CFLAGS) $($(2)_CFLAGS) -c -o $$@ $$< $($(1)_incdir)/%.h: src/$(1)/jni/%.h install -DC $$< $$@ # auto-dependencies for c files $($(1)_objdir)/%.d: src/$(1)/jni/%.c bin/status/$(1).classes @install -d $$(@D) @rm -f $$@ @$($(TARGET)_CC) -MM -MT "bin/$(1)/$(TARGET)/obj/$$*.o" -Isrc/$(1)/jni -Ibin/include/$(1) \ $($(TARGET)_CPPFLAGS) $($(2)_CPPFLAGS) $$< -o $$@.d 2>/dev/null @sed 's,\($$*\.o\) *:,\1 $$@ : ,g' $$@.d > $$@ ; rm $$@.d # .def files for nativez mapping $($(1)_jnidir)/%.h: src/$(1)/jni/%.def @install -d $$(@D) $(NATIVEZ_HOME)/bin/nativez-gen -J $($(2)_DEFSFLAGS) $$< > $$@ || ( rm $$@ ; exit 1) bin jni $(1) $(java_jmoddir)/$(1).jmod: \ $($(1)_libdir)/$(LIB)$(2)$(SO) \ $(java_libdir)/$(LIB)$(2)$(SO) \ $(addprefix $($(1)_incdir)/,$($(2)_HEADERS)) \ $(addprefix $(java_incdir)/,$($(2)_HEADERS)) \ $(addprefix $($(1)_bindir)/,$($(2)_COMMANDS)) \ $(addprefix $(java_bindir)/,$($(2)_COMMANDS)) \ $(addprefix $($(1)_libdir)/,$($(2)_LIBRARIES)) $(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include $$($(2)_OBJS:.o=.d)) endef #$(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(info $(call jni_library,$(module),$(library))))) $(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(eval $(call jni_library,$(module),$(library))))) #$(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(foreach def,$($(library)_DEFS),$(info $($(module)_objdir)/$(def:.def=.o): $($(module)_jnidir)/$(def:.def=.h))))) $(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(foreach def,$($(library)_DEFS),$(eval $($(module)_objdir)/$(def:.def=.o): $($(module)_jnidir)/$(def:.def=.h))))) # ###################################################################### dist: @install -d bin tar cfz bin/$(dist_NAME)-$(dist_VERSION).tar.gz \ --transform=s,^,$(dist_NAME)-$(dist_VERSION)/, \ config.make java.make Makefile src \ $(dist_EXTRA)