conditional include of sources in kbuild - linux-kernel

Say there is a source file a.c with some function func_a. I would like to call func_a based on some feature define and would also like a.c to be included in the module based on ideally same feature define.
so in my module source that is always present (say main.c) I could have something like
#ifdef FEATURE_A
func_a();
#endif
and in the kbuild for the module something like
obj-$(CONFIG_SAMPLE) += sample.o
sample-objs := main.o utils.o
only if FEATURE_A is defined, include a.c into the sample module
???
But this may not make sense since one is a pre-processor directive and the other a compiler/linker/build directive. Maybe the other way where the pre-processor directive uses some flag defined by the kbuild makes more sense? Is there some way to accomplish this?
Thanks.

I will answer your question by pointing out how sysctl support is conditionally included in the NFS module (I'm sure there are other examples, but this is what I'm familiar with):
include/linux/nfs_fs.h
fs/nfs/Makefile
fs/nfs/super.c
The kernel config system maintains a file "include/linux/autoconf.h" that exposes your configuration options as C preprocessor macros. So the files listed above compile differently depending on whether you configured sysctl support.
If sysctl support is enabled: The header "include/linux/nfs_fs.h" checks the macro CONFIG_SYSCTL and declares the C function nfs_register_sysctl(). This function is called in "fs/nfs/super.c". The Makefile (seeing nfs-y += sysctl.o) directs the build system to compile in the file "fs/nfs/sysctl.c" into the module, which defines the function nfs_register_sysctl().
If sysctl support is disabled: The header "include/linux/nfs_fs.h" checks the macro CONFIG_SYSCTL and declares the preprocessor macro nfs_register_sysctl() to be 0. This macro is used in "fs/nfs/super.c" to bypass some (dead) error-handling code. The Makefile (seeing nfs-n += sysctl.o) does not compile or link "fs/nfs/sysctl.c".

Please read 3.7 Compilation flags.
As I understand it, there's loosless reletionship between Kconfig option and preprocessed macros, passed while compiling. It's up to kernel developer to define which preprocessor flags to use during compilation.
For example in net/rds/Makefile:
ccflags-$(CONFIG_RDS_DEBUG) := -DDEBUG
Here preprocessor flag DEBUG will be passed if you kernel is configured with Kconfig option CONFIG_RDS_DEBUG.

Related

Passing extra compilation flags to debug build in bitbake recipe

As Bitbake builds -dev and -debug for recipes is it possible for defining compilation definitions specific to debug build for a particular recipe. Lets say I have some source code under DEBUG_INFO for some recipe i.e.,
#ifdef DEBUG_INFO
........... do something
#endif /* DEBUG_INFO */
and uses cmake in bitbake environment.
I want this flag be enabled for the debug binaries generated in the .debug folder. Is this possible?
If I use EXTRA_OECMAKE = "-DDEBUG_INFO" it gets enabled to both dev and debug builds.
No, it is not possible. All packages of a recipe are built in one go, they're just the same files but split somehow.
The only difference is with "special flavors" of a recipe (native, nativesdk, target, multilib, toolchain-specific recipes, etc...), in that case, you can have different flags but still, all the packages resulting from the build of this "flavor" will be built with the same flag.
If you want to build another variant of a package where a certain CMake flag is set in the compilation, you can create a variant of the recipe. If the main recipe is named my-app_git.bb you can create another recipe file named my-app-tweak_git.bb and a common base, my-app.inc. In the bb files, include the inc file:
require my-app.inc
Move most of what's now in my-app_git.bb to my_app.inc, e.g. SRC_URI, but define different contents for EXTRA_OECMAKE in the .bb files.
Now you will have to decide which one of my-app and my-app-tweak goes into the image by specifying either my-app or my-app-tweak in an IMAGE_INSTALL definition.
This is not exactly what you asked for, but as has been stated by qschulz, you cannot change the contents of the -dev and -dbg sub-packages.
Also note that dbg and dev can be considered reserved words for variants of the package name, so if you want to use something other than tweak, as in my example, you cannot use any of them.

Why does cmake always use `-isystem` on imported interface target?

I'm trying to write a CMakeLists.txt to compile my Arduino-Projects to get to know cmake better.
I defined the Arduino-Core library as an imported interface and try to link my own target against it. The problem is, that, when calling make the avr-gcc is provided with the specified include-paths via -isystem instead of -I. This results in several errors.
CMakeLists.txt (minimal-version to reproduce the problem)
cmake_minimum_required(VERSION 3.1)
set(ARDUINO_DIR "/opt/arduino/arduino-1.8.13")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_COMPILER ${ARDUINO_DIR}/hardware/tools/avr/bin/avr-gcc)
set(CMAKE_CXX_COMPILER ${ARDUINO_DIR}/hardware/tools/avr/bin/avr-g++)
set(CMAKE_SYSTEM_NAME NONE)
set(CMAKE_SYSTEM_PROCESSOR NONE)
add_library(Arduino::Core INTERFACE IMPORTED)
target_include_directories(Arduino::Core INTERFACE
"${ARDUINO_DIR}/hardware/arduino/avr/cores/arduino/"
"${ARDUINO_DIR}/hardware/arduino/avr/variants/eightanaloginputs/"
)
file(GLOB_RECURSE ARDUINO_CORE_SRC "${ARDUINO_DIR}/hardware/arduino/avr/cores/arduino/*.c[p]*")
file(GLOB_RECURSE ARDUINO_CORE_ASM "${ARDUINO_DIR}/hardware/arduino/avr/cores/arduino/*.S")
target_sources(Arduino::Core INTERFACE ${ARDUINO_CORE_SRC} ${ARDUINO_CORE_ASM})
project(Blinky)
set(${PROJECT_NAME}_SRC
src/Blink.cpp
)
add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRC})
target_link_libraries(${PROJECT_NAME} Arduino::Core)
Here is my Blink.cpp:
#include <Arduino.h>
void setup()
{
pinMode(13,OUTPUT);
}
void loop()
{
digitalWrite(13,HIGH);
delay(1000);
digitalWrite(13,LOW);
delay(1000);
}
make --trace gives me the following output:
[ 5%] Building CXX object CMakeFiles/Blinky.dir/src/Blink.cpp.obj
/opt/arduino/arduino-1.8.13/hardware/tools/avr/bin/avr-g++ -isystem /opt/arduino/arduino-1.8.13/hardware/arduino/avr/cores/arduino -isystem /opt/arduino/arduino-1.8.13/hardware/arduino/avr/variants/eightanaloginputs -std=gnu++11 -o CMakeFiles/Blinky.dir/src/Blink.cpp.obj -c /tmp/so/src/Blink.cpp
As you can see, linking against the imported target includes the dependencies with -isystem even though I haven't declared SYSTEM anywhere? How can I prevent that?!
Is it, because it is an INTERFACE IMPORTED target?
I tried taget_include_directories(Arduino::Core PRIVATE ${my_include_dirs}) but obviously that is not allowed for INTERFACE-Targets.
Thanks in advance for every hint.
P.S. please note, that I'm aware, that this would not compile my arduino-code. This is just a mcve to show you my problem.
edit
I'm using Arduino-SDK 1.8.13 and cmake 3.18.2
It is because it is an imported target.
From the CMake docs on buildsystems at the section for "include directories and usage requirements" (one of the last paragraphs in the section):
When the INTERFACE_INCLUDE_DIRECTORIES of an imported target is consumed, the entries in the property are treated as SYSTEM include directories, as if they were listed in the INTERFACE_SYSTEM_INCLUDE_DIRECTORIES of the dependency. This can result in omission of compiler warnings for headers found in those directories. This behavior for Imported Targets may be controlled by setting the NO_SYSTEM_FROM_IMPORTED target property on the consumers of imported targets, or by setting the IMPORTED_NO_SYSTEM target property on the imported targets themselves.
See the docs for include_directories and target_include_directories for other documentation on SYSTEM.
As stated in the docs, you can solve this by modifying consumers of the imported target like set_target_property(${PROJECT_NAME} PROPERTIES NO_SYSTEM_FROM_IMPORTED TRUE) or set_property(TARGET ${PROJECT_NAME} PROPERTY NO_SYSTEM_FROM_IMPORTED TRUE).
But there's another option not mentioned in the docs I quoted that I think may be better: In the docs for NO_SYSTEM_FROM_IMPORTED, it says:
See the IMPORTED_NO_SYSTEM target property to set this behavior on the target providing the include directories rather than consuming them.
I think it's better because NO_SYSTEM_FROM_IMPORTED will change the "system-ness" of all imported targets that the consumer links to, which may not be desirable. Perhaps a similar argument could be made against IMPORTED_NO_SYSTEM, but I personally can't think of a good backing for such an argument at the moment.

How does gcc make use of __builtin_<target>_func functions during compilation

When compiling gcc for a aarch64 target, I see several __builtin_aarch64_##func## functions in the include/arm_neon.h file in the build directory.
For example,
__extension__ extern __inline float64_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vmulxd_f64 (float64_t __a, float64_t __b)
{
return __builtin_aarch64_fmulxdf (__a, __b);
}
Where is the definition of __builtin_aarch64_fmulxdf() ? I cannot figure out how these builtins connect to the target specific md files.
Does the above mean the only way to generate this instruction is via an explicit call to this GCC extension ?
These __builtin_aarch64_* functions are AArch64-specific GCC builtins. They are primarily used to implement the intrinsics in arm_neon.h.
GCC defines them internally in its code, not in some header file. They are not documented anywhere as they can be changed from release to release and users should not be relying on their behaviour.
The Advanced SIMD intrinsics in arm_neon.h are documented and defined in ACLE (https://developer.arm.com/technologies/neon/intrinsics for example) so you should be using those.
The target-specific builtins themselves are just an implementation detail in this context.

How do I specify header files for make headers_install in an out-of-tree kernel module?

I couldn't find any information regarding this in kbuild modules documentation and only an oblique reference (suggesting that it's possible) in the headers_install documentation.
The "make headers_install" command can be run in the top level directory of the
kernel source code (or using a standard out-of-tree build).
I have an out-of-tree kernel module with an associated header file (I have #defines for an IOCTL), and I want to provide that header file as part of the module installation. It seems like the in-tree way for kernel modules to provide header files (for userspace use) is to place them in include/linux/. What do I have to do for this to work for out-of-tree?
Ok, this seems to be another case where I didn't read all the manuals... the manual needed is the makefiles documentation for kbuild...
The kernel includes a set of headers that is exported to userspace.
Many headers can be exported as-is but other headers require a
minimal pre-processing before they are ready for user-space.
The pre-processing does:
drop kernel-specific annotations
drop include of compiler.h
drop all sections that are kernel internal (guarded by ifdef KERNEL)
Each relevant directory contains a file name "Kbuild" which specifies the
headers to be exported.
See subsequent chapter for the syntax of the Kbuild file.
--- 7.1 header-y
header-y specifies header files to be exported.
Example:
#include/linux/Kbuild
header-y += usb/
header-y += aio_abi.h
This seems to be deprecated. The headers_install target does not exist for out-of-tree module builds (see this answer).

Linking kernel module with a static lib

I'm trying to link my kernel module with an external static lib, like this:
obj-m += my_prog.o
my_prog-objs := some/path/lib.a
# all the standard targets...
For some reasone, the above Makefile doesn't compile my_prog.c at all, and the resulting module doesn't contain its code. Certainly, if I remove my_prog-objs line, my_prog.c gets compiled.
What's wrong with such an approach in a Makefile?
You must create a synthetic name as well as the source file and it's object name. You can not use my_prog.o directly as there are rules to make it from source. Here is an sample,
obj-m += full.o
full-src := my_prog.c
full-objs := $(full-src:.c=.o) lib.o # yes, make it an object.
Libraries are only supported from some special directories. Your object should be named lib.o_shipped and placed in the same directory. So, you need to take the external library and provide it locally as a shipped version. You need two object files; one is your compiled 'C' code/driver and the other is it linked together with the library.
The above is relevant to 2.6.36 kbuild infra-structure. The current documentation is in modules.rst section 3.3 Binary Blobs. I think the technique above will still work for libraries as opposed to just objects.
When you create the my_prog-objs list, you tell kbuild to use only the object files in that list. kbuild will no longer compile my_prog.c, and including my_prog.o in my_prog-objs results in a circular dependency. Instead, you need to create a unique obj-m and include both my_prog.o and /path/lib.a in its objs list. For example:
obj-m += foo.o
foo-objs += my_prog.o /path/lib.a
Took me about 2 hours to figure out why my module was doing nothing!
You're overriding the default my_prog-objs, which is just my_prog.o. Instead of replacing the contents with the library, add the library to the default:
my_prog-objs := my_prog.o some/path/lib.a
Hopefully you're not trying to link against a general userspace library... that won't work at all in kernelspace.

Resources