Makefile separate directories - makefile

It really takes a long time to read the make and gcc manual. Since I just need some basic function of them, I want to learn them quickly.
The project directory is like the following.
CWD
|----Source----1.cpp
|----Header----1.h
|----Object----1.o
|----Makefile
There are three directories and one Makefile in Current Working Directories, and "1.cpp" includes "1.h". I want to use Makefile which is in the CWD to compile the project such that the object output is in Object directory.
This is simplified version of the problem I have now. Since it is relatively hard to begin from scratch, could anyone help me to write a Makefile for this simple problem? And I will try to learn from it and solve my own problem. Or could anyone suggests which parts of make and gcc I need to learn to solve this problem.
Thanks in advance.

This will be enough to compile the source and produce the object:
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c Source/1.cpp -IHeader -o Object/1.o
If you want to build an executable, maybe called "one", add another rule above that:
one: Object/1.o
$(CXX) Object/1.o -o one
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c Source/1.cpp -IHeader -o Object/1.o
To clean things up a little, use automatic variables:
one: Object/1.o
$(CXX) $^ -o $#
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c $< -IHeader -o $#
And if you want to make the second rule more general, so that it can handle more objects you can turn the second rule into a pattern rule and separate the header dependency of 1.o:
one: Object/1.o
$(CXX) $^ -o $#
Object/1.o: Header/1.h
Object/%.o: Source/%.cpp
$(CXX) -c $< -IHeader -o $#
And of course there is a lot more you can do, when you're ready.

Related

Order of libraries and source files from makefile

I should start by saying I'm a bit of a newbie when it comes to gcc and makefiles.
On an Ubuntu machine that I've recently started using, I find that when running gcc, the order in which I put the source files and the libraries/headers makes a difference. On another machine I could do:
gcc -I../include -L../lib myProgram.c -o myProgram
But on the new machine, this will not link the libraries, and I must do:
gcc myProgram.c -o myProgram -I../include -L../lib
Now, I have the following makefile:
SHELL = /bin/sh
CC = gcc -O3
CFLAGS = -I../include
LDFLAGS = -L../lib
PROGS = myProgram
all: $(PROGS)
$(all): $(PROGS).o
$(CC) -o $# $#.o $(LIBS) $(CFLAGS) $(LDFLAGS)
rm -f $#.o
clean:
rm -f *.o $(PROGS)
But when I do "make", the actual gcc command that it runs has the libraries and source files in the wrong order. My question is: what do I need to do in the makefile to force the "-L../libs" option to come after the source files, so that the libraries will link properly?
I've also tried including the "-Wl,--no-as-needed" option, as I thought that an --as-needed flag might be the reason that the order matters in the first place, but this didn't appear to change anything (i.e. it still fails to link the libraries unless "-L../libs" comes after the source files).
The problem was that you thought you were using that rule, but you weren't. You never defined a variable named all, so the target of the second rule actually expanded to nothing. When you commanded Make to build myProgram, Make found no suitable rule in this makefile. Make has a toolbox of implicit rules it can fall back on in such cases; it wanted to build myProgram, it saw a file named myProgram.c, and one of its rules looks something like this:
%: %.c
$(CC) $(LDFLAGS) $^ -o $#
There you have it, linker flags before sources.
You can write your own pattern rule which Make will use instead:
%: %.o
$(CC) -o $# $^ $(LIBS) $(CFLAGS) $(LDFLAGS)
(Note that this builds myProgram from myProgram.o, and lets Make figure out how to build myProgram.o.)
If your executable is to be built from several object files, add a rule like this:
myProgram: other.o yetAnother.o
If you like you can have one more rule (the first) to tell Make what you want built:
all: myProgram myOtherProgram friendsProgram
(A final note: we've all had tight work deadlines. Asking for help once can be faster than learning the tools, but learning the tools is faster than asking for help N times. Determining the value of N is up to you.)

Variable dependent target in makefile

I have a small project for testing and I want to link different implementations of a solution to test.
So, I create makefile that looks like this
CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp
all: instance
instance: instance.cpp .implementation.o
$(CC) $(FLAGS) instance.cpp .implementation.o -o $#
.implementation.o: $(I_PATH)
$(CC) $(CFLAGS) $(I_PATH) -o $#
clean:
-rm .implementation*
-rm instance
Here, I_PATH is a path to solution implementation. And I want to test different solution passing different implementation via command line arguments: make I_PATH=implementation2.cpp.
But, because of all my implementations compiled to the same object file .implementation.o, make can't understand that something changes and doesn't rebuild project.
Of course, I can call make clean before run make for a specific implementation. But this increase build time (I can run tests for one implementation many times) and not very comfortable.
I can fix this makefile to something like this:
CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp
C_PATH := $(shell echo -n $(I_PATH) | md5sum | awk '{print ".implementation_" substr($$1, 0, 10) ".o";}')
all: force instance
force_relink:
touch -c $(C_PATH)
instance: instance.cpp $(C_PATH)
$(CC) $(FLAGS) instance.cpp $(C_PATH) -o $#
$(C_PATH): $(I_PATH)
$(CC) $(CFLAGS) $< -o $#
clean:
-rm .implementation*
-rm instance
Here I create I_PATH dependent object file(take hash of path to implementation) and in addition force re-linking instance.cpp with object file every time make runs.
But maybe there is some mechanism in make to fix this behavior? Or I can achieve the same goal with different approaches?
Wouldn't it make more sense to give each compiled .o file a distinct name, and simply link to the compiled .o file you want?
instance: instance.cpp $(IMPL_O)
$(CC) $(FLAGS) $^ -o $# # propably no need to override default rule
Use make IMPL_O=implementation2.o to generate the example in your question.
This way, the name of each file truly reveals its identity, and you don't have to keep track of anything explicitly.
(Obviously, you could refactor the .o extension into the Makefile itself so you can just say IMPL=implementation2 or whatever.)

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.

Recovering from an abruptly ended make

When I compile large programs (like gcc or clang for example) there is a chance that my computer will overheat, and be forced to shut down.
I would like to resume the make process from where I left off. The problem seems to be that there are half completed/written .o files that are floating around that cause the rest of the built to break (this is especially bad when I specify -j 8)
Is there an easy way to get around this problem (whithout doing a make clean or make distclean or the like)?
Using GNU Make 3.81
Along the same lines as Beta's comment, but more reliable and less confusing IMO, would be to change your compile rule so that you compile to a temporary file, then at the end rename it to the real file. So where you might have something like:
%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $# -c $<
instead you would use something like:
%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $#.tmp -c $< \
&& mv -f $#.tmp $#
You may or may not want to add a "rm -f $#" as well.
As to whether you can make this change "programmatically" or not, it all dependes on your makefile and how it's structured. If it's a well-formed makefile then you can just make these changes in a few places in a few implicit rules, as above.

How do I write a clean Makefile?

The Makefiles that I have dealt with, for the most part, are complex and hide a lot of relationships. I have never written one myself, and was wondering if anybody had some tips on writing a Makefile that is easy to read and reusable?
I usually use something like this, in this example the source files are main.c file2.c file3.c file4.c, to add more you simply add to the OBJECTS var.
They all depend on Makefile, so for a full recompile a simple touch Makefile would suffice.
PROGNAME = hi2u
LIBS = -ljpeg -ldirectfb -pthread
INCLUDES = -I/usr/local/include/directfb
LDFLAGS = -Llibs/
OBJECTS = main.o file2.o \
file3.o file4.o
CFLAGS = -W -Wall -O2 -ggdb
all: $(PROGNAME)
$(PROGNAME): $(OBJECTS)
gcc -o $(PROGNAME) $(OBJECTS) $(LIBS) $(INCLUDES) $(LDFLAGS)
$(OBJECTS): Makefile
.c.o:
gcc -c $(CFLAGS) $(INCLUDES) -o $# $<
clean:
rm *.o $(PROGNAME)
In all honesty, the complexity of a makefile relies on the complexity of the program. If you have a lot of folders and files and different compiling processes, you're makefile is probably going to be a little long and complicated. If you have a helloworld program, there's no reason for it to be longer than a few lines.
Here's some tips on makefiles : http://mrbook.org/tutorials/make/
Here's a very reusable makefile that's not too complicated:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
A tutorial that I've found helpful for understanding Makefiles is http://www.jfranken.de/homepages/johannes/vortraege/make_inhalt.en.html
Another tip is to make generous use of regular expressions for source files and dependencies
For me, the read that got me thinking about these issues, is the classic "Recursive Make Considered Harmful".
When I get the chance to create makefiles from scratch, I try to use implicit rules as much as possible, and also define rules in a separate file, which I can include from the "real" makefile.
The challenges with using make can be divided in two major groups:
issues inherent with make itself, its rich semantics and syntax and somewhat archaic appearance
issues which are not makes "fault", but come from when make is used to call another make process. Suddenly we have another task at hand - communicating between two or more make processes. It is very easy to get lost with environment variables or other ways to pass information. Platform differences which make itself is designed to hide, may become visible.

Resources