#
# Copyright (C) 2019,2022 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.
# native_MODULES list of native-only "modules".
# 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.
# JAVAFLAGS java flags for run targets
# Module specific variables
# _JDEPMOD Lists modules which this one depends on.
# _JAVACFLAGS Extra module-specific flags for each command.
# _JARFLAGS
# _JMODFLAGS
# all paths are relative to the root package name
# _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.
# _RESOURCES_GENERATED Java generated sources.
# 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).
# _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.
# _NATIVE_LIBRARIES list of libraries to build.
# library names match System.loadLibrary().
# Global variables
# _LDFLAGS
# _LDLIBS
# _CPPFLAGS
# _CFLAGS
# _CC
# _CXXFLAGS
# _CXX
# 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 source files for library. Paths are relative to src//native.
# _CXXSOURCES .c source files for library. Paths are relative to src//native.
# _HEADERS header files for install/jmod
# _COMMANDS commands/bin/scripts for install/jmod
# _LDFLAGS link flags
# _LIBADD extra objects to add to link line
# _LDLIBS link libraries
# _CPPFLAGS c and c++ pre-processor flags. "-Isrc//jni -Ibin/include/" is implicit.
# _CCFLAGS c compiler flags
# _CXXFLAGS c++ compiler flags
# _DEPENDENCIES A list of other objects on which this library depends before linking.
# .c and .cc 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
# 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.
# ######################################################################
all_MODULES = $(java_MODULES) $(native_MODULES)
E:=
S:=$(E) $(E)
SO=$($(TARGET)_SO)
LIB=$($(TARGET)_LIB)
# Define some useful variables before including fragments
define common_variables=
$1_gendir:=bin/gen/$1/gen
$1_genjavadir:=bin/gen/$1/classes
$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
endef
define java_variables=
ifndef $1_JAVA
$1_JAVA := $$(shell cd src/$1/classes && find * -type f -name '*.java')
endif
ifndef $1_RESOURCES
$1_RESOURCES := $$(shell cd src/$1/classes && find * -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) $(native_MODULES),$(eval $(call common_variables,$(module))))
$(foreach module,$(java_MODULES),$(eval $(call java_variables,$(module))))
# ######################################################################
all:
jar:
gen:
.PHONY: all clean jar gen $(java_MODULES) dist
clean:
rm -rf bin
# dist things
dist_TAR = bin/$(dist_NAME)-$(dist_VERSION).tar.gz
dist_FILES = config.make.in java.make Makefile src $(dist_EXTRA)
# Gen is things that go into the jar (sources and resources)
include $(wildcard $(all_MODULES:%=src/%/gen/gen.make))
# Native is things that go into the sdk/jmod
include $(wildcard $(all_MODULES:%=src/%/native/native.make))
# ######################################################################
# create module depencies
# variables:
# _sdk is the target location of an expanded 'sdk' for this module
# it resides in a common location bin//
# _jmod is the target location of a staging area for jmod files
# is resides in a per-module lcoation bin///
# _java is all the targets that will cause the invocation of javac
# it includes the module source, generated sources, and sentinals for generated sources
# targets:
# bin/status/.depjava marks all source/generated sources are ready/updated
# bin/status/.depjar all compiled class files and resources are ready/updated
# bin/status/.sdk all files are available in bin/ as if it was an installed image
define module_vars=
$1_sdk := $(addprefix $(java_bindir)/,$($1_COMMANDS)) $(addprefix $(java_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$(java_libdir)/lib%.so)
$1_jmod := $(addprefix $($1_bindir)/,$($1_COMMANDS)) $(addprefix $($1_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$($1_libdir)/lib%.so)
$1_java :=$($1_JAVA:%=src/$1/classes/%) $($1_JAVA_GENERATED:%=$($1_genjavadir)/%)
$1_resources:= $($1_RESOURCES:%=bin/modules/$1/%) $($1_RESOURCES_GENERATED:%=bin/modules/$1/%)
$1_depjava := $($1_API:%=bin/status/$1-%.export) $(patsubst %,bin/status/%.classes, $(filter $($1_JDEPMOD),$(java_MODULES)))
ifneq ("$$(strip $$($1_java) $$($1_depjava))", "")
bin/status/$1.depjava: $$($1_java) $$($1_depjava)
@install -d $$(@D)
touch $$@
bin/status/$1.depjar: bin/status/$1.classes $$($1_resources)
@install -d $$(@D)
touch $$@
bin/status/$1.depmod: bin/status/$1.classes $$($1_resources) $$($1_jmod)
@install -d $$(@D)
touch $$@
bin/status/$1.sdk: $(java_jardir)/$1.jar
jar: $(java_jardir)/$1.jar
gen: bin/status/$1.depjava
$1 all: $(java_jardir)/$1.jar $(java_jmoddir)/$1.jmod
else
# acutally not sure here?
$1 all: bin/status/$1.sdk
endif
$1-sdk sdk: bin/status/$1.sdk
bin/status/$1.sdk: $$($1_sdk) $$($1_jmod)
@install -d $$(@D)
touch $$@
endef
#$(foreach m,$(all_MODULES),$(info $(call module_vars,$m)))
$(foreach m,$(all_MODULES),$(eval $(call module_vars,$m)))
# ######################################################################
# notzed.nativez export-api
# ######################################################################
define api_targets=
bin/status/$1-$2.export: src/$1/gen/$2.api src/$1/gen/$2.h
bin/status/$1-$2.export:
mkdir -p bin/gen/$1/gen bin/status
$(NATIVEZ_HOME)/bin/export-api \
-w bin/gen/$1/gen -d bin/gen/$1/classes $($1_APIFLAGS) $($1_$2_APIFLAGS) src/$1/gen/$2.api
touch $$@
bin/status/$1-$2.export.d:
@$(NATIVEZ_HOME)/bin/export-api -M -MT "$$(@:.d=) $$@" -MF $$@ \
-w bin/gen/$1/gen -d bin/gen/$1/classes $($1_APIFLAGS) $($1_$2_APIFLAGS) src/$1/gen/$2.api 2>/dev/null
$(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include bin/status/$1-$2.export.d)
endef
$(foreach m,$(all_MODULES),$(foreach a,$($m_API),$(eval $(call api_targets,$m,$a))))
# ######################################################################
# Java
# ######################################################################
# Build targets for java modules
define java_targets=
# Create (modular) jar
$(java_jardir)/$1.jar: bin/status/$1.depjar
@install -d $$(@D)
$(JAR) cf $$@ \
$(JARFLAGS) $$($(1)_JARFLAGS) \
-C bin/modules/$(1) .
# Create a jmod
$(java_jmoddir)/$1.jmod: bin/status/$1.depmod
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.depjar
@install -d $$(@D)
$(JAR) -c -f $$@ -M \
$$($1_JAVA:%=-C src/$1/classes %) \
$$($1_JAVA_GENERATED:%=-C bin/gen/$1/classes %)
# resources
bin/modules/$1/%: src/$1/classes/%
install -vD $$< $$@
bin/modules/$1/%: $($1_gejavadir)/%
install -vD $$< $$@
# Compile module.
bin/status/$1.classes: bin/status/$1.depjava
@install -d $$(@D)
$(JAVAC) \
--module-source-path "src/*/classes:bin/gen/*/classes" \
$(if $(JAVAMODPATH),--module-path $(subst $(S),:,$(JAVAMODPATH))) \
$(JAVACFLAGS) $($1_JAVACFLAGS) \
-d bin/modules \
-m $1 \
$$($1_JAVA:%=src/$1/classes/%) \
$$($1_JAVA_GENERATED:%=bin/gen/$1/classes/%)
touch $$@
endef
#$(foreach module,$(java_MODULES),$(info $(call java_targets,$(module))))
$(foreach module,$(java_MODULES),$(eval $(call java_targets,$(module))))
# ######################################################################
# setup run-* targets
define run_targets=
run-$1/$2: bin/status/$1.sdk $($1_JDEPMOD:%=bin/status/%.sdk)
LD_LIBRARY_PATH=$(FFMPEG_HOME)/lib \
$(JAVA) \
$(if $(strip $(JAVAMODPATH) $($1_JAVAMODPATH)),--module-path $(subst $(S),:,$(strip $(JAVAMODPATH) $($1_JAVAMODPATH)))) \
$(JMAINFLAGS) $($1_JMAINFLAGS) \
-m $1/$2 \
$(ARGV)
.PHONY: run-$1/$2
endef
#$(foreach module,$(java_MODULES),$(foreach main,$($(module)_JMAIN),$(info $(call run_targets,$(module),$(main)))))
$(foreach module,$(java_MODULES),$(foreach main,$($(module)_JMAIN),$(eval $(call run_targets,$(module),$(main)))))
# ######################################################################
# C and c++ native library support
# ######################################################################
define native_library=
# Rule for library $$2 in module $$1
$2_OBJS = $(patsubst %.c, $($1_objdir)/%.o, $($2_SOURCES)) \
$(patsubst %.cc, $($1_objdir)/%.o, $($2_CXXSOURCES))
$2_SRCS = $(addprefix src/$1/native/,$($2_SOURCES))
$2_SO = $($1_libdir)/$(LIB)$2$(SO)
# Copy anything from staging area for jmods bin/module//* to sdk area bin//*
$(java_libdir)/%: $($(1)_libdir)/%
@install -d $$(@D)
ln -fs $$(abspath $$<) $$@
$(java_bindir)/%: $($(1)_bindir)/%
@install -d $$(@D)
ln -fs $$(abspath $$<) $$@
$(java_incdir)/%: $($(1)_incdir)/%
@install -d $$(@D)
ln -fs $$(abspath $$<) $$@
$($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)
$($1_objdir)/%.o: src/$1/native/%.c
@install -d $$(@D)
$($(TARGET)_CC) -Isrc/$1/native -Ibin/include/$1 \
$($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) \
$($(TARGET)_CFLAGS) $($2_CFLAGS) -c -o $$@ $$<
$($1_objdir)/%.o: src/$1/native/%.cc
@install -d $$(@D)
$($(TARGET)_CXX) -Isrc/$1/native -Ibin/include/$1 \
$($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) \
$($(TARGET)_CXXFLAGS) $($2_CXXFLAGS) -c -o $$@ $$<
# auto-dependencies for c files
$($1_objdir)/%.d: src/$1/native/%.c
@install -d $$(@D)
@rm -f $$@
@$($(TARGET)_CC) -MM -MT "$$(@:.d=.o) $$@" -Isrc/$1/jni -Ibin/include/$1 \
$($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) $$< -o $$@ 2>/dev/null
# auto-dependencies for c++ files
$($1_objdir)/%.d: src/$1/native/%.cc
@install -d $$(@D)
@rm -f $$@
@$($(TARGET)_CXX) -MM -MT "$$(@:.d=.o) $$@" -Isrc/$1/jni -Ibin/include/$1 \
$($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) $$< -o $$@ 2>/dev/null
$(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include $$($2_OBJS:.o=.d))
endef
#$(foreach module,$(all_MODULES),$(foreach library,$($(module)_NATIVE_LIBRARIES),$(info $(call native_library,$(module),$(library)))))
$(foreach module,$(all_MODULES),$(foreach library,$($(module)_NATIVE_LIBRARIES),$(eval $(call native_library,$(module),$(library)))))
# ######################################################################
dist:
@install -d bin
tar cfz bin/$(dist_NAME)-$(dist_VERSION).tar.gz \
--transform=s,^,$(dist_NAME)-$(dist_VERSION)/, \
$(dist_FILES)