Is this makefile example correct? - c

I'm looking at this makefile example from an academic course I'm following and some doubts emerged. Hope you will be able to clarify them.
(1) I'm wondering why the automatic variable $^ in the $(SRCDIR)/%.o: %.c receipe is needed? Couldn't just $(CC) -c $< $(CFLAGS) $(LDFLAGS) suffice?
(2) Regarding the % wildcard, if I have for instance ./src/main.c, $(SRCDIR)/%.o: %.c will be translated to ./src/main.o : ./src/main.c or just ./src/main.o : main.c ? In the second case, wouldn't the resulting receipe be wrong?
$(CC) -c ./src/main.c $(CFLAGS) $(LDFLAGS) VS $(CC) -c main.c $(CFLAGS) $(LDFLAGS)
(3) Also, why is -lpthread needed? Is it something related to the makefile options or it means just that some of the files are potentially using the pthread library? I thought many of this basic libraries were already present in the basic GNU toolchain.
Thanks in advance as always.
NAME = myprog
CC = gcc
CFLAGS = -Wall -O3 -I $(INCDIR)
LDFLAGS = -lpthread -lm
SRCDIR = ./src
INCDIR = ./include
BINDIR = /usr/local/bin
SOURCES = $(SRCDIR)/main.c $(SRCDIR)/dummy_functions.c
OBJECTS = $(SOURCES:.c=.o)
all: $(NAME)
$(NAME): $(OBJECTS)
$(CC) $^ -o $# $(CFLAGS) $(LDFLAGS)
$(SRCDIR)/%.o: %.c
$(CC) $^ -c $< $(CFLAGS) $(LDFLAGS)
clean:
...

Yikes. You should definitely not try to learn how to write makefiles from this course :-/.
For (1), you definitely do not want to use $^ when compiling, because it will add all your header files (should you declare any or set up to autogenerate them) to the compile line which is wrong. It should use $<.
For (2), you're right: the % is identical between the target and prerequisite, or the pattern rule doesn't match. The pattern rule should be either %.o : %.c or else $(SRCDIR)/%.o : $(SRCDIR)/%.c, or else you need to set VPATH = $(SRCDIR) in your makefile so make knows where to look for sources it can't find.
For (3), this is not related to make or makefiles: if your code uses threading then you need to add this option to the link line or you'll get link errors. Technically this is obsoleted by the -pthread option which should appear on both the compile and link lines. The compiler/linker do not add these libraries on their own you have to do it yourself.

$< expands to the first dependency. $^ contains them all. If the target has multiple dependencies (perhaps via a separate dependency declaration somewhere else in the Makefile), $< will not contain them all. Whether that is incorrect will depend on additional circumstances, but typically I would say it is at least surprising (and if you really only want the first file, you should spell that out in a comment at least).

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.

No rule to make target 'main.o', needed by 'out'. Stop

I keep getting this error and I can't figure out what I am doing wrong. I am using an template so I can get in the dir bin the executable. The dir include the header files. The dir obj for the object files created and the src for the .c files.
My makefile
OBJ_dir = obj
INC_DIR = include
OBJECTS = main.o client.o private.o memory.o process.o proxy.o server.o
main.o = main.h memory-private.h stdio.h stdlib.h string.h syscall.h unistd.h wait.h sysexits.h memory.h
client.o = client.h
private.o = private.h
memory.o = memory.h memory_private.h
process.o = process.h
proxy.o = proxy.h
server.o = server.h
CC = gcc
CFLAGS = -Wall –I $(INC_DIR)
LIBS = -lm
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
clean:
rm –f *.o out
rm –f out
There are many issues here. It's probably a good idea to read at least the first few chapters of the GNU make manual to understand how make and makefiles work.
Take this rule:
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
First, it's not right to list a different target than the file you actually build. Here you told make you'd build a target named out, but your recipe actually builds a target named bin/out. That's wrong.
Second, but similarly, it's not right to have your target depend on one set of prerequisites (the files defined by $(OBJECTS)) but then have the recipe of your rule use a completely different set of prerequisites (by adding a $(OBJ_dir)/ prefix to all the files).
This tells make "please build files main.o, client.o, etc., but what my command will actually use is files obj/main.o, obj/client.o, etc.". It doesn't make sense to tell make to build targets that you aren't going to actually use.
This should be:
bin/out: $(addprefix $(OBJ_dir)/,$(OBJECTS))
$(CC) $^ -o $# $(LIBS)
In general if you ever find yourself writing a recipe where you are modifying the automatic variables like $# or $^ instead of using them as-is, you're almost certainly doing something wrong.
Next your pattern rule has other issues:
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
First, you cannot use automatic variables like $# in a prerequisite list. Those values are only set when expanding the recipe of a rule. They are not set (empty) when evaluating the prerequisite list. So $($#) expands to the empty string here and does nothing.
Second you have the same problem as above where you are not creating $# you are creating $(OBJ_dir)/$# which is wrong. You should write your rule like this:
$(OBJ_dir)/%.o: src/%.c
$(CC) $(CFLAGS) -o $# -c $<
so that the target lists the file you want to build, and the recipe uses $# without modification.
As for your prerequisites, you should just create them directly rather than trying to use fancy variables (which can't work). As the comment above suggests, just change:
proxy.o = proxy.h
to:
proxy.o : proxy.h
(and all the rest) and it will work. Note, though, that make always builds the first explicit target it sees by default so you may have to re-arrange your makefile a little bit if you want bin/out to be the default target.

How can I improve this Makefile to optimize the usage of the SRC and BIN folders?

This is my first attempt at making a Makefile after having gone through several tutorials and the gnu make manual. The Makefile works and creates the .o, .a and .exe files in the BIN folder. However, I have have added src\ and bin\ prefixes to all files. I know there must be a better way of addressing folder issues while using Makefiles. Only problem is, I am unable to figure it out after hours of editing and trying out different things, based on the tutorials. I find GNU make manual too overwhelming at this stage of my learning curve.
I am using MinGW GCC toolchain on Windows 7. I have copied mingw32-make.exe to make.exe for the purpose of trying out the tutorials and exampples I have been going through.
I would really appreciate any help on the subject. Thank you.
My Makefile is as follows:
CC = gcc
CFLAGS = -O3 -Wall -c
BIN = bin/
LDFLAGS = -L$(BIN) -lmyLib
all: test.exe
test.exe: test.o libmyLib.a
gcc bin\test.o -o bin\test.exe $(LDFLAGS)
test.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\test.o src\test.c
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
clean:
del bin\*.* /Q
First, there are some issues with your Makefile, even if it apparently works. When you write:
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
you are lying to make:
You tell it that the result of the rule is myLib.o while it is bin\myLib.o, that is, a different file.
You tell make that myLib.o depends on src\test.c while it in fact depends on src\myLib.c.
Same with your other rules as in:
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
You tell make that the rule shall be executed if myLib.o is newer than libmyLib.a while the real prerequisite is bin\myLib.o and the real target is bin\libmyLib.a.
By doing so you totally prevent make from doing what it is supposed to do: decide if a recipe must be executed or not, depending on the last modification times of target files and prerequisite files. Give it a try: run make twice and you'll see that it uselessly redoes what it did already. Never, never lie to make.
Second, you can improve your Makefile by using several advanced features like automatic ($#, $<, $^), standard (LDLIBS, AR, ARFLAGS) and regular (BIN, SRC) make variables. Here is an example of what you could try, after fixing the above mentioned issues and better using variables (plus adding the missing -I gcc option, and declaring all and clean as phony because these targets are not real files and we do not want to lie to make):
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/test.o: $(SRC)/test.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
$(BIN)/myLib.o: $(SRC)/myLib.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
clean:
del $(BIN)\*.* /Q
Now, all non-phony targets and prerequisites are regular files, the ones that are really involved in the rules. Again, give it a try and you'll see that make rebuilds only what is out of date and thus needs to be rebuilt.
If you want to get rid of the $(SRC)/ prefix you can use the vpath directive that tells make where to look for source files (I insist on source, many people try to use it for target files, this is not what it is intended for):
vpath %.h $(SRC)
vpath %.c $(SRC)
And then:
$(BIN)/test.o: test.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/myLib.o: myLib.c myLib.h
$(CC) $(CFLAGS) -o $# $<
Note: you could also use the VPATH variable instead of the vpath directive.
Pattern rules are used to factor similar rules, like, for instance, your compilation rules that differ only by the names of the source file and object file:
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
All in all:
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
clean:
del $(BIN)\*.* /Q
Finally, if you really want to avoid the $(BIN)/ prefix in your rules you will have to move to the $(BIN) directory and call make from there. You can leave the Makefile in the main directory and use the -f ../Makefile option, if you wish.
But of course this is less convenient that just typing make [goals] from the main directory. There are ways to let make test from where it has been called, and if it is not from the build directory, re-call itself with the -C and -f options such that it does its job from the build directory. But it is probably a bit too complicated if you are new to make.
If you are however interested have a look at this post that covers this topic (and more). If we simplify as much as possible what the post suggests and specialize it for your case, the final Makefile could be something like:
# here starts the black magic that makes it possible
.SUFFIXES:
BIN := bin
SRC := src
ifneq ($(notdir $(CURDIR)),$(BIN))
.PHONY: $(BIN) clean
$(BIN):
#$(MAKE) --no-print-directory -C $# -f ../Makefile SRC=$(CURDIR)/$(SRC) $(MAKECMDGOALS)
Makefile: ;
% :: $(BIN) ; :
clean:
del $(BIN)\*.* /Q
else
# here ends the black magic that makes it possible
# here starts the Makefile you would really like to write
CC := gcc
CFLAGS := -O3 -Wall -c -I$(SRC)
LDFLAGS := -L.
LDLIBS := -lmyLib
AR := ar
ARFLAGS := rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all
all: test.exe
test.exe: test.o libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
libmyLib.a: myLib.o
$(AR) $(ARFLAGS) $# $^
# here ends the Makefile you would really like to write
# a last bit of black magic
endif
The Makefile you would really like to write is what you would write if your source files and target files were all in the source directory. No prefixes any more; vpath takes care of the $(SRC)/ prefix and $(BIN)/ is useless because when this part of the Makefile is used we are already inside $(BIN).
Note: I know nothing about Windows and its various command line interfaces so there are probably some things to adapt (backslashes instead of slashes for instance).

Creating a more generic makefile

I have the following makefile:
CC=gcc
CFLAGS= ---
LDFLAGS = ---
all: abc_test
abc_test: abc_test.o defn_abc.o abc.o cmocka_compass.o
$(CC) $(LDFLAGS) abc_test.o defn_abc.o abc.o cmocka_compass.o -o
abc_test
abc_test.o : abc_test.c
$(CC) $(CFLAGS) abc_test.c
defn_abc.o : ../defn_abc.c
$(CC) $(CFLAGS) ../defn_abc.c
abc.o : ../abc.c
$(CC) $(CFLAGS) ../abc.c
knownfile.o : ../../../../../knownpath.c
$(CC) $(CFLAGS) ../../../../../knownpath.c
clean:
rm *o *.log abc_test
Which will work (changed some files names) but I want to make it generic. I tried the following but I keep getting errors that there are no targets.
CC=gcc
CFLAGS= ---
LDFLAGS = ---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,%(SRCFILES))
OBJFILES: all
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) %< -o %#
knownfile.o : knownpath.c
$(CC) $(CFLAGS) knownpath.c
the make file is a test folder, which contains all the test code (abs_test.c). This is also where all the objects should go. One directory up contains the c files defn_abc.c and abc.c.
Any idea what I am doing wrong?
UPDATE: Here is my latest makefile, with the error 'missing separator'
CC=gcc
CFLAGS=-c -Wall -DUNIT_TESTING -DSYS_LINUX -Ipath1 -Ipath2
LDFLAGS = -Wl,---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
all: $(PROG)
$(PROG): $(OBJFILES)
$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) %< -o %#
knownfile.o : knownpath.c
$(CC) $(CFLAGS) knownfile.c
This line does not do what you think it does:
OBJFILES: all
Or at least I assume so, for although it is mostly harmless, it is also useless. It declares that a target named 'OBJFILES' depends on target 'all'. It also happens to be the first target in the file, so it is the default target, but because 'all' is its prerequiste, it will cause the 'all' target to be rebuilt by default. This is precisely what would happen if you omitted that line altogether. Note, too, that this has nothing to do with the variable $(OBJFILES).
Your main problem appears to be that you are using the wrong syntax for most of your variable references. The values of variables with multi-character names are obtained via expressions of the form $(VAR) or ${VAR}, not %(var). The parentheses / braces can be omitted for single-character names. I advise you to favor the form with parentheses over the one with curly braces, especially in commands in recipes, for the latter is easy to confuse with shell syntax.
I would recommend you read about the basics of Makefile. This is a useful link intro to makefile
The variable OBJFILES is being over-written in consecutive lines in the example provided. I suspect removing line
OBJFILES: all
and using patsubst as
$(patsubst %suffix,%replacement,$(var))
might help.
#edit: Since now you asked on how to use LDFLAGS and get rid of the 'missing separator' error, here are some suggestions.
Purpose of LDFLAGS is to use to provide link time flags to compiler when all the object files are linked to make the final executable. They could look like this
all: $(PROG)
$(PROG): $(OBJFILES)
$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
The error 'missing seperator' is fixed by inserting tabs instead of space in the beginning of a line describing an action/recipe to a rule. Open the Makefile again in an editor and remove the spaces in front of below lines and replace with tab.. the arrow I am using to show a tab
---->$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
---->$(CC) $(CFLAGS) %< -o %#
---->$(CC) $(CFLAGS) knownfile.c

Rule not recognized in makefile?

I have a basic makefile to compile C files necessary for compiling a shared library, I have an error because the makefile is not recognized:
SOURCES=/home/test/project/sources
OBJECTS=/home/test/project/objects
$(OBJECTS)/%.o:$(SOURCES)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJECTS)/%.o
$(CC) -shared -o libsharedlib.so $<
When I run make I get that there is no rule for target: $(OBJECTS)/%.o needed by sharedlib. While the rule is written right before sharedlib.
The main problem is that nowhere you are explicitly telling make what your source files are. Start by doing that:
SOURCEDIR=/home/test/project/sources
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
Then, derive the object file names from the source file names by substituting .c for .o:
OBJECTDIR=/home/test/project/objects
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(OBJECTDIR)/%.o,$(SOURCES))
You can still keep your generic rule to build object files:
$(OBJECTDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) -fPIC -c $^ -o $#
But you give the explicit list of object files to the rule to make sharedlib:
libsharedlib.so: $(OBJECTS)
$(CC) -shared -o $# $<
Note that I made the name of the rule the same as the file that is being generated. That's important, because calling make twice in a row will then skip building the library a second time. You can always add an alias if you want:
sharedlib: libsharedlib.so
In that case, it's also good to tell make that sharedlib is not a real file:
.PHONY sharedlib
This prevents weird things from happening if you ever did have a file called sharedlib in the directory.
The library rule
sharedlib: $(OBJECTS)/%.o
is not enough to tell Make which objs are needed for the library.
This should work, and gives explicit control on which are the sources/objs pairs you want in the library:
SOURCESDIR=/home/test/project/sources
OBJECTDIR=/home/test/project/objects
OBJLIST = \
$(OBJECTS)/file1.o \
$(OBJECTS)/file2.o
$(OBJECTDIR)/%.o: $(SOURCESDIR)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJLIST)
$(CC) -shared -o libsharedlib.so $<

Resources