Makefile dependency error after using flags $(#:.o=.d) - makefile

I have created a Makefile for the below code structure
work
├── code
| |
| ├──inc/
| | └── main.h and test.h files here
| |
| ├──src/
│ └── main.c and test.c files here
├── _Build/
│ └── Makefile here
Here is the Makefile
# All path are referenced with the directory path of Makefile
# Directory Path for workspace
WORKSPACE = ..
# Directory path for code
PATH_DIR_CODE = $(WORKSPACE)/code
# Directory path for c source files
PATH_DIR_C_SOURCES = $(PATH_DIR_CODE)/src
# Directory path for c header files
DIR_PATH_C_HEADERS = $(PATH_DIR_CODE)/inc
# Directory path for obj files
DIR_PATH_OBJ = $(WORKSPACE)/obj
# Directory path for executables
DIR_PATH_BIN = $(WORKSPACE)/bin
# Executable name declaration
FILE_PATH_EXE = $(DIR_PATH_BIN)/main
# Command mkdir
MKDIR = mkdir
FILE_PATH_C_HEADER = $(shell find $(PATH_DIR_CODE) -name *.h)
DIR_PATH_C_HEADER = $(patsubst %/,%,$(sort $(dir $(FILE_PATH_C_HEADER))))
FILE_PATH_C_SRC = $(shell find $(PATH_DIR_CODE) -name *.c)
DIR_PATH_C_SRC = $(patsubst %/,%,$(sort $(dir $(FILE_PATH_C_SRC))))
INC_FILE_C_HEADER = $(addprefix -I, $(DIR_PATH_C_HEADER))
FILE_PATH_OBJ = $(patsubst $(DIR_PATH_C_SRC)/%.c, $(DIR_PATH_OBJ)/%.o, $(FILE_PATH_C_SRC))
CC = gcc
CFLAGS = -Werror -Wall
CDEPS = -MMD -MP -MF $(#:.o=.d)
LDFLAGS = -Llib
LDLIBS = -lm
MKDIR = mkdir
-include $(FILE_PATH_OBJ:.o=.d)
all : $(FILE_PATH_EXE)
.PHONY : all
$(FILE_PATH_EXE) : $(FILE_PATH_OBJ) | $(DIR_PATH_BIN)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(DIR_PATH_OBJ)/%.o : $(DIR_PATH_C_SRC)/%.c | $(DIR_PATH_OBJ)
$(CC) $(CFLAGS) -c $< $(CDEPS) -o $#
$(DIR_PATH_BIN) $(DIR_PATH_OBJ):
$(MKDIR) -p $#
clean :
$(RM) -rv $(DIR_PATH_BIN) $(DIR_PATH_OBJ)
Based on tutorial for dependencies I have used the flags
CDEPS = -MMD -MP -MF $(#:.o=.d)
and
-include $(FILE_PATH_OBJ:.o=.d)
still I am getting the following error
mkdir -p ../obj
gcc -Werror -Wall -c ../code/src/main.c -MMD -MP -MF ../obj/main.d -o ../obj/main.o
../code/src/main.c:4:10: fatal error: test.h: No such file or directory
#include "test.h"
^~~~~~~~
compilation terminated.
make: *** [Makefile:56: ../obj/main.o] Error 1
To remove this error what should be included in the Makefile?
Dependencies should be removed by this logic or some other logic should be used?

You are conflating two different things.
The .d files tell make where to look for prerequisites of the target. In this case the target is an object file (.o) and the prerequisite is a header file, but to make they're just "targets" and "prerequisites". Make is not restricted to just compiling C programs: it can do essentially any task where changing some files means that some other files need to be updated: compiling programs (not just C programs) is one common use but it can build documentation, web sites, run tests, etc. Make does its job by running commands, just as you would do it yourself from the command line (except make never forgets to add an option and doesn't make typos). It doesn't really know anything about "compilers" and "linkers", internally.
The error you are getting is from the compiler (or to be pedantic, the preprocessor), not make, and the compiler has to be told where to look for the header files it needs to include. Those are two completely different things and require different operations: the compiler requires that you provide the directories to search using the -I command line option.
I suppose it might be nice if the compiler could parse make's .d files and figure out where to look for headers, but it can't. You have to specify the flags yourself.
In your situation it's even more clear: you are actually using the compiler to generate the .d files! So there's a chicken-and-egg problem: if the compiler could get the paths from the .d files, but the .d files are being created from the compiler, then where do the paths come from in the first place?

Related

Use Makefile and sdcc to build a perfect automation for MCS-51 development

Since sdcc have some limitations, like compiling one file at a time, I've tried hard to write a Makefile to perfect the automation of MCS-51 development, which have some requirements:
Source file (.c) expect main.c are stored in ProjectFolder/Sources/, while main.c are stored at the root of project folder.
Headers are stored in ProjectFolder/Includes/.
Outputs through compiling, linking and locating should be stored at ProjectFolder/Builds/
Makefile should be smart enough to find all source files, instead of type their file name by hand.
Makefile should be smart enough to if there are some files in Sources/, or there's only main.c in the project.
The file structure can be depicted like:
Project Folder
|
|- Sources
| |
| |(some source files, but OPTIONAL)
|
|- Includes
| |
| |(some headers, but OPTIONAL)
|
|- Builds
| |
| |(some .rel .o .hex files. OUTPUT here)
|
|- main.c
|
|- Makefile
Here's my solution but still have a problem. It cannot be used for project only have one file main.c which means no source file in Sources/.
INCLUDES = Includes/
SOURCES = Sources/
BUILDS = Builds/
CC = sdcc
CFLAGS = -o $(BUILDS)
LOADER = stcgal
LOADER_FLAGS = -P stc89
$(BUILDS)main.ihx: main.c $(BUILDS)main.rel
# Link
#$(CC) main.c $(shell find $(BUILDS) -name "*.rel" -not -name "main.rel" -maxdepth 1) $(CFLAGS)
#echo Link & Locate Succeeded
$(BUILDS)main.rel: $(SOURCES) $(BUILDS)
# Compile
#for f in $(shell ls $(SOURCES)*.c) ; do \
$(CC) -c $${f} $(CFLAGS) ; \
done
#echo Compile Succeeded
$(SOURCES):
#mkdir $(SOURCES)
$(BUILDS):
#mkdir $(BUILDS)
clean:
# Remove all files in build folder
#rm $(BUILDS)*
#echo Build Folder Cleaned
load: $(BUILDS)main.ihx
# Load data to MCU via USB port
#$(LOADER) $(LOADER_FLAGS) -p $(shell ls /dev/tty.usbserial*) $(BUILDS)main.ihx
Let's try something. First note that I've not looked at the load target.
Let's start with the same definition as you:
INCLUDES = Includes/
SOURCES = Sources/
BUILDS = Builds/
CC = sdcc
We need a variable with the source files from Sources. GNU Make has a wildcard functions which does the same thing as your find. See that I'm using := to have an immediate expansion of the value, so the wildcard will not be executed several times.
SRCFILES := $(wildcard $(SOURCES)*.c)
Now a variable with the .rel files. It is build from main.rel and the SRCFILES value:
RELFILES := $(BUILDS)main.rel $(SRCFILES:$(SOURCES)%.c=$(BUILDS)%.rel)
Let's define another variable with the flag to pass so the Includes directory is searched:
CPPFLAGS = -I$(INCLUDES)
Now we can define pattern rules to describe how to build .rel files from .c files. I'm using an order-only prerequisite for the build directory:
$(BUILDS)%.rel: $(SOURCES)%.c | $(BUILDS)
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# -c $<
$(BUILDS)%.rel: %.c | $(BUILDS)
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
Let's define some usability targets:
.PHONY: all clean
all: $(BUILDS)main.ihx
clean:
rm $(BUILDS)*
And finally define how to build the targets which aren't handled by the pattern rules:
$(BUILDS)main.ihx: $(RELFILES) | $(BUILDS)
$(CC) $(LDFLAGS) -o $# $^ $(LOADLIBES) $(LDLIBS)
$(BUILDS):
mkdir $(BUILDS)
I've used a few variables (CC, CPPFLAGS, CFLAGS, LDFLAGS, LOADLIBES, LDLIBS) in the same way as they are used by the built-in rules of GNU Make.
I've kept your makefile behavior. There are good reasons to have Makefiles targeting to build in the current directory. Explaining them and modifying the Makefile for that is out of scope for this answer, you may look at MadScientist's GNU Make White Papers and the GNU Make Manual.

How can I pass a rule pattern in a makefile to filter dependencies?

I have a rule in my project to generate libraries from sourcecode. I already have the function to compile %.c to %.o, but I split my library code in multiple source files that begin with the same prefix. I have two separate library code in the same directory, but their source files have different prefixes, that's why I am trying to build a single rule for both (or maybe more) libraries. But I can't pass the prefix of the codebase to the dependencies to filter the object files needed.
The rule I have is this in my Makefile:
# ...
BINDIR = bin
LIBDIR = lib
# ...
# These are all the libraries source files.
LIB_SOURCES = $(wildcard $(LIBDIR)/*.c)
# These are all the libraries "main" source files.
LIB_SRCS = $(filter-out $(wildcard $(LIBDIR)/*_*.c), $(LIB_SOURCES))
# These are all the source files to which I have exported some code from the "main" library source file.
LIB_CODE = $(filter-out $(LIB_SRCS), $(LIB_SOURCES))
# These are all the objects produced by compiling the c source files.
LIB_OBJS = $(patsubst %.c, %.o, $(LIB_CODE))
# ...
# These are all the libraries produced.
LIBS = $(patsubst $(LIBDIR)/%.c,$(BINDIR)/lib%.so,$(LIB_SRCS))
# ...
.PHONY: libs
# ...
%/:
mkdir -p $#
libs: $(BINDIR)/ $(LIBS)
.SECONDEXPANSION:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
$(LIBDIR)/%.o: $(LIBDIR)/%.c $(LIBDIR)/%.h
#echo $(CC) $(CFLAGS) -o $# -c $<
For the moment I just print the (incomplete) command, but it still doesn't get the correct output with all the objects needed.
In the directory lib I have the following files:
$ tree lib
lib
├── app.c
├── app_db.c
├── app_db.h
├── app.h
├── app_logic.c
├── app_logic.h
├── app_net.c
├── app_net.h
├── server.c
├── server.h
├── server_queue.c
└── server_queue.h
But it never builds the dependencies correctly.
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o
I have read the following question How to use pattern-dependent variables in dependencies in make pattern rules, which had a tip I thought it would help me, but it didn't.
Any idea how can I achive this?
EDIT 1:
I want the output of the last command to be:
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o lib/app_db.o -c lib/app_db.c
gcc -Wpedantic -O3 -o lib/app_logic.o -c lib/app_logic.c
gcc -Wpedantic -O3 -o lib/app_net.o -c lib/app_net.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o lib/app_db.o lib/app_logic.o lib/app_net.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o lib/server_queue.o -c lib/server_queue.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o lib/server_queue.o
Thanks for your attention.
You added .SECONDEXPANSION, but you didn't escape anything in the prerequisites list so it doesn't actually do anything:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
None of these variables/functions are escaped, so everything here is expanded during the initial read-in, so there's nothing for secondary expansion to do.
The secondary expansion feature consists of two parts: first, you enable it with the special target. Second, you escape the variables and/or functions you want to delay expansion of. So this could be:
getobjs = $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $$(getobjs)
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
Note how we escape the $(getobjs) as $$(getobjs) so that this variable is not expanded until the second pass.
Make isn't very deft with wildcards, and your approach requires it to handle two different wildcards in one line. If that's possible at all, it will be a terrible thing to see. I suggest a different approach.
First, your variables are wrong. It's not clear what your intention was, but here are the ones that fit your desired results:
LIB_SOURCES := $(wildcard $(LIBDIR)/*.c)
LIB_OBJS := $(patsubst %.c,%.o,$(LIB_SOURCES))
Now, you want your makefile to act as if it had these two rules:
$(BINDIR)/libapp.so: $(filter $(LIBDIR)/app%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
$(BINDIR)/libserver.so: $(filter $(LIBDIR)/server%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
But rather than spelling them out in the makefile, you want Make to build them at run time. So we'll use a "canned recipe":
define librule
$(BINDIR)/lib$(1).so: $(filter $(LIBDIR)/$(1)%,$(LIB_OBJS))
#echo building $$# somehow from $$^
endef
$(eval $(call librule,app))
$(eval $(call librule,server))
Then rather than writing those last two lines in the makefile, specifying app and server, we can have Make extract them from LIBS:
LIB_NAMES := $(patsubst $(BINDIR)/lib%.so,%,$(LIBS))
$(foreach libname,$(LIB_NAMES),$(eval $(call librule,$(libname))))

makefile .mod compilation rule

I'm modifying makefile of a code. After compiling, I see that some *.mod files are generated. looking online, I figured out they are module files, but I don't see a compilation rule for them. I'm trying to change the directory in which these files are generated. I can change the rule for object files, but I can't find the rule that generates *.mod files.
Looking at the makefile, can someone advise me if a line in this file generates them or how to change their directory. Here is the makefile:
# GNU Makefile
# Paths
SDIR=./solver
ODIR=./obj
_CASE=./WorkCases/problem
CASE=$(SDIR)/$(_CASE)
TOP = .
FC = ifort
FFLAGS = -fpp -O1 -DPTR_INTEGER8 -warn nousage
# Define rule to make .f90
$(ODIR)/%.o : $(SDIR)/%.f90
$(FC) -c $(FFLAGS) $< -o $#
# set executable name
EXEC = $(dir ${CASE})/$(basename $(notdir ${CASE})).out
# shared global variables
_SHARED_OBJ = shared_modules.o main_vars.o debug_vars.o
SHARED_OBJ = $(patsubst %,$(ODIR)/%,$(_SHARED_OBJ))
OBJ = ${_SHARED_OBJ} $(_CASE).PARAMS.o
OBJ = $(patsubst %,$(SDIR)/%,$(_OBJ))
MAIN_OBJ = $(ODIR)/main.o
main : ${SHARED_OBJ} $(OBJ) $(MAIN_OBJ)
$(FC) ${FFLAGS} $(OBJ) $(MAIN_OBJ) -o $(EXEC) -lstdc++ -shared-intel
You can specify the destination directory for the .mod files by using the -module compiler option.
-module <directory>
See the ifort documentation here:
You can use the module path compiler option to specify the directory
in which to create the module files. If you do not use this option,
module files are created in the current directory.

Creating makefile for c++ static library with g++

I want to use GNU make to compile a static library. On my disc, the project is arranged this way:
.
├── makefile
├── publicAPI
│ └── Some headers (.h)
└── source
├── All .cpp files
└── Some headers (.h)
I have written the following makefile, so far:
CPPC = gcc
STANDARD_FLAGS = -std=c++0x
WARN_AS_ERRORS_FLAGS = -pedantic-errors\
-Wall\
-Wextra\
-Werror\
-Wconversion
DEBUG_FLAGS = -g3
OPT_FLAGS = -0O
NO_LINKER_FLAGS = -c
CPPFLAGS = $(OPT_FLAGS) $(DEBUG_FLAGS) $(NO_LINKER_FLAGS) $(STANDARD_FLAGS) \
$(WARN_AS_ERRORS_FLAGS)
# Source files, headers, etc.:
ROOT = $(CURDIR)
INCLUDES = -I$(ROOT)source -I$(ROOT)publicAPI
SRCS = ./source/AsciiColorCode.cpp\
./source/Color.cpp
OBJS = AsciiColorCode.o\
Color.o
LIBS =
MAIN = libcXbase.a # static library
all: $(MAIN)
#echo $(MAIN) has been compiled!
$(MAIN): $(OBJS)
ar -r $(MAIN) $(OBJS) $(LIBS)
.cpp.o:
$(CPPC) $(CPPFLAGS) $(INCLUDES) -c $< -o $#
depend: $(SRCS)
makedepend $(INCLUDES) $^
When I run make all, I get the following error: make: *** No rule to make target 'AsciiColorCode.o', needed by 'libcXbase.a'. Stop. which indicates that the AsciiColorCode.o file has not been created. I can't find what is missing from this:
I find the dependencies
I compile .o object files from .cpp files
I ar everything into a .a file.
What is missing? Also, if you have any comment on my makefile, please don't hesitate as this is my first one.
Regards
You should specify where the prerequisites are. This can be done by adding this line:
VPATH = source
Also, in the rule .cpp.o, the variable CPCC is not defined (probably should be CXX)
Also, OPT_FLAGS should be -O0

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)

Resources