Overriding Implicit Rules in Makefiles - linux

My Makefile contains an implicit rule override in the form of an explicit rule definition. However, make still invokes the default implicit rule.
This is on RHEL 6.3, GNU Make Version 3.81.
CPPFLAGS = -Wall -O2
DEPDIR = .d
DEPFLAGS = -MT "$# $(DEPDIR)/$*.d" -MMD -MP -MF $(DEPDIR)/$*.d
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
%.o: %.cpp $(DEPDIR)/%.d
g++ -c $< $(CPPFLAGS) $(DEPFLAGS) -o $#
$(DEPDIR)/%.d: $(DEPDIR) ;
$(DEPDIR):
mkdir -p $#
include $(wildcard $(DEPDIR)/*.d)
.PHONY: clean clobber
clean:
rm -f *.o
rm -rf $(DEPDIR)
Invocation of 'make' outputs this:
[tlytle#tlytle-dev]$ make
g++ -Wall -O2 -c -o my_source.o my_source.cpp
Why is make invoking the default implicit rule for %.o files and not my explicit rule for %.o files defined in my Makefile?

You are not overriding the default rule for building .o files from .cpp files. In order to override it you'd need to define a new rule with identical target and prerequisites; your implicit rule has extra prerequisites, so you're just adding a new implicit rule that could build a .o file.
The rules for choosing implicit rules when multiple ones may match can be confusing.
The simplest thing to do is delete the builtin rule so that it's not available to be considered. You can do this by defining an implicit rule with the same target and prerequisites as the builtin rule, but no recipe:
%.o : %.cpp
Now make will have no choice but to use your implicit rule.
Note that GNU make 3.81 is really old. In newer versions of GNU make you can delete all the builtin rules to start by adding this to your makefile:
MAKEFLAGS += -r

I'd start from trying to run it with --no-builtin-rules to prove/disprove the theory about implicit/default (both are legit terms) rules being involved.
The manual says, that for an override to work both the target and prerequisites must match, and in your case it's not. Could be that.

Related

Struggling with a GCC Makefile

I am trying to write what I thought would be quite a simple Makefile and I'm just baffled! I'm not a makefile writer, but I thought I understood them enough to be able to get a simple one working.
Okay, I have a small project in a directory and also in this directory is a libs directory containing many .c files. What I'm trying to do is write a makefile that will build the contents of the /libs directory into a static lib file in the /libs directory and then compile a few source files in the / directory and link it against the built .a file.
I'm sure someone's going to suggest "why not use cmake", but that's not answer I'm looking for (waves hand like a Jedi.. ehehehehe)
CC = gcc
CFLAGS = -Wall
SOURCES = lzx.c csum.c dirs.c listner.c tree.c
OBJECTS = $(SOURCES:.c=.o)
TARGETLIB = libs/mylib.a
TARGET = TestApp
libs/%.o : libs/%.c
$(CC) $CFLAGS -c $<
$(TARGETLIB) : $(OBJECTS)
ar rcs $# $^
$(TARGET) :
$(CC) $CFLAGS Source1.cpp Source2.cpp -llibs/mylib.a -o $#
My understanding was that the first recipe, would compile all the .c files into objects, but it seems to compile the first .c file and then stop.
Any help anyone could give me would be appreciated.
Since Your final app is TARGET, You should make it first Makefile rule. And since it also depends on TARGETLIB it should be given as dependency, like so:
$(TARGET): $(TARGETLIB)
$(CC) $(CFLAGS) Source1.cpp Source2.cpp -Lmylib -o $#
next I assume that *.c files You mentioned are lib files. Thus You will need a prefix to them, since You want to specify them by hand, not via wildcard or rule.
OBJECTS = $(addprefix(libs, $(SOURCES)):.c=.o)
and last thing that comes to my mind is library name, which supposed to be libSOMENAME.a (well, linker searches for this name in path and -Lotherpaths). So we have:
TARGETLIB = libs/libmylib.a
summing it all up:
CC = gcc
CFLAGS = -Wall
SOURCES = lzx.c csum.c dirs.c listner.c tree.c
OBJECTS = $(addprefix(libs, $(SOURCES)):.c=.o)
TARGETLIB = libs/libmylib.a
TARGET = TestApp
$(TARGET) : $(TARGETLIB)
$(CC) $(CFLAGS) Source1.cpp Source2.cpp -static -L./libs -lmylib -o $#
$(TARGETLIB) : $(OBJECTS)
ar rcs $# $^
And yes, this could be written much better, but I assume if You wanted to learn more about Makefiles or linker, and not just shown where You made mistakes, You'd know how to find manual pages.

How can I makefile with this

My program comprises sharedmemory.c sharedmemory.h semaphore.c semaphore.h sumprime.c, now I want to compile in Linux an executable file named sumprime
sumprime.c code calls some methods that are declared in sharedmemory.h semaphore.h and implemented in sharedmemory.c semaphore.c
My makefile is like this:
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
OBJFILES = sumprime.o semaphore.o sharedmemory.o
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
DISTFOLDER = lab5
HANDIN = ${DISTFOLDER}.tar.bz2
DEST=sumprime
CCFLAG=
.PHONY: all clean pack
all: $(DEST)
$(DEST): sumprime.o
gcc sumprime.o -o $(DEST)
sumprime.o: $(HEADERFILES) $(SOURCEFILES)
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
clean:
pack:
#echo [PACK] Preparing for packaging...
#rm -fr ${DISTFOLDER} ${HANDIN}
#mkdir ${DISTFOLDER}
#echo [PACK] Copying solution files
#for file in ${DISTFILES}; do\
cp -f $$file ${DISTFOLDER};\
echo \>\>\> $$file;\
done;
#echo [PACK] Creating ${HANDIN}...
#tar cjf ${HANDIN} ${DISTFOLDER}
#rm -fr ${DISTFOLDER}
#echo [PACK] Done!
I tried multiple ways in vain after searching. Please help me with this
As gcc should tell you, you cannot use -c with multiple input files, so
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
does not work.
Fortunately, it also isn't necessary; in fact, you don't need special rules for the .o files because the built-in rules work quite well. This is particularly the case because the name of the output binary corresponds with one of the object files (sumprime.o; see "Linking a single object file" behind the link).
I would use something like
#!/usr/bin/make -f
CC = gcc
CPPFLAGS = -MD
CFLAGS = -O2 -g
LDFLAGS =
LDLIBS =
TARGET = sumprime
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
DISTFOLDER = lab5
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
HANDIN = $(DISTFOLDER).tar.bz2
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
all: $(TARGET)
$(TARGET): $(OBJFILES)
clean:
rm -f $(TARGET) $(OBJFILES)
distclean: clean
rm -f $(DEPFILES) $(HANDIN)
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
#echo [DIST] Preparing for packaging...
#rm -f $#
#tar cjf $# --transform 's,^,$(DISTFOLDER)/,' $+
#echo [DIST] Done!
.PHONY: all clean distclean dist pack
-include $(DEPFILES)
Obviously, this requires some explanation.
Explanation
Implicit rules
I mentioned these above: make predefines a number of rules that often just Do The Right Thing™; we can make them do most of our work. In fact, the shortest Makefile you could use to build your program is
sumprime: sumprime.o semaphore.o sharedmemory.o
This uses an implicit rule to build the .o files and an implicit recipe to build sumprime. Note that there are variables that influence the behavior of implicit rules; behind the link above is a list of such rules that includes their recipes, and in them the names of the variables they use. Since we're compiling C code, the ones we're interested in are:
CPPFLAGS = -MD # C preprocessor flags, such as -Ipath -DMACRO=definition
CFLAGS = -O2 -g # C compiler flags
LDFLAGS = # linker flags, such as -Lpath
LDLIBS = # linked libraries, such as -lpthread (Alternatively:
# LOADLIBES, but this is less usual)
Pattern substitution
The lines
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
use pattern substitution to generate a list of .o files from a list of .c files, and .d from .o. We'll use .d files for dependency tracking.
Dependency tracking
This is perhaps the most complex part, but it's not that bad.
One of the practical problems with the minimal Makefile is that it doesn't know about #includes. If sumprime.c includes semaphore.h and semaphore.h is changed, we would really like sumprime.c to be rebuilt. Fortunately, gcc has a mechanism to facilitate this that we invoke with
CPPFLAGS = -MD
When given this option, the preprocessor generates a .d file corresponding to the input .c it was given (i.e., if sumprime.c is compiled, sumprime.d is generated) that contains a make-compatible list of dependencies of the source file. For example, I expect a sumprime.d that looks something like
sumprime.c: semaphore.h sharedmemory.h
Then, with
-include $(DEPFILES)
make is instructed to include these files into its code if they exist. This means that make always knows the dependencies of source files as they were during the last build (!). That it lags one behind is not a problem because a change in the dependencies requires a change in one of the files that a target depended on last time, and that no dependencies are pulled in the first time is not a problem because the first time everything has to be built anyway.
And so we get dependency tracking with a minimum of fuss.
Packing with GNU tar
The
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
#echo [DIST] Preparing for distaging...
#rm -f $#
#tar cjf $# --transform 's,^,$(DISTFOLDER)/,' $+
#echo [DIST] Done!
rule requires GNU tar, but if it is available, its --transform option makes for a much nicer dist rule, as you can see. I took the liberty of changing it to that. Of course, if you prefer, you can still use your old way.
Side note: It is more usual to call what you called the pack rule dist. There is no technical reason for this, it's just a convention; people expect make dist. With this code, both names work.

makefile with multiple dependencies for a single file

I have a makefile similar to the following:
SRCS = a.c b.cpp
OBJS = objs/a.o objs/b.o
all: $(OBJS)
objs/%.o: %.c
gcc -c $< -o $#
objs/%.o: %.cpp
gcc -c $< -o $#
It seems to work. But I don't really understand why.
Why doesn't it try to generate a.cpp and b.c?
as I read it : a.cpp is a prerequisite for objs/a.o and it should try to generate it. And because it doesn't find a matching rule for it - it should fail
Where am I wrong?
P.S - I execute my makefile using -r -R to avoid builtin rules
Make does not combine the prerequisite lists of different pattern rules.
When Make is looking for a way to build objs/a.o, it finds that the first pattern rule matches the target, and the prerequisite (a.c) exists. The second pattern rule matches the target, but the prerequisite (a.cpp) does not exist and cannot be built, so Make uses the first rule. Likewise, Make chooses the second rule over the first when looking for a way to build objs/b.o.
Make would try to generate a.cpp and b.c if these files depended on something else. However it is not the case here, these two files are leaves in the dependency tree, so Make has no reason to try to generate them.

Converting a visual studio makefile to a linux makefile

i am new to makefiles and have just rescently created a makefile that works for a c++ project. it has two cpp files and one h file. i am trying to convert my file to work in linux but cant seem to figure out how. any ideas?
EXE = NumberGuessingGame.exe
CC = cl
LD = cl
OBJ = game.obj userInterface.obj
STD_HEADERS = header.h
CFLAGS = /c
LDFLAGS = /Fe
$(EXE): $(OBJ)
$(LD) $(OBJ) $(LDFLAGS)$(EXE)
game.obj: game.cpp $(STD_HEADERS)
$(CC) game.cpp $(CFLAGS)
userInterface.obj: userInterface.cpp $(STD_HEADERS)
$(CC) userInterface.cpp $(CFLAGS)
#prepare for complete rebuild
clean:
del /q *.obj
del /q *.exe
For in depth treatment of make on Linux, see GNU make.
There are a few differences. Binaries have no extension
EXE = NumberGuessingGame
The compiler is gcc, but need not be named, because CC is built in, same goes for LD. But since your files are named .cpp, the appropriate compiler is g++, which is CXX in make.
Object files have extension .o
OBJ = game.o userInterface.o
STD_HEADERS = header.h
Compiler flags
CXXFLAGS = -c
The equivalent for /Fe is just -o, which is not specified as LDFLAGS, but spelled out on the linker command line.
Usually, you use the compiler for linking
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $(OBJ) -o $(EXE)
You don't need to specify the rules for object creation, they are built in. Just specify the dependencies
game.o: $(STD_HEADERS)
userInterface.o: $(STD_HEADERS)
del is called rm
clean:
rm -f $(OBJ)
rm -f $(EXE)
One important point is, indentation is one tab character, no spaces. If you have spaces instead, make will complain about
*** missing separator. Stop.
or some other strange error.
You can also use CMake to accomplish your task:
Put following into CMakeLists.txt file in the root directory of your project (<project-dir>):
cmake_minimum_required (VERSION 2.6)
project (NumberGuessingGame)
add_executable(NumberGuessingGame game.cpp serInterface.cpp)
Then on the console do
"in-source" build
$ cd <project-dir>
$ cmake .
$ make
or "out-source" build
$ mkdir <build-dir>
$ cd <build-dir>
$ cmake <project-dir>
$ make
You can adjust build setting using nice GUI tool. Just go to the build directory and run cmake-gui.
You don't need to include headers in the dependency list. The compiler will fail on its own, stopping make from continuing. However, if you're including them in the dependency list to force make to rebuild files in case the header changes, nobody will stop you.
CFLAGS never needs to contain -c, nor does LDFLAGS need -o. Below is a revamped makefile. Note that you can always override a macro explicitly defined in a makefile or implicitly defined using something like make CFLAGS=-Wall for example. I used the de facto standard CXX macro name in the event that you have C source files, which must be compiled using a C compiler (the value of the CC macro) instead of a C++ compiler.
.POSIX:
#CC is already implicitly defined.
CXX = g++
OBJ = game.o userInterface.o
STD_HEADERS = header.h
.SUFFIXES:
.SUFFIXES: .o .cpp .c
NumberGuessingGame: $(OBJ) $(STD_HEADERS)
$(CXX) $(CFLAGS) -o $# $(OBJ) $(LDFLAGS)
.cpp.o: $(STD_HEADERS)
$(CXX) $(CFLAGS) -c $<
#There is already an implicit .c.o rule, thus there is no need for it here.
#prepare for complete rebuild
clean:
-rm -f NumberGuessingGame *.o
As yegorich answered, you can use a build system like Cmake. It is much more flexible, cross-platform, and can generate Unix Makefiles as well as Nmake Makefiles and Visual Studio solutions on Windows.

Makefile for Shared Libraries?

I've just written a Makefile to build a shared library, similar to the following:
libmystuff.so: CFLAGS+=-fPIC -shared
libmystuff.so: libmystuff.o otherstuff.o
$(CC) $(CFLAGS) -o $# $^
I like to avoid doing explicit actions when this seems like a common operation, but it seems there's no implicit rule or other built-ins to standardize this. I'm using GNU Make on Linux at the moment, but will need this to work on OS X as well.
EDIT: I'm asking about make rules rather than compiler/linker flags.
Can you recommend clean, reusable Makefile rules to build shared libs? Perhaps a %.so: or .c.so: type rule?
For portability, I'd look into integrating libtool.
define compile_rule
libtool --mode=compile \
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
endef
define link_rule
libtool --mode=link \
$(CC) $(LDFLAGS) -o $# $^ $(LDLIBS)
endef
LIBS = libmystuff.la
libmystuff_OBJS = libmystuff.lo otherstuff.lo
%.lo: %.c
$(call compile_rule)
libmystuff.la: $(libmystuff_OBJS)
$(call link_rule)
install/%.la: %.la
libtool --mode=install \
install -c $(notdir $#) $(libdir)/$(notdir $#)
install: $(addprefix install/,$(LIBS))
libtool --mode=finish $(libdir)
libtool will automatically add -fPIC/-DPIC/-shared flags as appropriate, and generate whatever .o/.a/.so files would be used on the current platform.
Or you could use Automake's libtool integration.
Building shared libraries is platform dependent. For example, the flags you are using are
ok for GCC for ELF platforms, for cygwin, for example, you do not add -fPIC for some other platforms and compilers you need other flags.
You need one of:
Provide an option to set flags for user platform.
Use standard build system like Autotools

Resources