Added Makefile Logic to work with Submodules

These changes allow for projects that were created and built using the
same Makefile to be placed under the submodules directory. This Makefile
will recursively build the submodules and link to the top project.

The submodules will be built as a static library using ar rcs.
This commit is contained in:
xavi 2025-12-23 21:28:56 -08:00
parent 3677b50fe1
commit 0924650090
2 changed files with 55 additions and 141 deletions

View File

@ -11,8 +11,6 @@
# Change date file was created to today # Change date file was created to today
# run make dirs to create project hierarchy # run make dirs to create project hierarchy
# Place headers in include and source files in src # Place headers in include and source files in src
# Delete this text
.POSIX: .POSIX:
# DIRECTORIES # DIRECTORIES
@ -20,48 +18,89 @@ SRC_DIR := src
INCLUDE_DIR := include INCLUDE_DIR := include
OBJ_DIR := obj OBJ_DIR := obj
TESTS_DIR := tests TESTS_DIR := tests
SUBMODULES_DIR := submodules
# Final Binary Name
PROJECT_NAME := placeholder
PROJECT_OBJ := $(OBJ_DIR)/$(PROJECT_NAME).o
# SUBMODULE VARS FOR GENERATING STATIC LIBS
SUBMODULES := $(wildcard $(SUBMODULES_DIR)/*)
SUBBARE := $(SUBMODULES:$(SUBMODULES_DIR)/%=%)
SUBMODULE_SLIB := $(foreach m,$(SUBBARE),$(SUBMODULES_DIR)/$(m)/$(m).a)
STATIC_LIBS = $(shell find ./ -name "*.a")
# C compiler settings # C compiler settings
CC := gcc CC := gcc
CFLAGS := -ggdb -I$(INCLUDE_DIR) -Wall -Wextra -MMD -MP INCLUDE_LIST := $(foreach m,$(SUBMODULES),$(m)/$(INCLUDE_DIR)) $(INCLUDE_DIR)
INCLUDES := $(addprefix -I,$(INCLUDE_LIST))
CFLAGS := -ggdb $(INCLUDES) -Wall -Wextra -MMD -MP
DFLAGS := DFLAGS :=
# Main Executable Filename
MAIN := main.c
# Files # Files
SRC := $(wildcard $(SRC_DIR)/*.c) SRC := $(filter-out $(SRC_DIR)/$(MAIN), $(wildcard $(SRC_DIR)/*.c))
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
TESTS := $(wildcard $(TESTS_DIR)/*.c) TESTS := $(wildcard $(TESTS_DIR)/*.c)
# Get Dependencies from gcc using -MMD and -MP # Get Dependencies from gcc using -MMD and -MP
DEPENDENCIES := $(OBJ:%.o=%.d) DEPENDENCIES := $(OBJ:%.o=%.d)
# Final Binary Name
PROJECT_NAME := placeholder
all: $(PROJECT_NAME) all: $(PROJECT_NAME)
# CREATE STATIC LIBRARY OF MODULE
$(PROJECT_NAME).a: $(PROJECT_OBJ) check_submods
ar rcs $(@) $(<)
$(TESTS:$(TESTS_DIR)/%.c=%): $(OBJ) # CREATE TEST EXECUTABLES
$(CC) $(CFLAGS) $(DFLAGS) -o $(@) $(^) $(TESTS:$(TESTS_DIR)/%.c=%): %: $(OBJ_DIR)/%.o $(OBJ) check_submods
$(CC) $(CFLAGS) $(DFLAGS) -o $(@) $(<) $(OBJ) $(STATIC_LIBS)
# CREATE TEST OBJS
$(OBJ_DIR)/%.o: $(TESTS_DIR)/%.c $(OBJ)
$(CC) $(CFLAGS) $(DFLAGS) -c -o $(@) $(^)
$(PROJECT_NAME): $(OBJ) # CREATE MAIN OBJ
$(CC) $(CFLAGS) $(DFLAGS) -o $(@) $(^) $(PROJECT_NAME): $(MAIN:%.c=$(OBJ_DIR)/%.o) $(OBJ) check_submods
$(CC) $(CFLAGS) $(DFLAGS) -o $(@) $(<) $(OBJ) $(STATIC_LIBS)
# CREATE OBJS
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(DFLAGS) -c -o $(@) $(<) $(CC) $(CFLAGS) $(DFLAGS) -c -o $(@) $(<)
# RECURSE THROUGH SUBMODULES AND RUN MAKE *.a
$(SUBMODULE_SLIB):
$(MAKE) -C $(dir $(@)) $(notdir $(@))
check_submods: $(SUBMODULE_SLIB)
# RECURSE AND CLEAN ALL FILES
clean: clean:
rm -f $(PROJECT_NAME) $(OBJ_DIR)/* $(TESTS:$(TESTS_DIR)/%.c=%) @for sm in $(SUBMODULES) ; do \
$(MAKE) -C $$sm clean ; \
done
rm -f $(PROJECT_NAME) $(OBJ_DIR)/* $(TESTS:$(TESTS_DIR)/%.c=%) ./*.a
-include $(DEPENDENCIES) -include $(DEPENDENCIES)
.PHONY: clean all help:
@echo "SUBMODULES: $(SUBMODULES)"
@echo "SUBMODULE_SLIB: $(SUBMODULE_SLIB)"
@echo "STATIC_LIBS: $(STATIC_LIBS)"
.PHONY: clean all check_submods help
# Create Project Hierarchy # Create Project Hierarchy
dirs: $(SRC_DIR) $(OBJ_DIR) $(TESTS_DIR) $(INCLUDE_DIR) dirs: $(SRC_DIR) $(OBJ_DIR) $(TESTS_DIR) $(INCLUDE_DIR) $(SUBMODULES_DIR) $(SRC_DIR)/$(MAIN)
$(SRC_DIR) $(OBJ_DIR) $(TESTS_DIR) $(INCLUDE_DIR): $(SRC_DIR) $(OBJ_DIR) $(TESTS_DIR) $(INCLUDE_DIR) $(SUBMODULES_DIR):
mkdir -p $(@) mkdir -p $(@)
$(SRC_DIR)/$(MAIN):
touch $(SRC_DIR)/$(MAIN)

View File

@ -1,125 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
// printf Formating
#define X_RED "\x1B[31m"
#define X_GREEN "\x1B[32m"
#define X_YELLOW "\x1B[33m"
#define X_RST "\x1B[0m"
// TEST FRAMEWORK STRUCT
typedef struct testnode{
char* name;
int (*op)(void);
struct testnode* next;
}testnode;
// LL nodes
static testnode* head = NULL;
static testnode* tail = NULL;
static testnode* ptr = NULL;
// TEST FRAMEWORK MACRO
// create a new node and pass in the name of the test. Then make a new function
// that adds the test to the LL. __attribute__((constructor)) has the function
// run before main
#define TEST(UNIT)\
static int UNIT(void);\
static testnode UNIT##node = {#UNIT, UNIT, NULL};\
__attribute__((constructor)) \
static void add##UNIT(void){ \
if (head == NULL){\
head = &UNIT##node;\
tail = head;\
return; \
}\
ptr = tail;\
tail = &UNIT##node;\
ptr->next = tail;\
}\
static int UNIT(void)
// ASSERT MACRO
#define ASSERT()
// DEFINE TESTS
TEST(fail){
return -1;
}
TEST(success){
return 0;
}
TEST(segfault){
int* x = NULL;
int y = *x;
}
// END OF TEST DEFINITIONS
int main(){
int total_tests = 0;
int errors = 0;
int status;
ptr = head;
while (ptr != NULL){
total_tests++;
pid_t cpid = fork();
if (cpid < 0){
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0){
int rc = ptr->op();
_exit(rc);
}else{
if (waitpid(cpid, &status, 0) < 0){
perror("waitpid");
exit(EXIT_FAILURE);
}
}
if (WIFEXITED(status)){
int rc = WEXITSTATUS(status);
if (rc == 0) {
printf("%s[PASS]%s ", X_GREEN, X_RST);
printf("%s", ptr->name);
}
else{
printf("%s[FAIL]%s ", X_RED, X_RST);
printf("%s ", ptr->name);
printf("- Exit Code %s(%d)%s", X_YELLOW, rc, X_RST);
errors++;
}
}else if (WIFSIGNALED(status)){
printf("%s[FAIL]%s ", X_RED, X_RST);
printf("%s ", ptr->name);
printf("- Termination Signal %s(%d)%s", X_YELLOW, WTERMSIG(status), X_RST);
errors++;
}
printf("\n");
ptr = ptr->next;
}
printf("Tests completed with %s%d PASS%s", X_GREEN, total_tests - errors, X_RST);
printf(" and %s%d FAIL%s\n", X_RED, errors, X_RST);
if (errors > 0){
return 1;
}
return 0;
}
// INSERT HEADERS FOR FUNCS
// DEFINE TESTS
// END OF TEST DEFINITIONS