Does the target .SUFFIX have any meaning in a Makefile? - makefile

In a Makefile I encountered:
.SUFFIX: .c
Is that a misspelling of .SUFFIXES: .c, because I can't find anything about .SUFFIX only. Does this do anything at all?
If the Makefile only uses pattern rules, do I even need that hanging around in the Makefile at all?

Assuming you are using GNU make, unless there is really a user target named .SUFFIX, this is probably a misspelling of .SUFFIXES: .c. And if there is no recipe you can safely remove it: without a recipe it's useless.
If it was .SUFFIXES: .c and if it had a recipe it would redefine the implicit rules for:
%: %.c
<recipe>
which is:
LINK.c = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#

Related

Adding additional dependencies for all files with a given extension

Let's say I am using the implicit rule to build an .o file from a .c file.
If I want to add a specific additional dependency for one particular .o file, it is as easy as adding a rule without a recipe:
file.o : header.h
This makes file.o depend on header.h in addition to file.c.
What if I want to do that for all .o files? The following doesn't work:
%.o : header.h
For this to make sense, header.h must a header that is (and has to be) included by every .c file
and is hence a prerequisite of every .o file. If that is your situation you
need to write your own pattern rule, like:
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
But the usual approach to managing header file dependencies is Auto-Dependency Generation
Later
My goal was to avoid duplicating the existing implicit rule (the recipe part) for $(CC) compilation. Is that possible?
You have to define a new pattern rule that adds header.h to the %.c prerequisite,
and has the appropriate recipe. In fact I ought
to have advised you also to cancel the builtin pattern rule:
%.o: %.c
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#

Makefile decoupled dependencies

With the following makefile snippet:
main: main.o f1.o f2.o
$(CC) $(CFLAGS) -o program main.o f1.o f2.o
main.o: main.cc
$(CC) $(CFLAGS) -c main.cc
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
f2.o: f2.cc
$(CC) $(CFLAGS) -c f2.cc
If I just change one file, only that file get recompiled when I rerun make, as desired. However, I'm having a hard time generalizing this without having to list each file individually. When I try something like:
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(patsubst %.o,%.cc,$#)
It builds each object file individually, but each object file depends on ALL my sources, so a change in any one file causing a full recompile. What's a good way to accomplish this?
Basically,
you do have to list each .o file's dependencies individually.
For example, each .o is likely to depend on a different bunch of headers.
Taking your f1.o, you need something like:
f1.o: include/i.h
f1.o: another.h dir/and-another.h
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
(you can have as many dependency lines for a target as you like).
Maintaining that list is a nightmare.
Broken dependency lists render your Makefile worse than useless—you might as well use a batch file.
All is not lost!
If you are tidy,
you can get the compiler to do it automatically,
and pretty much for free.
Makes your Makefile tidier to boot.
Win Win.
As Ismail Badawi commented, pattern rules provide a nice solution. They are a type of implicit rule for make. Basically, implicit rules are automatic recipes based off the file extension. For example, make knows how to convert .c files into .o files implicitly. By default make will run the following recipe for .c files (see the rule catalogue):
$(CC) $(CPPFLAGS) $(CFLAGS) -c
You can modify the process either by setting the variables CC, CPPFLAGS, and CFLAGS, or by defining a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -c $<
The "$<" above matches the name of the first prerequisite, which will be the .c file in this example. See Beta's comment and automatic variables.

Why doesn't this make file work?

CC=g++
CFLAGS=-Wall -ggdb
OBJDIR=Objects
SRCDIR=Source
HDIR=Headers
OBJ=$(patsubst %,$(OBJDIR)/%,main.o vector.o obstacle.o \
person.o simulation.o map.o wall.o room.o )
all: CrowdSim
CrowdSim: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
$(OBJDIR)/%.o: $(SRCDIR)/%.cc $(HDIR)/%.h
$(CC) $(CFLAGS) -c -o $# $<
clean:
rm -rf Objects/*.o Source/*.o
When attempting to make, I receive the error: "No rule to make target 'Objects/main.o' needed by 'CrowdSim'. Note: this is my first attempt at a makefile, and I'm following the example here.
Additional information: All my .cc files are stored in Source, all my .h files are in Headers, and I want to put all my .o files in Objects.
A rule like this:
$(OBJDIR)/%.o: $(SRCDIR)/%.cc $(HDIR)/%.h
requires both the prerequisites to exist. If either one does not exist, then the rule doesn't match and make will ignore it and look for another rule. In this case there is no other rule, so make fails.
If you don't always have both a .cc and .h file for every .o file, then you cannot write your rule like this.
Instead, you'll have to write the pattern rule like this:
$(OBJDIR)/%.o: $(SRCDIR)/%.cc
$(CC) $(CFLAGS) -c -o $# $<
Then you'll have to declare the header files separately, like this:
$(OBJDIR)/vector.o: $(HDIR)/vector.h
etc. for any headers. You might consider implementing a method to automatically manage dependencies, such as this one.
By the way, CC and CFLAGS are for C compilers. You have C++ code here. By convention in makefiles you should use CXX and CXXFLAGS for C++ compilers.

How to make an exception in a pattern rule in a makefile?

My makefile has the following rule for creation of object files :
%.o: %.c
$(CC) $(CFLAGS) -c $(INCPATH) -I$(INC_DIR) $< -o $#
But I want another rule for my main.o. Is there a way to achieve it ?
Just add your specific rule. If it already exists, pattern matching wouldn't happen for it.

make, write a rule for single file

I need a file to have a dedicated rule for use special flags.
Now I use
$(OBJDIR)/%.$(OE): special_file.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(CFLAGS_SPECIAL) $(DEFINES) $(INCLUDE) $< -o $#
$(OBJDIR)/%.$(OE): %.c $(OBJDIR)
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE) $< -o $#
But isn't working for special_file.c. It seems the path is not known, but when I comment my special rule and let make all files, file is compiling fine.
How to divert make to a rule just for one file?
Thanks very much in advance,
You should use Target-specific Variable Values:
$(OBJDIR)/special_file.$(OE): CFLAGS += --specific_flags
$(OBJDIR)/special_file.$(OE): special_file.c
$(OBJDIR)/%.$(OE): %.c $(OBJDIR)
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE) $< -o $#
If you want to do it this way, you'll have to write it as a static rule:
$(OBJDIR)/special_file.$(OE): special_file.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(CFLAGS_SPECIAL) $(DEFINES) $(INCLUDE) $< -o $#
However, much simpler and more flexible is to use recursive variable naming. Do something like this:
special_file_FLAGS = $(CFLAGS_SPECIAL)
$(OBJDIR)/%.$(OE): %.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $($*_FLAGS) $(DEFINES) $(INCLUDE) $< -o $#
The automatic variable $* expands to the stem (the part that matches %). Now when you build anything other than special_file.c, say other_file.c, make will expand $(other_file_FLAGS) which is empty. When you build special_file.c, make will expand $(special_file_FLAGS).
BTW, you should (almost) never list a directory as a prerequisite of a target. Search for other answers to find out why not and the right way to ensure the target directory is created.
ETA:
Target-specific variables are definitely a cool feature. I tend to not use them, though. Why? Because I prefer to separate my data from my rules.
If you use target-specific variables, you are mixing together the rule syntax (the target) with the data syntax (the variable assignment). Using the recursive variable name method, I keep the rule syntax and the data assignment separate. What if I decide I need to change my pattern rule so that the target name changes? With target-specific variables I have to go through all my files and change the target names. With recursive variable naming, I just change the pattern rule and it Just Works.
In my build environments I typically have makefiles containing only data (variable assignments), plus an include of a common makefile that declares all my rules. Avoiding the need to leak target formatting syntax all over my general data-driven makefiles, escaping from my uber-magical common rule definitions, keeps me from doing much with target-specific variables.

Resources