One of the first concepts you learn when building open source software is the
existance of -devel packages. You have package
foo to provide some
foo-devel for building other programs with the
functionality. The kernel follows this pattern in its own special kernel
way for building external modules.
First a little bit about how a module is built. A module is really just a
fancy ELF file compiled and linked with the right options. It has
.data, and other kernel specific sections.
Some parts of the build environment
also get embedded in modules. Modules are also just a socially acceptable way
to run arbitrary code in kernel mode. Modules are loaded via
a system call (either by fd or an mmaped address). The individual sections
.data etc.) get placed based on the ELF header. The kernel
does some basic checks on the ELF header to make sure it’s not complete
crap (loading for an incorrect arch etc.) but can also do some more complicated
verification. Each module gets a version magic
embedded in the ELF file. This needs to match the running kernel but can be
overridden with a force option. There’s also
CONFIG_MODVERSIONS which will
generate a crc over functions and exported symbols to make sure they match
the kernel that was built. If the CRC in the module and kernel don’t match,
the module loading will fail.
Now consider an out of tree module. The upstream Linux kernel doesn’t provide an ABI guarantee. In order to build an external module, you need to use the same tree that was used to build the kernel. You might be able to get away with using a different base but it’s not guaranteed to work. These requirements are well documented. Actually packaging the entire build tree would be large and unecessary. Fedora ends up packaging a subset of the build tree:
- Kconfigs and Makefiles
- header files, both generic and architecture specific
- Some userspace binaries built at
- The kernel symbol map
- A few linker files for some arches
Annoyingly, because each distribution does something different, all of this has to be done manually. This also means we find bugs when there are new dependencies that need to be packaged. I really wish we could just get away with building the module dependencies at runtime but doesn’t work with the requirements.