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