277 lines
12 KiB
Bash
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"
|
|
}
|