how to factorise makefile targets? - makefile

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.

Related

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 build apps in subfolders with 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

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)

Makefile to compile lists of source files

I have lists of files that I want my Makefile to compile, one list for each source language:
CFILES= Src/Application/main.c Src/Core/data.c Lib/routines.c
ASFILES= Src/Application/startup.s Lib/sqrt.s
I want all the output in one directory:
OBJDIR= output
How do I do the equivalent of:
output/main.o : Src/Application/main.c
cc -c -o output/main.o Src/Application/main.c
output/data.o : Src/Core/data.c
cc -c -o output/data.o Src/Core/data.c
output/routines.o : Lib/routines.c
cc -c -o output/routines.o Lib/routines.c
output/startup.o : Src/Application/startup.s
as -o output/startup.o Src/Application/startup.s
output/sqrt.o : Lib/sqrt.s
as -o output/sqrt.o Lib/sqrt.s
The recipes are the same for every file in its list.
The input files are in all sorts of different directories and it is not acceptable to just list their filenames and use a search path to find them, their explicit paths must be used.
The output filename is the basename of the source file name with the extension changed to o. There are no duplicated basenames between the lists for the different source languages.
I do not want to have to list the object files, this should be derived from the source lists.
I am using gnu make, but bonus points for a portable solution.
Something like the following could do:
all :
OBJDIR := output
CFILES := Src/Application/main.c Src/Core/data.c Lib/routines.c
ASFILES := Src/Application/startup.s Lib/sqrt.s
target = ${OBJDIR}/$(patsubst %.s,%.o,$(notdir ${1}))
obj.c :=
obj.s :=
define obj
$(call target,${1}) : ${1} | ${OBJDIR}
obj$(suffix ${1}) += $(call target,${1})
${1} : ; mkdir -p `dirname $$#` && touch $$# # Create the source for testing. Remove this.
endef
define SOURCES
$(foreach src,${1},$(eval $(call obj,${src})))
endef
$(eval $(call SOURCES,${CFILES}))
$(eval $(call SOURCES,${ASFILES}))
all : ${obj.c} ${obj.s}
${obj.c} : % :
#echo cc -c -o $# $^; touch $# # echo and touch are for testing. Remove these.
${obj.s} : % :
#echo as -o $# $^; touch $# # echo and touch are for testing. Remove these.
${OBJDIR} :
mkdir $#
.PHONY: all
Output:
$ make
make: Entering directory '/home/max/tmp'
mkdir -p `dirname Src/Application/main.c` && touch Src/Application/main.c # Create the source for testing. Remove this.
mkdir output
cc -c -o output/main.c Src/Application/main.c
mkdir -p `dirname Src/Core/data.c` && touch Src/Core/data.c # Create the source for testing. Remove this.
cc -c -o output/data.c Src/Core/data.c
mkdir -p `dirname Lib/routines.c` && touch Lib/routines.c # Create the source for testing. Remove this.
cc -c -o output/routines.c Lib/routines.c
mkdir -p `dirname Src/Application/startup.s` && touch Src/Application/startup.s # Create the source for testing. Remove this.
as -o output/startup.o Src/Application/startup.s
mkdir -p `dirname Lib/sqrt.s` && touch Lib/sqrt.s # Create the source for testing. Remove this.
as -o output/sqrt.o Lib/sqrt.s
make: Leaving directory '/home/max/tmp'
I have little experience in writing makefiles, so this is just an attempt. In my example I have C and C++ files in a few directories and build a program made of these files.
$ cat Makefile
.PHONY : clean all
CC=gcc
CXX=g++
CFILES = c/f.c c/g.c
CPPFILES = cpp/main.cpp
OUTPUT = ./output
SOURCE_DIRS := $(dir $(CFILES))
SOURCE_DIRS += $(dir $(CPPFILES))
VPATH = $(sort $(SOURCE_DIRS))
C_FILENAMES := $(notdir $(CFILES))
CPP_FILENAMES += $(notdir $(CPPFILES))
OBJ_FILES := $(patsubst %.c, $(OUTPUT)/%.o, $(C_FILENAMES) )
OBJ_FILES += $(patsubst %.cpp, $(OUTPUT)/%.o, $(CPP_FILENAMES) )
all : $(OUTPUT)/program
$(OUTPUT)/program : $(OBJ_FILES)
g++ -o $# $^
$(OUTPUT)/%.o : %.cpp
$(shell mkdir -p $(OUTPUT) )
$(CXX) $(CXXFLAGS) -c $< -o $#
$(OUTPUT)/%.o : %.c
$(shell mkdir -p $(OUTPUT) )
$(CC) $(CFLAGS) -c $< -o $#
clean:
rm -fr $(OUTPUT)
And this is an example of using my makefile:
$ make
gcc -c c/f.c -o output/f.o
gcc -c c/g.c -o output/g.o
g++ -c cpp/main.cpp -o output/main.o
g++ -o output/program output/f.o output/g.o output/main.o
The following method should do what you want: compile all of your specified source files and put the object files in the directory ./output automatically. Of course, you need to provide compiler options, proper libraries necessary for linking, and so on.
OBJDIR =./output
SRCDIR1 =./Src/Application
SRCDIR2 =./Src/Core
SRCDIR3 =./Lib
SRC1 =$(SRCDIR1)/main.c
SRC2 =$(SRCDIR2)/data.c
SRC3 =$(SRCDIR3)/routines.c
SRC4 =$(SRCDIR1)/startup.s
SRC5 =$(SRCDIR3)/sqrt.s
OBJ1 =$(patsubst $(SRCDIR1)/%.c,$(OBJDIR)/%.o,$(SRC1))
OBJ2 =$(patsubst $(SRCDIR2)/%.c,$(OBJDIR)/%.o,$(SRC2))
OBJ3 =$(patsubst $(SRCDIR3)/%.c,$(OBJDIR)/%.o,$(SRC3))
OBJ4 =$(patsubst $(SRCDIR1)/%.s,$(OBJDIR)/%.o,$(SRC4))
OBJ5 =$(patsubst $(SRCDIR3)/%.s,$(OBJDIR)/%.o,$(SRC5))
vpath %.c $(SRCDIR1): $(SRCDIR2): $(SRCDIR3)
vpath %.s $(SRCDIR1): $(SRCDIR3)
all: $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(OBJ5)
cc $^ -o executable
$(OBJDIR)/%.o: %.c | $(OBJDIR)
cc -c $< -o $#
$(OBJDIR)/%.o: %.s | $(OBJDIR)
cc -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)

How to produce different objects with the same file

I am trying to modify a Makefile, and I can't find the rule for that.
The following doesn't work. I don't know how to write the src to obj rules.
# foo.c bar.c main.c
SRC = $(wildcard *.c)
OBJ_1 = $(patsubst %.c,%_1.o,$(SRC))
OBJ_2 = $(patsubst %.c,%_2.o,$(SRC))
GCC1 = vtcc
GCC2 = vtcc
LD_FLAGS= -lm -lpthread
all: a1 a2
# executables :
a1: $(OBJ_1)
$(GCC1) $(LDFLAGS) $^ -o $#
a2: $(OBJ_2)
$(GCC2) $(LDFLAGS) $^ -o $#
# objects :
$(OBJ_1) : $(SRC)
$(GCC1) -c $< -o $#
$(OBJ_2) : $(SRC)
$(GCC2) -c $< -o $#
It's hard tell what your question is, but I think the last two rules should be:
# objects :
$(OBJ_1) : %_1.o : %.c
$(GCC1) -c $< -o $#
$(OBJ_2) : %_2.o : %.c
$(GCC2) -c $< -o $#

Resources