All compiled artifacts in separate directory? - c

I'd like to write a simple Makefile which creates all *.o, *.so, and binary files in a build directory, possibly build/.
Is there a straightforward way of doing this in a Makefile? I'm on Linux, Ubuntu 14.04.
The linked question puts all *.o artifacts in a build directory, but not the executables themselves. To be clear, I'd like to hit make and have all items compiled and stored in build/.

Assuming you use GNU make, something like:
O ?= build
OBJS := $(patsubst %.c,$(O)/%.o,$(wildcard *.c))
SOS := $(O)/<you know better than me>
EXECS := $(O)/<you know better than me>
all: $(OBJS) $(SOS) $(EXECS)
$(OBJS): $(O)/%.o: %.c
mkdir -p $(O); \
$(CC) $(CFLAGS) -c $< -o $#
$(SOS): ...
$(EXECS): ...
should be close to what you want. As I do not know which *.so and executables you want to build and how, I just indicate a possibility for the rule that builds the *.o. It should be easy to adapt to the other targets.
If you type make, the build sub-directory will be created if it does not exist. If you type make O=foo, the foo sub-directory will be created (if it does not exist) and be used instead of build.
$(OBJS): $(O)/%.o: %.c is a static pattern rule. In case it is not clear enough, the GNU make documentation will tell you everything about them.

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

Having trouble placing object files in a new directory using makefile

I am very new at make. Thus far I've managed to create the following using some of GNU manual and tutorials found online. I'd like for make to place all of the created object files into the directory 'obj.' I've been able to successfully create this directory, but I cannot figure out how to place the files in it. Any suggestions or tips are appreciated. Also, on a general note, is there a good source for learning how to work with make besides the GNU documentation?
# specify compiler
CC := gcc
# set compiler flags
CFLAGS := -M -Igen/display -Igen/logic -Iman -Ilib/include -pipe -march=native -ftime-report
# set linker flags
LDFLAGS := -lglut32 -loglx -lopengl32 -Llib
# specify separate directory for objects
OBJDIR := obj
# include all sources
SOURCES := $(wildcard gen/display/*.c gen/logic/*.c man/*.c)
# create objects from the source files
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
# specify the name and the output directory of executable
EXECUTABLE := win32/demo
# all isn't a real file
all: $(EXECUTABLE)
# compile
%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$#
# link
$(EXECUTABLE): $(OBJECTS)
$(CC) $^ $(LDFLAGS) -o $#
# clean objects
clean:
#$(RM) -rf $(OBJDIR)
.PHONY: all clean
Any time you see a rule where the output generated does not go to the file $#, you know it's not right. Make will set the $# automatic variable to the file name that it expects to be created and if the recipe does something different, the makefile will not work.
Your rule sends the file to $(OBJDIR)/$#, not $#, so it's not right.
So, you need to write your pattern rule like this:
%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -c $< -o $#
If that doesn't work you'll need to provide more information such as an example of the compile line make invokes, what errors you see, etc.
I've been able to successfully create this directory, but I cannot
figure out how to place the files in it.
There are two parts writing to doing that explicitly.
First, and most fundamental, is that if you want make to create a file, you have to give it a rule for doing so. You do have a pattern rule that could, in principle, have that effect ...
%.o: %.c
# ...
... but in practice, that rule cannot ever be matched to files in the obj/ directory because your sources are not in that directory. This might be more effective:
$(OBJDIR)/%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -c $< -o $#
Note in particular how now the target of the rule matches the artifact actually produced by that rule.
Second, you must have a requirement to build the target of the rule, usually by having it be a dependency of some other rule. Observe that your variable defining the object files contributing to $(EXECUTABLE) does not rely on objects from the obj/ directory. It is generated by this pattern substitution ...
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
... which generates object names with the same path as the corresponding sources. You probably want something more like this:
OBJECTS := $(patsubst %.c,$(OBJDIR)/%.o,$(SOURCES))
You will note how that also corresponds to the change presented in the previous point.
But that's a lot of work for little gain. You would not have to modify your clean target very much to do without it there. You could write your file in a somewhat simpler and more conventional form and still get output into a separate directory by leveraging the VPATH feature of GNU (and some other) make.

How to modify makefile to compile changed source into object directory except for a list of files

I inherited a makefile that uses GNU Make 3.81. It is overly complicated, IMHO because it does not use patterns. In addition, it does not automatically create an object file directory when needed. I've looked at several examples and read the a GNU makefile manual, but still not seeing something that should be simple. There seem to be many ways recommended, but not clear what to use. I have about 60 c files that need to be compiled into a directory named obj. But, I don't want 6 test programs that have 'main' programs compiled into that directory. They are in a list called OTHERSRCS. I'd like to have the c files less the OTHERSRCS compiled into obj if anything changes in those files. Also, if the obj directory doesn't exist, I'd like to create it. The 'make clean' should remove that directory. I've used ANT with Java and can get the dependencies to work, but I'm not succeeding with this makefile. A simple example would be helpful that used some sort of exclusion along with the pattern for the c files.
In this simple example, the C source files in the current directory
are foo.c, bar.c, atest.c, anothertest.c. We have:
OTHERSRCS := atest.c anothertest.c
Each of the $(OTHERSRCS) is to be separatedly compiled and linked into
a program in current directory. All remaining C source files, whatever
the are, are to be compiled into a directory obj, which shall be
created when required, and the resulting object files all linked into
a program foobar.
Makefile
ALLSRCS := $(wildcard *.c)
OTHERSRCS := atest.c anothertest.c
foobar_SRCS := $(filter-out $(OTHERSRCS),$(ALLSRCS))
foobar_OBJS := $(addprefix obj/,$(foobar_SRCS:.c=.o))
PROGS := foobar atest anothertest
.PHONY: all clean
all : $(PROGS)
obj/%.o: %.c | obj
$(COMPILE.c) $< -o $#
obj:
mkdir -p $#
foobar: $(foobar_OBJS)
$(LINK.o) -o $# $^ $(LDLIBS)
clean:
rm -fr $(PROGS) obj
The default make runs like:
$ make
mkdir -p obj
cc -c foobar.c -o obj/foobar.o
cc -c foo.c -o obj/foo.o
cc -c bar.c -o obj/bar.o
cc -o foobar obj/foobar.o obj/foo.o obj/bar.o
cc atest.c -o atest
cc anothertest.c -o anothertest
and of course make foobar like the first 5 lines of that.
To understand the key details, see 4.3 Types of Prerequisites
and 8.2 Functions for String Substitution and Analysis
in the manual. No recipes need be written for the programs atest and anothertest in this example because they're correctly built by GNU make's default rules.
If you are going to rework your inherited makefile, consider rationalising the source tree, e.g. by at least not having test sources in the same directory as application sources.
Here's my Makefile
This should get you going. I tried to be as descriptive as I could.
Edit:
To exclude a .c file you can change:
SRC = $(shell find $(SRC_DIR) -name '*.c')
to
SRC = $(shell find $(SRC_DIR) -name '*.c' ! -iname 'myFile.c')

Makefile dependencies on multiple files

I have created a Makefile for unit tests which uses GCC with arguments to create profiling files (gcno) during compiling. Here's a similified part of it where compiling and linking takes place:
UTEXE = $(UTOBJSDIR)\$(UTUNIT).exe
UTOBJS = $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o)
UTOBJSFULL = $(addprefix $(UTOBJSDIR)\,$(UTOBJS))
UTOBJSGCNO = $(addprefix $(UTOBJSDIR)\,$(UTOBJS:.o=.gcno))
$(UTOBJS): %.o: %.c $(UTMAKEDEP)
$(call report,Compiling $(*F).c)
$(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $(subst /,\,$<)
$(CC) -c $(CFLAGS) $(subst /,\,$<) -o $(UTOBJSDIR)/$#
$(UTOBJSGCNO): $(UTOBJS) $(UTMAKEDEP)
utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP)
$(UTEXE): $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP)
$(call report,Linking to $(UTUNIT).exe)
$(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $(UTEXE)
It compiles all the object and profile files and links together a binary. However when i delete some profile file (gcno) and call "utbuild" again it won't re-compile to restore the .gcno file. It tries to do linking again because gcno is a prequisite to it, but it wont do the compiling.
I don't know how to name this case so couldn't find solution from internet. Basically one recipe creates two files and i don't know how to write the rule that re-run's recipe even when only one file needs to re-created.
I would appreciate some links or hints.
thanks for all the comments. I've tried no-op ";" and ":=" with same outcome.
I think i need to take one step back and explain why i asked this question. It's not just about deleting or not-deleting gcno files manually, it's about general understanding how to write such a Makefile which restores any missing or out-of-date file. My Makefile has similar cases in few places and it's using parallel build so when some file goes missing it gives lot of weird errors. Usually it's solved by "clean" and "all", but i'd like the Makefile to be perfect and handle the missing file issues nicely.
As the example above is not so clear without all the rest of the Makefile then i made a new simple test.
hello.c
#include <stdio.h>
int main()
{
printf("Hello world\n");
}
Makefile
CCDIR = C:\tools\MinGW
CCBINDIR = $(CCDIR)\bin
CCINCDIR = $(CCDIR)\include;$(CCDIR)\lib\gcc\mingw32\4.8.1\include
CCLIBDIR = $(CCDIR)\lib;$(CCDIR)\lib\gcc\mingw32\4.8.1
# Overcome "missing dll file" messages on Windows
CC = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe
LINK = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe
# Compile and link for code coverage
CFLAGS = -fprofile-arcs -ftest-coverage -g3 -O0 $(addprefix -I,$(CCINCDIR))
LNKFLAGS = -fprofile-arcs -ftest-coverage -static -static-libgcc $(addprefix -L,$(CCLIBDIR))
OBJECTS = hello.o
EXE = hello.exe
$(OBJECTS): %.o: %.c
$(CC) -c $(CFLAGS) $(subst /,\,$<) -o $#
$(EXE): $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
build: $(EXE)
"make build" creates following files:
hello.o
hello.gcno
hello.exe
Now if i delete the "hello.gcno" and run build again it tells me:
mingw32-make: Nothing to be done for 'build'.
The goal is to update Makefile so that the make re-creates the "hello.gcno". It would probably re-create "hello.o" and "hello.exe" also during that process but that's not a problem.
Edit:
Just to be clear: in real Makefile i really-really need the .gcno files. It's not just an additional information or something which to avoid or do optionally. The Makefile builds the unit test executables, runs them and executes gcov to generate code coverage information and gcovr creates a report of all the .gcov files. If .gcno file is missing it won't work. Also - as it's parallel build then dependencies shall be absolutely correct to avoid some process starting earlier and it's tricky because coverage report has dependencies coming from two "branches" - .gcno files from compile stage and .gcda files from execute stage. So that's why i need it to be correct.
your only option here is this :
(if you can change the rule)
$(EXE): $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
to this:
%.exe %.gnco: $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
$(GENERATE_GNCO) $<
Here is a very simple solution of one thing dependig on two other things
compile:./src/main.c ./src/error.c
gcc ./src/error.c ./src/main.c -o ./exe/calc
run : ./exe/calc
./exe/calc
The correct answer in my opinion, is, don't delete any .gcno files by themselves. If you have to "clean", use make clean, but don't just go about deleting files.
The "build" is a state machine, with all the files constituting a "state". Don't corrupt the state!
Some people say, one should be able to delete arbitrary files and the build should recover. My answer is, what about if you corrupt some .o file by hand, say, add some 0's and 1's, making it unusable (thank you user3629249 for pointing that needs to be clarified, that I am talking about corruption, not intentional editing). Should the build also recover from that? Obviously no - no build system in the world will recover if you touch the .o file this way. Then why allow deleting a file, but not allow modifying it?? Where do you draw the line?
Simply put, any corruption should not be allowed. Use make clean only, or better yet, write your Makefile properly, so you never need to clean period.
The whole Makefile has a number of problems, here is how it should look like (I am assuming this is on Windows/DOS):
.SUFFIXES:
UTEXE := $(UTOBJSDIR)\$(UTUNIT).exe
UTOBJSFULL := $(addprefix $(UTOBJSDIR)\,$(subst /,\, $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o)))
UTOBJSGCNO := $(UTOBJSFULL:.o=.gcno)
.PHONY: utbuild all
all: utbuild
utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTMAKEDEP)
$(UTOBJSGCNO): %.gcno: %.o $(UTMAKEDEP) ;
.SECONDARY: %\.
%\.: Makefile
mkdir $*
.SECONDEXPANSION:
$(UTOBJSFULL): $(UTOBJSDIR)\%.o: %.c $(UTMAKEDEP) | $$(#D)\.
$(call report,Compiling $<)
$(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $<
$(CC) -c $(CFLAGS) $< -o $#
$(UTEXE): $(UTOBJSFULL) $(UTMAKEDEP) | $$(#D)\.
$(call report,Linking to $(#F))
$(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $#

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