Adding dependencies changes the target to the first C file - makefile

Consider the following makefile:
.SUFFIXES:
SRC:=../Src
OBJ:=../Obj
# Sources
SOURCES := $(SRC)/App/a.c $(SRC)/App/b.c $(SRC)/App/c.c
HEADERS := $(wildcard $(SRC)/App/*.h)
# Directories
INC_DIRS := $(SRC)/App
OBJ_INC_DIRS := $(INC_DIRS:$(SRC)/%=$(OBJ)/%)
# Objects
OBJECTS := $(SOURCES:$(SRC)%=$(OBJ)%.obj)
# Dependencies
DEPS := $(SOURCES:$(SRC)%.c=$(OBJ)%.d)
-include $(DEPS)
GCC_INCLUDES := $(foreach directory, $(INC_DIRS), -I$(directory))
all: target
target: $(OBJECTS)
touch target
#Objects
$(OBJ)%.c.obj: $(SRC)%.c
#echo Compiling $#
#touch $#
# Dependencies
$(OBJ)%.d: $(SRC)%.c
#echo Checking dependencies for $<
#gcc -MM $< $(GCC_INCLUDES) -MT '$(patsubst %.d,%.c.obj,$#)' -MT '$#' -MF '$#'
#[ ! -s $# ] && rm -f $#
# Creating directory tree before checking dependencies
$(DEPS):|$(OBJ_INC_DIRS)
$(OBJ_INC_DIRS):
#mkdir $#
clean:
echo clean
#rm $(OBJ_INC_DIRS)
When running the first time, I get:
Checking dependencies for ../Src/App/a.c
Checking dependencies for ../Src/App/b.c
Checking dependencies for ../Src/App/c.c
clean
Compiling ../Obj/App/a.c.obj
Compiling ../Obj/App/b.c.obj
Compiling ../Obj/App/c.c.obj
touch target
It's ok, but now, make again (without modifying any file):
make: `../Obj/App/a.c.obj' is up to date.
Now if I modify the file a.c
Checking dependencies for ../Src/App/a.c
Compiling ../Obj/App/a.c.obj
target isn't remade !
It's like my file a.c is the target but it isn't... Can someone explain me what's wrong here?
If I remove the include to the DEPS, I observe the expected behavior...
Thanks
EDIT
By putting the include at the end as mentioned by #Beta works but now I added the target clean and show the result...

I'll have to do some experiments to be sure, but I think the problem is:
-include $(DEPS)
...
all: target
You include $(DEPS) before the first target. So if you modify a.c, Make sees that it must rebuild a.d, then since it includes that file it must start over, and now a.c.obj is an earlier target than all.
Try moving -include $(DEPS) to the end of the makefile.
EDIT:
(Two small points: your clean rule is incorrect, since it tries to rm a directory, and I would do make clean; make all rather than make all, since I am not certain that Make promises to build targets in the given order in all cases.)
Yes, this makefile will rebuild the DEPS even when running clean. The makefile includes those files and has a rule for them, so if they are missing or out of date it must rebuild them and restart, no matter what the target is. The best way to deal with this is by Advanced Auto-Dependency Generation; basically, the commands that build dependency files go in the %.obj rule, so that a.d is a side effect of building a.c.obj. It's a sophisticated technique, not obvious, but it works beautifully. (Let us know if you try this and have trouble setting it up.)

Related

Makefile do not regenerate main target after delete it

I learning to write makefile. I meet a problem today. My makefile makes the main target successfully. Then I delete the main target and run the "make" command again. But the makefile did not make the main target, just show "make: `main.o' is up to date". I don't know why. Here is my makefile and folder structure:
CXX := g++
FLAGS := -std=c++11
INCLUDE_DIR := $(shell find . -type d)
SOURCE_DIR := $(INCLUDE_DIR)
SOURCE_FILE := $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)/*.cpp))
OBJECT_FILE := $(SOURCE_FILE:%.cpp=%.o)
-include $(OBJECT_FILE:%.o=%.d)
TARGET := app
all: $(TARGET)
$(TARGET): $(OBJECT_FILE)
$(CXX) $(FLAGS) -o $# $(OBJECT_FILE)
$(OBJECT_FILE): %.o: %.cpp | $(SOURCE_DIR)
$(CXX) $(FLAGS) -c $< -o $# -MD -MF $(#:.o=.d)
./-----main.cpp
|---test
|---func.h
|---func.cpp
Unless you choose a specific target to be built on the command line (via make <target>), make will always choose the first target it sees in the makefile as the default target to be built
Consider these lines in your makefile:
-include $(OBJECT_FILE:%.o=%.d)
TARGET := app
all: $(TARGET)
When nothing is built, there are no .d files so the -include doesn't include anything. Then make finds the target all and uses that as the default.
The second time through the makefile, there are .d files so the -include command includes them. Those files define some targets, the first of which is main.o, and so now that is the first target and built by default.
You should move your -include down to the end of the makefile and ensure that the all target is always the first one built.
Just as an aside, I don't know if it's an artifact of your cut and paste into SO, but many of your lines have extra whitespace at the end. You should be aware that extra whitespace at the end of lines IS SIGNIFICANT in makefiles, in many places. I highly recommend using an editor that will allow you to visualize whitespace and/or automatically strip extra whitespace at the end of lines.

Makefile skips dependency

I've created a makefile for my little project
.SUFFIXES:
%.cpp:
$(COMP) -c -o $(subst .cpp,.o,$#) $(SRCDIR)$# $(CFLAGS)
platformL: COMP:=gcc
platformL: $(FILES)
$(COMP) -o $(NAME) $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
platformW: COMP:=wine gcc
platformW: $(FILES)
$(COMP) -o $(NAME).exe $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
default: platformL platformW
echo Done!
Everything worked fine until I branched to 2 different platforms, 'make' command executes only my platformL branch. After spending some time with it I discovered that adding '.PHONY' won't fix the problem. Also, it appears that only the first branch from the top gets executed (I have put the lines of platformW before platformL and only Windows compilation was performed).
How can I make it execute both branches?
Make always builds the first explicit target (and all prerequisites of the first explicit target) in the makefile, by default. That's all it will build by default.
You can either specify multiple things to build on the command line, like make platformL platformW, or you can add a new first target that depends on all the other targets you want built. By tradition that target is named all but you can call it whatever you want:
all: platformL platformW
.PHONY: all
...
platformL: ...
...
platformW: ...

Makefile with Fortran - src and bin directories

I'm having some trouble understanding how to design my makefile to build my project the way I want to. Specifically, I can't figure out how to keep all source files in a src directory, while putting all binaries in a bin directory except the linked executable, which goes in the project root.
This is my makefile:
# Compiler options
FC := mpif90
FFLAGS := -O3 -g -Wall -Warray-bounds -ffixed-line-length-none -fbounds-check
VPATH := src
BINDIR := bin
# Define file extensions
.SUFFIXES:
.SUFFIXES: .f .o .mod
# All modules
OBJS := $(BINDIR)/ratecoeffs.o $(BINDIR)/interpolation.o $(BINDIR)/io.o $(BINDIR)/eedf.o $(BINDIR)/single_particle.o $(BINDIR)/physics.o $(BINDIR)/random.o $(BINDIR)/mpi.o $(BINDIR)/precision.o $(BINDIR)/populations.o
# Build rules
all: runner | $(BINDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(BINDIR)/%.o: $(VPATH)/%.f | $(BINDIR)
$(FC) $(FFLAGS) -c $^ -o $#
runner: $(OBJS)
clean:
#rm -rf $(BINDIR)
Running make builds everything allright - it finds all source files in src and puts all .o files in bin - but the module files (.mod) that are generated by the compiler are put in the project root instead of in the bin directory. I realize I could just specify a rule to place them there, but that messes with the build order, and will sometimes break the build.
What is the "correct" way to get this behavior?
And yes, I've looked at autotools and automake, but I've never used them before and they seem to be overkill for this project. As I couldn't find any good tutorials on how they work (no, I didn't like the tutorial on gnu.org) I'd prefer if I could avoid having to learn this tool just to get this work...
Assuming your underlying Fortran compiler is gfortran, use the -J command line option.
$(FC) $(FFLAGS) -c $^ -o $# -J$(BINDIR)
With an eye to the future, you may be better off creating a MODDIR or similar variable, that you use instead of BINDIR. Object code (*.o) and mod files have different roles to play in later compilation and linking steps - in larger projects they are often kept separate.
It would be probably more in the sense of the make system to change into the obj-directory and do the compilation from there. Via the VPATH option you can let make to find your source files automatically. You could easily call your makefile recursively from the right directory. Below you find a trivial example which would be straightforward to adapt to your case. Please note, that it only works with GNU make.
ifeq (1,$(RECURSED))
VPATH = $(SRCDIR)
########################################################################
# Project specific makefile
########################################################################
FC = gfortran
FCOPTS =
LN = $(FC)
LNOPTS =
OBJS = accuracy.o eqsolver.o io.o linsolve.o
linsolve: $(OBJS)
$(LN) $(LNOPTS) -o $# $^
%.o: %.f90
$(FC) $(FCOPTS) -c $<
.PHONY: clean realclean
clean:
rm -f *.mod *.o
realclean: clean
rm -f linsolve
accuracy.o:
eqsolver.o: accuracy.o
io.o: accuracy.o
linsolve.o: accuracy.o eqsolver.o io.o
else
########################################################################
# Recusive invokation
########################################################################
BUILDDIR = _build
LOCALGOALS = $(BUILDDIR) distclean
RECURSIVEGOALS = $(filter-out $(LOCALGOALS), $(MAKECMDGOALS))
.PHONY: all $(RECURSIVE_GOALS) distclean
all $(RECURSIVEGOALS): $(BUILDDIR)
+$(MAKE) -C $(BUILDDIR) -f $(CURDIR)/GNUmakefile SRCDIR=$(CURDIR) \
RECURSED=1 $(RECURSIVEGOALS)
$(BUILDDIR):
mkdir $(BUILDDIR)
distclean:
rm -rf $(BUILDDIR)
endif
The principle is simple:
In the first part you write your normal makefile, as if you would create the object files in the source directory. However, additionally you add the VPATH option to make sure the source files are found (as make will be in the directory BUILDDIR when this part of the makefile is processed).
In the second part (which is executed first, when the variable RECURSED is not set yet), you change to the BUILDIR directory and invoke your makefile from there. You pass some helper variables (e.g. the current directory) and all make goals, apart of those, which must be executed from outside BUILDDIR (e.g. distclean and the one creating BUILDDIR itself). The rules for those goals you specify also in the second part.

Why isn't make detecting changes in header dependencies

I'm not sure what I'm doing wrong here. I'm trying to get make to figure out what dependencies my project has for, not only source files, but non-system included header files. I've many resources from this very site related to this subject.
Such as: Makefile header dependencies and Makefile, header dependencies
However, when I do
touch MyHeader.h
as a test to see if this works, my make process fails to rebuild the source files that include this header. So, here's what I have in my makefile (of relevance that is)
CPP=g++
CPPFLAGS=-Iadditional/includes -MMD
CXXFLAGS=-std=c++0x -c
# not every source file in this directory needs to be included in this build
# this is because of shared code with Windows
SOURCESFILTER = File1.cpp File2.cpp
OBJ_DIR=obj
SOURCES = $(filter-out $(SOURCEFILTER),$(wildcard *.cpp))
OBJECTS = $(addprefix $(OBJ_DIR)/,$(SOURCES:.cpp=.o))
DEPENDENCIES = $(OBJECTS:.o=.d)
.PHONY: archive
archive : $(OBJECTS)
ar mylib.a obj/*.o
-include $(DEPENDENCIES)
$(OBJ_DIR)/%.o: $(SOURCES) $(DEPENDENCIES)
$(CPP) $(CPPFLAGS) $(CXXFLAGS) $< -o $#
I've verified that the above process does indeed generate the expected *.d files. I assume that I'm including them correctly. However, as mentioned, as a test I do:
touch MyHeader.h
which is in the same directory as the sources, and rerun the make, none of the source files which include this header are remade. What am I missing?
Andy
First, you cannot include prerequisites in a suffix rule. Even if you could, you certainly would not want to include $(SOURCES) or $(DEPENDENCIES), because that would cause every object to rebuild whenever any source or dependency file changed.
Second, you cannot create the target file in a different directory from where make expects it to be. Make will put the place where it wants to find the target in the variable $#, and you must write the output into that location exactly. If you ever see a rule that modifies the target, such as above where you use obj/$#, that won't work.
Most likely GCC is writing the files as obj/foo.d, but your include is trying to include foo.d but that doesn't exist... but since you used -include make doesn't complain.
I recommend you first write the object files into the local directory and get that working with dependencies. Once that works, then read up on how to write targets to a different directory and/or ask again.
ETA:
Try something like this:
CXX := g++
CPPFLAGS := -Iadditional/includes -MMD
CXXFLAGS := -std=c++0x
# not every source file in this directory needs to be included in this build
# this is because of shared code with Windows
SOURCESFILTER := File1.cpp File2.cpp
OBJ_DIR := obj
SOURCES := $(filter-out $(SOURCEFILTER),$(wildcard *.cpp))
OBJECTS := $(addprefix $(OBJ_DIR)/,$(SOURCES:.cpp=.o))
DEPENDENCIES := $(OBJECTS:.o=.d)
.PHONY: archive
archive: mylib.a
mylib.a: $(OBJECTS)
$(AR) $# $^
-include $(DEPENDENCIES)
$(OBJ_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<

How to force make to always rebuild a file

I have a version.c file in my project that contains current revision of the project and some other stuff that is passed as a definition (-D compiler option) from makefile.
I know that to force make to compile version.c always regardless of modification date I can touch version.c.
Is there a makefile only way to achieve this? If I write .PHONY : version.o the object file doesn't get build at all.
EDIT:
Here is my makefile:
export CC = gcc
export MODULES = $(sort \
sys \
cim \
version \
)
export FILES = $(sort \
main.c \
cim.c \
version.c \
)
VPATH = $(MODULES)
OBJS = $(FILES:.c=.o)
INCLUDES = $(addprefix -I,$(MODULES))
all:$(OBJS)
$(CC) $(INCLUDES) $(OBJS) -o main.exe
clean:
rm -rf *.o *.exe
cim.o: cim.c
main.o: main.c cim.o
version.o: version.c
.PHONY: version.o
.c.o :
$(CC) $(CFLAGS) $(INCLUDES) -c $<
The classic way to do it is:
version.o: .FORCE
.FORCE:
(and you might add .PHONY: .FORCE). The file '.FORCE' is presumed not to exist, so it is always 'created', so version.o is always out of date w.r.t it, so version.o is always compiled.
I'm not sure that making version.o into a phony file is correct; it is actually a real file, not a phony one.
Not a makefile way, but easier than touch:
make -B
‘-B’ ‘--always-make’
Consider all targets out-of-date. GNU make proceeds to consider targets and their prerequisites using the normal algorithms; however,
all targets so considered are always remade regardless of the status
of their prerequisites. To avoid infinite recursion, if MAKE_RESTARTS
(see Other Special Variables) is set to a number greater than 0 this
option is disabled when considering whether to remake makefiles (see
How Makefiles Are Remade).
If you want to do this using the FORCE mechanism the correct solution looks like this:
version.o: FORCE
.PHONY: FORCE
FORCE:
By explicitly declaring FORCE to be phony we make sure things will work right even if .SECONDARY: is used (.SECONDARY: will cause FORCE to be considered an intermediate file, and make doesn't rebuilt intermediate files unless they have prerequisites newer than the ultimate target, and FORCE doesn't have any prerequisites, so .PHONY: FORCE is needed).
The other solution (using $(shell touch version.c)) also has a problem: it may cause your editor to think version.c has been updated, and prompt for a reload of the file, which might end up being destructive if you've been editing the file's buffer but haven't yet saved it. If you don't mind this, it can be made even simpler by observing that the touch command is silent, so the assignment to the hack dummy variable isn't needed:
$(shell touch version.c) # This is enough, but will likely confuse your editor
The .PHONY "trick" referred to in the comments on the question generally DOES NOT work. It may look like it does because it will force a relink iff version.o already exists, but the actual object file won't get rebuilt if the .o file rule is an implicit rule (which it usually is). The problem is that make doesn't do the implicit rule search for explicitly phony targets. This make file shows the failure:
fooprog: test.o
cp $< $#
%.o: %.c
cp $< $#
.PHONY: test.o # WRONG
clean:
rm test.o fooprog
If a static pattern rule is used instead of an implicit rule the .PHONY: version.o trick will work. In general using static pattern rules instead of implicit rules cuts out most of the more confusing Make behaviors. But most make files use implicit rules.
The quick hack version when you just need it to work and you don't want to play Make games:
# Hack to get main.c rebuilt
hack := $(shell touch main.c)
Basically just make Make run touch for you.

Resources