# [ʞ] gdjn
#  ~ lexi hale <lexi@hale.su>
#  ? write godot games in a civilized language
#  🄯 AGPLv3
#  > make all

o = out#  final binary output
g = gen#  where to store intermediate build artifacts
s = src#  source of the main gdjn library
t = tool# source of utilities built for use during build
x = ext#  where to fetch external binary libraries
l = lib#  libraries written in janet

# in case these are confusing:
# * ["src] only contains valuable files written by human hand
#
# * ["gen] does not contain any files that cannot be deleted
#   without any repercussions beyond having to run `make`
#   again.
#
# * ["tool] contains valuable hand-written source files which
#   are interpreted during the build process and help generate
#   artifacts that contribute to the final binary. [!however],
#   none of the tool code itself ends up in the binary in any
#   form.
#
# * ["ext] is a Keter-class high-security containment unit for
#   Other People's Code.
#
# * ["lib] contains (mostly janet) code that will be included
#   as blobs in the binary. janet code will be able to import
#   them. these will be compiled down to .jimage files and
#   then bundled into rsrc.o. libraries used in ["tool/*] 
#   should only be placed in this directory if they are also
#   used at runtime in the godot environment (e.g. the OOP
#   macros). library code used only by tools belongs in the
#   tool directory.
#
# * ["out] contains all live binaries and object files.

godot = godot4
godot.flags = --headless
godot.cmd = "$(godot)" $(godot.flags)
janet = $o/janet
git = git
git.flags.clone = --depth=1

janet.src.path = $x/janet
janet.src.git = https://github.com/janet-lang/janet.git
janet.root = $x/janet/src
janet.cfg = 

cc.link = -flto
cc.comp = -fPIC

ifeq ($(debug),1)
    cc.link += -g
    cc.comp += -g -O0
endif

cc.gdjn.comp = $(cc.comp) \
	-std=gnu23 \
	-I"$g" \
	-I"$s" \
	-I"$(janet.root)/include" \
	-I"$(janet.root)/conf"

cc.gdjn.link = $(cc.link) -shared
cc.janet.link = $(cc.link)

cc ?= $(CC)

path-ensure = mkdir -p "$(@D)"

# tell our scripts where to look for various files
export JANET_PATH = $(realpath $l)
export CC := $(cc)
export gd_build_out = $o
export gd_build_gen = $g
export gd_api_spec  = $g/extension_api.json
export gd_api_iface = $g/gdextension_interface.h

.PHONY: all clean purge
all: $o/gdjn.so 
clean:
	rm "$o/"*.o "$g/"*.{jimage,h} "$o/gdjn.so"
purge:
	rm "$o/"* "$g/"*

%/:; $(path-ensure)
%: | $(@D)/

tags: .
	find "$s" "$g" -name "*.h" -o -name "*.c" | xargs ctags

$o/gdjn.so: $o/gdjn.o $o/rsrc.o $o/interface.o \
            $o/janet-lang.o $o/janet-rsrc.o \
			$o/libjanet.a 
	"$(cc)" $(cc.gdjn.link) $^ -o"$@"

$o/interface.o: $t/c-bind-gen.janet \
                $g/interface.h \
				$(gd_api_spec) \
				$(gd_api_iface)
	"$(janet)" "$<" loader | "$(cc)" $(cc.gdjn.comp) -c -xc - -o "$@"

$g/interface.h: $t/c-bind-gen.janet \
				$(gd_api_spec)
	"$(janet)" "$<" header >"$@"

$g/%.h: $s/%.gcd $t/class-compile.janet $(realpath $(janet))
	"$(janet)" "$t/class-compile.janet" "$<" header >"$@"
$o/%.o: $s/%.gcd $g/%.h $t/class-compile.janet $(realpath $(janet))
	"$(janet)" "$t/class-compile.janet" "$<" loader \
		| "$(cc)" $(cc.gdjn.comp) -c -xc - -o "$@"

$o/%.o: $s/%.c $s/%.h $(realpath $(janet.root)/include/janet.h)
	"$(cc)" -c $(cc.gdjn.comp) "$<" -o"$@"

$o/rsrc.o: $t/rsrc.janet $(realpath $(janet)) \
           $g/api.jimage
	"$(janet)" "$<" -- "$g/api.jimage"

%.jimage: $(realpath $(janet))

$g/api.jimage: $t/api-compile.janet $(gd_api_spec)
	"$(janet)" "$<" "$(gd_api_spec)" "$@"

$g/%.jimage: $l/%.janet
	"$(janet)" -c "$<" "$@"

$x/janet $x/janet/src/include/janet.h:
	"$(git)" $(git.flags) clone $(git.flags.clone) "$(janet.src.git)" "$x/janet"

canon = $(realpath $(dir $1))/$(notdir $1)
define janet.build =
	"$(MAKE)" -C "$(janet.src.path)" "$(call canon,$@)" \
		JANET_$1="$(call canon,$@)"    \
		$(janet.cfg)
endef

$o/libjanet.a: $(janet.src.path)
	$(call janet.build,STATIC_LIBRARY)
$o/janet: $(janet.src.path)
	$(call janet.build,TARGET)

$g/extension_api.json $g/gdextension_interface.h:
	cd "$g" && $(godot.cmd) --dump-extension-api-with-docs \
	                        --dump-gdextension-interface


# individual dependencies

janet-header = $(janet.root)/include/janet.h

$o/gdjn.o: $s/util.h $g/interface.h $g/janet-lang.h $g/janet-rsrc.h $(gd_api_iface)
$o/janet-lang.o: $s/util.h $(janet-header)
$o/janet-rsrc.o: $s/util.h $g/janet-lang.h $(janet-header)
