TARGET_DIR = ./rust/target
LIBDIR = $(TARGET_DIR)/release
STATLIB = $(LIBDIR)/libkoopman_dmd_r.a
PKG_LIBS = -L$(LIBDIR) -lkoopman_dmd_r -lresolv

# CARGO_HOME is kept inside the build tree. CRAN packages must not write to the
# user's home directory, and cargo would otherwise populate ~/.cargo.
CARGOTMP = $(CURDIR)/.cargo
VENDOR_DIR = $(CURDIR)/rust/vendor

all: $(SHLIB) rust_clean

$(SHLIB): $(STATLIB)

$(STATLIB):
	# CRAN build machines have no network access, so the whole dependency tree ships
	# in vendor.tar.xz and cargo is pointed at it and run with --offline. See
	# https://cran.r-project.org/web/packages/using_rust.html
	#
	# The source-replacement config goes in CARGO_HOME, NOT beside the manifest:
	# cargo looks for .cargo/config.toml relative to its working directory, which is
	# src/ here, so a config at src/rust/.cargo/config.toml is never read. The
	# vendor directory is given as an absolute path for the same reason.
	mkdir -p $(CARGOTMP)
	export PATH="$(PATH):$(HOME)/.cargo/bin" && \
		export CARGO_HOME=$(CARGOTMP) && \
		if [ -f ./rust/vendor.tar.xz ]; then \
			tar xf ./rust/vendor.tar.xz -C ./rust && \
			printf '[source.crates-io]\nreplace-with = "vendored-sources"\n\n[source.vendored-sources]\ndirectory = "$(VENDOR_DIR)"\n' > $(CARGOTMP)/config.toml && \
			cargo build --lib --release --offline --locked -j 2 \
				--manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR); \
		else \
			cargo build --lib --release -j 2 \
				--manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR); \
		fi
	# Reclaim space unless a developer asked to keep it (NOT_CRAN=true).
	if [ "$(NOT_CRAN)" != "true" ]; then \
		rm -Rf $(CARGOTMP) $(VENDOR_DIR) && \
		rm -Rf $(LIBDIR)/build; \
	fi

# The static archive must not survive into the checked build tree: since R
# 4.6.0 (PR#18789), `checking compiled code` scans the symbol tables of local
# static libraries linked into the .so, and libstd's bundled runtime objects
# reference exit/_exit/abort even though the linker never pulls them into the
# final .so (verified: the linked koopman.dmd.so carries no such references).
# Deleting the archive after the link removes the false positive at its
# source, the same way string2path does.
rust_clean: $(SHLIB)
	rm -Rf $(CARGOTMP) $(VENDOR_DIR) $(STATLIB)

C_clean:
	rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS)

clean:
	rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(TARGET_DIR) $(CARGOTMP) $(VENDOR_DIR)

.PHONY: all rust_clean C_clean clean
