Makefile doesn't rebuild objects on header modification - c

I have made a Makefile for compiling my C programm but it's not building object when i change one of the headers.
My MakeFile:
CC=gcc
CFLAGS=-O3 -Wall
LDFLAGS=-I/usr/include/mysql -L/usr/lib/x86_64-linux-gnu -lmysqlclient
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=bin/beta_parser
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) -o $# $^ $(CFLAGS) $(LDFLAGS)
%.o:%.c types.h cstes.h headers.h mysql.h
$(CC) -o $# -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper:
rm -rf $(EXEC)
What have I done wrong ?
EDIT : Corection of the Makeil after a great comment.

Although there are other more elegant tricks, in your case, I think something like
$(OBJECTS): types.h cstes.h headers.h mysql.h
%.o: %.c
$(CC) -o $# -c $< $(CFLAGS)
should be sufficient.

Scanning your sources for dependencies is outside the scope of Make (although there are other tools, such as CMake which will do this automatically). You need to add an explicit rule to generate these dependencies, but this can be done in many different ways. I've sometimes used the following technique:
OBJECTS = ....
-include $(OBJECTS:.o=.d)
...
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(CC) $(CFLAGS) $(DEPFLAGS) $< > $*.d
Google for "make automatic dependency generation" will show you other ways to do it as well.

Related

Makefile how to use logical OR between prerequisites?

My source files are organized nicely in a folder, that contains subfolders, that also contains source files.
The subfolders don't branch any further.
All object files are just meant to be created and stored in the same folder.
I don't want to manually list the name of the subdirs in the prerequisites when writing the target that generates my object files:
Right now this works:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir1)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir2)/%.c
$(CC) -c $< -o $# $(CFLAGS)
...
But I want it to look something like this:
$(OBJ)/%.o: $(SRC)/%.c OR $(SRC)/*/%.c
$(CC) -c $< -o $# $(CFLAGS)
I understand that the title most likely isn't the real question to be asked, but I'm looking for any solution. Also, I know that the * doesn't work as a placeholder here.
First, you can simplify the makefile you have by using vpath:
$(OBJ)/%.o: %.c
$(CC) -c $< -o $# $(CFLAGS)
vpath %.c $(SRC) $(SRC)/$(subdir1) $(SRC)/$(subdir2)
Then, if you really don't want to specify the subdirectories:
vpath %.c $(shell find $(SRC) -type d)

How to explicitly link library path via makefile

I installed a real-time library libre from brew install libre in my macOS. It is located in the directory /usr/local/Cellar/libre/0.5.7. I am trying to explicitly add this path in Makefile so I declare RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7. The entire makefile looks like this:
TARGET = run
LIBS = -O2 -lm
CC = gcc-7
CFLAGS = -fopenmp
RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7/lib
.PHONY: default all clean
all: $(TARGET)
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
#$(CC) $(CFLAGS) $(RT_LIBS_PATH) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
#$(CC) $(OBJECTS) $(CFLAGS) $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
However, it seems makefile does not recognize the libre, thus I assume I use RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7/lib in a wrong way. Kindly, is there something wrong in this way?
You have to specified library path when you are creating .o, you have to specify it when link all objs into executable
$(TARGET): $(OBJECTS)
#$(CC) $(OBJECTS) $(CFLAGS) $(RT_LIBS_PATH) $(LIBS) -o $#

C shared library problems

I am trying to create a shared library called -lrfc7539
with the structure below:
rfc7539.o: rfc7539.c chacha20poly1305.o
$(CC) $(CFLAGS) -c -o $# $<
chacha20poly1305.o: chacha20poly1305.c chacha20.o poly1305.o
$(CC) $(CFLAGS) -c -o $# $<
chacha20.o: chacha_merged.c
$(CC) -fPIC $(CFLAGS) -c -o $# $<
poly1305.o: poly1305-donna.c
$(CC) -fPIC $(CFLAGS) -DPOLY1305_16BIT -c -o $# $<
rfc7539_test: rfc7539.o chacha20poly1305.o poly1305.o chacha20.o
.PHONY: clean
clean:
#rm -f *.o
#rm -f rfc7539_test
I then do this command gcc -shared -o lrfc7539.so *.o to create .so file
Is there a better practice for my makefile to be able to do this automatically ?
You need to create a target in your makefile that runs the gcc command you gave. If this library is the main output, make an all target pointing to in.
all: lrfc7539.so
lrfc7539.so: rfc7539.o chacha20poly1305.o chacha20.o poly1305.o
gcc -shared -o $# *.o
You can just make a rule with that target:
librfc7539.so: rfc7539.o chacha20poly1305.o poly1305.o chacha20.o
$(LINK.c) $(OUTPUT_OPTION) -shared $^ $(LOADLIBES) $(LDLIBS)
I copied the command from make --print-data-base (you could update your other commands likewise). You may need to add -fPIC to LDFLAGS, too.
I called your library librfc7539.so so that you can link to it using -lrfc7539 - I think that's what you're wanting.
I believe it's best practice to explicitly specify the object files you intend to link, but some like to assume that every source file must be compiled and linked:
sources := $(wildcard *.c)
librfc7539.so: $(sources:.c=.o)
This wouldn't work for you, though, unless you renamed the source files that are compiled to differently-named object files.
I note that it's strange that your object files depend on other object files. That shouldn't be the case, although they may need dependencies on some header files.
Here's a complete Makefile (assuming GNU Make):
CFLAGS += -Wall -Wextra
CFLAGS += -fPIC
LDFLAGS += -fPIC
%.so: LDFLAGS += -shared
all: rfc7539_test librfc7539.so
librfc7539.so: rfc7539.o chacha20poly1305.o poly1305.o chacha20.o
$(LINK.c) $(OUTPUT_OPTION) $^ $(LOADLIBES) $(LDLIBS)
rfc7539_test: rfc7539.o chacha20poly1305.o poly1305.o chacha20.o
$(LINK.c) $(OUTPUT_OPTION) $^ $(LOADLIBES) $(LDLIBS)
# Default %.o:%.c rule works, except for these files with misnamed sources:
chacha20.o: chacha_merged.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
poly1305.o: poly1305-donna.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
# Specific flags for this source file
poly1305.o: CFLAGS += -DPOLY1305_16BIT
.PHONY: clean
clean:
#$(RM) *.o
#$(RM) rfc7539_test
.DELETE_ON_ERROR:

passing target name to secondary targets

The makefile has multiple targets which will called for all files in the directory. The automatic variable does not get replaced for the target.
TARGETS += txyz_abc txyz_def
.PHONY: all clean
all: $(TARGETS)
txyz_abc: $(UY_DIR)/$(OBJ)/support.o \
$(UX_DIR)/$(OBJ)/%.o
$(CC) $(CFLAGS) -c $< -o $#
$(UX_DIR)/$(OBJ)/%.o: %.c
$(call mkdir, $(UX_DIR)/$(OBJ))
$(CC) $(CFLAGS) -c $< -o $#
$(UY_DIR)/$(OBJ)/support.o: $(UY_DIR)/src/support.c
$(call mkdir, $(UY_DIR)/$(OBJ))
$(CC) $(CFLAGS) -c -o $# $<
on make support.o is generated. but throws an error that no rule to make target '../ux_src/obj/%.o", needed by 'txyz_abc'.

Gnu make exclusive OR (kinda) in prerequistires list?

I have a pattern rule like this:
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Is it possible to do something like:
$(BIN_DIR)/%: $(SOURCES_DIR)/%.c OR $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Where OR means if there the target $(BIN_DIR)/progname requsted, first look for $(SOURCEDS_DIR)/progname.c and it will be the only prerequisite. If there is no such file, prerequisites list will be $(SOURCES_DIR)/progname/*.c as it is now in the original rule? Maybe some other way to achieve this behaviour?
Full Makefile (tests ommited as irrelevant):
SOURCES_DIR = src
INCLUDE_DIR = $(SOURCES_DIR)/include
OBJECTS_DIR = build
BIN_DIR = bin
LIB_DIR = lib
INCLUDE_FLAGS = -I$(INCLUDE_DIR)
CFLAGS=-g --std=c99 -Wall -Wextra -O2 $(INCLUDE_FLAGS)
LDLIBS=-ldl -lm $(OPTLIBS)
LIB_SOURCES=$(wildcard $(SOURCES_DIR)/lib*)
BIN_SOURCES=$(filter-out $(INCLUDE_DIR) $(LIB_SOURCES),\
$(patsubst %.c,%,$(wildcard $(SOURCES_DIR)/*)))
BINS=$(addprefix $(BIN_DIR)/, $(notdir $(BIN_SOURCES)))
OBJECTS=$(patsubst %.c,%.o,\
$(subst $(SOURCES_DIR),$(OBJECTS_DIR),\
$(wildcard $(SOURCES_DIR)/lib**/*.c)))
LIBS=$(addsuffix .a, $(addprefix $(LIB_DIR)/, $(notdir $(LIB_SOURCES))))
SO_LIBS=$(patsubst %.a,%.so,$(LIBS))
all: $(OBJECTS) $(LIBS) $(SO_LIBS) $(BINS)
$(OBJECTS_DIR)/%.o: CFLAGS+= -fPIC
$(OBJECTS_DIR)/%.o: $(SOURCES_DIR)/%*
#mkdir -p $(#D)
$(CC) $(CFLAGS) -c $(SOURCES_DIR)/$*.c -o $# $(LDFLAGS) $(LDLIBS)
$(LIB_DIR)/%.a: $(OBJECTS)
$(AR) rcs $# $(OBJECTS_DIR)/$*/*.o
ranlib $#
$(LIB_DIR)/%.so: $(LIBS)
$(CC) -shared $(OBJECTS_DIR)/$*/*.o -o $# $(LDFLAGS) $(LDLIBS)
# the rule i'm talking about
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Confession: tl;dr
Is it possible to do something like:
$(BIN_DIR)/%: $(SOURCES_DIR)/%.c OR $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
You can do it by declaring the pattern rule twice.
Put the recipe in a macro to avoid writing that twice.
define recipe
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
endef
$(BIN_DIR)/%: ${SOURCES_DIR}/%.c
$(recipe)
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(recipe)
Ok, but don't do this.
Pattern rules are an ugly hack IMHO—I don't like the ambiguity.
Different make versions do different things.
(Wildcards aren't much better, but I won't comment further here.)
It always feels cleaner to write explicitly what you want.
You can still use patterns,
but use static pattern rules by explicitly listing the targets that the patterns apply to.
recipe = $(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
single-source-targets := $(addprefix ${BIN_DIR}/,counter filter)# for example
multi-source-targets := $(addprefix ${BIN_DIR}/,engine database)
${single-source-targets}: ${BIN_DIR}/%: ${SOURCES_DIR}/%.c ; $(recipe)
${multi-source-targets}: ${BIN_DIR}/%: ${SOURCES_DIR}/%/*.c ; $(recipe)
Its impossible to give a specific answer without the entire Makefile.
But since this is a question of two variable file paths: conditional search directories ($(SOURCES_DIR) or $(SOURCES_DIR)/progname), AND conditional files to search for ($(SOURCES_DIR)/progname.c or $(SOURCEDS_DIR)/progname/*.c), the solution is more complicated than a simple makefile rule.
The best way I can think of is to use conditionals to set the dependency directory and filename as shown below.
ifneq ("$(wildcard $(SOURCES_DIR)/progname.c)","")
DEPS = $(SOURCES_DIR)/progname.c
else
DEPS = $(SOURCES_DIR)/progname/*.c
endif
$(BIN_DIR)/%: $(DEPS)
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Well, i got what i want, even though i don't really like how I did this, so any other variants are appritiated. It's difficult to build prerequisites list conditionally, so i decided to use different targets, and then just copy files where i wanted. This did the job, but still not very pretty. I just added following lines to the Makefile:
ONEFILERS_SOURCES=$(wildcard $(SOURCES_DIR)/*.c)
ONEFILERS=$(patsubst %.c,%,$(subst $(SOURCES_DIR),$(ONEFILERS_TMP),\
$(ONEFILERS_SOURCES)))
$(ONEFILERS_TMP)/%: $(SOURCES_DIR)/%.c $(SHARED_INCLUDES)
#mkdir -p $(#D)
$(CC) $< $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
#install $# $(BIN_DIR)
Any better solutions are welcome.

Resources