Make not setting correctly the location of the source code - makefile

Here is a little problem that I've encountered:
I have the following project layout:
.
├── Makefile
├── README.md
├── inc
│ └── include.hpp
├── out
│ ├── debug
│ └── release
└── src
└── main.cpp
And the following Makefile (which was copied from this post, and edited a little bit by me, to adequate to my project):
# Compiler flags
CXX := g++
CXXFLAGS := -Wall -Werror -Wextra
# Project files
SRC_DIR := src
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
INC_DIR := inc
INCLUDES := -I $(INC_DIR)
OBJS := $(SRCS:.cpp:=.o)
EXE := <ProgramName>
BUILD_DIR := out
# Debug build settings
DBGDIR := $(BUILD_DIR)/debug
DBGEXE := $(DBGDIR)/$(EXE)
DBGOBJS := $(addprefix $(DBGDIR)/, $(OBJS))
DBGCXXFLAGS := -g -O0 -DDEBUG
# Release build settings
RELDIR := $(BUILD_DIR)/release
RELEXE := $(RELDIR)/$(EXE)
RELOBJS := $(addprefix $(RELDIR)/, $(OBJS))
RELCXXFLAGS := -O3 -DNDEBUG
.PHONY: all clean debug prep release remake
# Default build
all: prep release
# Debug rules
debug: $(DBGEXE)
$(DBGEXE): $(DBGOBJS)
$(CXX) $(CXXFLAGS) $(DBGCXXFLAGS) -o $(DBGEXE) $^
$(DBGDIR)/%.o: $(SRC_DIR)/%.cpp
#echo $#
$(CXX) -c $(CXXFLAGS) $(DBGCXXFLAGS) -o $# $<
# Release rules
release: $(RELEXE)
$(RELEXE): $(RELOBJS)
$(CXX) $(CXXFLAGS) $(RELCXXFLAGS) -o $(RELEXE) $^
$(RELDIR)/%.o: $(SRC_DIR)%.cpp
$(CXX) -c $(CXXFLAGS) $(RELCXXFLAGS) -o $# $<
# Other rules
prep:
#mkdir -p $(DBGDIR) $(RELDIR)
remake: clean all
clean:
#rm -rf $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)
#echo "Cleaned!"
Produces the following error:
make: *** No rule to make target 'out/release/src/main.cpp', needed by 'out/release/<ProgramName>'. Stop.
Where is the issue? And when does make assume that the directory of the source files is in '/out/release'? I'm still a noob writing makefiles, I've always been a little bit lazy and used Visual Studio even when targeting linux.
Any help is vastly appreciated!!

You have a couple of small errors.
OBJS := $(SRCS:.cpp:=.o)
You have an extra colon. As written, you change all instances of .cc:, but there are none, so OBJS is src/main.cpp.
You probably meant this:
OBJS := $(SRCS:.cpp=.o)
But this gives src/main.o. You probably did not intend to keep the path. You can correct that with another line:
OBJS := $(notdir $(OBJS))
Then here:
$(RELDIR)/%.o: $(SRC_DIR)%.cpp
...
You are missing a slash. The correct line is
$(RELDIR)/%.o: $(SRC_DIR)/%.cpp
...
The rule as written searches for a file that doesn't exist.
You can detect such errors yourself -- and correct them as you develop the makefile -- with diagnostics like this:
$(info OBJS is $(OBJS))
$(info RELOBJS is $(RELOBJS))
Write a small makefile that works perfectly, then add complexity a little at a time, testing at every step, and never add to code that doesn't work.

Related

C++ Makefile path include and src directory makefile

I'm trying to create a Makefile for my C++ project, which has the following structure:
root
├── include/
| └──external
| └── stb_image.h
│ └── all .h files here
├── src/
| └── main.cpp
│ └── all .cpp files here
└── Makefile
To compile this project, I'm trying to use the Makefile proposed in this answer, which is for gcc, but I have added CC:=g++ so it should work (I think):
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/color
SRC := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
CPPFLAGS := -Iinclude -MMD -MP
CFLAGS := -g -std=c++2a -Wall
LDFLAGS := -Llib
LDLIBS := -lpthread
CC := g++
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
But when running make I obtain a very long error which I do not understand. I do not know if this error comes from having main.cpp without a main.h.
I need this makefile because I want to separate the declarations and the implementations of my project. Before doing that, I had everything done in headers files and I could compile my project with the following command:
g++ -g -std=c++2a -Wall -Isrc/include -o bin/color.exe src/main.cc -lpthread
Any idea what am I doing wrong? I still do not know a lot about Makefiles, so maybe I'm doing something weird.

*.c not rebult when dependency x.h changed, using auto-generated *.d file

I am facing one issue while handling dependency files during compilation. I am just giving you the scenario which I faced in my project.
I have two C source files called a.c, b.c which includes one header file called c.h. I ran makefile which has instructions to compile both files. I can successfully compile the a.c file, but I have seen some failures while comping b.c which requires to do some changes in c.h to fix that issue. After I made change in c.h and trigger build (incremental build) the a.c file should compile again, too, right? Because a.c also depends on the c.h file.
I followed all dependency mechanism (creating auto dependency files & including .d files, etc)
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
-include $(DEPSALL)
$(TGTFILES)/%.o: $(TGTFILES)/%.c
mkdir -p $(#D)
$(CC64) -MT $# -MMD -MP -MF $(patsubst %,%.d,$(basename $#)) -o $(#) -c $(CFLAGS64) $<
...
...
Am I missing something here? I want to rebuild all the .c files which are including the particular header file which I changed.
Your question is incomplete: you do not really describe the problem you are facing (but we can probably guess that object files are not rebuilt while they should) and the part of the Makefile you show is not sufficient to understand what your goals are.
Anyway, first of all, this expression:
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
is uselessly complex. It is equivalent to the much simpler and easier to understand:
DEPSALL := $(wildcard $(TGTFILES)/*.d))
Similarly, in your compilation recipe you can replace:
$(patsubst %,%.d,$(basename $#))
by:
$(TGTFILES)/$*.d
But let's go back to your main problem (at least what I guess is your main problem): when modifying your header file, some object files are not rebuilt while they should.
My guess is that you think:
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
will assign to DEPSALL a list of dependency files, one per source file, like this other form would do:
DEPSALL := $(patsubst %.c,%.d,$(wildcard $(TGTFILES)/*.c))
If this is what you think, then you are wrong. Your version will assign to DEPSALL the list of dependency files that currently exist in $(TGTFILES) when you invoke make. If some (or all) are missing, some object files will not be rebuilt...
I suggest that you carefully read this excellent post about Auto-Dependency Generation. If you adapt it to your set-up, you should end up with something like:
TGTFILES := tgtfiles
SRCS := $(wildcard $(TGTFILES)/*.c)
OBJS := $(patsubst %.c,%.o,$(SRCS))
DEPS := $(patsubst %.c,%.d,$(SRCS))
INCLUDES := include
CFLAGS += -I$(INCLUDES)
.PHONY: objs clean
objs: $(OBJS)
%.o: %.c
%.o: %.c %.d
$(CC) -MT $# -MMD -MP -MF $*.Td $(CFLAGS) $(CPPFLAGS) -c -o $# $<
#mv -f $*.Td $*.d && touch $#
%.d: ;
.PRECIOUS: %.d
clean:
rm -f $(OBJS) $(DEPS)
include $(DEPS)
Several aspects may look strange, useless or even completely wrong. But if you carefully read the above mentioned post you will see that it perfectly makes sense. Demo:
$ tree
.
├── Makefile
├── include
│   └── c.h
└── tgtfiles
├── a.c
└── b.c
2 directories, 4 files
$ make
cc -MT tgtfiles/b.o -MMD -MP -MF tgtfiles/b.Td -Iinclude -c -o tgtfiles/b.o tgtfiles/b.c
cc -MT tgtfiles/a.o -MMD -MP -MF tgtfiles/a.Td -Iinclude -c -o tgtfiles/a.o tgtfiles/a.c
$ tree
.
├── Makefile
├── include
│   └── c.h
└── tgtfiles
├── a.c
├── a.d
├── a.o
├── b.c
├── b.d
└── b.o
2 directories, 8 files
$ cat tgtfiles/a.d
tgtfiles/a.o: tgtfiles/a.c include/c.h
include/c.h:
$ make
make: Nothing to be done for 'objs'.
$ touch include/c.h
$ make
cc -MT tgtfiles/b.o -MMD -MP -MF tgtfiles/b.Td -Iinclude -c -o tgtfiles/b.o tgtfiles/b.c
cc -MT tgtfiles/a.o -MMD -MP -MF tgtfiles/a.Td -Iinclude -c -o tgtfiles/a.o tgtfiles/a.c
wildcard function application doesn't look right. Should probably be:
DEPSALL := $(patsubst %,%.d,$(basename $(wildcard $(TGTFILES)/*.c)))

Generic Makefile build directory error

I have the following directory structure for a dummy C project.
.
├── inc
│   ├── getmsg.c
│   └── getmsg.h
├── makefile
└── src
└── main.c
My current generic Makefile is below,
TARGET = main
# finds all .c files, inc/getmsg.c src/main.c
SOURCES := $(shell find * -name *.c)
# converts all .c files to .o files, inc/getmsg.o src/main.o
OBJECTS := $(SOURCES:.c=.o)
# directories that contain .h files for gcc -I flag, inc/
HEADERS := $(dir $(shell find * -name *.h))
CC = gcc
CFLAGS = -Wall -std=c99 -iquote "$(HEADERS)"
all: $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET): $(OBJECTS)
$(CC) -o $# $^
clean:
rm -rf $(shell find * -name *.o) $(TARGET)
This all compiles fine however it just dumps the .o files into the same directory as its corresponding .c file.
What I would like to do is have all object files put into a build directory. To do this I change the OBJECTS to OBJECTS := $(patsubst %,build/%,$(notdir $(SOURCES:.c=.o))) which lists the files build/getmsg.o build/main.o. Then I set the %.o target to build/%.o: %.c.
This however returns No rule to make target 'build/getmsg.o'. So the make file is unable to build the .o files. What am I missing here?
Try changing
%.o: %.c
to
build/%.o: %.c

Autodependencies with GNU make

Here is my folder view:
-> tree
.
├── Makefile
└── src
├── a10.c
├── a11.c
├── a12.c
├── a13.c
├── a14.c
├── a15.c
├── a16.c
├── a1.c
├── a2.c
├── a3.c
├── a4.c
├── a5.c
├── a6.c
├── a7.c
├── a8.c
├── a9.c
├── a.c
└── test.h
a1.c to a10.c are all empty, just test, only a.c and test.h have code:
-> cat src/a.c
#include "test.h"
int main(void)
{
printf("VAR = %d\n", VAR);
printf("VAR1 = %d\n", VAR1);
return 0;
}
-> cat src/test.h
#include <stdio.h>
I have a makefile with a function:
-> cat Makefile
ifeq '${INPUT}' ''
STR = LATEAST
else
STR = ${INPUT}
endif
CC := gcc
LD := gcc
PROGRAM = Test
MAKE_DIR = $(PWD)
MODULES := src
SRC_DIR := $(addprefix $(MAKE_DIR)/,$(MODULES))
BUILD_DIR := $(MAKE_DIR)/output
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
OBJ := $(patsubst %.c,%.o,$(SRC))
INCLUDES := $(addprefix -I,$(SRC_DIR))
INCLUDES += -I$(MAKE_DIR)/include
#test
F_VAR = 43
F_VAR1 = 40+1+2
$(warning F_VAR=$(F_VAR), F_VAR1=$(F_VAR1))
CFLAGS :=
CFLAGS = -DVAR=41+2 -DVAR1=40+1+2
vpath %.c $(SRC_DIR)
define make-goal
$1/%.o: %.c
#$(CC) $(CFLAGS) $(INCLUDES) -c $$< -o $$#
#$(CC) -MM $(CFLAGS) $(INCLUDES) $$< > $1/$$*.d
#echo "Compile $$*.c"
endef
.PHONY: all checkdirs clean help flowchart
all: checkdirs $(BUILD_DIR)/$(PROGRAM)
$(BUILD_DIR)/$(PROGRAM): $(OBJ)
#echo "${STR}"
#$(LD) $^ -o $#
#echo "Generate $(PROGRAM)"
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
mkdir -p $#
clean:
rm -f $(OBJ) $(BUILD_DIR)/$(PROGRAM)
rm -rf $(BUILD_DIR)
help:
#echo "SRC DIR: $(SRC_DIR)"
#echo "Build DIR: $(BUILD_DIR)"
#echo "Source: $(SRC)"
#echo "Obj: $(OBJ)"
#echo "Includes: $(INCLUDES)"
flowchart:
#cflow2dot pdf ${SRC}
$(foreach sdir,$(SRC_DIR),$(eval $(call make-goal,$(sdir))))
My quesation is, when I touched a header file, it did not trigger a re-compilation, any problem in my makefile?
-> make
Makefile:28: F_VAR=43, F_VAR1=40+1+2
mkdir -p /home/haochen/Work/test_code/test_make/output
Compile a10.c
Compile a11.c
Compile a12.c
Compile a13.c
Compile a14.c
Compile a15.c
Compile a16.c
Compile a1.c
Compile a2.c
Compile a3.c
Compile a4.c
Compile a5.c
Compile a6.c
Compile a7.c
Compile a8.c
Compile a9.c
Compile a.c
LATEAST
Generate Test
the Autodependenciescan be generated:
-> cat src/a.d
a.o: /home/haochen/Work/test_code/test_make/src/a.c \
/home/haochen/Work/test_code/test_make/src/test.h
Problem:
I modified test.h, add a error:
-> vim src/test.h
-> cat src/test.h
#include <stdio.h>
#error here
No re-compile:
-> make
Makefile:28: F_VAR=43, F_VAR1=40+1+2
make: Nothing to be done for `all'.
UPDATE:
I add:
DEP := $(patsubst %.c,%.d,$(SRC))
Meanwhile, I add -include at my last line of make file:
-include $(DEP)
I did not see any improvement
The .d files are makefiles that express the header-dependencies. So you need to -include
the .d files in the makefile, e.g.
OBJ := $(patsubst %.c,%.o,$(SRC))
DEP := $(patsubst %.c,%.d,$(SRC))
...
-include $(DEP)
The dependencies files are properly generated, but you never use them : with #$(CC) -MM $(CFLAGS) $(INCLUDES) $$< > $1/$$*.d, make give the command to generate the dependency file, but it does not use it.
The dependencies files are little Makefiles of themselves, destined to be read by make. So, you need to tell make to read them as well as your main Makefile.
For this, you have the include directive, which suspends the reading of the current makefile and read all listed files as makefiles before resuming reading of the current makefile(I'm quoting the manual here...).
Since the dependencies files won't exist on a first build, you might want to add - in front of it, to nullify the warning saying no such file.
As a side note, be sure to include the dependencies file after your default target (or to use .DEFAULT_GOAL), because if you don't, the default target will become the first found in the included files.
Also, you might want to add your dependencies files as prerequisites of your object files, since a missing dependency file will make make miss some prerequisites.
All of this is from the make maintainer's blog, here, where you can find additional info.
EDIT :
Sorry, I've missed it last time. If I'm not wrong, a.o and $1/%.o cannot match the same target. Even though the Makefile include files in a subdir, it did not automatically know that, and to him a.o and src/a.o are not the same (and indeed). So there is two separate rules, and one is empty, with no recipe (the one in the dependency file)
One solution might be to use the -MT flag for the dependency generation (which set the target to the string you specify, so $# here for example.)
You might want to use the --debug option of make to catch that kind of errors ; so far, I've found it quite useful to track incorrect dependencies.
I found the problem, I should:
write the deps
DPES = ...
compile c file with -MMD option:
... -MMD -c $< -o $#
and then, add:
-include $(DPES)

function define in makefile

I have test project folder structure view:
TOPDIR
├── a
│   └── a.c
├── b
│   └── b.c
├── c
│   └── c.c
└── makefile
I wrote a test makefile:
CC := gcc
LD := ld
MAKE_DIR = $(PWD)
MODULES := a b c
SRC_DIR := $(addprefix ${MAKE_DIR}/,$(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
OBJ := $(patsubst %.c,%.o,$(SRC))
INCLUDES := $(addprefix -I,$(SRC_DIR))
vpath %.c $(SRC_DIR)
define make-goal
$1/%.o: %.c
$(CC) $(INCLUDES) -c $$< -o $$#
endef
all:
$(foreach sdir,$(SRC_DIR),$(eval $(call make-goal,$(sdir))))
during the make, it just STOPPED and shows:
makefile:37: *** prerequisites cannot be defined in command scripts. Stop.
the line 37 is:
$(foreach sdir,$(SRC_DIR),$(eval $(call make-goal,$(sdir))))
what is wrong with my makefile?
You are expanding make-goal inside a command. Just move it outside:
all: $(OBJ)
$(foreach sdir,$(SRC_DIR),$(eval $(call make-goal,$(sdir))))
Note that defining a recipe, then using foreach-eval-call is overkill in this case. A pattern rule will do:
all: $(OBJ)
%.o: %.c
$(CC) $(INCLUDES) -c $< -o $#
EDIT:
You can even get away without a pattern rule, using Make's implicit rule for compiling C files:
CFLAGS += $(INCLUDES)
all: $(OBJ)

Resources