debugging a makefile - c

I have a makefile which has statements like below:
TOPICS = dmic
SRV_MODE =
ifeq "$(SRV_FLAG)" "ON"
SRV_MODE = 2
endif
vpath d%_srv.h $(CNT_PATH)
USER_PRE_TARGETS := $(foreach topic,$(TOPICS),$(topic)_srv.h)
dmic_srcs = $(wildcard $(CCWSCA)/dmic/src/*.c) \
$(wildcard $(CCWSCA)/dmic/src/*.ppc)
dmic_srv.h: $(dmic_srcs)
srvgen dmic $(SRV_MODE)
users_topic =
users_topic := $(shell ls -tr $(CCWPA)/$(CCBB)/Makefile.pre* | \
tail -1 | awk 'BEGIN{FS="Makefile.pre."}{printf("%s\n", $$2);}')
USER_PRE_TARGETS := $(foreach topic,$(users_topic),d$(topic)_srv.h)
After I run the build, I get messages like the ones below:
gmake: Entering directory `/veluser2/vel/abp/bvijays/proj/c9mi790V64OG/cmi9dl'
echo dmic
dmic
srvgen dmic 2
Working on directory : /veluser2/vel/abp/bvijays/bb/cmi9dl/v79_0/dmic/src
Working on directory : /velhome/vel/ccvel/ccvel/bb/cmi9dl/v79_0/dmic/src
foreach: No match.
gmake: *** [ddmic_srv.h] Error 1
gmake: Target `pre' not remade because of errors.
gmake: Leaving directory `/veluser2/vel/abp/bvijays/proj/c9mi790V64OG/cmi9dl'
So it seems like there is some issue with the foreach command issued?
As I am new to these makefiles, could anybody please suggest how to debug the makefile?

This is a bit of a mess, and it is hard to diagnose without knowing more about the environment it is running it. But lets go with a few basics:
You have only defined on target (dmic_srv.h), so when you run GNU make without arguments it will use that target.
Making the header depend on the source files is very unusual, I doubt that is what you want this to do. but you're doing code generation, so you are OK there.
There are two different kinds of assignment in GNU make. Plain = has lazy evaulation, but := forces immediate evaluation. This effects the environment in which you $(foreach )'s are running.
You have two definitions of USER_PRE_TARGETS, but never use it anywhere. Added: Given that the all the $(foreach ) commands exist in these definitions, you might just remove these and see if it get better.

Related

Using makefile file as prerequisite in a rule

I am inexperienced with make, and wanted to replicate a build structure provided by some third-party SDK and adapt it to my own compiler and project.
The thing is that I found that some rules are generated using the makefile as prerequisite, something like:
...
$(eval $(1): Makefile | $(dir $(1)).) \
...
or
$(OUTPUT_DIRECTORY)/%.inc: Makefile | $(OUTPUT_DIRECTORY)
$(info Generating $#)
$(NO_ECHO)$(call dump, $(call target_specific, INC_PATHS, $*)) > $#
Originally, their makefile is Capitalized (Makefile) and the one I am working on is lowercase (makefile). Anyway, When I try my current changes, this error appears:
*** No rule to make target 'Makefile', needed by '...'
I supposed that was due to the capitalization, so changed to lowercase in both places and tried again, but this time the error is that the makefile is treated as a C file (This is my guess...)
"makefile", line 1: error #171: expected a declaration
-include makefile.local
^
"makefile", line 67: error #8: missing closing quote
${CG_TOOL_ROOT}/include"
^
"makefile", line 99: error #10: "#" not expected here
.SUFFIXES: # ignore built-in rules
^
"makefile", line 100: error #10: "#" not expected here
%.d: # don't try to make .d files
^
"makefile", line 100: error #8: missing closing quote
%.d: # don't try to make .d files
What could be the issue here? Is there something I am missing?
EDIT 1:
These are the files I am trying to use.
Nordic provides these as part of their SDK for development using arm-gcc for ARM platforms. There is a Makefile per project and there is a Makefile.common included in the main Makefile.
Makefile
Makefile.common
On the other side, I am trying to understand and replicate the same but for another proprietary compiler with different options and syntax (TI's cl430 for MSP430 platforms). From the original Makefile.common I removed some references to the gnu-arm suite and replace it with the proper compiling tools. In the makefile I also tried to replicate the same structure of the original but using my sources and options.
makefile
makefile.common
Just to make it clear, originals are capitalized, mine are lowercase.
EDIT 2:
After running make --debug --print-data-base I found this:
The error appears in the first attempt to build a file:
Updating goal targets....
File 'default' does not exist.
File 'test_project' does not exist.
File '_build/test_project.out' does not exist.
File '_build/test_project/<SOURCE_FILE>.c.o' does not exist.
Must remake target '_build/test_project/<SOURCE_FILE>.c.o'.
Building file: "makefile"
Invoking: MSP430 Compiler
"cl430" -vmspx --use_hw_mpy=F5 <... a lot of options ...> --obj_directory="./_build" "makefile"
"makefile", line 1: error #171: expected a declaration
-include makefile.local
^
[ ... more errors ...]
However, from the debug and DB information, I found that the source file rule indeed requires makefile, and that makefile is not a target, but somehow it is trying to build it:
# Not a target:
makefile:
# Implicit rule search has been done.
# Last modified 2020-02-25 11:43:33.609423171
# File has been updated.
# Successfully updated.
_build/test_project/<SOURCE_FILE>.c.o: makefile | _build/test_project/.
# Implicit rule search has been done.
# Implicit/static pattern stem: '_build/test_project/<SOURCE_FILE>'
# Modification time never checked.
# File has been updated.
# Failed to be updated.
# automatic
# # := _build/test_project/<SOURCE_FILE>.c.o
# automatic
# % :=
# automatic
# * := _build/test_project/<SOURCE_FILE>
# automatic
# + := makefile
# automatic
# | := _build/test_project/.
# automatic
# < := makefile
# automatic
# ^ := makefile
# automatic
# ? := makefile
# variable set hash-table stats:
# Load=8/32=25%, Rehash=0, Collisions=1/30=3%
# recipe to execute (from 'makefile.common', line 192):
#echo 'Building file: "$<"'
#echo 'Invoking: MSP430 Compiler'
"${CG_TOOL_ROOT}/bin/cl430" -vmspx --use_hw_mpy=F5 <... a lot of options ...> "$(shell echo $<)"
#echo 'Finished building: "$<"'
#echo ' '
That dependency on Makefile is to make sure that it rebuilds when Makefile has been changed. For example, if you change CFLAGS in Makefile or a rule to compile or link, this dependency triggers a rebuild (provided object files depend on Makefile, as they should). Without dependency on Makefile those changes won't cause a rebuild.
The error messages in the form of "makefile", line 1: error #171: expected a declaration suggest that makefile is passed as a source file to a C compiler that produces the error message.
The rules most likely do $(filter-out Makefile,$^). You need to replace all occurrences of Makefile to makefile.
*** No rule to make target 'Makefile', needed by '...' means that Makefile is still a prerequisite of some targets. You can find what those targets are by passing --debug --print-data-base command line options to make.

Expanding pattern twice for dependency

Is it possible to expand % twice for a dependency name?
I have project split into several sections, where each section is in it's own folder and file of the same name, e.g.
sections/first/first.c,sections/hello/hello.c, etc.
Now I would like to build for each section a target in another folder build; I've come up with the following
SECTIONS = $(wildcard sections/*/*.c)
TARGETS = $(addprefix build/,$(notdir $(SECTIONS)))
$(TARGETS): build/%.c: sections/%/%.c
# do something
The problem however is that % is expanded only once, so I end up with an error
make: *** No rule to make target 'sections/first/%.c', needed by 'build/first.o'.
Is there a way to expand % twice?
It's not possible to get the % to expand more than one time. If you need this you'll have to do something more fancy: you can use either secondary expansion or eval. For example, this should work:
.SECONDEXPANSION:
$(TARG) : build/%.c : source/$$*/$$*.c
#echo copy $< $#
For more in-depth discussion you can check these blog posts.
SECTIONS = $(wildcard sections/*)
.PHONY: all
all: $(SECTIONS)
$(foreach dir,$(SECTIONS), \
( cd $d && $(MAKE) -f ../makefile.bot name=$(dir) all ); )
Where the above is in a top level makefile
and a second makefile (in this case makefile.bot) performs the actual work.
a similar rule as the all rule for clean install,etc would be in the top level makefile, but the target would be changed from all to clean, etc
The makefile.bot would use $name to set the executable name, etc
Notice the use of the parens around the cd and make -f ... so those commands are run in a 'new' shell so when the make exits, execution is in the original top level directory and ready to loop to do it all again in the next directory.

Makefile can't find a target that is already there

So I've got the following folder structure
makefile
src/my_lib.c
src/myhead.h
and I'm trying to compile *my_lib.c* with the header myhead.h as a library. This is the makefile. I attempt to put the obj files in OBJFOLDER and the compiled library in the OUTPUTFOLDER
PLUGNAME=my_lib
SOURCEFOLDER=src
OUTPUTFOLDER=bin
OBJFOLDER=bin/obj
OBJS=$(PLUGNAME).o
DEPS=myhead.h
# Configuration finishes here
_OBJS = $(patsubst %,$(OBJFOLDER)/%,$(OBJS))
_DEPS = $(patsubst %,$(SOURCEFOLDER)/%,$(DEPS))
ifeq ($(OS),Windows_NT)
EXT = .dll
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
EXT = .so
endif
endif
all : $(OUTPUTFOLDER)/$(PLUGNAME)$(EXT)
$(OUTPUTFOLDER)/$(PLUGNAME)$(EXT) : $(_OBJS)
gcc -Wl,--add-stdcall-alias -shared -o $# $(_OBJS)
$(OBJFOLDER)/%.o: $(SOURCEFOLDER)/%.c $(_DEPS)
mkdir -p $(OUTPUTFOLDER)
mkdir -p $(OBJFOLDER)
gcc $(foreach d, $(INC), -I$d) -c $< -o $#
.PHONY: clean
clean :
rm -f $(OBJFOLDER)/*.o $(OUTPUTFOLDER)/$(PLUGNAME)$(EXT) $(SOURCEFOLDER)/TSDRPlugin.h
When I do make all it fails
make: *** No rule to make target `bin/obj/my_lib.o', needed by `bin/
my_lib.dll'. Stop.
I have no idea how this could be possible since I already have defined
$(OBJFOLDER)/%.o: $(SOURCEFOLDER)/%.c $(_DEPS)
Strangely if I change the above line in the makefile, to
bin/obj/my_lib.o: $(SOURCEFOLDER)/%.c $(_DEPS)
I now get
make: *** No rule to make target `src/%.c', needed by `bin/obj/my_lib.o'. Stop.
Your second error is because by removing the % in the target you've turned this into an explicit rule, not a pattern rule. So, the % in the prerequisite is not replaced.
Your first error means that for some reason make is deciding that your pattern rule doesn't match. This means, usually, that make can't find and doesn't know how to create one of the prerequisites. I recommend you run make with the -d flag and see why make decides your rule doesn't apply.
What version of GNU make are you using? Some very old versions would not match pattern rules if the directory that the target was to be placed into didn't exist already.
The problem was that header was missing... Stupid mistake on my side.
I overlooked it, because this was a snippet from a longer makefile that was supposed to copy over the header but it didn't which means that this line was outputting the error. Stupid me...

Make file Error when listing Dir Contents

When I try to list all the contents of a directory (to use later as a dependency) it gives this error at the end of the listing (my permissions are not the problem):
gmake: execvp: filename: Permission denied
gmake: *[test] Error 127
I don't quite understand this, the file is the first in the directory and is fine until the end of the listing, this does list all the files. I ran gmake -n to see if its trying to execute and it does not for this target. Sorry if I speak incorrectly, this is my first try at a complex make file.
Here is my code:
test:
$(wildcard $(MY_DIR)/*.cpp)
Thanks.
Now I have to find out what's going on. Time for some more experiments. With one .cpp file in the working directory, call it foo.cpp, and this makefile:
SRC := $(wildcard *.cpp)
$(info SRC is $(SRC))
test1: foo.cpp
#echo $# sees $^
try make, and tell us the result.

Makefile excluding files

I am creating a GNU Makefile and I have a following problem:
I have a list of exclude files (and directories) that need to be excluded from source list.
Now, removing listed files from list isn't to big of a problem. I just do the following:
NEWSRC := $(shell find $(SOURCEDIR) -name '*.c')
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt) #TARGET12 is a Makefile parameter
CSRC := $(filter-out $(EXCLUDES),$(NEWSRC))
The problem is when EXCLUDES contain directory (not the file name), and all the file names under the same directory should be also excluded. For example, if the one member of EXCLUDES variable is ../sources/filesystem/SomePath, then all the files under that directory should be excluded from CSRC also. For example, those files could be:
../sources/filesystem/SomePath/something.c
../sources/filesystem/SomePath/src/something.c
../sources/filesystem/SomePath/Some1/src/something.c
Do you know how this could be solved inside Makefile?
Thank you in advance!
If the elements in NEWSRC necessarily start with
../sources/filesystem/SomePath, how about adding suffix to EXCLUDES as
the following?
$(filter-out $(addsuffix /%,$(EXCLUDES)),$(NEWSRC))
If you're allowed to modify the ..._exclude.txt files, you could use patterns.
foo.exclude.txt:
badFile.cc anotherBadFile.cc \
../sources/filesystem/SomePath/% \
yetAnotherBadFile.cc
Just slap a '%' on the end of every directory you want to exclude.
If you're not allowed to modify foo_exclude.txt, you can do the same thing within the makefile, but it's kind of ugly:
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt | sed -e 's|\/ |\/% |' -e 's|\/$$|\/%|')
you can use
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt)
EXCLUDES_FILE := { notdir $(EXCLUDES )}
CSRC := $(filter-out $(EXCLUDES_FILE),$(NEWSRC))
Let me know if it works

Resources