How to link files within other directories? - kernel-module

I have a project that is big enough to benefit from having its files classified by directory. I'm trying to build one kernel module out of all of them.
The documentation states the following:
--- 3.6 Descending down in directories
A Makefile is only responsible for building objects in its own
directory. Files in subdirectories should be taken care of by
Makefiles in these subdirs. The build system will automatically
invoke make recursively in subdirectories, provided you let it know of
them.
To do so, obj-y and obj-m are used.
ext2 lives in a separate directory, and the Makefile present in fs/
tells kbuild to descend down using the following assignment.
Example:
#fs/Makefile
obj-$(CONFIG_EXT2_FS) += ext2/
If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular)
the corresponding obj- variable will be set, and kbuild will descend
down in the ext2 directory.
However, this seems to be different from what I need. What comes out of this is two independent .ko files; one in each directory, each an amalgamation of the object files in its own directory.
This is my project (simplified):
root directory
|
+--- Makefile
|
+--- foo.c
|
+--- subdir
|
+--- Makefile
|
+--- bar.c
I would think that ending up with something like this would be reasonable:
root directory
|
+--- Makefile
|
+--- foo.c
|
+--- foo.o (containing foo.c's stuff)
|
+--- subdir
| |
| +--- Makefile
| |
| +--- bar.c
| |
| +--- bar.o (containing bar.c's stuff)
|
+--- kernel-module.ko (containing foo.o and subdir/bar.o)
What I really end up with is this:
root directory
|
+--- Makefile
|
+--- foo.c
|
+--- foo.o (containing foo.c's stuff)
|
+--- subdir
| |
| +--- Makefile
| |
| +--- bar.c
| |
| +--- bar.o (containing bar.c's stuff)
| |
| +--- bar.ko (containing bar.o)
|
+--- kernel-module.ko (containing only foo.o)
I'm hoping that building one module per directory is not a fundamental assumption of Kbuild's design. Shipping several modules sounds like a lot of mess for no gain.
This is my root Makefile:
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o
all:
make -C ${KERNEL_DIR} M=$$PWD
modules:
make -C ${KERNEL_DIR} M=$$PWD $#
clean:
make -C ${KERNEL_DIR} M=$$PWD $#
This is subdir/Makefile:
obj-m += bar.o
This is foo.c:
int external_function(void);
int test(void)
{
return external_function();
}
And this is subdir/bar.c:
int external_function(void)
{
return 4;
}
make (in the root directory) spits the following warning:
WARNING: "external_function" [(...)/kernel-module.ko] undefined!
And my attempts to insert kernel-module.ko are refused:
$ sudo insmod kernel-module.ko
insmod: ERROR: could not insert module kernel-module.ko: Unknown symbol in module
$ dmesg | tail -1
[11688.540153] kernel_module: Unknown symbol external_function (err 0)
How do I tell Kbuild that subdir/bar.o is supposed to be part of kernel-module.ko and not its own module?

One solution is to append bar's object file to the kernel module's object listing. The problem with this code:
obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o
Is that it's telling Kbuild to descend to subdir/, but it's not telling it to include the results of that in kernel-module.
This would fix that:
obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o subdir/bar.o
However, I don't like this solution at all because it breaks the DRY principle: It means bar.o has to be named twice; one in /Makefile and the other one in /subdir/Makefile.
Also, this solution doesn't prevent Kbuild from creating the redundant subdir/bar.ko module.
Finally, certain documentation states that it is "NOT recommended practice" for some completely unstated reason.
So this solution is pretty bad. I don't think I will stick to it.
Another solution (which branches from the previous one) is to just delete subdir/Makefile and, within the root Makefile, instead of this:
obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o
do this:
obj-m += kernel-module.o
kernel-module-objs += foo.o subdir/bar.o
This fixes the DRY issue and prevents subdir/bar.ko from being generated but still suffers from discouraged practice.
I will stick to this solution in the meantime, but since neither of them is ideal, I guess I'll leave the question open for a while.

Related

Makefile with arbitrarily many mains. How to compile all mains with one command?

I am still newish to makefile patterns. I have been working on a project based on a template makefile and project structure, however I have a good sense of what all the makefile instructions are doing.
I would like to modify this so that all the .c files in /src/mains, each with a different main call gets compiled to its own executable.
The original template had no /src/mains folder, and only one file in the /src could contain a main function call.
First the project structure
root
|
|------ Makefile
|
|------ build
| |
| |--- apps
| | |--- prog
| | |--- hello
| |
| |---- objects
| |--- *.o
|
|----- include
| |--- *.h
|
|------ src
|--- *.c // for each .h (no main calls)
|--- mains
|--- prog.c (call to main)
|--- hello.c (call to different main)
Current Makefile
Without manually writing new linking rules for each make, I found no success. I am just going to leave the cleaner, unmodified makefile here, I'd like to change this so that it automatically builds all the files in mains to /build/apps
As of right now it makes an executable called prog in /build/apps, using a main function call from within /src
CXX := gcc
CXXFLAGS := -pedantic-errors -Wall -Wextra -Werror
LDFLAGS := -lm
BUILD := ./build
OBJ_DIR := $(BUILD)/objects
APP_DIR := $(BUILD)/apps
TARGET := prog # OP: this probably needs to become a wildcard, right?
INCLUDE := -Iinclude/
SRC := $(wildcard src/*.c)
OFLAGS := -O1 -flto
OBJECTS := $(SRC:%.c=$(OBJ_DIR)/%.o)
DEPENDENCIES := $(OBJECTS:.o=.d)
all: build $(APP_DIR)/$(TARGET)
$(OBJ_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -MMD -o $# $(OFLAGS)
$(APP_DIR)/$(TARGET): $(OBJECTS)
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -o $(APP_DIR)/$(TARGET) $^ $(LDFLAGS)
-include $(DEPENDENCIES)
build:
#mkdir -p $(APP_DIR)
#mkdir -p $(OBJ_DIR)
clean:
-#rm -rvf $(OBJ_DIR)/*
-#rm -rvf $(APP_DIR)/*
If you could modify the Makefile outright that would be great, I would also appreciate any explanation so I don't need a template next time.
Also more generally, How do you like to structure your projects?
Thanks!
Make has no knowledge of programming languages at all. It is simply a tool that receives your set of rules and dependency trees.
So create a target that has all your programs as dependencies. Add it to the .PHONY target, as it is not a real file.
Also write your rules so that each program can be built independently from the others. You can have synergies, if your programs are built with common modules.
The options -p, -n and -d are helpful to debug the Makefile. Reading the manual and tutorials is a must, as always.

Makefile: Manage multiple include path

I have a project with this kind of tree:
/arch/arm/include/
/include/
I want to include files from /arch/arm/include/ with #include <arch/header.h> and files from /include with #include <header.h>.
How to do this in a Makefile ?
Thanks
this can be solved by creating a symbolic link include/arch that points to arch/arm/include
ln -s arch/arm/include include/arch
then in the makefile:
CFLAGS += -I/include
Use -I< include directory > option.
ex:
$(CC) -o $(TGT) test.c -I/include
You can add this method in your makefile. Assuming your filesystem looks like this
--------------------------------
| | |
include arch src
| |
arm makefile
|
include
LIBS_INC = -I../include
LIBS_INC += -I../arch/arm/include

Simple Non-recursive Makefile with object files in separate directory

I have searched and tried a few examples to get a simple project done using non-recursive makefiles. In the past, I had used simple single directory codebase but now I am putting together an environment for more than one engineer :-)
+--app
| +-- obj/
| +-- Makefile
| +-- first.c
| +-- second.c
|
+--lib1
| +-- obj/
| +-- Makefile
| +-- foo.c
| +-- bar.c
|
+--lib2
| +-- obj/
| +-- Makefile
| +-- sample.c
Nothing fancy- just two directories (maybe a third later) with library code and multiple applications all in the "app" directory. I want to keep the .o and .d files in a separate obj/ directory for cleanliness.
I would like to be able to do a "make" in each of the sub-directories like lib1 and lib2 to verify the libraries. They will produce libabc.a and libxyz.a respectively.
I wrote some simple Makefile but my rules don't work and I tried to understand the GNU make manual but am getting lost.
lib1/Makefile:
lib_src = foo.c bar.c
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src))
libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr libabc.a $^
obj/%.c : %.c
$(CC) $(CFLAGS) -c -o $# $<
app/Makefile:
ALL_APP = first second
% : %.c libabc.a libxyz.a
$(CC) $(CLFAGS) $^ -o $#
include ../lib1/Makefile
include ../lib2/Makefile
Now, I have trouble defining the same target in each Makefile (obviously). Like I couldn't define a clean in lib1/Makefile and app/Makefile because lib1 is included there. Makes sense though I was hoping that I could do a make clean in lib1 alone.
now when I do a make in "app", there is no rule to make obj/foo.o. I guess because the paths are all bogus. "obj/" refers to the lib1/obj/ but as the Makefile got included, that is all lost.
What am I doing wrong and can I get my project built using really simple Makefiles like I have above. Most examples online are fairly complex since they try to achieve more (I believe).
Thanks in advance (and sorry for a topic that has been discussed many times). I would rather not learn automake and cmake right now, if I can avoid it. I am hoping that my project is simple enough to not warrant use of these powerful tools.
Best regards,
Let's start with lib1/Makefile:
lib_src = foo.c bar.c
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src))
libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr libabc.a $^
obj/%.c : %.c
$(CC) $(CFLAGS) -c -o $# $<
We introduce the variable HERE, and make a couple of small changes:
HERE := ../lib1
lib_src := foo.c bar.c
lib_obj := $(patsubst %.c,$(HERE)/obj/%.o,$(lib_src))
$(HERE)/libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr $# $^
$(HERE)/obj/%.c : $(HERE)/%.c
$(CC) $(CFLAGS) -c -o $# $<
This makefile will still work just as before when invoked from within lib1/. But once we make corresponding changes to lib2/Makefile, we can change app/Makefile:
ALL_APP = first second
% : %.c ../lib1/libabc.a ../lib2/libxyz.a
$(CC) $(CLFAGS) $^ -o $#
include ../lib1/Makefile
include ../lib2/Makefile
Now for the clean rule. We rename lib1/Makefile => lib1/lib1.mak and lib2/Makefile => lib2/lib2.mak, write a new lib1/Makefile:
include lib1.mak
clean:
#rm -f lib*.a obj/*
do the same in lib2/, and modify app/Makefile:
...
include ../lib1/lib1.mak
include ../lib1/lib1.mak
clean:
#rm -f $(ALL_APP)
#$(MAKE) -C ../lib1 clean
#$(MAKE) -C ../lib2 clean
(We could do it without recursion, but it would be more complicated, and there's really nothing wrong with using recursive Make in this way.)
Some further refinements are possible. For instance, it's not good to have paths hard-coded into lib1/lib1.mak and lib2/lib2.mak this way, and that can be fixed. But this is enough for one day.

Build file (Rake or Make?) for building a few simple libraries with common options?

So, I have a set of different libraries in C and C++ that I need to build with some common options. My current "template" makefile looks something like so:
#Change this for different MCUs. Standard includes atmega328
VARIANT = ../variants/standard
HDRS=RedBot.h
OBJS=RedBot.o RedBotAccel.o RedBotMotor.o RedBotSensor.o
CPPFLAGS = -I../arduino/ -I./ -DF_CPU=16000000UL -Os -mmcu=atmega328p
CC=avr-gcc
CPP=avr-g++
AR=avr-ar
default: libredbot.a
libredbot.a: ${OBJS}
${AR} crs libredbot.a $(OBJS)
.c.o: ${HDRS}
${CC} -I ${VARIANT} ${CFLAGS} -c $*.c
.cpp.o: ${HDRS}
${CPP} -I ${VARIANT} ${CPPFLAGS} -c $*.cpp
clean:
rm -f ${OBJS} core a.out errs *.a
I place the makefile in the same folder as all the sources. However, this is ugly for a few reasons. For one, it's only a template. I have to duplicate this across about 15 libraries. And I need for the compilation options to be very easy to change across all libraries, because multiple targets is common. Currently, the best thing I can think of is making a root makefile with the options passed to each library makefile. However, I still have to keep track of all the files (the OBJS bit). And not all libraries are capable of being built on all targets.
Can someone point me either to a more comprehensive makefile, or possibly an example build file for something like Rake that could handle this?
Make one (or more) template files that you put in a common base folder, then in each project directory place a makefile which sets flags specific to the library being built, as well as listing only the source files. Then it includes the common makefile(s) templates, which contains implicit rules and variables that takes the local flags for building.
So a structure something like this:
project root
|-- makefiles
| |-- rules.mk
| |-- vars.mk
| |-- exe.mk
| `-- lib.mk
|-- libraryA
| |-- Makefile
| `-- (other sources and headers for this library)
|-- libraryB
| |-- Makefile
| `-- (other sources and headers for this library)
|-- programA
| |-- Makefile
| `-- (other sources and headers for this program)
`-- programB
|-- Makefile
`-- (other sources and headers for this program)
The rules.mk contains rules such as clean or the implicit build rules like .c.o.
The vars.mk contains global variables and uses local flag variables to set the global flag variables like CFLAGS.
The exe.mk contains rules to make an executable program.
The lib.mk contains rules to make a library.
A local makefile will then look something like this:
LOCAL_CFLAGS = <some C flags specific to just this library/executable>
# Other local flags, e.g. LOCAL_LDFLAGS, LOCAL_LIBS, etc.
TARGET = <name of target executable/library>
LOCAL_SOURCES = <list of all source files for $(TARGET)>
LOCAL_HEADERS = <list of all headers>
include ../makefiles/vars.mk
include ../makefiles/rules.mk
include ../makefiles/exe.mk # If making an executable
include ../makefiles/lib.mk # If making a library
# Note: Don't include both the above two files
The vars.mk file can look something like this
CFLAGS = <some common C flags>
CFLAGS += $(LOCAL_CFLAGS)
# All other flag variables
HEADERS = $(LOCAL_HEADERS)
CFILES = $(filter %.c,$(LOCAL_SOURCES))
CXXFILES = $(filter %.cpp,$(LOCAL_SOURCES))
OBJECTS = $(CFILES:%.c=%.o)
OBJECTS += $(CFILES:%.cpp=%.o)
I ended up writing my own little hacky thing with Ruby to get this done easily. You can draw inspiration from it here: https://github.com/Earlz/make-wiring/blob/master/build.rb
Basically, it consists of a "template" makefile that takes many environment variables. And the build.rb script just passes them off to the makefile without you having to manually specify everything on the command line. Usage thus would look like so:
./build.rb build redbot
./build.rb build arduino
or whatever, and all flags and arguments are neatly contained within build.rb, instead of being spread among dozens of makefiles or being manually specified on the command line

Trouble building C library (with makefile)

I'm doing a project in which I need to connect to an AR.Drone 2.0. I have a functional GUI in Java, but to control the drone I have to use it's SDK which is a C library. I wrote the necessary functions to combine Java and C via JNI, but because of the modifications I did to an example delivered with the SDK, it doesn't build anymore. It is thought to be built with a makefile (which I also have tried changing without success) running the make command. The problem is I am very new to C and makefiles, and I have searched the web a lot but have not found any solution. So here's how the library looks like:
.: Folder root
|
+ src: Sources
|
+ ARDroneLib: The AR.Drone Library
| |
| + Soft: Containing the "interesting" part of the whole lib
| | |
| | + More subdirs... (Build: contains a makefile, Common: c and h files, Lib: stuff)
| |
| + Many other subdirectories (FFMPEG, ITTIAM, VLIB, VP_SDK)
|
+ DroneControl: My own code
|
+ Source:The source files
| |
| + Navdata: Code to retrieve the navigation data
| | |
| | + navdata.c
| | + navdata.h
| |
| + Video: Code to retrieve the drone's video stream
| | |
| | + video_stage.c
| | + video_stage.h
| |
| + ardrone_testing_tool.c: Main file, containing the main function, etc.
| + ardrone_testing_tool.h: Its header
| + dronecontrol_ARDrone: My own file, containing JNI methods (also has an init() function which calls main() in ardrone_testing_tool.c)
| + dronecontrol_ARDrone: Its header
| + vars.h: Some shared variables
|
+ Build:Contains the makefile
|
+ makefile: The makefile
Here's the makefile in ./src/DroneControl/Build/:
SDK_PATH:=$(shell pwd)/../../ARDroneLib
PC_TARGET=yes
USE_LINUX=yes
ifdef MYKONOS
include $(ARDRONE_CUSTOM_CONFIG)
include $(ARDRONE_BUILD_CONFIG)
else
include $(SDK_PATH)/Soft/Build/custom.makefile
include $(SDK_PATH)/Soft/Build/config.makefile
endif
ifeq "$(RELEASE_BUILD)" "yes"
ARDRONE_TARGET_DIR=$(shell pwd)/../../../
else
ARDRONE_TARGET_DIR=$(shell pwd)/../../../Debug
endif
TARGET=linux_sdk_demo
SRC_DIR:=$(shell pwd)/../Sources
# Define application source files
GENERIC_BINARIES_SOURCE_DIR:=$(SRC_DIR)
GENERIC_BINARIES_COMMON_SOURCE_FILES+= \
Navdata/navdata.c \
Video/video_stage.c
GENERIC_INCLUDES+= \
$(SRC_DIR) \
$(LIB_DIR) \
$(SDK_PATH)/Soft/Common \
$(SDK_PATH)/Soft/Lib
GENERIC_TARGET_BINARIES_PREFIX=
GENERIC_TARGET_BINARIES_DIR=$(ARDRONE_TARGET_DIR)
GENERIC_BINARIES_SOURCE_ENTRYPOINTS+= \
ardrone_testing_tool.c
GENERIC_INCLUDES:=$(addprefix -I,$(GENERIC_INCLUDES))
GENERIC_LIB_PATHS=-L$(GENERIC_TARGET_BINARIES_DIR)
GENERIC_LIBS=-lpc_ardrone -lgtk-x11-2.0 -lrt
SDK_FLAGS+="USE_APP=yes"
SDK_FLAGS+="APP_ID=linux_sdk_demo"
export GENERIC_CFLAGS
export GENERIC_LIBS
export GENERIC_LIB_PATHS
export GENERIC_INCLUDES
export GENERIC_BINARIES_SOURCE_DIR
export GENERIC_BINARIES_COMMON_SOURCE_FILES
export GENERIC_TARGET_BINARIES_PREFIX
export GENERIC_TARGET_BINARIES_DIR
export GENERIC_BINARIES_SOURCE_ENTRYPOINTS
export GENERIC_LIBRARY_SOURCE_DIR=$(GENERIC_BINARIES_SOURCE_DIR)
.PHONY: $(TARGET) build_libs
all: build_libs $(TARGET)
$(TARGET):
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
mv $(ARDRONE_TARGET_DIR)/ardrone_testing_tool $(TARGET)
mv $(TARGET) $(ARDRONE_TARGET_DIR)/
$(MAKECMDGOALS): build_libs
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
build_libs:
#$(MAKE) -C $(SDK_PATH)/Soft/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
But when I try to make this, the make command gives me following error:
Libs already extracted
Building target static
/bin/sh: 1: ./autoConf.bash: Permission denied
make[2]: *** [build] Error 126
Checking required Ubuntu packages ...
ok.
Building ARDroneTool/Lib
Building ARDroneTool/Lib
ld ardrone_testing_tool
/usr/bin/ld: cannot find -lswscale
/usr/bin/ld: cannot find -lavformat
/usr/bin/ld: cannot find -lavcodec
/usr/bin/ld: cannot find -lavutil
collect2: ld returned 1 exit status
make[3]: *** [/home/user/workspace/AutoFlight/lib/native/DroneControl/src/DroneControl/Build/../../..//ardrone_testing_tool] Error 1
make[2]: *** [all] Error 2
make[1]: *** [build_app] Error 2
make: *** [linux_sdk_demo] Error 2
I have not been able to figure out what -lwscale, -lavformat, etc. are. I have also tried the make command as su (mainly because that "Permission denied" error), and hope this is the right place to ask this.
So does anybody have suggestions on how to get this compiled into a dynamically linked library (.so file)? Any help would be highly appreciated!
UPDATE 1: The permission denied error is now solved (thanks #eyalm)
UPDATE 2: It works now. I've rewritten the makefile but I don't know what's different now that could affect ld's path.
autoConf.bash is probably not executable. Running with su will not help. try:
# chmod a+x autoConf.bash
> /usr/bin/ld: cannot find -lswscale
> /usr/bin/ld: cannot find -lavformat
> /usr/bin/ld: cannot find -lavcodec
> /usr/bin/ld: cannot find -lavutil
> collect2: ld returned 1 exit status
It could be that these dependencies (i.e., libswscale, libavformat, libavcodec,
and libavutil) are either not present on your system, or are present
in directories that are not part of ld's standard search path.
If the dependencies are absent, then you would need to install them. On Debian-derived systems you could use the apt-file command to find the package you would need to install. For example:
% apt-file -l find libswscale.a
libswscale-dev
% apt-file -l find libavutil.a
libavutil-dev
...etc...
If these libraries are already present on your system, but are in non-standard locations,
you could use ld's -L option to add the relevant directories to its search path. For example:
% ld ..other-options... -L SEARCHDIR1 -L SEARCHDIR2 ... -lswscale -lavutil ...etc...
Note that the -L SEARCHDIR options need to appear before the -l
LIB options.

Resources