Makefile and subdirectories - makefile

I'm struggling with the correct syntax of a makefile.
This is my folder structure:
project
│ Makefile
│ HERE SHOULD BE THE OUT FILE AFTER make command
│
└───include
│ header.h
│
│
└───src
function1.c
function2.c
How must the makefile look to ensure correct results?
This is my current makefile:
SOURCES = src/function.c src/function.c src/function.c
OBJECTS = $(SOURCES:.c=.o)
CC = cc
RM = rm -f
CFLAGS = -Wall -Wextra -Werror
NAME = output.a
all: $(NAME)
$(NAME):
$(CC) $(CFLAGS) -c $(SOURCES)
ar rcs $(NAME) $(OBJECTS)
clean:
$(RM) $(OBJECTS)
fclean: clean
$(RM) $(NAME)
re: fclean $(NAME)
my current output if i run make all:
cc -Wall -Wextra -Werror -c src/function1.c src/function2.c
ar rcs output.a src/function1.o src/function2.o src/function1.o
ar: src/function1.o: No such file or directory
make: *** [Makefile:15: output.a] Error 1
if i run make flcean the output looks the following:
rm -f src/function1.o src/function2.o
rm -f output.a
So it doesn´t remove anything because the .o files are stored in the root, not the /src subdirectory

I'm struggling with the correct syntax of a makefile.
Your makefile syntax is fine. In fact, your makefile is syntactically valid and reasonably well structured. It looks a lot better than many of the ones we see around here.
I guess what you're actually struggling with is that it doesn't work, even after you fix the weird disagreement between the source file list in the makefile itself and the actual source files on disk. But "doesn't work" is a pretty vague, though lamentably common, description. You would get better help, faster, by saying something along the lines of "the .o files are created in the top-level directory instead of in the src/ directory." (Which is exactly what I expect to happen, and as a result, the ar command will fail, and the clean target will not clean the .o files.)
You need to understand that make itself doesn't know much about building software. What it knows is how to match rules to patterns so as to execute associated recipes of shell commands. The particular kinds of patterns it matches and the built-in rules that come with it are oriented toward building software, but you can't expect it to go very far with anticipating what you mean. It, like any other computer program, will happily do what you say, instead, when that differs. In this case, it just runs the cc command with the arguments you specify, and cc will choose under those circumstances to put the .o files in the working directory.
From a stylistic and best-practices standpoint, it's best to write rules that build only their target file, unlike your rule for $(NAME) that attempts to build not just $(NAME) but also all the component object files. The object files would be better built according to their own rule or rules. Making the object files prerequisites of the rule for $(NAME) will ensure that they get built when needed. That will also allow for them to not be built when that is not needed. That variation on your rule would look like this:
$(NAME): $(OBJECTS)
ar rcs $# $^
Note also that in the recipe, I have substituted automatic variable $# for a repetition of the rule target name. That's good form, but not obligatory. I have also substituted automatic variable $^ for a repetition of the prerequisite list. That's less clear-cut, in part because $^ is specific to GNU make, but if you're ok with that dependency then it's a great way to avoid repeating yourself.
Now, about building the object files: you could write a pattern rule (GNU make only) or a suffix rule that builds an object file from a corresponding C source file, or you could even write a separate rule for each object file. But you don't actually need to do that. make comes with a built in rule that will serve your needs in that area just fine, so your best bet may be to not attempt to provide your own rule for that at all. That is: modifying the rule for $(NAME) as suggested above should be sufficient for successful building, supposing, again, that the contents of your SOURCES variable accurately reflect the source files you want to build.

Related

How do I read source files from a directory and create object files into another folder in a makefile?

I have the following source files:
% ls
data_lexicon.c data_lexicon.h lex.l makefile
And the following makefile:
% cat makefile
CC = cc
CFLAGS = -Wall -std=c89
LDFLAGS = -ll
OBJFILES = lex.o data_lexicon.o
TARGET = lexical_analyzer_1
all: $(TARGET) lex.c
lex.c: lex.l data_lexicon.h
lex -olex.c lex.l
$(TARGET): $(OBJFILES)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS)
clean:
rm -f $(OBJFILES) lex.c $(TARGET)
If I do make all I get:
% ls
data_lexicon.c data_lexicon.o lex.l
lexical_analyzer_1 data_lexicon.h lex.c
lex.o makefile
So far so good.
However, I would like to move the source files (data_lexicon.c, data_lexicon.h, lex.l) to a folder src and generate the intermediate files (data_lexicon.o lex.c, lex.o) into a obj folder.
I create both folders but I do not understand how the makefile file shall be configured.
I am using FreeBSD make, so the more portable the solution given the better.
However, I would like to move the source files (data_lexicon.c,
data_lexicon.h, lex.l) to a folder src and generate the intermediate
files (data_lexicon.o lex.c, lex.o) into a obj folder.
It never ceases to amaze me how people insist on making extra work for themselves. You can certainly do what you describe, but it will require writing explicit rules for the object files.
First of all, however, you need to understand that make itself doesn't really know anything about directories. (Traditional make doesn't, anyway. GNU make and perhaps others know a little about them.) That is, it doesn't have any sense of varying directories against which it resolves file names. Rather, every target name is resolved against make's working directory. If you want to refer to something in a subdirectory, then you must say so. To begin with:
OBJFILES = obj/lex.o obj/data_lexicon.o
Similar goes for target and prerequisite names in rules:
obj/lex.c: src/lex.l src/data_lexicon.h
lex -o$# src/lex.l
That's also one reason to favor make's automatic variables, such as the $# in the above rule representing the name of the target being built.
Your makefile presently relies on make's built-in rule for building object files from corresponding C source files, but "corresponding" means target and prerequisite names are identical, including any path components, except for the suffixes (.c vs .o). You will no longer have that correspondence for data_lexicon.o, so you will need to write an explicit rule for it building it. This part is left as an exercise.

Delete targets with recipes failed in Makefile

I tried to use .DELETE_ON_ERROR target in makefile in order to delete both $(OBJ)
and executable files if the recipe fails, but it doesn't work. If I put an error inside any object file than while compiling the pattern rule an error occurs and it stops. The old object file is still on its place but I expect .DELETE_ON_ERROR to remove it.
Can anyone test the code? Can -include $(DEP) or flag -DDBG influence? The goal is to delete both the .o file that failed and the executable.
OUTPUT = executable
CPP := $(shell find $(SRC) -type f -name "*.cpp")
OBJ := $(CPP:.cpp=.o)
DEP := $(OBJ:.o=.d)
CXX := g++
CXXFLAGS =-MMD -MP -DDBG
INCLUDES = -I.
.DELETE_ON_ERROR :
$(OUTPUT): $(OBJ)
$(CXX) $^ -o $#
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
-include $(DEP)
.PHONY : clean
clean:
rm -rf $(OBJ) $(DEP)
EDIT: According to the Ondrej K. solution to fix this problem you need to add #touch command before compilator in order to make the object files changed (the docs read "delete the target of a rule if it has changed".). So, the code should look like this:
%.o: %.cpp
#touch $#
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
Not sure what failure you're seeing, but I am afraid there really isn't a good way for you to do that. .o files and executable ($(OUTPUT)) are separate rules. If the latter fails, former is already out of consideration. See the documentation:
.DELETE_ON_ERROR:
If .DELETE_ON_ERROR is mentioned as a target anywhere in the makefile, then make will delete the target of a rule if it has changed and its recipe exits with a nonzero exit status, just as it does when it receives a signal. See Errors in Recipes.
In other words, if your the target producing a binary object failed after .o target itself got updated, make would prune the changed file. But if your executable did not link, it won't go back and delete object files.
Not sure it'd be nice, but if you really needed to, you could probably achieve this by refactoring your makefile to basically have direct exec + objs from source prerequisites rule with a single recipe. Obvious downside, such rule would mean single .c file change causing all files being recompiled (basically negating substantial benefit of using make).
EDIT: I'll expand on the comment a bit to clarify. What you seem to want is: in case there is a broken .c file and compilation fails, remove the old .o file. That is quite clearly not how .DELETE_ON_ERROR works though. If the .o file already got updated, and then the rule failed, it would remove it ("delete the target of a rule if it has changed"), but in case of a mentioned syntactical problem, the compiler would fail before it would produced an .o file.
So, if for instance you updated your (pattern) rule for compilation so that it first touches (effectively updates timestamp) on the .o file and then tries to compile. After the compiler call and rule failed make would consider the target of the failed root to have been updated and remove it. Alternatively you could also change to rule to first try to rm the expected '.o' file in which case you actually wouldn't need to use .DELETE_ON_ERROR (and if there is no change in the relevant sources, the rule does not get used, so it's actually not as terrible as it sounds). Either way is not exactly very clean, but leads towards the behavior I understand you're describing.
It is possible that the Compiler crashes while writing the Output file. In this case, there is a corrupt output file that is newer than its sources. Make will stop due to the error, but on next run, it won't recompile the output file as it is newer than ist sources - and the make will fail again and again in the build step.
With the .DELETE_ON_ERROR rule, make will delete the Output file if the compiler (or whatever build step failed) exits with an error after touching (and corrupting) the Output file, so it will be recompiled on next run. (if the Compiler failed without touching the old output file, it will always be recompiled on next run anyway)

Makefile's 'vpath' doesn't work when searching prerequisites with wildcards

My project includes .c and .s (asm) files. I compile both types with 'gcc' and put output .o files to separate directory './bin'. To do that I'm using single makefile rule like this
bin/%.o: %.[cs]
$(CC) $(CFLAGS) -o $# -c $<
(As far as I understand, using square brackets wildcard in such context is a little bit unconventional, but it's working and it looks neat, so...)
The other day I decided to move some of my .c files to dedicated directory './common', so I added
vpath %.c common
at the beginning of the makefile. And now each time I try to 'make', it stops and throws an error on a file I had moved. For example, for 'common/foo.c' I get
"*** No rule to make target bin/foo.o, needed by..."
as if I haven't specified 'vpath'. But when I modify the rule to compile only .c files
bin/%.o: %.c
... ...
magically it starts to operate properly again and checks './common' for sources.
Looks like 'vpath' mechanism and wildcards can not work together, but I'm still new to 'make' and eager to learn what's the exact reason of such behavior. Any ideas anyone? Thanks in advance.
(Tested with make–3.81 and make–4.1.)
UPD: Having all the files and 'bin' directory reside on the same level like so
|-bin/
|-foo.c
|-bar.s
|-baz.c
|-Makefile
here's MWE
ROOTS = foo.o bar.o
OBJS = baz.o
SS = $(addprefix bin/,$(ROOTS) $(OBJS))
all: ff.out
ff.out: $(SS)
ld -o $# $^
bin/%.o: %.[cs]
gcc -o $# -c $<
Now if I move, say, 'foo.c' to separate directory and specify 'vpath', build stops with "No rule to make target bin/foo.o, needed by ff.out".
I suggest careful reading of How Not to Use VPATH as you seem to be at Step Three of that by having the OBJDIR in some places but not others.
To be explict, using a static pattern rule doesn't get you away from needing either at least one rule per source directory, or at least one make invocation per source directory. So, the simple answer is add a new rule for the new common/ directory that's the same as the other one:
bin/%.o: common/%.[cs]
gcc -o $# -c $<
There are lots of more comprehensive, but complex, answers, see the followon article for some of them.
For simple projects, there is no reason not to just track what directories you have in your main Makefile by adding extra rules. Also, there's a reasonable case for not having that bin/ dir and splitting .o and .out locations. Distributors and others expect to be able to control where files are created running from a seperate directory anyway.
I've thrown up a git repo with branches based on your cut down example that may clarify things.

How to handle dependencies from recursive Makefile invocations?

I have a C project that consists of a fairly large number of source files, and to make some sense of them, I have put them into subdirectories (with subdirectories). The whole project results in only one executable file, however.
In order to build this project, then, I am using recursive Makefiles, where the Makefile in each non-toplevel directory links all the object files produced in that directory into a concatenated lib.o file (using ld -r, that is). I do have a Makefile system that can build this and works rather fine for what it is, but it cannot support parallel make, which I would like to fix.
The problem is that I cannot figure out a proper way to both force make to descend into each directory's subdirectories, but also have the local lib.o target depend on that without being forced to rebuild even when nothing has changed.
This is how it works, somewhat abbreviated (leaving out CFLAGS and whatnot):
default: build
SUBOBJECTS = $(patsubst %,%/lib.o,$(SUBDIRS))
.PHONY: $(SUBDIRS)
$(SUBDIRS):
#$(MAKE) -C $#
build: $(SUBDIRS) lib.o
lib.o: $(OBJECTS) $(SUBOBJECTS)
$(LD) $(LDFLAGS) -r -o $# $^
This is from a Makefile.common which all other Makefiles include. Every other Makefile would also define their own SUBDIRS and OBJECTS. It might look like this, for instance:
SUBDIRS = dir1 dir2
OBJECTS = object1.o object2.o
include ../Makefile.common # Or ../../Makefile.common, &c.
As you can see from this, the main target is really the build target, which depends on the subdirectories and lib.o. If I invoke parallel make on this, it won't know that lib.o cannot be built until make has already run recursively on the subdirectories and will sometimes attempt that, causing errors. However, if I make lib.o depend on the subdirectories, then lib.o will always be unnecessarily rebuilt on each invocation, in each directory.
Is there a way to solve this? I've wrecked my brains on this for quite a while now without being able to find a way out. I'm only using GNU make, so don't worry too much about being POSIX-compatible.

Canonical 'simple project' makefile

Your small C/C++ project has reached a point where it's no longer practical to have all your code in one file. You want to split out a few components. So you make a src/ directory, and then... you have to write a real Makefile. Something more than hello: hello.o. Uh-oh... was it $# or $< or $^? Crap. You don't remember (I never do).
Do you have a 'one-size fits all' simple Makefile that can deal with straightforward source trees? If so, what's in it and why? I'm looking for the smallest, simplest Makefile that can compile a directory full of C files nicely without me having to edit the Makefile every time I add a file. Here's what I have so far:
CXX = clang++
CXXFLAGS = ...
LDFLAGS = ...
EXENAME = main
SRCS = $(wildcard src/*.cc)
OBJS = $(patsubst src%.cc,build%.o, $(SRCS))
all: $(EXENAME)
build/%.o: src/%.cc
#mkdir -p $(dir $#)
$(CXX) -c -o $# $^ $(CXXFLAGS)
$(EXENAME): $(OBJS)
$(CXX) -o $# $^ $(LDFLAGS)
clean:
rm -rf $(EXENAME) build/
This Makefile builds all the .cc files in the src/ directory into .o files in the build/ directory, then links them up into the parent directory.
What would you do differently?
I would reconsider you decision not to have an explicit list of sources-- I think it may cause you trouble in the long run. But if that's your decision, this makefile is pretty good.
In the %.o rule I would use $< instead of $^, so that later you can add dependencies like
build/foo.o: bar.h
And when you're ready, you can take a look at Advanced Auto-Dependency Generation.
I've never used CMake, so I really can't say anything about that. The best that I can offer is a program that we have at school called 'makemake', which automatically makes Makefiles - http://www.cs.rit.edu/~swm/makemake/ It's not a very advanced program, but it gets the job done. On the plus side, it's incredibly easy to use - simply do 'makemake > Makefile' in the directory and you have a Makefile which will build and link all the source files in that directory(C and C++). On the bright side, if you ever add more files, you just run makemake again and you have a new makefile. On the downside, there's no way to keep any custom targets that you've done from one generated makefile to the next.
As for 'one size fits all' makefiles, while you could definitely do that, it takes away from the purpose of the 'make' command in the first place - which is to keep track of the files last modified time, and thus only re-compile the files that have recently changed, or depend on header files that have just changed(although to generate the correct you can use 'makedepend' - http://www.x.org/archive/X11R7.5/doc/man/man1/makedepend.1.html ). You could use what you currently have plus makedepend in order to make a self-updating makefile.
Use automake tools. Its easy to make changes and less burden to the developer. Its as simple as specifying the SOURCES, LDLIBS, LDFLAGS as variables. At first it may seem like a bit weird. But it becomes your favorite as you do more on it.

Resources