Search code examples
makefilelinux-kernelautoconf

How to integrate autoconf into a kernel Makfile?


I have a kernel module project, and use autoconf to generate Makefile file inside the kernel module. And such autoconf usage breaks the kernel in tree source code build, because kernel Makefile doesn't support autoconf thus can't generate a configure file for the module. Is there a way to make kernel Makefile and autoconf compatible ? Thanks !


Solution

  • A trick I have used frequently in the past is to have two Makefiles - an automake generated one and a kernel one, and switch them around during "make".

    Here is an example:

    Makefile.am

    ## Process this file with automake to produce Makefile.in
    
    ## this is so that Automake includes the C compiling definitions, and
    ## includes the source files in the distribution.
    
    ## [@]kerneldir[@] is the kernel build directory.
    ## [@]kernelext[@] is the kernel module extension `ko`.
    ## [@]moduledir[@] is the module installation directory.
    ## [@]depmod[@] is the depmod program.
    
    EXTRA_PROGRAMS = automake_dummy
    automake_dummy_SOURCES = mymodule.c Makefile.kernel
    generated_sources =
    
    ## there is no *just* object file support in automake.  This is close enough
    module_DATA = mymodule.o
    export_objs = mymodule.o
    
    # where the kernel build is located
    KERNEL_LOCATION=@kerneldir@
    
    MYMODULE_TOP_SRCDIR = @abs_top_srcdir@
    MYMODULE_TOP_BUILDDIR = @abs_top_builddir@
    MYMODULE_BUILDDIR = @abs_builddir@
    
    # some magic for using linux kernel settings
    # when compiling module(s)
    MYMODULE_EXTRA_CFLAGS = -DEXPORT_SYMTAB $(DEFS) -I$(MYMODULE_BUILDDIR) \
        -I$(MYMODULE_TOP_BUILDDIR) -I$(MYMODULE_TOP_SRCDIR)/include
    export MYMODULE_EXTRA_CFLAGS KERNEL_LOCATION module_DATA export_objs
    
    .PHONY: FORCE
    
    $(automake_dummy_SOURCES): FORCE
        @test "$(srcdir)" == "." || test -e "$@" || ln -vs "$(srcdir)/$@" .
    
    # Add FORCE in case the kernel has changed.
    $(module_DATA): $(generated_sources) $(automake_dummy_SOURCES) FORCE
        mv Makefile Makefile.automake
        cp Makefile.kernel Makefile
        $(MAKE) -C $(KERNEL_LOCATION) SUBDIRS=$(MYMODULE_BUILDDIR) M=$(MYMODULE_BUILDDIR) modules
        mv Makefile.automake Makefile
    
    install-moduleDATA: $(module_DATA)
        $(mkinstalldirs) $(DESTDIR)$(moduledir)
        @list='$(module_DATA:.o=.@kernelext@)'; for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          f="`echo $$p | sed -e 's|^.*/||'`"; \
          echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(moduledir)/$$f"; \
          $(INSTALL_DATA) $$d$$p $(DESTDIR)$(moduledir)/$$f; \
        done
    
    uninstall-moduleDATA:
        @list='$(module_DATA:.o=.@kernelext@)'; for p in $$list; do \
          f="`echo $$p | sed -e 's|^.*/||'`"; \
          echo " rm -f $(DESTDIR)$(moduledir)/$$f"; \
          rm -f $(DESTDIR)$(moduledir)/$$f; \
        done
    
    if SANDBOXED
    else
    install-data-local: install-moduleDATA
        -@depmod@ -a
    endif
    
    MOSTLYCLEANFILES = $(module_DATA) $(module_DATA:.o=.@kernelext@) \
        Modules.symvers Module.symvers Module.markers modules.order
    CLEANFILES = $(module_DATA:.o=.mod.c) $(generated_sources)
    
    clean-local:
        -rm -f .*.cmd .*.flags
        -rm -rf .tmp_versions
        -if test "$(srcdir)" != "."; then \
            for f in $(automake_dummy_SOURCES); do \
                if test "$$f" -ef "$(srcdir)/$$f"; then \
                    rm -f "$$f"; \
                fi; \
            done; \
        fi
    
    FORCE:
    

    It uses some automake substitutions:

    • kerneldir is the kernel build directory, e.g. /lib/modules/${version}/build
    • kernelext is the module extension, which should be ko.
    • moduledir is the module installation directory, e.g /lib/modules/${version}/extra
    • depmod is the depmod program, e.g. set by AC_PATH_PROG(depmod, depmod, /sbin/depmod, $PATH:/sbin)

    (You can replace all instances of @kernelext@ in Makefile.am with ko if you want.)

    The automake_dummy_SOURCES, module_DATA, export_objs, and MYMODULE_EXTRA_CFLAGS variables can be tweaked as necessary.

    Note how the rule for target $(module_DATA) copies the Makefiles around before and after invoking the kernel's Makefile. The original (automake-generated) Makefile is renamed to Makefile.automake, and the other Makefile (Makefile.kernel) is copied in its place. When the sub-make completes without error, the Makefile.automake is moved back to Makefile. This doesn't work when the sub-make does not complete successfully, but that is dealt with by the other Makefile.

    Makefile.kernel

    EXTRA_CFLAGS += $(MYMODULE_EXTRA_CFLAGS)
    
    obj-m := $(module_DATA)
    ifeq ($(VERSION).$(PATCHLEVEL), 2.4)
    export-objs := $(export_objs)
    endif
    
    all mostlyclean clean maintainer-clean distclean:
        $(warning **************************************************)
        $(warning *** Makefile trick not undone, trying to recover *)
        $(warning **************************************************)
        mv Makefile.automake Makefile
        $(MAKE) $@
    
    # The following is needed for 2.5 kernels and also let's the makefile work
    # when things get screwed.
    ifneq (,$(wildcard $(KERNEL_LOCATION)/Rules.make))
    include $(KERNEL_LOCATION)/Rules.make
    endif
    

    This gets renamed to Makefile by the automake-generated Makefile rules during the kernel sub-make, and renamed back to Makefile.kernel afterwards.

    The all mostlyclean clean maintainer-clean distclean: rule is for recovery when the previous make ended in an error, leaving the Makefile.kernel in place of Makefile. It moves the original automake-generated Makefile (now in Makefile.automake) back to Makefile and runs make again automatically.