How to build multiple targets from one makefile - c

I'm trying to parameterize my makefile targets. Currently, it has a
TARGET = main
declaration near the top. It derives the SRC list from that as well as does lots of other things.
I've changed my C code though, so that I have multiple different top level .c files to basically get variant builds. So what I want to be able to do is basically do
make target1
or
make target2
And vary what TARGET is set to in the makefile. I'm confused how to accomplish this. I thought I might add something like
target1: all
TARGET=target1
This didn't seem to work too well at all though. Is there a general pattern for how one does this?

I would suggest simply spelling out your targets as separate targets in the makefile:
all: target1 target2
OTHER_OBJS = misca.o miscb.o miscc.o
target1: target1.o $(OTHER_OBJS)
target2: target2.o $(OTHER_OBJS)
Then make, make target1, make target2, and so on will all do what you want.
You say your makefile "derives the SRC list from [$(TARGET)]" in some presumably high-tech way, but it might be interesting to try explicitly listing the object files in a low-tech way instead, as above. Using different make targets is arguably Make's general pattern for producing different results.

Parameterized variable names and target-specific variables may do what you want, as the value of a target-specific variable is normally "inherited" by the prereqs of that target (assuming you are using GNU make):
target1_SRC=123 456
target2_SRC=abc def
target1: TARGET=target1
target2: TARGET=target2
target1: all
target2: all
all: ; #echo $($(TARGET)_SRC)
Then you can run make target1 or make target2, for example:
$ make target1
123 456
$ make target2
abc def

Well... Using pmake we can do this: (If use gmake we can replace $(.THINGS) for equivalanet $# $< and so...
.PHONY: clean run
PROGRAMS = progrname_one progrname_two... and so
all: $(PROGRAMS)
$(PROGRAMS): $(PROGRAM=$(.TARGET))
CC = clang -I.
CFLAGS = -O0 -g -std=gnu11
OBJS =
LIBS =
CPATH = .
$(PROGRAM): $(PROGRAM).c $(OBJS)
$(CC) $(CFLAGS) -o $(.TARGET) $(.IMPSRC) $(OBJS) $(LIBS)
$(PROGRAM).o: $(PROGRAM).c
clean:
rm -f *~
rm -f *.core
rm -f $(PROGRAMS) $(PROGRAMS).o
run:
./$(PROGRAM)
dbg:
lldb ./$(PROGRAM)

Related

Simplest C makefile using implicit rules

I know it is not optimal at all to rely on make's implicit rules but
my goal is to understand why they are not working in this case.
I want to write the simplest makefile one can write for a C project
without having to specify the sources.
I have tried to run make -d but the ouput is too big and verbose to
really be helpful.
I have written makefiles for some time and I believe I am familiar with how it
works. I am pretty sure I have managed to get implicit rules to work for me both
compiling and linking in the past but apparently I am forgetting something.
Here's what I have tried :
SRCS = $(wildcard *.c)
OBJS = ${SRCS:.c=.o}
NAME=exe
${NAME}: ${OBJS}
clean:
rm -rf *.o
fclean: clean
rm -rf ${NAME}
re: fclean ${NAME}
.PHONY: clean fclean re
It almost works but it doesn't link.
I am using gnu make version 4.3
Your Makefile doesn't execute the link step because there is only a very simple implicit rule for linking. From the documentation:
Linking a single object file
n is made automatically from n.o by running the C compiler to link the program. The precise recipe used is $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS).
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
In other words, for your Makefile to work, NAME needs to match the basename of one of your object files.
For example, if I have your Makefile and a single source file named hello.c, I can run:
make NAME=hello
And see the result:
cc -c -o hello.o hello.c
cc hello.o -o hello

How to properly create and use makefile

I'm getting started with makefiles and I'm having some problems.
I have one file which is fase_1.c that I want to compile and run.
I'm trying to make a simple makefile where I make and make clean.
This is what I tried:
OBJECTS = fase_1.o
CFLAGS = -Wall
NAME = makefile
build: $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) -o $(NAME)
clean:
rm -f *.o
rm -f $(NAME)
I do make, and it creates fase_1.o and makefile. Then I run ./makefile (is there another way to do it without like make or make clean but to run it?). Then I type make clean, and it says that there's a missing separator and that the line is ignored and doesn't remove fase_1.o and makefile (what I want to do). Am I separating the lines right? Maybe it has something to do with tab or my editing but I can't find where.
Here's a rewrite. Call it Makefile, though, not makefile:
OBJECTS = fase_1.o
CFLAGS = -Wall
NAME = fase
$(NAME): $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) -o $(NAME)
run : $(NAME)
./fase
.PHONY: clean
clean:
rm -f *.o
rm -f $(NAME)
There are fancier improvements that could be made, but it's probably best not to get bogged down at this stage. As a bonus, I have added .PHONY. This tells make that the target clean is a phony target; it doesn't actually create anything called clean.
You don't have to make run dependent on $(NAME), of course, but it makes sense in this particular context.
It looks like you are using GNU make. From the info page:
By default, when 'make' looks for the makefile, it tries the following
names, in order: 'GNUmakefile', 'makefile' and 'Makefile'.
Your executable is called makefile. When you run make, it tries to parse the executable as Makefile. Either rename the executable, or specify the makefile explicitly:
make -f Makefile clean

Where do i put CFLAGS in this makefile? Need the -g so i can use gdb debugger

I'm not used to this style of makefile my teacher created for one of our homeworks because it doesn't have the gcc command in it. Here is the makefile. All I need to know is where to put the -g cflag.
### Architecture choice
#Uncomment for 64-bit
LIBRARY = libmtron.a
#Uncomment for 32-bit
#LIBRARY = libmtron32.a
### File lists
BINS = simulate
OBJS = driver.o
### Phony targets all/clean
.PHONY: all clean
all: $(BINS)
clean:
$(RM) $(BINS) $(OBJS)
### Build rules
# Be sure to link in the library
$(BINS): $(OBJS) $(LIBRARY)
# update if the header file is changed
driver.o: driver.h mtron.h
simulate: mtron.h
Thanks for any help!
This makefile is utilizing make's built-in set of rules to create the objects and link executables, rather than having you type them in yourself.
Make has a default rule that looks (more or less) like this:
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
If you don't specify any rule yourself to build a .o and make needs to build one and it has a .c, it will use the default built-in rule.
So, the answer to your question is, "put the assignment of CFLAGS wherever you want". Wherever you put it, it will be used by the default rule.

Make recursive all C files

I really can't get into makefiles. In previous projects, I hardcoded all compile tasks in the Makefile:
all: compile_a compile_b compile_c
compile_a:
${CC} ${CFLAGS} ${A_SRC} -o ${A_OUT}
and so on.
But as the latest project has more files than every project before, I want to write better make tasks and of course LESS characters as make is not really friendly to my eyes (it makes them suffer)! :-P
What I want:
One task to rule them all (just make projectname or make all, you know?)
One task for every C file to compile (I read something about this %.o: %.c syntax, but didn't really get it)
One task for linking (how to get all .o files and link them without hardcoding each?)
One task for cleaning (oh, i can do this!)
The project structure is:
bin (binary goes here!)
src
some
directories
are
here
I don't know if I need a directory for object files, I put them in ./bin, I think that's good enough, isn't it?
Maybe I just need someone who can explain it with easy words!
EDIT:
As someone pointed out, there's no real question, so here it goes:
how to recursively compile all C files to bin/(filename).o
how to link all .o files in 'bin/' without knowing their names
maybe this helps.
Try this:
CC = gcc
CFLAGS = -c -Wall -g -Os
LD = $(CC)
LDFLAGS = -lfoo
TARGET = MyProject
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) -o $# $^ $(LDFLAGS)
# You don't even need to be explicit here,
# compiling C files is handled automagically by Make.
%.o: %.c
$(CC) $(CFLAGS) $^ -o $#
clean:
rm $(TARGET) $(OBJECTS)
I frequently use the wildcard function in combination with the foreach function for something like you want to achieve.
If your sources are in src/ and you want to put the binaries into bin/ the basic construction of my Makefile would look like follows:
SOURCES=$(shell find src -type f -iname '*.c')
OBJECTS=$(foreach x, $(basename $(SOURCES)), $(x).o)
TARGET=bin/MyProject
$(TARGET): $(OBJECTS)
$(CC) $^ -o $#
clean:
rm -f $(TARGET) $(OBJECTS)
I usually take advantage of make's built in implicit rules and predefined variables (Make manual, Chap 10).
without going into specifics of makefiles, use the * to your advantage.
i.e.
compileAll: gcc -c *.c
linkAll: gcc *.o -o output.exe

Including multiple sub directories in a make file

I am trying to write a makefile for a small scale application I wrote in C under Linux. Currently all my source files .c are in the top level directory and all header files in
an include directory. Here is the makefile I used for this.
IDIR =include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
_OBJ = main.o kernel.o user_app.o myargs.o ofp_msgs.o pkt_ip.o pkt_ether.o pkt_tcp.o pkt_udp.o pkt_icmp.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
#DEPS = ofp_msgs.h
$(ODIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
all: jam
jam: $(OBJ)
gcc -o $# $^ $(CFLAGS) -lpthread
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ jam
It works fine but what I want is that for example I make a sub directory called "Packet" and all my packet parsing files i-e "pkt_ip.c, pkt_tcp.c etc" should be in that directory where as their header files should still be in the top level directory i-t "toplevel/include". I did a bit of search and the most common way was to use recursive make. Then I see a lots of pages complaining about recursive make. Can anyone please help me in this as how to do this right ?
Thanks
I recommend checking out the method described in Recursive Make Considered Harmful.
I have used it on several projects (small to medium-size), and find it simpler to use, and easier to wrap ones head around, than the recursive approach.
Basically, you have a Makefile in the root directory which includes a (partial) makefile from each of the subdirectories:
SRC := main.c
MODULES := Packet lib etc
-include $(patsubst %, %/module.mk, $(MODULES))
OBJ := $(patsubst %.c, %.o, $(filter %.c,$(SRC)))
# (...)
Packet/module.mk:
SRC += Packet/pkt_ip.c Packet/pkt_tcp.c
LIBS += -lsome_library
These module makefiles can of course also define their own module targets, or special build requirements.
Unlike recursive make, "make" will only be invoked once, which for most use cases will lead to a faster build.
However, for most smaller projects neither build time nor complexity will be a major concern, so use what feels most natural.
there are several ways to do this but you can certainly use VPATH:=Packet to tell make to look for source files inside the 'Packet' directory. see make manual

Resources