.POSIX:

all: help

help:
	@echo "Please use: 'make init', 'make debug', 'make build', 'make release', or 'make clean'"
	@echo "Note: parallel builds (via 'make -jN' where N is some number of how many jobs to generate)"
	@echo "This is supported via recursive build shell calls. Not actually passing -j to make so should work even on a pure POSIX system."

init:
	@mkdir -p output source_code includes config
	@touch config/version source_code/main.c
	@echo "_00.000.00.0000" > config/version
	@printf '%s\n' \
		'# POSIX Virtual Environment for C Build System.' \
		'# Usage: . config/activate' \
		'' \
		'# Prevents double-sourcing.' \
		'if [ -n "$$_OLD_VIRTUAL_CC" ]; then' \
		'    deactivate' \
		'fi' \
		'' \
		'_OLD_VIRTUAL_CC="$$CC"' \
		'_OLD_VIRTUAL_LIBS="$$LIBS"' \
		'_OLD_VIRTUAL_CFLAGS="$$CFLAGS"' \
		'_OLD_VIRTUAL_DEBUG_FLAGS="$$DEBUG_FLAGS"' \
		'_OLD_VIRTUAL_RELEASE_FLAGS="$$RELEASE_FLAGS"' \
		'_OLD_VIRTUAL_PS1="$$PS1"' \
		'' \
		'# Base configuration variables (Updated by "env_set VARIABLE value")' \
		'export CC="cc"' \
		'export LIBS=""' \
		'export CFLAGS=""' \
		'export DEBUG_FLAGS=""' \
		'export RELEASE_FLAGS=""' \
		'export C_VENV_ACTIVE="true"' \
		'' \
		'# Prepend (directory_name_env) to the shell prompt' \
		'ENV_NAME="$$(basename "$$PWD")"' \
		'PS1="($${ENV_NAME}_env) $$PS1"' \
		'export PS1' \
		'' \
		'# Function to dynamically set variables in the terminal AND save them to this file.' \
		'env_set() {' \
		'    if [ -z "$$1" ]; then' \
		'        echo "Usage: env_set <CC|LIBS|CFLAGS|DEBUG_FLAGS|RELEASE_FLAGS> [value]"' \
		'        return 1' \
		'    fi' \
		'    ' \
		'    VAR_NAME="$$1"' \
		'    shift' \
		'    VAR_VALUE="$$*"' \
		'    ' \
		'    # Update the active shell session' \
		'    export "$$VAR_NAME"="$$VAR_VALUE"' \
		'    ' \
		'    # Update this activate file using POSIX sed. To ensure the new value persists the next activate.' \
		'    sed "s|^export $$VAR_NAME=.*|export $$VAR_NAME=\"$$VAR_VALUE\"|" config/activate > config/activate.tmp' \
		'    mv config/activate.tmp config/activate' \
		'    ' \
		'    echo "Updated $$VAR_NAME to '\''$$VAR_VALUE'\''"' \
		'}' \
		'' \
		'deactivate() {' \
		'    # Restore prior environment variables' \
		'    if [ -n "$$_OLD_VIRTUAL_CC" ]; then' \
		'        export CC="$$_OLD_VIRTUAL_CC"' \
		'    else' \
		'        unset CC' \
		'    fi' \
		'' \
		'    if [ -n "$$_OLD_VIRTUAL_LIBS" ]; then' \
		'        export LIBS="$$_OLD_VIRTUAL_LIBS"' \
		'    else' \
		'        unset LIBS' \
		'    fi' \
		'' \
		'    if [ -n "$$_OLD_VIRTUAL_CFLAGS" ]; then' \
		'        export CFLAGS="$$_OLD_VIRTUAL_CFLAGS"' \
		'    else' \
		'        unset CFLAGS' \
		'    fi' \
		'' \
		'    if [ -n "$$_OLD_VIRTUAL_DEBUG_FLAGS" ]; then' \
		'        export DEBUG_FLAGS="$$_OLD_VIRTUAL_DEBUG_FLAGS"' \
		'    else' \
		'        unset DEBUG_FLAGS' \
		'    fi' \
		'' \
		'    if [ -n "$$_OLD_VIRTUAL_RELEASE_FLAGS" ]; then' \
		'        export RELEASE_FLAGS="$$_OLD_VIRTUAL_RELEASE_FLAGS"' \
		'    else' \
		'        unset RELEASE_FLAGS' \
		'    fi' \
		'' \
		'    if [ -n "$$_OLD_VIRTUAL_PS1" ]; then' \
		'        export PS1="$$_OLD_VIRTUAL_PS1"' \
		'    fi' \
		'    ' \
		'    unset _OLD_VIRTUAL_CC' \
		'    unset _OLD_VIRTUAL_LIBS' \
		'    unset _OLD_VIRTUAL_CFLAGS' \
		'    unset _OLD_VIRTUAL_DEBUG_FLAGS' \
		'    unset _OLD_VIRTUAL_RELEASE_FLAGS' \
		'    unset _OLD_VIRTUAL_PS1' \
		'    unset C_VENV_ACTIVE' \
		'    unset ENV_NAME' \
		'    unset -f env_set' \
		'    unset -f deactivate' \
		'}' > config/activate
	@echo "Project initialized. type '. config/activate', or 'source config/activate' to enter the virtual environment."

clean:
	@rm -rf output/obj_debug output/obj_release config/*.mk
	@rm -f output/*
	@echo "Project Cleaned"

# Dynamic Build Graph Generators
debug:
	@if [ -z "$$C_VENV_ACTIVE" ]; then \
		echo "Error: Virtual environment not active."; \
		echo "Please run: '. config/activate' (or 'source config/activate') before building."; \
		exit 1; \
	fi
	@mkdir -p config output/obj_debug
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null || echo "_00.000.00.0000"); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/debug.mk"; \
	ACTIVE_CC=$${CC:-c99}; \
	ACTIVE_LIBS=$${LIBS:-}; \
	ACTIVE_CFLAGS=$${CFLAGS:-}; \
	ACTIVE_DEBUG_FLAGS=$${DEBUG_FLAGS:-}; \
	echo ".POSIX:" > $$MK; \
	OBJS=""; \
	SRCS=$$(find source_code -type f -name '*.c' 2>/dev/null); \
	for SRC in $$SRCS; do \
		OBJ="output/obj_debug/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_DEBUG_FLAGS -I includes -c $$SRC -o $$OBJ $$ACTIVE_LIBS" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_DEBUG_FLAGS -o $$OUT $$OBJS $$ACTIVE_LIBS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"

build:
	@if [ -z "$$C_VENV_ACTIVE" ]; then \
		echo "Error: Virtual environment not active."; \
		echo "Please run: '. config/activate' (or 'source config/activate') before building."; \
		exit 1; \
	fi
	@mkdir -p config output/obj_release
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null || echo "_00.000.00.0000"); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/build.mk"; \
	ACTIVE_CC=$${CC:-c99}; \
	ACTIVE_LIBS=$${LIBS:-}; \
	ACTIVE_CFLAGS=$${CFLAGS:-}; \
	ACTIVE_RELEASE_FLAGS=$${RELEASE_FLAGS:-}; \
	echo ".POSIX:" > $$MK; \
	OBJS=""; \
	SRCS=$$(find source_code -type f -name '*.c' 2>/dev/null); \
	for SRC in $$SRCS; do \
		OBJ="output/obj_release/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_RELEASE_FLAGS -I includes -c $$SRC -o $$OBJ $$ACTIVE_LIBS" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_RELEASE_FLAGS -o $$OUT $$OBJS $$ACTIVE_LIBS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"

release:
	@if [ -z "$$C_VENV_ACTIVE" ]; then \
		echo "Error: Virtual environment not active."; \
		echo "Please run: '. config/activate' (or 'source config/activate') before building."; \
		exit 1; \
	fi
	@mkdir -p config output/obj_release
	@DATE_STR=$$(date +_%y.%j.%H.%M%S); \
	echo "$$DATE_STR" > config/version; \
	echo "Project version updated to: $$DATE_STR"
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/release.mk"; \
	ACTIVE_CC=$${CC:-c99}; \
	ACTIVE_LIBS=$${LIBS:-}; \
	ACTIVE_CFLAGS=$${CFLAGS:-}; \
	ACTIVE_RELEASE_FLAGS=$${RELEASE_FLAGS:-}; \
	echo ".POSIX:" > $$MK; \
	OBJS=""; \
	SRCS=$$(find source_code -type f -name '*.c' 2>/dev/null); \
	for SRC in $$SRCS; do \
		OBJ="output/obj_release/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_RELEASE_FLAGS -I includes -c $$SRC -o $$OBJ $$ACTIVE_LIBS" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$$ACTIVE_CC $$ACTIVE_CFLAGS $$ACTIVE_RELEASE_FLAGS -o $$OUT $$OBJS $$ACTIVE_LIBS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"
