How do I write a "selective" Makefile? - c

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 $#

Related

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).

Multiple targets but same dependency

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.

Makefile: wildcard and patsubst does not change file source names

I am trying to write a Makefile for my project, all the *.c and *.h files are in a folder called src, and the Makefile looks like this --
CC := gcc
CFLAGS := -g -Wall -ansi -pedantic -std=gnu99
LDFLAGS := -lm
INCLUDES := $(wildcard src/*.h)
IFLAGS := $(addprefix -I/,$(INCLUDES))
SRC := $(wildcard src/*.c)
OBJS := $(patsubst %.c, %.o, $(SRC))
APP := app
all: $(OBJS)
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
clean:
rm -rf $(OBJS)
rm -rf *.out
rm -f $(APP)
At this point I am not building the executable, just trying to compile them to object files, so when I run, I am getting this output --
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/allocate.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/auxiliary.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/decode.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/display.o
You can see that in each gcc invocation, the source file names do not change, they are all always src/allocate.c why ? However, the object names are correctly expanded like src/allocate.o, src/auxiliary.o and src/decode.oetc.
It seems you've mixed up some things here.
They are basically two type of rules you need to use here, and they both share the same syntax:
targets : prerequisites
recipe
When you write this:
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
You're saying to make that you want to create $(APP), and to do that you need $(OBJS) to exist or to be created.
Now when you write this:
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
You're telling make you want to create a list of .o files, and for each individual file that you need all $(SRC) and $(INCLUDES).
Since in the recipe you're using $<, which is a shortcut for the first entry in the prerequisites list, you always end up with the same source file being compiled.
To do what you want, you must abstract things a little bit and tell make "Here is how I want you to build any .o file that depends on a corresponding .c". That is the job of pattern rules:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
Ultimately, your Makefile should look like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ)
Note another couple of things here that you missed:
The -I preprocessor flag (that should be placed in the CPPFLAGS variable) accept a directory, not a file.
The -ansi compiler flag is a synonym of -std=c89. You're using -std=gnu99 right after so that one will be picked ultimately
You don't need to list your header files at all. Don't bother.
Don't use the -r flag of the rm command without care, you'll end up removing folders. It is not used to remove multiple files but to remove recursively, read up your man.
You used $< instead of $^ at the linking phase, so your executable will miss many object files.
To address the comments:
GNU make has a lot of predefined rules, functions and variables that you should be using before rolling your own. It has basic rules for compiling and linking C and C++ programs, among other, this is why your Makefile does not need te redefine the %.o: %c rule that already exists.
You can see all of these by typing this in your favorite shell:
$ make -p > predefined.mk
$(RM), $(CC) are one of these predefined variables, you can see by yourself what they actually contain.
Now, as many users are concerned with header files dependencies, let's adress this issue. You won't have to manually do that, modern compilers like GCC and Clang do this for you once you set them up.
The dependencies for each .c file will be generated in a .d file that must be included in the Makefile.
To tell the compiler to generate these files while compiling, you need to pass a preprocessor flag:
CPPFLAGS := -MMD
Now the dependencies are auto-generated, we need to include them:
DEP := $(OBJ:.o=.d)
-include $(DEP)
You'd also want to clean them:
clean:
$(RM) $(APP) $(OBJ) $(DEP)
Now your Makefile looks like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ) $(DEP)
-include $(DEP)
Last point: the syntax $(SRC:.c=.o) is a shortcut for $(SRC:%.c=%.o) which is also a shortcut for $(patsubst %.c,%.o,$(SRC)).

Makefile does not make all targets

I am trying to have the compiled obj files in two different folder
dobjects: where the objects have the debug symbol (gcc with -g option)
sobjects: where the objects are compiled without the debug symbols.
Source files are the same,
I have the following makefile.
CC = gcc
CFLAGS = -Wall
OBJS = a.o b.o
SRCS = a.c b.c
SOBJS_DIR = sobjects
DOBJS_DIR = dobjects
SOBJS = $(addprefix $(SOBJS_DIR)/, $(OBJS))
DOBJS = $(addprefix $(DOBJS_DIR)/, $(OBJS))
all: release debug
release: $(SOBJS)
debug: $(DOBJS)
$(DOBJS_DIR)/%.o: CFLAGS += -g
$(DOBJS_DIR)/%.o $(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
rm dobjects/*
rm sobjects/*
But every time I try "make" only one target is made.
$ make
gcc -Wall -c a.c -o sobjects/a.o
gcc -Wall -c b.c -o sobjects/b.o
$ make
gcc -Wall -g -c a.c -o dobjects/a.o
gcc -Wall -g -c b.c -o dobjects/b.o
any help would be greatly appreciated
This rule does not do what you think it does:
$(DOBJS_DIR)/%.o $(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
Pattern rules with multiple targets tell make that one single invocation of the recipe will build BOTH targets. So when make runs that rule to build $(DOBJS_DIR)/a.o, make believes that $(SOBJS_DIR)/a.o was also built, so it doesn't try to run the rule to build it. But your rule doesn't actually build it, so when you run make a second time it sees that object file is missing and runs the above rule again, to build the missing one.
You have to write this as two different rules:
$(DOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#

How to use makefile to compile all sources (some only to object files)?

I'm getting an "undefined reference to main" error on one of my files when trying to compile. I know this is because this file doesn't have a main method. This is just an implementation file for some helper methods, so I only want it compiled to an object file not an executable. I know how to do this if I explicitly tell the makefile what to do for each file, but I'm trying to write a makefile that will compile all of my sources at once. I tried using the -c flag, but then it compiled all of my files to only object files rather than executables. How in the world do I do this?
Here it is:
CC = gcc
CFLAGS = -g -Wall
SRCS = ./src/server.c ./src/client_slave.c ./src/sockaddrAL.c
EXECS = ./bin/server ./bin/client_slave
OBJS = $(SRCS:.c=.o)
all: clean $(SRCS) server client
server: $(OBJS)
$(CC) $(CFLAGS) ./src/server.o -o ./bin/server
client: $(OBJS)
$(CC) $(CFLAGS) ./src/client_slave.o -o ./bin/client_slave
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You should add the -c flag to the rule that builds .o files (your .c.o suffix rule) and not add it to the rule that builds the executables (the $(EXECS) rule).
CC = gcc
CFLAGS = -g -Wall
EXECS = ./bin/server ./bin/client_slave
all: $(EXECS)
./bin/%: ./src/%.o ./src/sockaddrAL.o
$(CC) $(CFLAGS) -o $# $^
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You didn't show sockAddrAL at all in your question so I assumed it belonged in both executables. Also note that the above syntax assumes GNU make. If you want to use only features available in POSIX standard make you pretty much have to write it all out.
Let implicit rules be your friend. Your entire Makfefile should just be:
CC = clang
CFLAGS = -O0 -g -Wall
SRCS = server.c client_slave.c sockaddrAL.c
OBJS = $(SRCS:.c=.o)
EXECS = server
server: $(OBJS)
clean:
#rm -f $(EXECS) $(OBJS)
Invoke it from the src directory.

Resources