Simple Static library using KBuild - c

I've inherited a project which builds an image for an ARM processor. From what I can tell, the project uses kbuild Makefiles - each subdirectory contains a Makefile, e.g.
Makefile in DirA:
obj-y := DirB/
ccflags-y += <some_flags>
Makefile in DirB:
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
source := <path>source.c
obj_c := $(patsubst $(cur_dir)%,%,$(cur_dir)$(source))
obj-y := $(obj_c:.c=.o)
ccflags-y += \
-I<path_to_include_dir>
The build system produces a series of static libraries (and associated .o files) in the 'root/out' folder.
Now however, I simply want to generate just the static library with source code in DirA (and not the entire image) using the existing Makefiles but I'm having trouble.
Of course, I've looked in the root Makefile to work out how the Makefiles in the subdirectories are consumed, but it builds the entire image and is >1k lines long.
I've tried writing my own Makefile based on this:
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj_s := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.S))
obj_c := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c))
obj_cpp := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.cpp))
obj-y := $(obj_c:.c=.o) $(obj_s:.S=.o) $(obj_cpp:.cpp=.o)
obj-y += <DirA>
libother.a: $(obj-y)
ar rcs $# $^
and running make libother.a or simply make with the resulting error:
file format not recognized
On closer inspection, the obj-y doesn't contain the desired .o files, but just the path I've given it. So, there must be something I'm missing.
Any pointers?

Related

Makefile include list of object files recursively

I haven been working with the Linux kernel for some time now and I am interested in adapting the Makefile structures used there. I want to achieve something similar by creating a set of Makefiles in each subdirectory which only consists the names of the files I really want to compile when building my project. A typical similar example achieved in the Linux kernel looks like this:
obj-y += file1.o
obj-y += file2.o
obj-y += file3.o
obj-y += file4.o
# ...
obj-d += somesubdir
Now, when building my project, I use the Makefile in my root directory to recursively include each Makefile in the individual subdirectories and append it to the list of the obj-y variable. My current approach is to define a recursive function which handles including the Makefiles and iterate through each subdirectory automatically:
OBJS :=
objtree := .
srctree := .
# ...
define build_subdir
objtree := $$(objtree)/$(1)
srctree := $$(srctree)/$(1)
obj-y :=
obj-d :=
include $$(srctree)/Makefile
OBJS += $$(patsubst %,$$(objtree)/%,$$(obj-y))
$$(foreach subdir,$$(obj-d),$$(eval $$(call build_subdir,$$(subdir))))
srctree := $$(patsubst %/$(1),%,$$(srctree))
objtree := $$(patsubst %/$(1),%,$$(objtree))
endef
# ...
$(eval $(call build_subdir,src))
$(eval $(call build_subdir,src/subdir))
While iterating through all subdirectories, I add the individual files to the OBJS variable which is then later used to compile the file.
However, the OBJS variable only contains the name of the object file (i.e. the target), not the name of the actual source file. This is problematic since the source files in my project do not consist only of .c but also some assembly files (.S). Therefore I am not able to define a recipe which looks like this:
define compile_file
$(1): $$(patsubst %.o,%.c,$(1))
$(CC) $< -o $# $(CFLAGS)
endef
In my case, the compiler is always the same, so there's no problem in keeping the $(CC) variable as is. The same goes for the $(CFLAGS) variable.
Is there a way to achieve this similarily to the Linux kernel?
This is the current relevant content of my Makefile:
objtree := .
srctree := .
.PHONY: all
all: real-all
OBJS :=
define build_subdir
objtree := $$(objtree)/$(1)
srctree := $$(srctree)/$(1)
obj-y :=
obj-d :=
include $$(srctree)/Makefile
OBJS += $$(patsubst %,$$(objtree)/%,$$(obj-y))
$$(foreach subdir,$$(obj-d),$$(eval $$(call build_subdir,$$(subdir))))
srctree := $$(patsubst %/$(1),%,$$(srctree))
objtree := $$(patsubst %/$(1),%,$$(objtree))
endef
# $(eval $(call build_subdir, src))
$(eval $(call build_subdir,src/arch/$(ARCH)))
define compile_file
$(1): $$(patsubst %.o,%.S,$(1))
#echo "Compiling file $$< to file $$#"
endef
$(foreach file,$(OBJS),$(eval $(call compile_file,$(file))))
.PHONY: real-all
real-all: $(OBJS)
#echo "real-all"
And the current output:
Compiling file src/arch/x86/a20.S to file src/arch/x86/a20.o
make: *** No rule to make target 'src/arch/x86/acpi.S', needed by 'src/arch/x86/acpi.o'. Stop.
The last line obviously fails because there's no src/arch/x86/acpi.S file. Instead, the actual file is src/arch/x86/acpi.c. Thats what I addressed before with the issue being the source files can either be a .c or a .S file.
I solved it by using the $(wildcard) function in the following way:
define compile_file
srcbase := $$(basename $(1))
srcfile := $$(wildcard $$(srcbase).*)
$(1): $$(srcfile)
#echo "[ CC ] $$#"
endef
Since $(1) contains the path to the file, srcfile matches the file by looking for the file with $(wildcard $$(basename $(1)).*).
Now, I can compile all files easily.

MAKE: compiling all files once AND generating object files into different directory

I have a project that includes many source files in different folder locations. For some reason my Makefile can either do one of the following but not both at the same time (which is what I really want):-
1) Compile all files into a separate directory
2) Perform the compilation ONCE, gcc needs to be called once only as this significantly reduces the compilation time.
This is a code snippet that works to achieve option 1:-
INCLDDIRS := "The needed include directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_NAMES:.c=.o) )
all: $(OBJECT_DIRECTORY) $(C_OBJECTS)
$(OBJECT_DIRECTORY):
mkdir ObjDir
$(OBJECT_DIRECTORY)/%.o:%.c
$(CC) $(CFLAGS) $(INCLDDIRS) -c -o $# $<
For some reason the above compiles each c source file individually and generates an object file (i.e. gcc is called for all source files). Which is not what I want. However, at least all generated files are located in ObjDir
and this is the code snippet that works to achieve option 2:-
INCLDDIRS := "The needed iclude directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
C_OBJECTS = $(OBJECT_DIRECTORY)/*.o
all: $(OBJECT_DIRECTORY) $(C_OBJECTS)
$(OBJECT_DIRECTORY):
mkdir ObjDir
$(C_OBJECTS): (C_SOURCE)
$(CC) $(CFLAGS) $(INCLDDIRS) -c $(C_SOURCE)
For the above snippet, all files are compiled once (i.e. gcc is called only once) but the object files are generated at the same location as the Makefile and not into a separate directory. I do not want to mv the files after they are generated as this is not the cleaner solution.
My Question is:
What do I have to do to my Makefile so that compilation is performed once and that the object files are generated into a separate directory?
The makefile you want will look something like this.
INCLDDIRS := "The needed include directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
BINARY := your_binary
all: $(BINARY)
$(OBJECT_DIRECTORY):
mkdir $#
$(OBJECT_DIRECTORY/$(BINARY): $(C_SOURCE) | $(OBJECT_DIRECTORY)
$(CC) $(CFLAGS) $(INCLDDIRS) -o $# $^
It uses an order-only prerequisite for the output directory (so make knows to create it first but not count it as causing a rebuild).
It lists the source files as the prerequisites of the output binary and uses them all on the compilation line.
The main problem with this makefile, and with your goal, is that a change to any source file will cause every source file to be recompiled from scratch. That's fairly inefficient as far as incremental work goes. (That's why the default idea is to use intermediate object files. You trade some from-clean speed off against incremental speed.)
The reason your second makefile didn't work correctly is that, in a clean directory, the C_OBJECTS variable has no value. Your wildcard $(OBJECT_DIRECTORY)/*.o matches nothing.
That said it was also incorrect in that it listed every source file as a prerequisite for every object file which isn't at all correct.

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)

Maintaining a list of programs I don't want Make to compile that I could change with >> and SED instead of editing the makefile?

I'm pretty new to Make. My current Makefile is below. It compiles all .c files into the respective executable file. The list of c files is constantly growing (I'm adding more and more files, p1.c, p2.c, p3.c, ...). So I want it to compile most of them, but if there's a particular file that has errors I don't want to bother with, I'd like to be able to put it on do-not-compile list--that is, instead of telling make what I do want to compile, it would be faster to tell it what I don't want to compile. It would be easy to have a file say dont.txt that I add and remove lines to, each of which contain "px.c". If I had such a file, how would I tell make not to compile those .c files?
CFLAGS = -g -pedantic -std=c99 -Wall
SRCS = $(wildcard *.c)
PROGS = $(patsubst %.c,%,$(SRCS))
all: $(PROGS)
%: %.c
$(CC) $(CFLAGS) -o $# $<
Thank
you can filter out source files which you do not want to compile like
SRCS = $(filter-out excludefile.c, $(wildcard *.c))
Also if you maintain files name which you want to exclude then use command as follows
for example file is exclude.txt then
EXCLUDES := $(shell cat ./exclude.txt)
SRCS = $(filter-out $(EXCLUDES), $(wildcard *.c))

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