wandres.dev
COMPILAR (KBUILD) · Imagen, módulos, obj-m

Kbuild por dentro: obj-y y obj-m

Cómo funcionan los Makefiles del kernel: la variable obj-, cómo se añade un archivo a la compilación, y por qué el sistema de build del kernel es distinto a cualquier otro.

⏱ 11 min

Los Makefiles del kernel no se parecen a los normales (nivel 18 de C23): son declarativos y minimalistas gracias a Kbuild, que hace el trabajo pesado. Entender la variable obj- y cómo se ensamblan es lo que te deja añadir código al kernel de verdad.

🎯 Al terminar esta lección sabrás
  • La variable obj-y / obj-m.
  • Añadir un archivo a la compilación.
  • Compilar en varios archivos y subdirectorios.
  • Por qué los Makefiles del kernel son tan cortos.

La variable obj-

Un Makefile del kernel casi no tiene recetas: solo declara qué objetos construir, y Kbuild sabe cómo. La variable clave es obj-:

obj-y  += central.o        # SIEMPRE dentro del kernel
obj-m  += extra.o          # como MÓDULO
obj-$(CONFIG_MI_DRIVER) += midriver.o   # según el .config (y/m/n)
  • obj-y → se compila dentro de la imagen del kernel.
  • obj-m → se compila como módulo (.ko).
  • obj-$(CONFIG_X) → el truco del nivel 4.2: la config decide.

Kbuild recoge todos los obj-y de todos los directorios, los compila y los enlaza en el kernel; los obj-m los convierte en módulos. Tú solo dices qué, nunca cómo.

Un módulo de varios archivos

Si tu módulo se compone de varios .c, declaras el módulo y sus partes:

obj-m += midriver.o
midriver-y := main.o helpers.o interrupt.o   # midriver.ko = estos tres

Kbuild compila main.c, helpers.c e interrupt.c y los enlaza en midriver.ko. El nombre del módulo (midriver) no puede coincidir con ninguno de sus archivos fuente.

Subdirectorios

Para descender a un subdirectorio, se añade con obj-y apuntando al directorio (con barra):

obj-$(CONFIG_MI_SUBSISTEMA) += misubsistema/   # entra en ese directorio

Kbuild entra y procesa el Makefile de allí. Así se construye el árbol entero: cada directorio delega en sus subdirectorios, de arriba abajo.

Kbuild: declaras qué, no cómo

La belleza de Kbuild es que invierte la carga respecto a un Makefile normal. En un Makefile clásico (nivel 18) escribes las reglas: cómo compilar cada .o, con qué flags, en qué orden. En Kbuild, todo eso —los cientos de flags correctos del kernel, las dependencias, el orden, la generación de módulos— lo sabe el sistema. Tú solo declaras obj-y += archivo.o. Esto es lo que permite que un kernel de 30 millones de líneas, con miles de Makefiles, sea manejable: cada uno es una lista corta de “qué construir aquí”, y Kbuild orquesta el resto de forma uniforme. Es también por qué tu módulo necesita el andamiaje de Kbuild (el M= del nivel 5.1) y no un gcc suelto: sin Kbuild no tienes los cientos de flags, defines y reglas que hacen que tu .o sea compatible con el kernel. Declarar en vez de imperar es lo que domestica la complejidad.

⚔️ Ensambla un build
  1. Abre varios Makefile de drivers/ y localiza las líneas obj-$(CONFIG_...).
  2. Escribe un Makefile de módulo con tres archivos fuente usando midriver-y :=.
  3. Encuentra un Makefile que descienda a un subdirectorio con obj-y += dir/.
  4. Explica por qué tu módulo no se compila con un gcc normal.