How do I write a clean Makefile? - 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.

Related

How to configure a dynamic library using a macro / variable in a makefile?

I'm writing a small study project in C. I need to create a dynamic library and configure its use with macros. First, I create object files with the command:
$gcc -fPIC -c ../data_module/data_process.c
$gcc -fPIC -c ../data_libs/data_stat.c
Then I create a dynamic library like this:
$gcc -shared -o data_process.so data_process.o data_stat.o
And finally I build an executable file using this library:
$gcc main_executable_module.o ../data_libs/data_io.o ../yet_another_decision_module/decision.o -L. data_process.so -o test_main
It works and the executable works correctly. But there is a task to configure the library using macros:
Make the necessary changes to the code of the main_executable_module, configuring the use of the dynamic library using macros.
That is, if I understand correctly, you need to add macros to the main_executable_module.o so that you do not use the -L flags during assembly. But I can't find information anywhere on how to do it. Can you please tell me how to implement this or where can I read about it?
UPD: John Bollinger says
It is possible that the word "macros" is intended to be interpreted as makefile macros, which many people instead call (makefile) "variables". That would make this a question about make / makefiles, not about C.
My Makefile:
CC=gcc
LDFLAGS=
CFLAGS=-c -Wall -Wextra -Werror
SOURCES=main_executable_module.c ../data_libs/data_stat.c ../data_libs/data_io.c ../yet_another_decision_module/decision.c ../data_module/data_process.c
DYNLIB=../data_module/data_process.c
STAT=../data_libs/data_stat.c
BUILDDYN=main_executable_module.c ../data_libs/data_io.c ../yet_another_decision_module/decision.c
OBJECTS=$(SOURCES:.c=.o)
OBJBUILDDYN=$(BUILDDYN:.c=.o)
OBJDYNLIB=data_process.o
OBJDATASTAT=data_stat.o
EXECUTABLE=../../build/main
DEXECUTABLE=../../build/Quest_6
DLIBS=data_process.so
all: $(SOURCES) $(EXECUTABLE)
data_stat.a: $(OBJLIB) $(LIBS)
ar -rcs $(LIBS) $(OBJLIB)
data_process.so: $(OBJDYNLIB) $(OBJDATASTAT)
$(CC) -shared -o $(DLIBS) $(OBJDYNLIB) $(OBJDATASTAT)
$(OBJDYNLIB): $(DYNLIB)
$(CC) -fPIC -c $(DYNLIB)
$(OBJDATASTAT): $(STAT)
$(CC) -fPIC -c $(STAT)
build_with_dynamic:$(OBJECTS) $(EXECUTABLE)
$(CC) $(OBJBUILDDYN) -L. $(DLIBS) -o $(DEXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -rf $(EXECUTABLE) $(OBJECTS)
lclean:
rm -rf $(LEXECUTABLE) $(OBJECTS) $(LIBS) $(DEXECUTABLE)
rebuild: clean $(SOURCES) $(EXECUTABLE)
The results of the checks revealed nothing. There are two opinions about this task.
Leave everything as above. And in the file itself, add a header process.h. Then everything is assembled and working. And at the same time, if you change the code in the library, rebuild it, and do not rebuild the executable file, then the changes will be taken into account. That is, the idea of ​​a dynamic library is respected.
Implement in such a way that there is no need to include headers in the main_executable_module.c. Then a special library is used for working with dynamic libraries, which allows you to write the path to the library and take individual functions from it. More about it here.
What was meant when it was said about macros, I still did not understand ...

What are the automatic rules make is using to build objects files without being specified?

I have an old project with several C++ source and header files in a directory which are built in cygwin using GCC and a makefile. On editing the makefile to move all the temporary and output files into a sub-directory, the rules to build the object files didnt have any effect.
$(BIN): $(OBJ)
$(CXX) $(LDFLAGS) -o $(BIN) $^
%.o: %.c
$(CXX) $(INC) $(CXXFLAGS) $# -c -o $<
The following makefile still builds the output binary without having any rules to build the object files from source code.
INC=-I.
CXX=g++
CXXFLAGS=-std=c++11 -Wall -Wextra -Wconversion -pedantic -O2 -g
LDFLAGS=
CLEAN_FILES=*.o *.out *.stackdump *.exe *.gcno *.gcda
BIN=app
SRC=$(wildcard *.cpp)
OBJ=$(SRC:%.cpp=%.o)
all: $(BIN)
$(BIN): $(OBJ)
.PHONY: clean
clean:
rm -f $(CLEAN_FILES)
What is this automatic behavior called?
Two notes regarding built-in rules:
In large projects (which will have their owner rules for compiling, linking, ....), it might be easier to start with no built-in rules (make -r or make --no-builtin-rules).
Many built-in rules have hooks, via variables, that allow configuration changes. For example:
%.o: %.c:
$(COMPILE.c) $(OUTPUT_OPTION) $<
...
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
Where opssible to customize the command by modifying "CFLAGS", "CPPFLAGS", etc. Common examples will be make "CFLAGS=-O -g" to get optimized debug program, without having to redefine all the rules.
The set of rules that make knows about without you having to define them are called built-in rules. The manual lists most of them but not all of them. You can run make -p -f/dev/null to see a list of them all.

Multiple compilers in one Makefile

I found this question here, which does exactly what I want. However, being new to makefiles, I am having a hard time seeing how to implement the second answer in my current setup.
I have a simple makefile for which I would like to use different compilers when compiling for Linux or cross-compiling for Windows. As presented, the file below works. To make for Linux I just type make, and for windows I type make os=win. In the interest of learning how makefiles work a little better, I would like to be able to implement the linked answer in the current Makefile so that I can make for windows just by typing make win or make cross as presented in the linked question.
Could someone help me understand how the structure presented in the linked answer could be implemented in the specific case I have here? Presumably there is a more elegant way than having native: and cross: targets and replicating almost the entirety of the code across both.
Any suggestions for cleaning up the Makefile in general are also welcome.
ifeq ($(os),win)
CC=x86_64-w64-mingw32-gcc
OUT=cusum.exe
else
CC=gcc
OUT=cusum
endif
CFLAGS=-D_GNU_SOURCE -O3 -Wall -Wextra -lm --static
DEPS=bessel.h detector.h io.h stepfit.h lmmin_int64.h utils.h
ODIR=obj
_OBJ=main.o bessel.o detector.o io.o lmmin_int64.o stepfit.o utils.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
LIBS=-lm
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$(OUT): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
.PHONY: clean
clean:
rm -f $(OUT) $(ODIR)/*.o *~ core $(INCDIR)/*~
You only have to introduce an upper-level target. Target-specific variables are inherited by their prerequisites, so you don't have to change all the targets.
However, you cannot update the content of targets or prerequisites using this method so you can't remove the assignment of OUT. This means you can't get rid of the OS variable assignment.
One simple way to do it is to use recusive invocations of make. Write your makefile normally:
O = o
E =
CC = gcc
OUT = cusum$E
CFLAGS = -D_GNU_SOURCE -O3 -Wall -Wextra -lm --static
DEPS = bessel.h detector.h io.h stepfit.h lmmin_int64.h utils.h
ODIR = obj
_OBJ = main.$O bessel.$O detector.$O io.$O lmmin_int64.$O stepfit.$O utils.$O
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
LIBS = -lm
$(ODIR)/%.$O: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$(OUT): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
.PHONY: clean
clean:
rm -rf $(OUT)* obj wobj *~ core $(INCDIR)/*~
Then add a target that recursively invokes make overriding the relevant variables (be sure to put it at the end or at least after the $(OUT) target):
win:
$(MAKE) CC=x86_64-w64-mingw32-gcc E=.exe O=obj ODIR=wobj
Now you can run make win and it will recursively invoke make overriding the appropriate variables.

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.)

Is there a way to create a Makefile without running ./configure?

I'd like to skip the tests and create a (default) Makefile.
Of course you can write a makefile by hand. A quick googling shows LOTS of tutorials. This one looks promising.
For the cliffs notes version, the example boils down this:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
Why would you want to second guess what the author laboured over? People don't generate configure scripts for fun - they generate configure scripts because determining the correct way to compile the program on your system is hard and running ./configure is easier than all the alternatives.
If you happen to be using Perl, there's always good ol'
use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'Foo::Bar',
'DISTNAME' => 'Foo-Bar',
'EXE_FILES' => ["foobar.sh"],
'VERSION_FROM' => 'lib/Foo/Bar.pm',
);
However, your question is a bit short, if you are merely building an existing project you may find it impossible to skip configure.

Resources