I have a question about Makefiles with subdirectories:
I have a program with the structure
---src
|
|-> main.c
|-> morestuff.c
|-> [...]
|-> builtins -> builtin.c
-> builtin2.c
---obj
---inc
Now what I want to do is: I want to run make
such that I create object files in my object directory (order structure not necessarily needed) and that I (obviously) create an executable.
I am able to do that without the subdirectories, but my pattern rules break, once I try to include the subdirectories...
My current approach (without subdirectories) looks something like this:
NAME = minishell
SRC_DIR = src/
OBJ_DIR = obj/
INC_DIR = inc/
LIBFT_DIR = libft/
LIBFT_EXEC = libft.a
CC = gcc
CFLAGS = -Wall -Werror -Wextra -g
# place all source files here
SRC = $(SRC_DIR)main.c \
$(SRC_DIR)builtin1.c \
$(SRC_DIR)builtin2.c \
[...]
# takes all named source files and converts them to .o files in the /obj directory
OBJ = $(SRC:$(SRC_DIR)%.c=$(OBJ_DIR)%.o)
# prevents rules from being considered as files
.PHONY: all clean fclean re
all: $(NAME)
# creates subdirectory /obj
$(OBJ_DIR):
@mkdir $@
@echo "Creating object directory..."
# makes sure to make a /obj dir before compiling .o files
$(OBJ): | $(OBJ_DIR)
$(OBJ): $(OBJ_DIR)%.o: $(SRC_DIR)%.c
$(CC) $(CFLAGS) -c $< -o $@
# compiles all object files and builds executable file 'minishell' -> ADJUST READLINE FOR LINUX!
$(NAME): $(OBJ)
@echo "Compiling libft..."
$(MAKE) -C libft
@echo "Compiling $(NAME)..."
$(CC) $(CFLAGS) $^ $(LIBFT_DIR)$(LIBFT_EXEC) -L $(HOME)/goinfre/.brew/opt/readline/lib/ -lreadline -o $@
@echo "SUCCESSFULLY CREATED MINISHELL!"
So how can I scale that up to handle subdirectories? I know I could make Makefiles in subdirectories, but this is not worth the effort since there aren't a lot of files in there...
CodePudding user response:
Instead of just creating the object directory before compiling, you should create the object file directory tree prior to compiling each file:
$(OBJ_DIR)%.o: $(SRC_DIR)%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(dir $@)
is a GNU make extension. You can use @mkdir -p `dirname $@`
for portability to other make
flavors.