Multiple targets but same dependency - c

This is a part of my makefile :
SRC = ./
DIRS = src libs/maths libs/struct
BIN_DIR = ./bin/
SRC_DIRS= $(foreach dir, $(DIRS), $(addprefix $(SRC), $(dir)))
SRC_TEST= $(sort $(SRC_DIRS))
SRCS = $(foreach msrc, $(SRC_DIRS), $(wildcard $(msrc)/*.c))
DEL_PRE = $(foreach target, $(SRCS), $(notdir $(target)))
ADD_PRE = $(foreach target, $(DEL_PRE), $(addprefix $(BIN_DIR), $(target)))
OBJS = $(ADD_PRE:.c=.o)
.PHONY: all clean re
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LDLIBS)
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
When i use make all, i have in output :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c src/main.c
gcc -o bin/pears.o -c src/main.c
gcc -o bin/outil.o -c src/main.c
gcc -o bin/verif.o -c src/main.c
But i would like to have for each target, it assigned dependency :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c libs/maths/cosin.c
gcc -o bin/pears.o -c libs/maths/pears.c
gcc -o bin/outil.o -c libs/struct/outil.c
gcc -o bin/verif.o -c libs/struct/verif.c
How can i fix it ?

This seems like a very common misconception; I just answered effectively this same question yesterday. I'm not sure where it comes from or how to combat it.
This rule:
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
does not somehow magically combine the contents of the OBJS variable and the SRCS variable to figure out how they match up. The variable references are simply expanded, and the result is this:
bin/main.o bin/cosin.o ... : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
which is the same as if you'd written this:
bin/main.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
bin/cosin.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
...
Now, you can hopefully see why you compile the same file: in every rule you have the same prerequisites, so $< is always the first one, which is always src/main.c.
There are multiple ways to work this but if you really want to have all the source files from different directories compiled into object files in the same directory your job is harder, because there's no common pattern that will match them all. In this case the simplest thing to do is use VPATH for directory search: replace the above rule with this:
$(BIN_DIR)/%.o : %.c
$(CC) -o $# -c $<
then tell make how to find your source files, like this:
VPATH := $(sort $(dir $(SRCS))
Be aware this method can't be used for any source files that are themselves generated output that make is expected to create.

Related

"clang: error: cannot specify -o when generating multiple output files" fix

I'm trying to compile my C project using clang (I'm on MacOS Monterry) and a Makefile, but I keep getting the same error from clang in the command line:
> make
gcc -c src/ji.c src/main.c -o src/ji.o
clang: error: cannot specify -o when generating multiple output files
make: *** [src/ji.o] Error 1
These are the only files I have in the project so far:
src/main.c
src/ji.c
include/ji.h
The Makefile looks like this:
cc = gcc
src = $(wildcard src/*.c)
obj = $(src:.c=.o)
exec = ji
$(exec): $(obj)
$(cc) -Iinclude $< -o build/$#
%.o: %.c
$(cc) -c $(src) -o $#
clean:
-rm src/*.o
-rm ji
From YouTube videos I've seen, this should be the ideal Makefile for the project but no matter what I change I get the error.
There are a few issues:
-Iinclude needs to be on the %.o: %.c rule command
In %.o: %.c, we don't want $(src) but rather $<
We want patsubst to get the .o list obj
The $(exec) target doesn't match the -o option
The clean doesn't match the placement of the executable
Here's a refactored version (e.g. one way to do this--there are others):
cc = gcc
src = $(wildcard src/*.c)
obj = $(patsubst %.c,%.o,$(src))
exec = build/ji
$(exec): $(obj)
mkdir -p build
$(cc) $^ -o $#
%.o: %.c
$(cc) -c $< -o $# -Iinclude
clean:
rm -f src/*.o
rm -fr build
Here's the output of make:
gcc -c src/ji.c -o src/ji.o -Iinclude
gcc -c src/main.c -o src/main.o -Iinclude
mkdir -p build
gcc src/ji.o src/main.o -o build/ji
Here's the output of make clean:
rm -f src/*.o
rm -fr build

How to use filter with *F in Makefile?

There is this line in my Makefile:
$(CC) $(CFLAGS) -o $# -c $(filter %$(*F).cpp, $(SOURCES))
Suppose I have 2 cpp file like "docinfo.cpp" and "info.cpp", when g++ build "docinfo.cpp" to "docinfo.o", it works.
g++ -I ... -o docinfo.o -c docinfo.cpp
But when g++ build "info.cpp" to "info.o", it has an error.
g++ -I ... -o info.o -c docinfo.cpp info.cpp
How do I make it work?
This is my Makefile:
CC := gcc
RM := rm -rf
WORKSPACE := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TARGET := $(WORKSPACE)test.so
SOURCES := $(foreach dir,$(WORKSPACE),$(wildcard $(dir)source/*.c))
INCLUDE := -I$(WORKSPACE)include/
CFLAGS := $(INCLUDE) -O0 -Wall -fPIC
#CFLAGS += -g
#CFLAGS += -D__DEBUG__
OBJS := $(notdir $(SOURCES:.c=.o))
OBJ_PATH := $(WORKSPACE)object/
OBJS_O := $(addprefix $(OBJ_PATH), $(OBJS))
LIB_PATH := $(WORKSPACE)lib
LIBS := -ldl -shared
.PHONY: all clean
all: $(OBJ_PATH) $(LIB_TAG) $(TARGET)
$(OBJ_PATH):
mkdir -p $#
$(TARGET): $(OBJS_O)
$(CC) $(CFLAGS) -o $# $^ -L$(LIB_PATH) $(LIBS)
#echo "$#"
$(OBJS_O): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(filter %$(*F).c,$(SOURCES))
clean:
-$(RM) $(OBJS_O) $(OBJ_PATH) $(TARGET)
First, why don't you just use $< rather than trying to filter out something from $(SOURCES)?
$(CC) $(CFLAGS) -o $# -c $<
If, for some weird reason, you do need the filter, then if you don't want to return a match for any value ending with $(*F).cpp, then just don't prefix it with the pattern match character (%):
$(CC) $(CFLAGS) -o $# -c $(filter $(*F).cpp, $(SOURCES))
This is weird, though, because $(*F) should expand to foo.cpp which means this would resolve to foo.cpp.cpp.
So, I think there's something quite unusual (or possibly incorrect) about your makefile... but since you've only provided the recipe and not shown us the entire rule we can't say for sure.
ETA
Now that we see your makefile, sure enough it has a problem. This rule is wrong:
$(OBJS_O): $(SOURCES)
$(CC) ...
What does this expand to, once variables are resolved? Say you have SOURCES resolving to source/foo.c source/bar.c and OBJS_O resolving to object/foo.o object/bar.o. Then the above rule resolves to:
object/foo.o object/bar.o: source/foo.c source/bar.c
$(CC) ...
What does make do here? It doesn't magically do some kind of file-by-file matching of targets to prerequisites. It interprets this rule as if you'd written this:
object/foo.o: source/foo.c source/bar.c
$(CC) ...
object/bar.o: source/foo.c source/bar.c
$(CC) ...
That is, every object depends on all the source files, so if any source file is changed every object is rebuilt.
If you want this to work correctly and put all the object files into a single directory regardless of which source directory they exist in, then you'll have to use vpath with a pattern rule, like this:
vpath %.c $(sort $(dir $(SOURCES)))
$(OBJ_PATH)%.o : %.c
$(CC) $(CFLAGS) -o $# -c $<
Now you can use $< instead of the filter function, because each object file depends on exactly and only its source file, not all the source files.

How do I write a "selective" Makefile?

noob question here.
I have a directory with a lot of .c files, they're basicely libc functions that I code myself as an exercice.
I write a little main() in these files to test the functions, and I want to write a Makefile that allow me to compile only the file I want to test, for exemple:
make memset.c
And get only the executable of the code wrote in memset.c.
I tried to do something like this:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
all : %.o
$(CC) $(CFLAGS) $<
%.o : %.c
$(CC) $(CFLAGS) $< -c -o $#
But obviously it doens't work. I don't what to put in place of the "all".
I know it's very basic, but I didn't manage to do it, and I did research but didn't find an answer to this specific question.
Thanks in advance for your help.
If you do make -n -p you get a dump of all of the built-in rules in make. In GNU Make 4.1, this includes:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
So you might just needs a % in your makefile where you currently have all.
You also might find that you don't need those rules which are already built in. Suppose you have three C files, each with a main() as you specify: abs.c, div.c and fmax.c. Your Makefile needs to be no more than two lines:
CFLAGS = -Wall -Wextra -pedantic
all: abs div fmax
which would then allow you to do make abs to make the abs executable, and make all to make them all.
You can define static pattern rules to build the object files and the executables and then invoke make with the name of the executable you want as the goal:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
SRC := $(wildcard *.c)
OBJ := $(patsubst %.c,%.o,$(SRC))
EXE := $(patsubst %.c,%,$(SRC))
.PHONY: all obj
all: $(EXE)
obj: $(OBJ)
$(EXE): %: %.o
$(CC) $(LDFLAGS) $< -o $#
$(OBJ): %.o: %.c
$(CC) $(CFLAGS) $< -c -o $#
.PHONY: clean
clean:
rm -f $(OBJ) $(EXE)
Then:
$ make memset.o
builds only memset.o,
$ make memset
builds only memset (and memset.o if needed),
$ make obj
builds all object files,
$ make # or make all
builds all executables (and object files if needed), and
$ make clean
deletes all executables and object files.
With wildcard, you can achieve what you want.
Note that if each program depends on only one .c file, you don't need %.o rules:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
SRC := $(wildcard *.c)
EXEC = $(SRC:%.c=%)
all: $(EXEC)
%: %.c
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
And just invoke this way for instance:
make memset
You already have most you to compile the executable selectively:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
%.o : %.c
$(CC) $(CFLAGS) $< -c -o $#
% : %.o
$(CC) $(LDLAGS) $< -o $#
Then you just need to call make with the target you want, the executable:
make select
If you have several sets of executable with different flags, you can use:
EX0 = drink clean
${EXE0}: % : %.o
$(CC) $(LDLAGS) -lwater $< -o $#
EX1 = burn melt
{EX1}: % : %.o
$(CC) $(LDLAGS) -lfire $< -o $#

Make does not compile good files

I've got a problem with a Makefile, it just compiles many time the same file.
Here are my files:
$ ls *
carnet.data carnet.l carnet.y Makefile
struct:
carnet.c carnet.h ihm.c ihm.h struct.c struct.h
Here is my Makefile:
CC = gcc
LEX = lex
YACC = yacc
FLAGS = -Wall -Wextra -Werror -O3 -g
ELIB = -lfl # Flex library
TARGET = carnet
SRC = $(shell find struct/ -name "*.c")
OBJ = $(SRC:.c=.o)
SRCL = $(shell find -name "*.l")
OBJL = lex.yy.o
SRCY = $(shell find -name "*.y")
OBJY = y.tab.o
all : $(TARGET)
$(TARGET) : $(OBJ) $(OBJY) $(OBJL)
#echo "Linking"
#echo $(SRC)
#echo $(OBJ)
#$(CC) $^ -o $# $(FLAGS) $(ELIB)
$(OBJY) : $(SRCY)
#echo $<
#$(YACC) -d $<
#$(CC) -c y.tab.c -o $#
$(OBJL) : $(SRCL)
#echo $<
#$(LEX) $<
#$(CC) -c lex.yy.c -o $#
$(OBJ) : $(SRC)
#echo $<
$(CC) -c $< -o $# $(FLAGS)
clean :
rm y.tab.c $(OBJY) y.tab.h lex.yy.c $(OBJL)
rm $(OBJ)
destroy :
rm $(TARGET)
rebuilt : destroy mrpropper
mrpropper : all clean
And here is the output when I do a 'make':
struct/struct.c
gcc -c struct/struct.c -o struct/struct.o -Wall -Wextra -Werror -O3 -g
struct/struct.c
gcc -c struct/struct.c -o struct/carnet.o -Wall -Wextra -Werror -O3 -g
struct/struct.c
gcc -c struct/struct.c -o struct/ihm.o -Wall -Wextra -Werror -O3 -g
carnet.y
carnet.l
Linking
struct/struct.c struct/carnet.c struct/ihm.c
struct/struct.o struct/carnet.o struct/ihm.o
As we can see, when I do a 'echo $(SRC)' he finds all three files, but he only compiles the 'struct.c' file, and I don't understand why !
Thanks for your help,
Phantom
SRC = $(shell find struct/ -name "*.c")
You create a list here, $(SRC) will be struct/struct.c struct/carnet.c struct/ihm.c. Or any other order find may return, but according to your result, this seems to be the order.
OBJ = $(SRC:.c=.o)
This creates the modified list struct/struct.o struct/carnet.o struct/ihm.o
$(OBJ) : $(SRC)
#echo $<
$(CC) -c $< -o $# $(FLAGS)
Here we go, (partial, for clarity) expansion leads to
struct/struct.o struct/carnet.o struct/ihm.o : struct/struct.c struct/carnet.c struct/ihm.c
#echo $<
$(CC) -c $< -o $# $(FLAGS)
So you have a rule applied for building 3 targets, fine. Now, $< expands to the first prerequisite, which is struct/struct.c here.
One possible (and common) solution if you use a make capable of it, e.g. GNU make, is to use pattern rules instead of this find-hack:
struct/%.o : struct/%.c
#echo $<
$(CC) -c $< -o $# $(FLAGS)
Note that normally, you just maintain ONE list of the modules of your taget in your Makefile, usually the object files, manually, like here:
OBJS:= struct/struct.o struct/carnet.o struct/ihm.o

Using a Makefile to store object files in two different directories? [C]

I need to modify the Makefile I have to store only the object file associated with "record.c" into the bin folder. Here is what my directory structure looks like before executing Make.
bin/
include/
-hash_table.h
-history.h
-parser.h
-record.h
-shell.h
-variables.h
lib/
obj/
src/
-hash_table.c
-history.c
-parser.c
-record.c
-shutil.c
-sshell.c
-variables.c
...and here is the Makefile:
# Beginning of Makefile
SRC = src/shutil.c src/parser.c src/sshell.c src/history.c src/hash_table.c src/variables.c src/record.c
OBJS = obj/shutil.o obj/parser.o obj/sshell.o obj/history.o obj/hash_table.o obj/variables.o bin/record.o //<----
HEADER_FILES = include/shell.h include/parser.h include/history.h include/hash_table.h include/variables.h include/record.h
EXECUTABLE = sshell
LIBS = lib/libshell.so lib/libparser.so lib/libhistory.so lib/libhash_table.so lib/libvariables.so lib/librecord.so
LIBCFLAGS = $(CFLAGS) -D_REENTRANT -fPIC
CFLAGS = -Wall
CC = gcc
# End of configuration options
#What needs to be built to make all files and dependencies
all: $(EXECUTABLE)
#Create the main executable
$(EXECUTABLE): $(OBJS) $(LIBS)
$(CC) -o $(EXECUTABLE) obj/sshell.o -Llib -lparser -lshell -lhistory -lhash_table -lvariables -lrecord
#Create the library files
lib/libparser.so: obj/parser.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libshell.so: obj/shutil.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libhistory.so: obj/history.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libhash_table.so: obj/hash_table.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libvariables.so: obj/variables.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/librecord.so: bin/record.o //<----
$(CC) $(LIBFLAGS) -shared $^ -o $#
#Recursively build object files
obj/%.o: src/%.c //<---- I feel like this is causing the problem.
$(CC) $(CFLAGS) -I./include/ -c $< -o $#
#Define dependencies for objects based on header files
#We are overly conservative here, parser.o should depend on parser.h only
$(OBJS) : $(HEADER_FILES)
clean:
-rm -f $(EXECUTABLE) obj/*.o lib/*.so lib/*.a bin/*.o
-rm -f .sshell_history.txt
run: $(EXECUTABLE)
(export LD_LIBRARY_PATH=lib; ./$(EXECUTABLE))
# End of Makefile
With what I have done (most likely completely off) it doesn't compile record.c and says bin/record.o does not exist. I am not really experienced with Makefiles so I am wondering if I can have some help. Thanks!
Try using the rule .c.o instead of obj/%.o: src/%.c
Edit:
If that doesn't work, maybe adding the following rule will do the job:
bin/%.o: src/%.c
$(CC) $(CFLAGS) -I./include/ -c $< -o $#

Resources