Compile multiple **changed** source files at once in GNU make - c

I know there have been several questions with similar titles but none seem to provide an answer to what I need (correct me if I'm wrong).
Consider this makefile:
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $# $(OBJECTS)
file1.o: file1.cpp file1.h
file2.o: file2.cpp file2.h file1.h
file3.o: file3.cpp
.cpp.o:
$(CXX) $(CXXFLAGS) -c -o $# $<
If I change file1.h, the following is run:
g++ -c -o file1.o file1.cpp
g++ -c -o file2.o file2.cpp
g++ -o myprog file1.o file2.o file3.o
What I would like to have is:
g++ -c file1.cpp file2.cpp
g++ -o myprog file1.o file2.o file3.o
(I know I can't specify object output directory with GCC, but this I can live with; it should be possible to work around with some cd commands.)
In nmake, this is done with a double-colon inference rule (so-called called "batch-mode rule"). Basically, it groups the inference rules (e.g. ".obj.cpp:") for multiple targets and invokes the compiler for all dependencies instead of once per file. The $< variable gets the list of dependencies instead of just the first one.
Right now we're using parallel building (make -j) but it has its own issues, and VC++ compiler works much better in one-invocation mode so I'd prefer using that.

I don't see why you want this effect, but here's how to get it (in GNUMake):
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $?
$(CXX) -o $# $(OBJECTS)
EDIT:
I'm surprised that that solution works -- there's something wrong with my idea of what Make does -- but I don't think it'll work in your case, with header dependencies, without the following kludge. (There are one or two other approaches that might work, if this doesn't pan out.)
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $# $(OBJECTS)
file1.cpp: file1.h
file2.cpp: file2.h file1.h
$(SOURCES):
#touch $#
$(OBJECTS): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $?
#touch $(OBJECTS)

You can make GNUmake do what you want by collecting the files to be rebuilt in the build rule and then actually building them when you link:
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
.PHONY: build_list
build_list:
-rm -f build_list
$(OBJECTS): %.o: %.cpp | build_list
echo $< >> build_list
$(EXECUTABLE): build_list $(OBJECTS)
if [ -r build_list ]; then $(CXX) $(CXXFLAGS) -c `cat build_list`; fi
$(CXX) -o $# $(OBJECTS)
file1.o: file1.h
file2.o: file2.h file1.h

Related

How to make a modular Makefile for a modular c project?

I have a C program that has this code:
#if defined(MATRIX)
#include "Matrix.h"
#elif defined(QTREE)
#include "QTree.h"
#endif
and I want to create a Makefile that given a target passes de -D flag to GCC with the corresponding MACRO so that the correct header + source files are compiled.
Currently I have this Makefile:
# Makefile for compiling the battleship game
C=gcc
STANDARD=c99
HEADER_DIR=includes
ODIR=obj
CFLAGS=$(C) -c -std=$(STANDARD) -I$(HEADER_DIR)
SDIR=src
_OBJS = Battleship.o Game.o Cell.o Ship.o Bitmap.o IO.o Aux.o Matrix.o QTree.o Board.o
OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))
# Program name
PROG=battleship
$(ODIR)/%.o: $(SDIR)/%.c
$(CFLAGS) -o $# $<
$(PROG1): $(OBJS)
$(C) -o $(PROG) -D MATRIX $(OBJS)
$(PROG2): $(OBJS)
$(C) -o $(PROG) -D QTREE $(OBJS)
.PHONY: game_with_matrix
game_with_matrix: $(PROG1)
.PHONY: game_with_qtree
game_with_qtree: $(PROG2)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o $(PROG)
but it always outputs: make: Nothing to be done for [target].
I don't really know whats wrong :(
EDIT:
when I invoke make I am using either make game_with_matrix or make game_with_qtree.
Thanks in advance!
First, this:
C=gcc
CFLAGS=$(C) -c -std=$(STANDARD) -I$(HEADER_DIR)
$(ODIR)/%.o: $(SDIR)/%.c
$(CFLAGS) -o $# $<
"CFLAGS" is a bad name for that. I strongly advise this:
C=gcc
CFLAGS= -c -std=$(STANDARD) -I$(HEADER_DIR)
$(ODIR)/%.o: $(SDIR)/%.c
$(C) $(CFLAGS) -o $# $<
Now you could add a target-specific variable value:
$(PROG1): CFLAGS += -DMATRIX
$(PROG1): $(OBJS)
$(C) -o $(PROG) $(OBJS)
$(PROG2): CFLAGS += -DQTREE
$(PROG2): $(OBJS)
$(C) -o $(PROG) $(OBJS)
But you haven't yet defined PRG1 nor PROG2, and I see no need for them. Get rid of them and do this:
$(PROG): $(OBJS)
$(C) -o $# $^
game_with_matrix: CFLAGS += -DMATRIX
game_with_matrix: $(PROG)
game_with_qtree: CFLAGS += -DQTREE
game_with_qtree: $(PROG)
Is this the actual makefile you're using? Because you've not defined either the variable PROG1 or the variable PROG2, so if your makefile looks like that that's clearly the problem.
However, even if you fix that this is dangerous. You should not put both types of objects into the same subdirectory. You'll have to remember to always do a make clean when switching between them because make has no way to know if the previous build used the MATRIX or QTREE settings and you'll be trying to link object files compiled with different settings.
You should create two different OBJ directories, one for each, and use them when building that program.

How do I write a "selective" Makefile?

noob question here.
I have a directory with a lot of .c files, they're basicely libc functions that I code myself as an exercice.
I write a little main() in these files to test the functions, and I want to write a Makefile that allow me to compile only the file I want to test, for exemple:
make memset.c
And get only the executable of the code wrote in memset.c.
I tried to do something like this:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
all : %.o
$(CC) $(CFLAGS) $<
%.o : %.c
$(CC) $(CFLAGS) $< -c -o $#
But obviously it doens't work. I don't what to put in place of the "all".
I know it's very basic, but I didn't manage to do it, and I did research but didn't find an answer to this specific question.
Thanks in advance for your help.
If you do make -n -p you get a dump of all of the built-in rules in make. In GNU Make 4.1, this includes:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
So you might just needs a % in your makefile where you currently have all.
You also might find that you don't need those rules which are already built in. Suppose you have three C files, each with a main() as you specify: abs.c, div.c and fmax.c. Your Makefile needs to be no more than two lines:
CFLAGS = -Wall -Wextra -pedantic
all: abs div fmax
which would then allow you to do make abs to make the abs executable, and make all to make them all.
You can define static pattern rules to build the object files and the executables and then invoke make with the name of the executable you want as the goal:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
SRC := $(wildcard *.c)
OBJ := $(patsubst %.c,%.o,$(SRC))
EXE := $(patsubst %.c,%,$(SRC))
.PHONY: all obj
all: $(EXE)
obj: $(OBJ)
$(EXE): %: %.o
$(CC) $(LDFLAGS) $< -o $#
$(OBJ): %.o: %.c
$(CC) $(CFLAGS) $< -c -o $#
.PHONY: clean
clean:
rm -f $(OBJ) $(EXE)
Then:
$ make memset.o
builds only memset.o,
$ make memset
builds only memset (and memset.o if needed),
$ make obj
builds all object files,
$ make # or make all
builds all executables (and object files if needed), and
$ make clean
deletes all executables and object files.
With wildcard, you can achieve what you want.
Note that if each program depends on only one .c file, you don't need %.o rules:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
SRC := $(wildcard *.c)
EXEC = $(SRC:%.c=%)
all: $(EXEC)
%: %.c
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
And just invoke this way for instance:
make memset
You already have most you to compile the executable selectively:
CC = gcc
CFLAGS = -Wall -Wextra -pedantic
%.o : %.c
$(CC) $(CFLAGS) $< -c -o $#
% : %.o
$(CC) $(LDLAGS) $< -o $#
Then you just need to call make with the target you want, the executable:
make select
If you have several sets of executable with different flags, you can use:
EX0 = drink clean
${EXE0}: % : %.o
$(CC) $(LDLAGS) -lwater $< -o $#
EX1 = burn melt
{EX1}: % : %.o
$(CC) $(LDLAGS) -lfire $< -o $#

Makefile not compiling all C files in directory

Iam working with gcc and MinGW on a Windows platform. I have a directory containing two *.c files:
main.c and funcs.c
I am using the following makefile:
CC=gcc
CFLAGS=-c
LDFLAGS=
SOURCEDIR = src
BUILDDIR = build
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(BUILDDIR)/%.o,$(SOURCES))
LIBRARIES=-L/mingw64/lib
INC= -I./include
EXECUTABLE=testLink
VPATH = src include build
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBRARIES) -o ./dist/$#
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
Which should take the *.c files and generate *.o files with the same name. However I get the following output on make -
$ make
gcc -I./include -c src/funcs.c -o build/funcs.o
gcc -I./include -c src/funcs.c -o build/main.o
gcc build/funcs.o build/main.o -L/mingw64/lib -o ./dist/testLink
followed of course by a bunch of multiple definition errors. As you can see from the first two lines it is taking the same *.c file and compiling it twice into two different *.o files.
I am new to makefiles but I assume it is something wrong with my $(OBJECTS) rule and I'm pretty sure it's the $< which is causing the problem. I'm trying to create a generic makefile which will always work on my projects which have the same directory structure and take .c files turn them into .o files and link. Am I going about this entirely the wrong way or is there a simple fix to my makefile?
Thanks!
James
This rule:
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
expands to:
funcs.o main.c: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
which is equivalent to:
funcs.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
main.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
$< refers to the first dependency (funcs.c) so your Makefile is trying to generate both funcs.o and main.o from the same source.
You just want a generic rule using % wildcard matching:
%.o: %.c
$(CC) $(INC) $(CFLAGS) $< -o $#
See https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Jeff pointed the mistake in his answer (all objects depend on all sources: that isn't a generic compilation rule for c sources).
However, the generic rule must have source & object paths. To sum it up, just replace
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
by
$(BUILDDIR)/%.o : $(SOURCEDIR)/%.c
$(CC) $(INC) $(CFLAGS) $< -o $#
(as explained in How to generate a Makefile with source in sub-directories using just one makefile)
note that this kind of dependency test doesn't take included .h files into account, so it's only intended for first builds. Modifying .h files afterwards doesn't trigger a compilation since the header files are not listed as dependencies.

C - Makefile possibly missing a line

I'll say first I don't have as much experience which makefiles as I wished, this is actually my first.
The error I currently get is:
Makefile:1: missing separator. Stop.
This happens when I try to run the make command.
As far as I know this means that I'm missing a hard tab at the first line it tries to run, I think at least.
I'm not missing a hard tab though as far as I know, so I'm assuming I'm just missing a whole line somewhere.
CFLAGS = -ansi -Wall -pedantic
HEADERS = menu.h file1.h file2.h file3.h file4.h
OBJECTS = menu.o file1.o file2.o file3.o file4.o
CC = gcc
all:runprog
runprog:$(OBJECTS)
$(CC) $(OBJECTS) -o runprog
menu.o:menu.c $(HEADERS)
$(CC) $(CFLAGS)
file1.o:file1.c $(HEADERS)
$(CC) $(CFLAGS)
file2.o:file2.c $(HEADERS)
$(CC) $(CFLAGS)
file3.o:file3.c $(HEADERS)
$(CC) $(CFLAGS)
file4.o:file4.c $(HEADERS)
$(CC) $(CFLAGS)
clean:rm -f *.o runprog
The clean target has its code in the place of dependencies. Also, your code uses spaces instead of tabs. Additionally, you forgot to add the .c files to the CC command lines. Moreover, you can simplify all the rules to
CFLAGS = -ansi -Wall -pedantic
HEADERS = menu.h file1.h file2.h file3.h file4.h
OBJECTS = menu.o file1.o file2.o file3.o file4.o
CC = gcc
all:runprog
runprog:$(OBJECTS)
$(CC) $(OBJECTS) -o runprog
%.o: %.c $(HEADERS)
$(CC) -c -o $# $< $(CFLAGS)
clean:
rm -f *.o runprog

How to use a variable list as a target in a Makefile?

Suppose I am working on a makefile and I have the following variable declaration at the top:
FILES = file1.cpp file2.cpp file3.cpp
Now suppose I want to compile each of those with a special command without specifying each target like this:
file1.o : file1.cpp
custom_command file1.cpp
file2.o : file2.cpp
custom_command file2.cpp
file3.o : file3.cpp
custom_command file3.cpp
Is there a better way to do this using the $(FILES) variable I declared above?
Something like:
$(FILES:.cpp=.o) : $(FILES)
custom_command $(FILES)
...only it needs to do this for each file in the $(FILES) variable.
Yes. There are what are known as pattern rules. An example is the easiest to understand:
%.o: %.cpp
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
(remember that Makefiles require tabs). This rule describes how to make an object file from a cpp file.
If you do not want such a broad rule, you can use what are called static patterns:
objects = file1.o file2.o file3.o
all: $(objects)
$(objects): %.o: %.cpp
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
Here's the section on static pattern rules and pattern rules in the GNU Make manual.
You can do that, as per the following:
SRCS=a.c b.c
OBJS=$(SRCS:.c=.o)
$(OBJS): $(SRCS)
cc -c -o a.o a.c
cc -c -o b.o b.c
but you have to remember that the dependencies are complete - it assumes that a.o depends on b.c as well which is probably not the case.
What you're probably after is a single rule on how to turn one file type into another:
SRCS=a.c b.c
OBJS=$(SRCS:.c=.o)
all: $(OBJS)
.c.o:
gcc -c -o $# $<
.c.o is such a rule which states what commands to run to turn a .c file into a .o file. In the actual command, $# is replaced with the specific target and $< is replaced with the name of the first prerequisite.
There are many other automatic variables you can use, look them up with info make or look for a good book on make if you don't have the info stuff available.
SRCS = a.c b.c
OBJS = $(SRCS:.c=.o)
.c.o:
${CC} ${CFLAGS} -c -o $# $<
Though $< isn't quite portable (IIRC, bsdmake has the meaning of $^ and $< exactly swapped to what gmake uses), this is the default recipe for .c.o that would be in effect in either implementation.

Resources