# Debian packaging wrapper: fetch wolfSSL and wolfssljni from upstream and build
# the TLS stack the standalone Android runtime uses. wolfSSL is built with the
# JNI-enabled configuration; wolfssljni provides the JSSE provider
# (com.wolfssl.provider.jsse) as the native glue libwolfssljni.so plus the dexed
# wolfssljni-hostdex.jar boot-classpath jar. These two were previously vendored
# and shipped by art-standalone. Sources are downloaded at build time; Debian
# build fixes live in debian/patches/ and are applied to the fetched wolfSSL tree.

UPSTREAM_URL  ?= https://github.com/wolfSSL/wolfssl.git
UPSTREAM_REF  ?= v5.8.2-stable
SRC           ?= upstream

# wolfssljni is versioned independently. v1.15.0 is the most recent release with
# no lambdas or method references in its Java, so it dexes with dx without
# emitting invokedynamic, which this ART cannot execute. The getPrivateKey
# KeyStore null-check (added upstream later) is carried as a patch.
JNI_URL       ?= https://github.com/wolfSSL/wolfssljni.git
JNI_REF       ?= v1.15.0-stable
JNISRC        ?= wolfssljni
JNI_PATCHES   := $(sort $(wildcard debian/patches/wolfssljni/*.patch))

PREFIX        ?= /usr
LIBDIR        ?= lib
DESTDIR       ?=
CONFIGURE_HOST ?=

# := (not ?=): ignore any JAVA_HOME the environment exports (e.g. an Android
# Studio JBR without JNI headers); still overridable on the command line.
JAVA_HOME     := /usr/lib/jvm/java-21-openjdk-amd64
# Boot-classpath classes jar and dexer come from art-standalone.
ART_CORE      ?= $(shell pkg-config --variable=libdir art-standalone)/java/core-all_classes.jar
DX            ?= dx
STAGING       := $(CURDIR)/.wolfssl-staging

# wolfssljni's recommended wolfSSL configuration is "--enable-jni", which pulls
# in the opensslextra/certgen/crl/ocsp feature set the JSSE provider needs.
CONFIGURE_FLAGS := \
	--enable-shared --disable-static \
	--enable-aescbc-length-checks \
	--enable-curve25519 --enable-ed25519 --enable-ed25519-stream \
	--enable-oldtls --enable-base64encode --enable-tlsx --enable-scrypt \
	--disable-examples --enable-crl --enable-jni --enable-sessioncerts

PATCHES := $(sort $(wildcard debian/patches/*.patch))

.PHONY: all download patch build jni install clean distclean

all: build

# --- wolfSSL C library ------------------------------------------------------
$(SRC)/.downloaded:
	rm -rf $(SRC)
	git init -q $(SRC)
	cd $(SRC) && git remote add origin $(UPSTREAM_URL) \
		&& git fetch -q --depth 1 origin $(UPSTREAM_REF) \
		&& git checkout -q --detach FETCH_HEAD
	touch $@

download: $(SRC)/.downloaded

$(SRC)/.patched: $(SRC)/.downloaded $(PATCHES)
	@for p in $(PATCHES); do echo "applying $$p"; patch -d $(SRC) -p1 < "$(CURDIR)/$$p"; done
	touch $@

patch: $(SRC)/.patched

$(SRC)/Makefile: $(SRC)/.patched
	cd $(SRC) && autoreconf -i && ./configure --prefix=$(PREFIX) --libdir=$(PREFIX)/$(LIBDIR) $(CONFIGURE_HOST) $(CONFIGURE_FLAGS)

wolfssl-build: $(SRC)/Makefile
	$(MAKE) -C $(SRC)

# Stage wolfSSL (headers + lib) so the JNI glue can compile and link against it
# without a system-installed wolfSSL.
$(STAGING)/usr/include/wolfssl/options.h: wolfssl-build
	rm -rf $(STAGING)
	$(MAKE) -C $(SRC) install DESTDIR=$(STAGING)

# --- wolfssljni JNI glue + hostdex jar --------------------------------------
$(JNISRC)/.downloaded:
	rm -rf $(JNISRC)
	git init -q $(JNISRC)
	cd $(JNISRC) && git remote add origin $(JNI_URL) \
		&& git fetch -q --depth 1 origin $(JNI_REF) \
		&& git checkout -q --detach FETCH_HEAD
	touch $@

$(JNISRC)/.patched: $(JNISRC)/.downloaded $(JNI_PATCHES)
	@for p in $(JNI_PATCHES); do echo "applying $$p"; patch -d $(JNISRC) -p1 < "$(CURDIR)/$$p"; done
	touch $@

# Native glue, built with wolfssljni's own java.sh against the staged wolfSSL
# (its first argument is the wolfSSL install prefix). -D__ANDROID__ selects the
# code paths that match this runtime's Android libcore rather than a stock JDK:
# notably java.io.FileDescriptor's int field is named "descriptor" here (not
# "fd"), which the socket fd extraction in setFd depends on. The define also
# picks the Android jni.h AttachCurrentThread signature (JNIEnv** vs void**);
# against OpenJDK's jni.h that is an incompatible-pointer-type, which GCC 14
# turned into a default error, so demote it back to a warning. The mismatch is
# ABI-identical at runtime and no Android headers are pulled in by the define.
$(JNISRC)/lib/libwolfssljni.so: $(JNISRC)/.patched $(STAGING)/usr/include/wolfssl/options.h
	cd $(JNISRC) && CC="$(CC)" CFLAGS="-D__ANDROID__ -Wno-error=incompatible-pointer-types" \
		LDFLAGS="-L$(STAGING)$(PREFIX)/$(LIBDIR)" \
		JAVA_HOME=$(JAVA_HOME) bash java.sh $(STAGING)$(PREFIX)

# Boot-classpath jar: compile the Java against the ART API-27 core, then dex it.
# module-info.java is excluded (no JPMS on this runtime); extend the exclusion
# if the build surfaces classes referencing APIs absent from the core jar.
# -target 1.8 and a lambda-free wolfssljni keep the bytecode free of
# invokedynamic, which this ART's bootstrap-method support cannot execute.
wolfssljni-hostdex.jar: $(JNISRC)/.patched
	rm -rf .jni-classes .jni-dex
	mkdir -p .jni-classes .jni-dex
	find $(JNISRC)/src/java -name '*.java' ! -name 'module-info.java' > .jni-sources
	$(JAVA_HOME)/bin/javac -bootclasspath $(ART_CORE) -source 1.8 -target 1.8 \
		-d .jni-classes @.jni-sources
	$(DX) --dex --output=.jni-dex/classes.dex .jni-classes
	$(JAVA_HOME)/bin/jar cf $@ -C .jni-dex classes.dex

jni: $(JNISRC)/lib/libwolfssljni.so wolfssljni-hostdex.jar

build: wolfssl-build jni

install: build
	$(MAKE) -C $(SRC) install DESTDIR=$(DESTDIR)
	install -Dm644 $(JNISRC)/lib/libwolfssljni.so \
		$(DESTDIR)$(PREFIX)/$(LIBDIR)/java/dex/art/natives/libwolfssljni.so
	install -Dm644 wolfssljni-hostdex.jar \
		$(DESTDIR)$(PREFIX)/$(LIBDIR)/java/dex/art/wolfssljni-hostdex.jar

clean:
	rm -rf $(SRC) $(JNISRC) $(STAGING) .jni-classes .jni-dex .jni-sources wolfssljni-hostdex.jar

distclean: clean
	dh_clean
