Files
shmake/source_code/shmake_sync_makefile.sh
2026-04-05 15:09:32 -05:00

277 lines
12 KiB
Bash

#!/bin/sh
# shmake_sync_makefile.sh - Project synchronization for shmake
# Target: bmake with .POSIX: compatibility
sync_project()
{
printf "Syncing project files...\n"
SOURCE_FILES_LIST=$(mktemp)
SHARED_SOURCE_LIST=$(mktemp)
SHARED_BINARY_LIST=$(mktemp)
TEST_SOURCE_LIST=$(mktemp)
TEST_BINARY_LIST=$(mktemp)
DEBUG_SOURCE_LIST=$(mktemp)
DEBUG_BINARY_LIST=$(mktemp)
RELEASE_SOURCE_LIST=$(mktemp)
RELEASE_BINARY_LIST=$(mktemp)
INCLUDE_DIRS_LIST=$(mktemp)
LINKED_LIBS_LIST=$(mktemp)
trap 'rm -f "$SOURCE_FILES_LIST" "$SHARED_SOURCE_LIST" "$SHARED_BINARY_LIST" "$TEST_SOURCE_LIST" "$TEST_BINARY_LIST" "$DEBUG_SOURCE_LIST" "$DEBUG_BINARY_LIST" "$RELEASE_SOURCE_LIST" "$RELEASE_BINARY_LIST" "$INCLUDE_DIRS_LIST" "$LINKED_LIBS_LIST"' EXIT
printf "Scanning source_code/ for source files...\n"
[ -d "source_code" ] && find source_code -type f -name '*.c' ! -path '*/internal/*' 2>/dev/null | while read -r f; do
printf '%s\n' "$f" >> "$SOURCE_FILES_LIST"
done
printf "Scanning external_code/shared_libraries/ for source files...\n"
[ -d "external_code/shared_libraries/source_code" ] && find external_code/shared_libraries/source_code -type f -name '*.c' ! -path '*/internal/*' 2>/dev/null | while read -r f; do
case "$f" in
*example*) printf "Skipping %s (example code)\n" "$f" >&2 ;;
*) printf '%s\n' "$f" >> "$SHARED_SOURCE_LIST" ;;
esac
done
printf "Scanning external_code/shared_libraries/binary/ for binary libraries...\n"
[ -d "external_code/shared_libraries/binary" ] && find external_code/shared_libraries/binary -type f \( -name '*.a' -o -name '*.so' -o -name '*.lib' -o -name '*.dylib' \) 2>/dev/null | while read -r f; do
printf '%s\n' "$f" >> "$SHARED_BINARY_LIST"
done
printf "Scanning external_code/test_only/ for source files...\n"
[ -d "external_code/test_only/source_code" ] && find external_code/test_only/source_code -type f -name '*.c' ! -path '*/internal/*' 2>/dev/null | while read -r f; do
case "$f" in
*example*) printf "Skipping %s (example code)\n" "$f" >&2 ;;
*) printf '%s\n' "$f" >> "$TEST_SOURCE_LIST" ;;
esac
done
printf "Scanning external_code/test_only/binary/ for test libraries...\n"
[ -d "external_code/test_only/binary" ] && find external_code/test_only/binary -type f \( -name '*.a' -o -name '*.so' -o -name '*.lib' -o -name '*.dylib' \) 2>/dev/null | while read -r f; do
printf '%s\n' "$f" >> "$TEST_BINARY_LIST"
done
printf "Scanning external_code/debug_only/ for source files...\n"
[ -d "external_code/debug_only/source_code" ] && find external_code/debug_only/source_code -type f -name '*.c' ! -path '*/internal/*' 2>/dev/null | while read -r f; do
case "$f" in
*example*) printf "Skipping %s (example code)\n" "$f" >&2 ;;
*) printf '%s\n' "$f" >> "$DEBUG_SOURCE_LIST" ;;
esac
done
printf "Scanning external_code/debug_only/binary/ for debug libraries...\n"
[ -d "external_code/debug_only/binary" ] && find external_code/debug_only/binary -type f \( -name '*.a' -o -name '*.so' -o -name '*.lib' -o -name '*.dylib' \) 2>/dev/null | while read -r f; do
printf '%s\n' "$f" >> "$DEBUG_BINARY_LIST"
done
printf "Scanning external_code/release_only/ for source files...\n"
[ -d "external_code/release_only/source_code" ] && find external_code/release_only/source_code -type f -name '*.c' ! -path '*/internal/*' 2>/dev/null | while read -r f; do
case "$f" in
*example*) printf "Skipping %s (example code)\n" "$f" >&2 ;;
*) printf '%s\n' "$f" >> "$RELEASE_SOURCE_LIST" ;;
esac
done
printf "Scanning external_code/release_only/binary/ for release libraries...\n"
[ -d "external_code/release_only/binary" ] && find external_code/release_only/binary -type f \( -name '*.a' -o -name '*.so' -o -name '*.lib' -o -name '*.dylib' \) 2>/dev/null | while read -r f; do
printf '%s\n' "$f" >> "$RELEASE_BINARY_LIST"
done
printf "Auto-detecting include directories across entire project...\n"
find . -type d ! -path "*/internal/*" ! -path "./.git*" ! -path "./build_output*" ! -path "./intermediate_code*" ! -path "*/examples*" ! -path "*/example*" ! -path "./shmake_config*" 2>/dev/null | while read -r dir; do
clean_dir=$(printf "%s" "$dir" | sed 's|^\./||')
[ -z "$clean_dir" ] && continue
[ "$clean_dir" = "." ] && continue
find "$clean_dir" -maxdepth 1 -type f -name '*.h' 2>/dev/null | grep -q . && printf '%s\n' "$clean_dir" >> "$INCLUDE_DIRS_LIST"
done
printf "Reading linked libraries from shmake_config/linked.conf...\n"
[ -f "shmake_config/linked.conf" ] && grep '^LINKED_LIBS' "shmake_config/linked.conf" | sed 's/^LINKED_LIBS[[:space:]]*=[[:space:]]*//' | while read -r line; do
printf '%s\n' "$line" >> "$LINKED_LIBS_LIST"
done
printf "Sorting and deduplicating file lists...\n"
for list in "$SOURCE_FILES_LIST" "$SHARED_SOURCE_LIST" "$SHARED_BINARY_LIST" \
"$TEST_SOURCE_LIST" "$TEST_BINARY_LIST" "$DEBUG_SOURCE_LIST" \
"$DEBUG_BINARY_LIST" "$RELEASE_SOURCE_LIST" "$RELEASE_BINARY_LIST" \
"$INCLUDE_DIRS_LIST" "$LINKED_LIBS_LIST"; do
sort -u "$list" -o "$list"
done
printf "Reading project configuration...\n"
if [ -f "shmake_config/project.conf" ]; then
C_VERSION_RAW=$(grep -E '^C_VERSION[[:space:]]*=' "shmake_config/project.conf" | sed 's/^.*=[[:space:]]*//' | tr -d '"'\' | tr '[:upper:]' '[:lower:]')
fi
C_VERSION_LOWER=${C_VERSION_RAW:-c11}
[ ! -f "shmake_config/linked.conf" ] && touch "shmake_config/linked.conf"
write_objects_and_rules() {
_list_file="$1"
_prefix="$2"
_conf_file="$3"
printf '%s_OBJECTS = \\\n' "$_prefix" >> "$_conf_file"
while IFS= read -r file; do
[ -z "$file" ] && continue
obj="intermediate_code/${file%%.c}.o"
printf ' %s \\\n' "$obj" >> "$_conf_file"
done < "$_list_file"
printf '\n' >> "$_conf_file"
while IFS= read -r file; do
[ -z "$file" ] && continue
obj="intermediate_code/${file%%.c}.o"
dir_path=$(dirname "$obj")
printf '%s: %s\n' "$obj" "$file" >> "$_conf_file"
printf '\t@mkdir -p %s\n' "$dir_path" >> "$_conf_file"
printf '\t$(CC) $(CFLAGS) -c %s -o %s\n\n' "$file" "$obj" >> "$_conf_file"
done < "$_list_file"
}
printf "Generating makefile.conf...\n"
cat > "shmake_config/makefile.conf" << 'CONF_HEADER'
# --- shmake Base Configuration (Always Included) ---
CONF_HEADER
printf 'CFLAGS += -std=%s\n' "$C_VERSION_LOWER" >> "shmake_config/makefile.conf"
printf 'INCLUDE_DIRS = \\\n' >> "shmake_config/makefile.conf"
while IFS= read -r dir; do
[ -n "$dir" ] && printf ' -I%s \\\n' "$dir" >> "shmake_config/makefile.conf"
done < "$INCLUDE_DIRS_LIST"
printf '\nCFLAGS += $(INCLUDE_DIRS)\n\n' >> "shmake_config/makefile.conf"
printf 'SHARED_LIBS = \\\n' >> "shmake_config/makefile.conf"
while IFS= read -r file; do
[ -n "$file" ] && printf ' %s \\\n' "$file" >> "shmake_config/makefile.conf"
done < "$SHARED_BINARY_LIST"
printf '\n' >> "shmake_config/makefile.conf"
write_objects_and_rules "$SOURCE_FILES_LIST" "PROJECT" "shmake_config/makefile.conf"
write_objects_and_rules "$SHARED_SOURCE_LIST" "SHARED" "shmake_config/makefile.conf"
printf "Generating makefile_test.conf...\n"
cat > "shmake_config/makefile_test.conf" << 'CONF_HEADER'
# --- shmake Test Configuration ---
CONF_HEADER
printf 'TEST_LIBS = \\\n' >> "shmake_config/makefile_test.conf"
while IFS= read -r file; do
[ -n "$file" ] && printf ' %s \\\n' "$file" >> "shmake_config/makefile_test.conf"
done < "$TEST_BINARY_LIST"
printf '\n' >> "shmake_config/makefile_test.conf"
write_objects_and_rules "$TEST_SOURCE_LIST" "TEST" "shmake_config/makefile_test.conf"
printf "Generating makefile_debug.conf...\n"
cat > "shmake_config/makefile_debug.conf" << 'CONF_HEADER'
# --- shmake Debug Configuration ---
CONF_HEADER
printf 'DEBUG_LIBS = \\\n' >> "shmake_config/makefile_debug.conf"
while IFS= read -r file; do
[ -n "$file" ] && printf ' %s \\\n' "$file" >> "shmake_config/makefile_debug.conf"
done < "$DEBUG_BINARY_LIST"
printf '\n' >> "shmake_config/makefile_debug.conf"
printf 'CFLAGS += -g -O0 -DDEBUG\n\n' >> "shmake_config/makefile_debug.conf"
write_objects_and_rules "$DEBUG_SOURCE_LIST" "DEBUG" "shmake_config/makefile_debug.conf"
printf "Generating makefile_release.conf...\n"
cat > "shmake_config/makefile_release.conf" << 'CONF_HEADER'
# --- shmake Release Configuration ---
CONF_HEADER
printf 'RELEASE_LIBS = \\\n' >> "shmake_config/makefile_release.conf"
while IFS= read -r file; do
[ -n "$file" ] && printf ' %s \\\n' "$file" >> "shmake_config/makefile_release.conf"
done < "$RELEASE_BINARY_LIST"
printf '\n' >> "shmake_config/makefile_release.conf"
printf 'CFLAGS += -O2 -DNDEBUG\n\n' >> "shmake_config/makefile_release.conf"
write_objects_and_rules "$RELEASE_SOURCE_LIST" "RELEASE" "shmake_config/makefile_release.conf"
printf "Generating makefile_clean.conf...\n"
cat > "shmake_config/makefile_clean.conf" << 'CONF_HEADER'
# --- shmake Clean Configuration ---
CLEAN_TARGETS = build_output
EXTRA_CLEAN = intermediate_code
CONF_HEADER
printf "Updating Root Makefile...\n"
cat > "Makefile" << 'MAKEFILE_TEMPLATE'
# --- shmake Root Makefile ---
# Portable: Works on bmake in .POSIX: mode
.POSIX:
PROJECT_NAME ?= a.out
.include "shmake_config/project.conf"
.include "shmake_config/makefile.conf"
.include "shmake_config/linked.conf"
.if !defined(BUILD_MODE)
BUILD_MODE = release
.endif
.if "${BUILD_MODE}" == "test"
.include "shmake_config/makefile_test.conf"
ALL_MODE_OBJECTS = ${PROJECT_OBJECTS} ${SHARED_OBJECTS} ${TEST_OBJECTS}
ALL_MODE_LIBS = ${SHARED_LIBS} ${LINKED_LIBS} ${TEST_LIBS}
.endif
.if "${BUILD_MODE}" == "debug"
.include "shmake_config/makefile_debug.conf"
ALL_MODE_OBJECTS = ${PROJECT_OBJECTS} ${SHARED_OBJECTS} ${DEBUG_OBJECTS}
ALL_MODE_LIBS = ${SHARED_LIBS} ${LINKED_LIBS} ${DEBUG_LIBS}
.endif
.if "${BUILD_MODE}" == "release"
.include "shmake_config/makefile_release.conf"
ALL_MODE_OBJECTS = ${PROJECT_OBJECTS} ${SHARED_OBJECTS} ${RELEASE_OBJECTS}
ALL_MODE_LIBS = ${SHARED_LIBS} ${LINKED_LIBS} ${RELEASE_LIBS}
.endif
ALL_OBJECTS = ${ALL_MODE_OBJECTS}
ALL_LIBS = ${ALL_MODE_LIBS}
OUTPUT_DIR = build_output
OBJ_DIR = intermediate_code
CC ?= gcc
.PHONY: all debug test release clean distclean
all:
@if [ "${BUILD_MODE}" = "debug" ]; then \
${MAKE} debug; \
elif [ "${BUILD_MODE}" = "test" ]; then \
${MAKE} test; \
else \
${MAKE} release; \
fi
debug: ${OUTPUT_DIR}/${PROJECT_NAME}-debug
test: ${OUTPUT_DIR}/${PROJECT_NAME}-test
release: ${OUTPUT_DIR}/${PROJECT_NAME}
${OUTPUT_DIR}/${PROJECT_NAME}-debug: ${ALL_OBJECTS}
@mkdir -p ${OUTPUT_DIR}
${CC} ${CFLAGS} -o $@ ${ALL_OBJECTS} ${ALL_LIBS}
${OUTPUT_DIR}/${PROJECT_NAME}-test: ${ALL_OBJECTS}
@mkdir -p ${OUTPUT_DIR}
${CC} ${CFLAGS} -o $@ ${ALL_OBJECTS} ${ALL_LIBS}
${OUTPUT_DIR}/${PROJECT_NAME}: ${ALL_OBJECTS}
@mkdir -p ${OUTPUT_DIR}
${CC} ${CFLAGS} -o $@ ${ALL_OBJECTS} ${ALL_LIBS}
.include "shmake_config/makefile_clean.conf"
clean:
rm -rf ${CLEAN_TARGETS} ${EXTRA_CLEAN}
distclean: clean
rm -rf ${OBJ_DIR} ${OUTPUT_DIR}
MAKEFILE_TEMPLATE
printf "\nSync complete!\n"
}