How to build apps in subfolders with Makefile - makefile

I'm trying to write a Makefile that will build apps stored in subfolders. So structure of the folders is as follows:
examples/
Makefile
hello_world/
file1.c
main.c
**hello_world** <- expected build result
example1/
otherfile.c
main.c
**example1** <- expected build result
example2/
main.c
...
**example2** <- expected build result
My Makefile (simplified) looks like this:
EXAMPLES := hello_world example1 example2
SRC = $(wildcard */*.c)
OBJ = ${SRC:.c=.o}
OUT = $(foreach e, $(EXAMPLES), $(addprefix $(e)/,$(e)) )
CC := gcc
all: examples
$(OBJ): $(SRC)
#$(CC) -c $< -o $#
$(OUT): $(OBJ)
$(CC) $(filter $(dir $#)%,$^) -o $# $(LDFLAGS)
clean:
#rm -f $(OUT) $(OBJ)
Is there a way to make it work? Or maybe I should have Makefile in each folder separately?
This rule seems to solve my problem, matches outputs to .o, but filters files that are passed for linking with filter function
$(OUT): $(OBJ)
$(CC) $(filter $(dir $#)%,$^) -o $# $(LDFLAGS)
Replaced old rule:
$(OUT): $(OBJ)
$(CC) $^ -o $#
with
examples: $(OBJ)
$(foreach e, $(EXAMPLES), \
$(CC) $(wildcard $(e)/*.o) -o $(e)/$(e) $(LDFLAGS); \
)
almost works now, after clean, the compilation works as expected, only linking fails ($(wildcard $(e)/*.o) is empty?), after second run examples are created as expected

Inspired by comments by Beta and MadScientist, I think I have a solution:
EXAMPLES := hello_world example1 example2
SRC = $(wildcard */*.c)
OBJ = ${SRC:.c=.o}
OUT = $(foreach e, $(EXAMPLES), $(addprefix $(e)/,$(e)) )
CC := gcc
all: $(OUT)
%.o: %.c
#$(CC) $(CFLAGS) -c $< -o $#
$(OUT): $(OBJ)
#$(CC) $(filter $(dir $#)%,$^) -o $# $(LDFLAGS)
clean:
#rm -f $(OUT) $(OBJ)
.PHONY: all clean

Related

how to factorise makefile targets?

I have the following 'working' snippet:
c_file_path := toto.c
asm_file_path := toto.S
c_files = $(notdir $(c_file_path))
asm_files = $(notdir $(asm_file_path))
vpath %.c $(dir $(c_file_path))
vpath %.S $(dir $(asm_file_path))
OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))
$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))
%.c:
#touch $#
%.S:
#touch $#
objs/%.o:%.c
#mkdir -p $(OBJDIR)
#gcc -c $^ -o $#
objs/%.S.o:%.S
#mkdir -p $(OBJDIR)
#gcc -c $^ -o $#
clean:
#rm -rf objs/*
all: $(c_objs) $(asm_objs)
#ls $(c_objs) $(asm_objs)
#echo "hello"
I tried to merge targets:
c_file_path := toto.c
asm_file_path := toto.S
c_files = $(notdir $(c_file_path))
asm_files = $(notdir $(asm_file_path))
vpath %.c $(dir $(c_file_path))
vpath %.S $(dir $(asm_file_path))
OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))
$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))
%.c %.S:
#touch $#
objs/%.o objs/%.S.o:%.c %.S
#mkdir -p $(OBJDIR)
#gcc -c $^ -o $#
clean:
#rm -rf objs/*
all: $(c_objs) $(asm_objs)
#ls $(c_objs) $(asm_objs)
#echo "hello"
which gives:
gcc: error: toto.c no such file or directory
why weren't target merged?
how to merge targets?
I'm not sure what you're trying to do but this rule:
objs/%.o objs/%.S.o:%.c %.S
tells make that for two files foo.c and foo.S (for any string foo) they can be used to create the targets objs/foo.o and objs/foo.S.o by invoking the recipe (gcc) one time.
I'm pretty sure that that's not what you want to say because it means you can't use this pattern unless both files foo.c and foo.S exist for a given string foo.
If what you're asking is how to reduce these two pattern rules:
objs/%.o:%.c
#mkdir -p $(OBJDIR)
#gcc -c $^ -o $#
objs/%.S.o:%.S
#mkdir -p $(OBJDIR)
#gcc -c $^ -o $#
into a single pattern rule so you don't have to write it twice the answer is very simple:
You can't.
You could put the recipe into a variable, like this:
build = #mkdir -p $(OBJDIR) && gcc -c $^ -o $#
then you can simplify the pattern rules somewhat like this:
objs/%.o : %.c ; $(build)
objs/%.S.o : %.S ; $(build)
but that's the best you can do, without resorting to overly-complicated things like foreach/eval/call loops etc.

No rule to make target - Makefille

I need some help understanding why my makefile is not picking up the rule to convert my .c files in .o.
NAME = push_swap
INCLUDES = -I includes -I $(LIBFT_DIR)/includes/
LIBFT_DIR = libft/
CC = gcc
CFLAGS = -Wall -Wextra -Werror
DIR_SRCS = srcs
DIR_OBJS = objs
SRCS = push_swap.c utils_1.c
OBJS = $(subst $(DIR_SRCS), $(DIR_OBJS), $(SRCS:.c=.o))
all: $(NAME)
$(OBJF):
#mkdir -p $(DIR_OBJS)
$(DIR_OBJS)/%.o : $(DIR_SRCS)/%.c | $(OBJF)
#$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
$(LIBFT):
#make -C $(LIBFT_DIR)
$(NAME): $(OBJS) $(LIBFT)
#$(CC) $(CFLAGS) -o $(NAME) $(OBJS)
clean:
rm -f $(OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re bonus
I get the following error:
make: *** No rule to make target 'push_swap.o', needed by 'push_swap'. Stop.
It's the first time I'm adding folders to my makefile and maybe I'm doing something wrong there.
Thank you.
EDIT:
Thank you all for your help.
I ended up changing a few things because I was having a hard time doing it the other way.
NAME = push_swap
INCLUDES = -I includes -I $(LIBFT_DIR)/includes/
LIBFT_DIR = libft/
CC = gcc
CFLAGS = -Wall -Wextra -Werror
DIR_SRCS = srcs/
DIR_OBJS = objs/
SRCS_FILES = push_swap utils_1
SRCS = $(addprefix $(DIR_SRCS), $(addsuffix .c, $(SRCS_FILES)))
OBJS = $(addprefix $(DIR_OBJS), $(addsuffix .o, $(SRCS_FILES)))
all: $(NAME)
$(NAME): $(OBJS) $(LIBFT)
#$(CC) $(CFLAGS) -o $(NAME) $(OBJS) $(LIBFT_DIR)libft.a
$(DIR_OBJS)%.o : $(DIR_SRCS)%.c $(OBJF)
#mkdir -p $(DIR_OBJS)
#$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
$(LIBFT):
#make -C $(LIBFT_DIR)
clean:
rm -f $(OBJS)
rm -r $(DIR_OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re
Like this it runs perfectly.
With:
SRCS = push_swap.c utils_1.c
The line:
OBJS = $(subst $(DIR_SRCS), $(DIR_OBJS), $(SRCS:.c=.o))
is replacing the $(DIR_SRCS) (srcs) value with $(DIR_OBJS) (objs), BUT the SRC values does have objs in it so:
OBJS = push_swap.o utils_1.o
And so not finding a rule for it.
Try changing to:
SRCS = $(DIR_SRCS)/push_swap.c $(DIR_SRCS)/utils_1.c

How to work with an arbitrary set of source files in Make?

I have a makefile that looks like this:
SRCS := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
TARGET := foo
default : $(TARGET)
%.o : %.cpp %.h
$(CXX) $(CXXFLAGS) $< -o $#
$(TARGET) : $(OBJS)
$(CXX) $(LDFLAGS) $^ -o $(TARGET)
This assumes all the source files I need are at the same place.
What should I do if the files I want to build are (foo.cpp ../bar.cpp ../../xip/bas.cpp ) ?
You need VPATH, 4.5.1 VPATH: Search Path for All Prerequisites,
plus $(notdir ...)8.3 Functions for File Names
If your source files were as you suggest foo.cpp, ../bar.cpp, ../../xip/bas.cpp )
then your makefile would look like:
VPATH := ..:../../xip/
SRCS := $(notdir foo.cpp ../bar.cpp ../../xip/bas.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
TARGET := foo
default : $(TARGET)
%.o : %.cpp %.h
$(CXX) $(CXXFLAGS) $< -o $#
$(TARGET) : $(OBJS)
$(CXX) $(LDFLAGS) $^ -o $(TARGET)

I want to generate objects in subdirectory by makefile

How to specify a subdirectory for the generated .o files, e.g. objsdir, for this code in the make file
cc = gcc
CFLAGS = -o6 -Wall
LIBS = -lm
SOURCES = main.c\
extra.c
OBJECTS = $(SOURCES: .c = .o)
.c.o :; $(cc) -c $(CFLAGS) $<
all : $(OBJECT)
$(cc) -o ...
Actually this is a part of the mkefile code.
I usually use something like this:
cc=gcc
SOURCES=main.c extra.c
OBJECTS=$(patsubst %.c, objsdir/%.o, $(SOURCES))
objsdir/%.o: %.c
echo $^
all: $(OBJECTS)
echo $(OBJECTS)
I actually use this Makefile in general
CC := g++ # This is the main compiler
SRCDIR := src
BUILDDIR := build
TARGETDIR :=bin/
TARGET := pddlcrate
DATADIR := data
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g # -Wall
#LIB := -pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-
mt -lboost_system-mt
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGETDIR)$(TARGET) $(LIB)"; $(CC) $^ -o
$(TARGETDIR)$(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c - o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
for any c++ project with this tree structure
$ tree .
├── Makefile
├── bin
>exefile
├── include
> *.h files
├── obj
> *.o files
├── src
>*.cpp

Automatic dependency processing in Makefile

I have a simple makefile.
IDIR =./include
CC=gcc
CFLAGS=-I$(IDIR)
SRCDIR = ./src
ODIR=obj
LDIR =./lib
LIBS=-lm
SRC = hellomake hellofunc
OBJ = ${SRC:%=$(ODIR)/%.o}
_DEPS = hellomake.h
DEPS = ${_DEPS:%=$(IDIR)/%}
$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ hellomake
What I don't like about this Makefile is that the dependency generation.
.c.o
Is it possible to teach make file that the .c is in src directory, and .o is in obj directory to make this simple one?
.c.o:
$(CC) -c -o $# $< $(CFLAGS)
header dependency
Is it possible to teach make file that all the c files are recompiled automatically when header files that the c file contains is changed?
Preliminaries
Generating dependencies
gcc's -MM -MG can be used to create the dependencies: gcc -MM -MG src/hellofunc.c -I./include will create hellofunc.o: src/hellofunc.c include/hellomake.h. However, we need to include the .d file itself into the .d file, so we use sed to achieve that goal.
gcc -MM -MG src/hellofunc.c -I./include | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#'
The results will be as follows:
hellofunc.d hellofunc.o: src/hellofunc.c include/hellomake.h
When we want to change the content to include the different directory location, we can modify the sed script.
gcc -MM -MG src/hellofunc.c -I./include | sed -e 's#^\(.*\)\.o:#obj/\1.d obj/\1.o:#'
The results will be as follows:
obj/hellofunc.d obj/hellofunc.o: src/hellofunc.c include/hellomake.h
include
-include $(DEPS) will include the files in DEPS directory, the - in front of the include teaches the make to ignore when the directories does not exits.
Pattern matching and replacement
We can substitute any pattern (%) or pattern that ends with c (%.c) as follows:
OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))
We also can have shorthand form.
DEPS := $(OBJS:.o=.d)
filter
We can select only some of the files with filter, this is an example:
OBJ := $(patsubst %.c, %.o, $(filter %.c, $(SRC)))
Method 1
In this method, we specify the dependency (.d depends on .c), and include the created dependency file with include.
.PHONY: clean depend
CC := gcc
CXX := g++
LD := g++
CP := cp
PROG := hellomake
MODULES := src
OBJDIR := obj
default: $(PROG)
OPTFLAGS := -g -O
CFLAGS += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES))
GARBAGE := core core.* *.stackdump ./tags $(PROG)
include $(patsubst %, %/module.make, $(MODULES))
OBJ := \
$(patsubst %.c, %.o, $(filter %.c, $(SRC)))
DEP := $(OBJ:.o=.d)
# implicit rules
%.d: %.c
./depends.sh $(CC) `dirname $*.c` $(CFLAGS) $*.c > $#
-include $(DEP)
# Actual targets
depend: $(DEP)
clean:
rm -rf $(PROG) $(OBJ) $(GARBAGE) $(DEP) depends
$(PROG): $(OBJ)
$(LD) -o $# $^ $(LIBS)
Each module should contain the make file (module.make) to specify what files are included in the SRC variable.
`SRC += src/hellofunc.c \
src/hellomake.c`.
This is the script to generate the dependency file:
#!/bin/sh
#echo "## Got: $*"
CC="$1"
DIR="$2"
shift 2
case "$DIR" in
"" | ".")
$CC -MM -MG "$#" | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#'
;;
*)
$CC -MM -MG "$#" | sed -e "s#^\(.*\)\.o:#$DIR/\1.d $DIR/\1.o:#"
;;
esac
This method is simple, but the object files and dependency files are created in the same src directory with these statements.
SRC += src/hellofunc.c src/hellomake.c
OBJ := $(patsubst %.c, %.o, $(filter %.c, $(SRC)))
DEP := $(OBJ:.o=.d)
Method 2
This method creates the object directory, and puts all the generated (intermediate) files into the directory.
It enlists all the modules to specify the actions both for object file and dependency file generation.
In the example, we have only one module, but with multiple modules, we need to duplicate the statements.
obj/src/%.o: src/%.c
$(CC) -c $< -o $# $(CFLAGS)
obj/src/%.d: src/%.c
gcc -MM -MG $< $(CFLAGS) | sed -e 's#^\(.*\)\.o:#obj/src/\1.d obj/src/\1.o:#' > $#
This is the makefile:
.SUFFIX = .o .c
.PHONY: clean
CC := gcc
LD := gcc
PROG := hellomake
OBJDIR = obj
MODULES := src
SRCS := src/hellofunc.c src/hellomake.c
OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))
DEPS := $(OBJS:.o=.d)
default: $(PROG)
CFLAGS += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES))
CXXFLAGS += $(CFLAGS)
obj/src/%.o: src/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(PROG): $(OBJDIRS) $(OBJS)
$(LD) $(filter %.o, $^) -o $(PROG)
-include $(DEPS)
obj/src/%.d: src/%.c
gcc -MM -MG $< $(CFLAGS) | sed -e 's#^\(.*\)\.o:#obj/src/\1.d obj/src/\1.o:#' > $#
depend: $(DEPS)
GARBAGE := core core.* *.stackdump ./tags $(PROG)
clean:
rm -rf $(PROG) obj/*
$(OBJDIRS):
mkdir -p $#
References
Create directories when generating object files in gcc
How to place object files in separate subdirectory
make deleting dependency files
http://scottmcpeak.com/autodepend/autodepend.html
IDIR = ./include
CC = gcc
CFLAGS = -I$(IDIR)
SRCDIR = src
ODIR = obj
LDIR = ./lib
LIBS = -lm
SRC = hellomake hellofunc
OBJ = ${SRC:%=$(ODIR)/%.o}
_DEPS = hellomake.h
DEPS = ${_DEPS:%=$(IDIR)/%}
%.o: ../$(SRCDIR)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ) $(DEPS)
gcc -o $# $^ $(CFLAGS) $(LIBS)

Resources