Makefile excluding files - file

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

Related

checking subfolders recursively for additional make files [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a project. If it contains a Makefile in every level of each sub directories and there is a top most directory Makefile. Then how to make makefiles compile all the C files and output one resulted .o file at the root. How is it possible?
If you use GNU make under GNU/Linux (or any UNIX-like OS with the find utility), have no spaces in your directory names and all your makefiles are named Makefile, the following could be a starting point. Add it to your top makefile and type make all to build all subdirectories:
SUBDIRS := $(dir $(shell find . -mindepth 2 -type f -name 'Makefile'))
.PHONY: $(SUBDIRS) all
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
Explanations:
find . -mindepth 2 -type f -name 'Makefile' is a shell command that finds all files (-type f) named Makefile (-name 'Makefile') in any subdirectory (-mindepth 2) of the current directory.
$(shell CMD) is the make function that passes the shell command CMD to the shell and returns the result.
$(dir LIST) returns the directory part of all paths of LIST.
SUBDIRS := $(dir ...) assigns all this to the make variable SUBDIRS (replace SUBDIRS by any name you want, it's just a name). So, if you have two subdirectories named foo and bar/baz, and if they contain a file named Makefile, find . -mindepth 2 -type f -name 'Makefile' returns foo/Makefile bar/baz/Makefile, and SUBDIRS := $(dir $(shell find . ...)) assigns foo bar/baz to the make variable SUBDIRS.
.PHONY: $(SUBDIRS) all declares that any name in the value of make variable SUBDIRS, plus all, are phony targets: that is, they are not real file names (even if files or directories with these names actually exist), and make, when asked to, shall rebuild them even if they already exist and are up to date with respect to their prerequisites.
all: $(SUBDIRS) tells make that the all target depends on all names in the value of make variable SUBDIRS; in order to make all make shall first make all names in the value of make variable SUBDIRS.
Finally:
$(SUBDIRS):
$(MAKE) -C $#
is a make rule that explains how to make any name in the value of make variable SUBDIRS. The recipe ($(MAKE) -C $#) simply consists in invoking make again ($(MAKE)) but in the $# directory (-C $#). The reason why you must use $(MAKE) instead of just make can be found in the GNU make documentation. $# is one of the many make automatic variables. In recipes it expands as the current target. So, if the SUBDIRS make variable has value foo bar/baz, this rule is the same as the two separate rules:
foo:
$(MAKE) -C foo
bar/baz:
$(MAKE) -C bar/baz

In Makefile, how to make wildcard function work for files in all the paths set by VPATH variable

I have two files as below (from tree command).
.
|-- Makefile
|-- dir1
| `-- file1.c
`-- dir2
`-- file2.c
I wanted to compiles files in dir1 and dir2 directory so I wrote a Makefile as below.
VPATH = dir1:dir2
CFILES := ${wildcard *.v}
$(info CFILES = ${CFILES})
output :
CFILES =
So the wildcar function doesn't automatically search paths set by the VPATH variable.
If I specifically write the path in the wildcard function, it works.
CFILES := ${wildcard dir1/*.c dir2/*.c} <== this makes it work
$(info CFILES = ${CFILES})
output :
CFILES = dir1/file1.c dir2/file2.c
I want to add only the existing paths to the Makefile but is there any way that I can use wildcard function for paths set by VPATH? (Suppose I need to remove some files from compile list so I need the files list. Just curious..)
You can use Make's text transformation functions to turn a list of directories into your desired wildcard command. Take a look at the GNU Make manual, they even use extracting the directories of VPATH in their examples. Consider something like:
$(wildcard $(addsuffix /*.c,$(subst :, ,$(VPATH))
Since you get the full path to the file via wildcard, it seems like using VPATH shouldn't be necessary. IMHO, VPATH is a bad idea and well designed build system don't use it.
Also consider what you want to happen if files with the same name appear in different directories!

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 for potentially large project with automatic target creation

Let's say I have a C project. There are several files:
/myproject/makefile
/myproject/src
/myproject/build
/myproject/src/baseHeader.h
/myproject/src/module1/module1.h
/myproject/src/module1/module1_a.c
/myproject/src/module1/module1_b.c
/myproject/src/main.c
I want make to search in src for all *.h files which are not on the first depth level i.e. make should look for *.h files in
/myproject/src/module1/
so it will not use
/myproject/src/baseHeader.h
Then for every found .h make should create target with the basename of .h i.e. for
/myproject/src/module1/module1.h
it should be
./build/module1.o: ./src/module1/module1_a.c ./src/module1/module1_b.c ./src/module1/module1.h $(OTHER_DEPS) | $(OPTIONAL_DEPS)
$(CC) -c $< -o $#
also it should create target for every .c file in /myproject/src/ dir without going recursive in this example only main.c will be found and target should look like
./build/main.o: ./src/main.c $(OTHER_DEPS) | $(OPTIONAL_DEPS)
How this can be done?
Could someone provide me with the link to example if exists?
I'm asking for this because after a day of trying I think it's better to forget about make and use bash scripts instead...
This can be done but it is not trivial. One way to do it is to build a list of all of the .h files recursively in the src directory and its subdirectories, then remove from that list the .h files in the src directory.
We can search the src directory and all subdirectories for .h files with $(wildcard src/**/*.h)) and only the src directory for .h files with $(wildcard src/*.h). These can be combined with the filter-out function to produce a list containing only the .h files in subdirectories of src/ like
MODULES := $(filter-out $(wildcard src/*.h),$(wildcard src/**/*.h))
This will produce a list like
/myproject/src/module1/module1.h
/myproject/src/module2/module2.h
/myproject/src/module3/module3.h
We could remove the directory structure with
INCLUDES := $(notdir MODULES)
which will produce
module1.h
module2.h
module3.h
We can convert these into object files for the modules with
OBJDIR = build
OBJS := $(addprefix $(OBJDIR)/, $(patsubst %.h,%.o, $(INCLUDES)))
Then we define an empty target rule to create all these
.PHONY: modules
modules: $(OBJS)
And the implicit rule to create the objects
$(OBJDIR)/%.o: $(dir $(findstring %.h, $MODULES))*.c %.h $(OTHER_DEPS) | $(OPTIONAL_DEPS)
$(CC) -c $? -o $#
EDIT: Its not particularly advisable to use wildcards in prerequisite lists but it is the best solution I have for now.
To compile a target for every .c file in src without searching recursively we take a similar approach starting off.
SRCS := $(wildcard src/*.c)
will find all out the .c files in the top level src directory. We can compile targets for these with
$(SRCS:%.c=$(OBJDIR)/%.o): %.c $(OTHER_DEPS) | $(OPTIONAL_DEPS)

debugging a makefile

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.

Resources