checking subfolders recursively for additional make files [closed] - c

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

Related

Is is possible to create directory at root path in kernel module?

I am trying to create a directory at rootpath, e.g. /my_own_dir/.
Here's what I do:
struct file *fp = filp_open("/my_own_dir/",O_DIRECTORY|O_CREAT, 0755);
The .ko can be compiled. However, when I insmod .ko the terminal just froze.
Neither was the directory created nor the mod seemed to be inserted.
So my question is, is it possible to create such a directory? If so, what's wrong with my method?
I'm using a Ubuntu 18.04 with Kernel version 5.11.0.
My solution is to symlink the source files into the bin directory and dynamically generate a new MakeFile in the bin directory. This allows all build files to be cleaned up easily since the dynamic Makefile can always just be recreated.
INCLUDE=include
SOURCE=src
TARGET=mymodule
OUTPUT=bin
EXPORT=package
SOURCES=$(wildcard $(SOURCE)/*.c)
# Depends on bin/include bin/*.c and bin/Makefile
all: $(OUTPUT)/$(INCLUDE) $(subst $(SOURCE),$(OUTPUT),$(SOURCES)) $(OUTPUT)/Makefile
make -C /lib/modules/$(shell uname -r)/build M=$(PWD)/$(OUTPUT) modules
# Create a symlink from src to bin
$(OUTPUT)/%: $(SOURCE)/%
ln -s ../$< $#
# Generate a Makefile with the needed obj-m and mymodule-objs set
$(OUTPUT)/Makefile:
echo "obj-m += $(TARGET).o\n$(TARGET)-objs := $(subst $(TARGET).o,, $(subst .c,.o,$(subst $(SOURCE)/,,$(SOURCES))))" > $#
clean:
rm -rf $(OUTPUT)
mkdir $(OUTPUT)
If you are building inside the kernel tree you can use the O variable:
make O=/path/to/mydir
If you are compiling outside the kernel tree (module, or any other kind of program) you need to change your Makefile to output in a different directory. Here a little example of a Makefile rule which output in the MY_DIR directory:
$(MY_DIR)/test: test.c
gcc -o $# $<
and then write:
$ make MY_DIR=/path/to/build/directory
Or a workaround:
Create a sub-directory with/for every arch name (e.g. "debug_64").
Under "debug_64": create symbolic link of all .c and .h files. Keeping the same structure.
Copy the makefile to "debug_64" and set the right flags for 64 Debug build, e.g.
ccflags-y := -DCRONO_DEBUG_ENABLED
ccflags-y += -I$(src)/../../../lib/include
KBUILD_AFLAGS += -march=x86_64
Remember to set the relative directories paths to one level down, e.g. ../inc will be ../../inc.
Repeat the same for every arch/profile. Now we have one source code, different folders, and different make files. By the way, creating profiles inside make files for kernel module build is not an easy job, so, I preferred to create a copy of makefile for every arch.

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.

make - stripping unused files

In my current project, more than 200MB C files are present. While making targets I can able to see only < 100MB is used to create a binary. How, to identify what are the files are not touched while creating targets. So, that we can strip it off and make the codebase more sleek.
How, to identify the list of files created for target while compiling?
I think the best approach is to use one of the methods Linux offers for monitoring file system access:
inotifywait
kfsmd
loggerfs
auditd / auditctl / ausearch
You could also run the make command with strace (strace -f make) and parse the output for open() calls.
That is what I used to do in the past.
Take your pick.
I would probably:
make clean
make 2>out to capture the full log of the build to a file
grepthe out file for gcc invocations
Filter out the filenames from the gcc invocations
Build a sorted list of those filenames
Build a sorted list of filenames in the project.
Compare the two.
Or something like that. Shouldn't be too hard.
Another method is to open the (autogenerated) dependency files for you executables and shared libraries. They are going to contain .o as prerequisites, which normally correspond to .c.
This works best for non-recursive make build systems with complete dependency trees.
If your make is GNU make, as seems likely, you could consider
variations on the following approach. (For simplicity I'll assume that the only
source files of interest are .c files.)
Say we have Makefile in directory dir that makes some default
target and possibly others, including intermediate targets.
You can use another makefile, say, unused_srcs.mk that you include in
Makefile, such that in dir you can run:
make unused_srcs
which will display a list of all the source files in dir that don't
contribute to the default target. Or run:
make unused_srcs target=TARG
for some target TARG, and get a list of all the source files in dir that
don't contribute to TARG.
This assumes that Makefile has a clean target, or maybe several
variants of clean[-???], that can suitably clean the default target or
any target you might be interested in, and that you don't mind
a suitable clean[-???] being invoked for the unused_srcs target.
For example, in dir we have:
main.c
extern void boo(void);
int main(void)
{
boo();
return 0;
}
boo.c
#include <stdio.h>
void boo(void)
{
puts("Boo!");
}
noop.c
void noop(void){}
Makefile
.phony: all clean
all: boo
objs = main.o boo.o
boo: $(objs)
gcc -o $# $^
clean-obj:
rm -f *.o
clean: clean-obj
rm -f boo
# include /some/standard/place/unused_srcs.mk
include unused_srcs.mk
And in some standard place which, for simplicity, we'll assume is again dir,
we have:
unused_srcs.mk
.phony: unused_srcs
ifndef $(target)
target = all
endif
ifndef $(cleaner)
cleaner = clean
endif
all_srcs = $(wildcard *.c)
used_srcs = $(filter %.c,$(shell ($(MAKE) $(cleaner) && $(MAKE) -n -d $(target)) \
| grep -e 'Considering target file' | sed -e "s/[\`\']//g" -e "s/\.$$//g" -))
unused_srcs = $(filter-out $(used_srcs),$(all_srcs))
unused_srcs:
#echo $(unused_srcs)
In this project:-
noop.c is unused by boo (it is completely superfluous)
noop.c and main.c are unused by boo.o
noop.c and boo.c are unused by main.o
And we can discover such facts with make unused_srcs commands:
$ make unused_srcs
noop.c
$ make unused_srcs target=boo
noop.c
$ make unused_srcs target=boo.o
main.c noop.c
$ make unused_srcs cleaner=clean-obj target=boo.o
main.c noop.c
$ make unused_srcs target=main.o
boo.c noop.c
$ make unused_srcs target=clean
boo.c main.c noop.c
Clearly all the heavy-lifting is done in the evaluation of $(used_srcs)
and $(unused_srcs) in unused_srcs.mk, and mostly the former.
The evaluation of $(used_srcs) exploits GNU make's -d option, which
generates fulsome debugging info, together with the fact that any source
file that does contribute to the chosen TARG must itself be considered
a potential target when TARG is made.
Together, these things mean that if we clean TARG and then run make -n -d TARG
the output will be the debugging info of a dry-run (-n) of make TARG,
and in this output a line like:
Considering target file `FILE.c'.
will appear for each .c file FILE.c that contributes to TARG, and
for no other .c files that may be present.
The evaluation of $(used_srcs) generates that debugging info and filters
it to extract the names of the .c files.
The evaluating of $(unused_srcs) then just weeds out the $(used_srcs)
from the list of all the .c files there are.

Make target containing subdirectory based on target dependencies

Say I have a list of source files and each are to be compiled to separate binaries:
SRCS = abcd.c efgh.c ijkl.c
And I want output files in separate subdirectories based on the file names like this:
build/abcd/abcd
build/efgh/efgh
build/ijkl/ijkl
I'm thinking a static pattern rule is the way to go. The pseudo-make-rule can be something like:
$(TARGETS): build/%/%: %.c
# stuff ...
I started by making a list of the subdirectories based on the filenames:
DIRS = $(SRCS:%.c=build/%)
So now we have DIRS = build/abcd build/efgh build/ijkl. I thought I can make the list of targets now with something like:
BLDS = $(DIRS:%=%/$(basename %))
But of course this doesn't work since the wildcard can not be used multiple times within a pattern. Therefore I'm now stuck at BLDS = build/abcd/% build/efgh/% build/ijkl/%.
Obviously I'm totally going about this the wrong way. How would you go about this?
For now I'm writing each rule explicitly, which is starting to get a bit tedious:
compile = # command to do stuff
BD = build
all: $(BD)/abcd/abcd $(BD)/efgh/efgh $(BD)/ijkl/ijkl
$(BD)/abcd/abcd: abcd.c
$(call compile)
$(BD)/efgh/efgh: efgh.c
$(call compile)
$(BD)/ijkl/ijkl: ijkl.c
$(call compile)
clean:
rm -rf build/*
.PHONY: all
I believe this does what you want:
SRCS:=abcd.c efgh.c ijkl.c
# We could fold NAMES into BLDS's definition if NAMES is not used elsewhere.
NAMES:=$(SRCS:%.c=%)
BLDS:=$(foreach name,$(NAMES),$(subst foo,$(name),build/foo/foo))
# We don't use DIRS below but the question had this variable.
DIRS:=$(dir $(BLDS))
TARGETS:=$(BLDS)
.PHONY: all
all: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): $$(notdir $$#).c
#echo Build $# from $^
mkdir -p $(dir $#)
touch $#
There are two important changes. The first is to reorder how the variables are created, and use subst, which allows replacing a matched string multiple times. The second is to use secondary expansion so that make builds rules for each of your targets. You initially a pattern with two %, but the docs say:
A pattern rule looks like an ordinary rule, except that its target contains the character `%' (exactly one of them).
(Emphasis added.)
I've tested the above with fake files abcd.c efgh.c and ijkl.c and get the following output:
$ make
Build build/abcd/abcd from abcd.c
mkdir -p build/abcd/
touch build/abcd/abcd
Build build/efgh/efgh from efgh.c
mkdir -p build/efgh/
touch build/efgh/efgh
Build build/ijkl/ijkl from ijkl.c
mkdir -p build/ijkl/
touch build/ijkl/ijkl

sample make file for creating more than one exe files with different directory [duplicate]

This question already has answers here:
Building multiple executables with similar rules
(5 answers)
Closed 9 years ago.
I am having a directory called test where make file should be. i am having subdirectory called sub1, sub2, sub3.
test/Makefile
test/sub1
test/sub2
test/sub3
I want to create exe1 by compiling sub1, exe2 by compiling sub2 and exe3 from sub3.
Can i add more than one directory in vpath?? or any other solution
You could simply have a very simple makefile in the test directory, just going into the subdirectories and calling makefiles in them. The subdirectories have makefiles that builds normally, but simply put the executable in the parent directory.
First of all: Yes you could add more than one directory in vpath. Each entry is separated with a colon ':'
vpath %.c test/sub1:test/sub2:test/sub3
But you'll getting into trouble as soon you have the same filename (with different content) in two directories. Consider:
test/Makefile
test/sub1/main.c
test/sub1/foo.c
test/sub1/bar.c
...
test/sub2/main.c
test/sub2/blish.c
test/sub3/blash.c
...
test/sub3/main.c
test/sub3/okEnoughForNow.c
And your makefile containing:
vpath %.c sub1:sub2:sub3
exe1.exe : main.c foo.c bar.c
gcc -o $# $^
exe2.exe : main.c blish.c blash.c
gcc -o $# $^
exe3.exe : main.c okEnoughForNow.c
gcc -o $# $^
The result would be:
gcc -o exe1.exe sub1/main.c sub1/foo.c sub1/bar.c
gcc -o exe2.exe sub1/main.c sub2/blish.c sub2/blash.c
gcc -o exe3.exe sub1/main.c sub3/okEnoughForNow.c
As you can see, all exe's contain sub1/main.c as this is the main.c found first; Its path appears first on the vpath.
Joachim's Approach is definitive a simple, and very common solution. I would choose it as well if the programs in your subfolders are completely unrelated: You could have in each directory a makefile containing something like:
SRC := $(wildcard *.c)
%.exe : $(SRC)
gcc -o $# $^
Assuming, all .c files in each of your sub* shall be part of your program, and there are no subfolders in your sub's. Otherwise you'll need a different approach to scan your .c files, or specify them individually.
In your main makefile you can run for each subfolder a new instance of make, using those makefiles. Which gives you a main Makefile like:
# Get all subfolders name without trailing slash
PROGS := $(patsubst %/,%,$(wildcard */))
# Each subfolder can be made by calling make in
# that folder. A file prog.exe is created.
.PHONY : $(PROGS)
$(PROGS) :
$(MAKE) -C $# prog.exe
# Now every .exe depends on its subfolder, calls
# Make there - see rule above and copies the
# prog.exe from there into the root, with the name
# of the subfolder. (Alternatively you could use
# mv instead of cp)
%.exe : %
cp $</prog.exe $#
Assuming the name of your .exe is the same as the directory name and all subfolders are containing programs.
However, calling make from a running make instance (recursive make) can cause a real headache as soon as there are any dependencies between the generated files of the subfolders.
Another solution:
A different approach whithout using recursive make is having rules dynamically created. In that case your main Makefile could look like this. (I'm again assuming all subfolders are containing programs, all subfolders are flat, and all .c files in those subfolders are part of your program) This has the advantage that you'll have to maintain just one makefile, and there can be any dependency between the different programs. But still it has the disadvantage that you cannot manage your different programs seperately.
That's the complete makefile:
%.exe :
gcc -o $# $^
PROGS := $(patsubst %/,%,$(wildcard */))
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(wildcard $(P)/*.c)))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
.PHONY : all
all : $(addsuffix .exe,$(PROGS)
We're starting with a rule for compiling: Any .exe is generated by invoking gcc having all prerequisites as source files.
%.exe :
gcc -o $# $^
Then, next step is to obtain all "programs" by scanning for all subfolders and stripping off the trailing slash
PROGS := $(patsubst %/,%,$(wildcard */))
The next step is to create for each program a variable containig all Sources. Note the eval function expands, and passes everything to make as it has been written in the Makefile.
$(foreach P,$(PROGS),$(eval SRC_$(P) := $(wildcard $(P)/*.c)))
Thus the line above, with your sub1, sub2 and sub3 will become:
SRC_sub1 := $(wildcard sub1/*.c)
SRC_sub2 := $(wildcard sub2/*.c)
SRC_sub3 := $(wildcard sub3/*.c)
The eval function can even be used to create rules:
$(foreach P,$(PROGS),$(eval $(P).exe : $(SRC_$(P))))
So this will expand to (assuming the file structure in the example above)
sub1.exe : sub1/main.c sub1/foo.c sub1/bar.c
sub2.exe : sub2/main.c sub2/blish.c sub2/blash.c
sub3.exe : sub3/main.c sub3/okEnoughForNow.c
Now we have three rules without a recipe. Make says "if you have a rule without recipe, and an implicit rule that matches can be found, this rule is used with the prerequisites added from the rule that does not have the recipe" Thus, for those 3 rules the implicit rule of %.exe above applies.
Basically that's the trick. For your convenience you can add
.PHONY : all
all : $(addsuffix .exe,$(PROGS))
So make all makes everything.
Extension:
If you'd like to be able to make the .o files seperately as well, you could add one more implicit rule like:
%.o : %.c
gcc -c -o $# $<
and make your programs dependent on the .o rather than on the .c files:
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(patsubst %.c,%.o,$(wildcard $(P)/*.c))))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
Then you'll have your .exe dependend on the .o that can be found by changing .c into .o after scanning all sources. Via the implicit rule chain %.o : %.c make will know what to do.

Resources