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.
Related
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?
I am pretty familiar with Makefiles and kernel modules, but recently I got a problem in my Makefile that doesn't make any sense -- on using wildcards.
To demonstrate this, I am compiling a hello world kernel module from scratch.
The directory structure is like this:
hello_mod/
|
--- hello.c
|
--- Makefile
Here is the actual makefile :
CFILES := $(wildcard hello.c*)
#CFILES := hello.c
OBJS := $(CFILES:.c=.o)
KSRC := /lib/modules/$(shell uname -r)/build
obj-m += hello_world.o
hello_world-y := $(OBJS)
all:
#echo $(CFILES)
$(MAKE) -C $(KSRC) M=$$PWD modules
clean:
$(MAKE) -C $(KSRC) M=$$PWD clean
.PHONY: clean
The problem is that even though the commented $(CFILES) and the uncommented $(CFILES) are exactly the same, the build fails on using the first $(CFILES) with the following error:
*** No rule to make target `/home/test/hello_mod/hello_world.c', needed by
/home/test/hello_mod/hello_world.o'. Stop.
If the commented $(CFILES) is used, it works perfectly.
If someone wants to test this out, I'm including the source for the hello world source which is hello.c :
#include <linux/kernel.h>
#include <linux/module.h>
static int mod_init()
{
printk("Hello\n");
return 0;
}
static void mod_exit()
{
printk("Bye world\n");
}
module_init(mod_init);
module_exit(mod_exit);
Does anyone know why it is behaving as such? And I need to use wildcards in the makefile. Any help will be appreciated.
There are two makes happening here. The first really only relies on the KSRC variable and the recursive make call. The second make only needs the CFILES, OBJS, obj-m, and hello_world-y variables, and doesn't make use of the all: target. So your debug is showing that CFILES is set correctly for the first Make, where it's not being used, and is not showing it in the second make, where it is.
You're wildcard expanding from a different directory, and not picking up the right files. Try this for CFILES:
CFILES := $(notdir $(wildcard $M/hello.c*))
SRCDIRS := subdir1 subdir2
CFILES := $(strip $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)))
should probably be (see foreach example in documentation)
SRCDIRS := subdir1 subdir2
CFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c))
(no need to $(strip), .... or perhaps
CFILES := $(wildcard {subdir1,subdir2}/*.c)
Use remake, probably as remake -x, to debug such issues.
I am a newbie in creating makefiles, and would be glad if someone could help me.
I have created several header files (for function declarations) and corresponding .c programs (8 in total), for the function definitions (including the main function). These are listed in the .../include/ directory. Additionally, I have created another directory for the storing the output files : .../bin/ after compilation. I tried to link the .o files, but was unsuccessful. I have attached a small piece of the makefile code (similar one taken from the internet) :
CC = g++
CFLAGS = -Wall -O3
INC_DIR := /media/sf_~share/151*/Codes/include
OBJ_DIR := /media/sf_~share/151*/Codes/obj
INC_FILES := $(wildcard $(INC_DIR)/%.c)
OBJ_FILES := $(patsubst $(INC_DIR)/%.c, $(OBJ_DIR)/%.o, $(INC_FILES))
all : $(APP)
$(APP) : $(OBJ_FILES)
$(CC) $(CFLAGS) -o $# $^
$(OBJ_DIR)/%.o : $(INC_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
clean:
rm -f *.o $(APP)
I would be glad if someone could either suggest me a different code, or rectify this as it is.
There are a few mistakes in your Makefile:
Wildcard usage
You should use *.c rather than %.c for wildcard expansion, like this:
INC_FILES := $(wildcard $(INC_DIR)/*.c)
Patsubst usage
You don't need to specify the full pattern $(INC_DIR)/%.c for patsubst, instead, simply use:
OBJ_FILES := $(patsubst %.c, %.o, $(INC_FILES))
Missing $(APP) value
I don't know if you simply forgot to add this to the sample or not, but since $(APP) is an empty string, the makefile says:
make: Nothing to be done for `all'.
Adding APP := program triggers a build for all the *.c files in include.
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))
I am trying to make my Makefiles platform conditional with statements like:
ifeq ($(UNAME), Linux)
# LINUX version
program_NAME := lib$(TARGET).so
OBJDIR = ../build/linux
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS version
program_NAME := lib$(TARGET).dll
OBJDIR = ../build/windows
endif
and:
ifeq ($(UNAME), Linux)
# LINUX version
program_INCLUDE_DIRS := \
/home/ben/projects/g2/src \
/home/ben/projects/pulse_IO/src \
/home/ben/projects/core/src
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS Virtual Machine version
program_INCLUDE_DIRS := \
E:/g2/src \
E:/pulse_IO/src \
E:/core/src
endif
I then compile the src either under Linux or Windows 7 running as a VM (via virtualbox) on a Linux host OS. Problem I haven't managed to solve is how to get the object files and resulting shared libraries or executables to be written to a platform specific directory, e.g. /build/linux or /build/windows where the source code is in /src
As you can see I've added an OBJDIR variable but I can't figure out how to use that to redirect the .o, .so, .dll, .exe files to the correct dir conditional on platform. I'm sure it should be easy but my research keeps bogging down with articles on vpath usage which I don't think is what I'm after.
The part of my Makefile I think I need to modify is as follows:
LINK.c := $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
$(program_NAME): $(program_OBJS)
$(LINK.c) -shared -Wl,-soname,$(program_NAME) $(program_OBJS) -o $(program_NAME)
I should probably be using something smarter like autotools or cmake but it would be great just to get this working for now.
should also add, my list of object files is created as follows:
program_C_OBJS := ${program_C_SRCS:.c=.o}
Have tried:
program_OBJS := $(addprefix $(OBJDIR)/$program_C_OBJS)
but make compains that addprefix has the wrong no. of arguments
For gmake, see Here:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
What compiler and toolset are you using? In the case of QNX, it has macros like:
$OS
$CPU
$PRODUCT
$PROJECT
$SECTION
$VARIANT ($VARIANTLIST, $EXCLUDE_VARIANTLIST)
These allow you to customize the target folder and filename for the results of your build.
http://www.qnx.com/developers/docs/6.3.2/neutrino/prog/make_convent.html
Other compilers/toolchains have similar facilities.