GNU Make: different dependencies of several binaries in the same target? - c

First of all, I'm not familiar with GNU Make, so if I state some concept ridiculously wrong, please correct them instead of teasing me, thanks.
I want to have a default target that builds several executables with different dependencies, but I can't figure it out. Here is a minimal example I am using:
CC = gcc-4.8
CFLAGS = # some compiler flags
LDFLAGS = # some linker flags
SOURCES = prog1.c prog2.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = prog1 prog2
$(TARGET) : $(OBJECTS)
$(CC) $(CFLAGS) -o prog1 prog1.o $(LDFLAGS)
$(CC) $(CFLAGS) -o prog2 prog2.o $(LDFLAGS)
.PHONY: clean
clean:
#rm -f $(TARGET) $(OBJECTS) core
But, as you can see, though prog2 is not at all related to prog1.c, editing prog1.c will result in the relinking of prog2. Is there any way to prevent this?
(Also, I would really appreciate it if someone can direct me to a good tutorial to GNU Make. The official documentation is huge...)

Each target has to have its own set of prerequisites; if you write:
foo bar: biz baz
that means "foo depends on biz and baz, and bar also depends on biz and baz". You want to write:
prog1: prog1.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
prog2: prog2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
Alternatively, you can write both targets in the same rule and define the prerequisites separately:
prog1 prog2:
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
prog1: prog1.o
prog2: prog2.o
There are lots and lots of ways to make this more sophisticated and reduce typing. That's kind of what make is all about.
Update:
To build two targets at the same time by default, use
all: prog1 prog2
prog1 prog2:
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
prog1: prog1.o
prog2: prog2.o
where all is the first target.

Related

How to make static libraries with Makefile?

This is the Makefile
CC=gcc
CFLAGS=-Wall -pedantic -Werror -g
LDFLAGS=-lm
RM=rm -f
SOURCES=$(wildcard *.c)
TARGETS=$(SOURCES:.c=)
OBJECTS=$(SOURCES:.c=.o)
.PHONY: all clean
all: test_stack
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $#
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
%.a: %.o
ar rcs $# $<
ranlib $#
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
clean:
$(RM) $(OBJECTS) $(TARGETS)
I have the files genstacklib.c, genstacklib.h and test_stack.c
Now I want to compile genstacklib as static library
When test_stack calls the methods of genstacklib, it throws an exeception:
for example: "undefined reference to `genStackNew'"
I don't get why test_stack can't access the methods, for my current understanding it should have access to the library.
Please copy and paste the exact errors you get into your question, with proper formatting, and also including the compile or link command that make printed. A statement like "throws an exception" is not precise and in fact is not really accurate because exceptions are thrown from running programs, but (if I understand your problem correctly) you are not able to link your program.
The problem is that the order of arguments to the linker is critical: all libraries must appear on the link line after all object files. Also the order of libraries matters but since you have only one that's not an issue.
In your rule:
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
The $^ variable expands to the prerequisites, in this case genstacklib.a test_stack.o. So on your link line the library will appear before the object file, which won't work. Rewrite your rule like this:
test_stack: test_stack.o genstacklib.a
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
so the library comes after the object files and it will probably work.
As an aside, the variable LDFLAGS generally contains flags that manage the linker. Library references like -lm are traditionally put into a variable LDLIBS instead. Of course this is just convention but it's useful to follow conventions unless there's a good reason not to.

Makefile not compiling all C files in directory

Iam working with gcc and MinGW on a Windows platform. I have a directory containing two *.c files:
main.c and funcs.c
I am using the following makefile:
CC=gcc
CFLAGS=-c
LDFLAGS=
SOURCEDIR = src
BUILDDIR = build
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(BUILDDIR)/%.o,$(SOURCES))
LIBRARIES=-L/mingw64/lib
INC= -I./include
EXECUTABLE=testLink
VPATH = src include build
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBRARIES) -o ./dist/$#
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
Which should take the *.c files and generate *.o files with the same name. However I get the following output on make -
$ make
gcc -I./include -c src/funcs.c -o build/funcs.o
gcc -I./include -c src/funcs.c -o build/main.o
gcc build/funcs.o build/main.o -L/mingw64/lib -o ./dist/testLink
followed of course by a bunch of multiple definition errors. As you can see from the first two lines it is taking the same *.c file and compiling it twice into two different *.o files.
I am new to makefiles but I assume it is something wrong with my $(OBJECTS) rule and I'm pretty sure it's the $< which is causing the problem. I'm trying to create a generic makefile which will always work on my projects which have the same directory structure and take .c files turn them into .o files and link. Am I going about this entirely the wrong way or is there a simple fix to my makefile?
Thanks!
James
This rule:
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
expands to:
funcs.o main.c: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
which is equivalent to:
funcs.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
main.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
$< refers to the first dependency (funcs.c) so your Makefile is trying to generate both funcs.o and main.o from the same source.
You just want a generic rule using % wildcard matching:
%.o: %.c
$(CC) $(INC) $(CFLAGS) $< -o $#
See https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Jeff pointed the mistake in his answer (all objects depend on all sources: that isn't a generic compilation rule for c sources).
However, the generic rule must have source & object paths. To sum it up, just replace
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
by
$(BUILDDIR)/%.o : $(SOURCEDIR)/%.c
$(CC) $(INC) $(CFLAGS) $< -o $#
(as explained in How to generate a Makefile with source in sub-directories using just one makefile)
note that this kind of dependency test doesn't take included .h files into account, so it's only intended for first builds. Modifying .h files afterwards doesn't trigger a compilation since the header files are not listed as dependencies.

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.

Make different executables one library used by all

I have a project with the following structure:
- main1.c
- main2.c
- main3.c
- lib.h
- lib.c
All the mains use the import lib.
How can I write a Makefile that creates 3 executables (one per each main)?
First Approach
I created a Makefile that does that, but you'd need to append the name of the executable after calling the make command (i.e. make main1, make main2, etc), However if I try using only make (without arguments), it only makes the first main (main1).
CC=gcc
CFLAGS=-g -O2 -Wall
LDFLAGS=-framework OpenCL
DEPS=lib.h
OBJS=main1.o main2.o main3.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
main1: lib.o main1.o
$(CC) $(CFLAGS) -o $# $^
main2: lib.o main2.o
$(CC) $(CFLAGS) -o $# $^
main3: lib.o main3.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
clean:
rm -f *.o main1 main2 main3
Makefile
https://www.gnu.org/software/make/manual/html_node/Goals.html
By default, the goal is the first target in the makefile (not counting
targets that start with a period). Therefore, makefiles are usually
written so that the first target is for compiling the entire program
or programs they describe.
So just add the below line as the first target in your makefile:
all: main1 main2 main3

Makefile doesn't rebuild objects on header modification

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.

Resources