Resolving common errors when developing with the DDK

Table of contents

Generic steps for resolving missing header

Missing include/linux/compiler-version.h

Missing include/linux/kconfig.h

Incorrect header is included

modpost symbol undefined

Use out instead of outs

Missing Abseil Python

Appendix

<source>.c:<line>:<col>: fatal error: '<header>.h file not found

Resolving errors about missing headers can be tough. In general, debugging these errors involve the following steps:

  1. Check where the requested header is
  2. Check all of the include directories of the DDK module
  3. Add the requested header and necessary include directories to the module

Find a certain header with the given name

This step is straightforward with a find(1) command. Example: if the error is

#include <linux/i2c.h>
         ^~~~~~~~~~~~~

Then you can look for it with

$ find . -path "*/linux/i2c.h"
./common/include/uapi/linux/i2c.h
[... other results]

The above search result indicates that one expected search directory for linux/i2c.h is common/include/uapi.

NOTE: There might be multiple matches. However, usually you only want to include a specific one.

Step 1: Check all of the include directories of the DDK module

There are multiple ways to do this. You may look at the generated Kbuild file.

Example: If you are compiling //common-modules/virtual-device:x86_64/goldfish_drivers/goldfish_sync, you may look at:

$ grep -rn 'goldfish_sync' bazel-bin/common-modules/virtual-device/
[...]
bazel-bin/common-modules/virtual-device/goldfish_drivers/goldfish_sync_makefiles/makefiles/goldfish_drivers/Kbuild:2:obj-m += goldfish_sync.o
[...]

$ grep 'ccflags-y' bazel-bin/common-modules/virtual-device/x86_64/goldfish_drivers/goldfish_sync_makefiles/makefiles/goldfish_drivers/Kbuild
ccflags-y += '-I$(srctree)/$(src)/../../../common/include/uapi'
[... other ccflags-y]

The expression $(srctree)/$(src) evaluates to <package>/<dirname of output module>.

  • Package is common-modules/virtual-device.
  • Output module is the out attribute of the ddk_module target, which defaults to <target name>.ko. In this case, it is goldfish_drivers/goldfish_sync.ko.

Hence $(srctree)/$(src) is common-modules/virtual-device/goldfish_drivers in this case.

Hence, the above include directory points to

<repository_root>/common-modules/virtual-device/goldfish_drivers/../../../common/include/uapi

which is just

<repository_root>/common/include/uapi

Check if the expected search directories of the missing header found in the previous step is in these -I options.

Another way to determine is to use the --debug_annotate_scripts option. Example:

$ tools/bazel build \
  //common-modules/virtual-device:x86_64/goldfish_drivers/goldfish_sync \
  --debug_annotate_scripts > /tmp/out.log 2>&1
$ grep 'goldfish_sync.o' /tmp/out.log
[clang command]
[... other lines]

Examine the command and look for -I options, and compare it with the expected search directories found in step 1.

Step 2: Look for or define the appropriate target with the headers

See instructions to look for a ddk_headers target or filegroup target under the package with the requested header, or look for exports_files declarations manually.

If there's none, define one.

Step 3: Add to deps of the ddk_module target

See instructions for ddk_module.

<built-in>:1:10: fatal error: '<path>/include/linux/compiler-version.h' file not found

NOTE: This error is about include/linux/compiler-version.h or include/linux/kconfig.h.

If you see the following error:

<built-in>:1:10: fatal error: '<path>/include/linux/compiler-version.h' file not found
#include "<path>/include/linux/compiler-version.h"
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[3]: *** [<path>/scripts/Makefile.build:286: <module>.o] Error 1

The reason is that a module implicitly includes this header (and include/linux/kconfig.h) from the kernel source tree. This is usually listed in LINUXINCLUDE in the ${KERNEL_DIR}.

To resolve this:

  1. Ensure that the ${KERNEL_DIR} has a ddk_headers that exports these headers, or a filegroup target or an exports_files declaration that exports these files.

    • If ${KERNEL_DIR} points to the Android Common Kernel source tree, there should be a ddk_headers target named all_headers. There may be other smaller targets to use. Check the BUILD.bazel file under the ${KERNEL_DIR} for the exact declarations.
    • Hint: you may also search all valid ddk_headers target with a query command; see instructions.
    • If ${KERNEL_DIR} points to a custom kernel source tree that does not track the Android Common Kernel source tree, use the bazel query command above to look for a suitable ddk_headers or filegroup target, or manually look for exports_files declarations . If there's none, you can define one. Example:
      ddk_headers(
          name = "linuxinclude",
          hdrs = [
              "include/linux/compiler-version.h",
              "include/linux/kconfig.h",
          ],
      )
      
  2. Add the target found or defined in step 1 to the deps attribute of the ddk_modules target. For example, to add "//common:all_headers" to deps:

    ddk_module(
        name = "foo",
        out = "foo.ko",
        deps = ["//common:all_headers"],
    )
    

    For details, see ddk_module.

Incorrect header is included

Because include directories are searched from in a certain order, sometimes an incorrect header include/header.h is included if multiple include directories of a module module.ko includes include/header.h. If this is the case, you may see errors like:

  • use of undeclared identifier
  • no member named '<member>' in 'struct <struct>'
  • incomplete definition of type 'struct <struct>'
  • ... and other weird errors unlisted here.

This is especially hard to debug if you focus on one of the include/header.h that is not included, ignoring the one that is actually included with incompatible definitions.

To resolve such error, the best practice is to rename the headers to avoid confusion for both the build system and humans.

But if you would like to keep the names, go through generic steps for resolving missing header, but focus on the ordering of -I options in the clang command or in ccflags-y. The first directory with include/header.h is the one used. You can confirm this by putting an #error directive at the top of the suspicious include/header.h and recompiling, for example.

Once the correct ordering is determined, order the dependencies of the ddk_modules target to ensure that the correct include/header.h is used. Use the # do not sort magic line to prevent buildifier from sorting the list.

For details about ordering of include directories, see documentations of all rules and click ddk_module for details.

ERROR: modpost: “foo” [.../mod_using_foo.ko] undefined!

See link for help on resolving this error for external modules in general.

Error: kernel_module() got multiple values for parameter ‘outs’

You might be using outs instead of out. For example:

# Correct:
ddk_module(
    name = "foo",
    out = "foo.ko",
)

# Incorrect:
ddk_module(
    name = "foo",
    outs = ["foo.ko"], # WRONG! DO NOT USE
)

Missing Abseil Python

If you encounter the following error:

ERROR: /path/to/WORKSPACE:17:23: fetching local_repository rule //external:io_abseil_py: java.io.IOException: The repository's path is "external/python/absl-py" (absolute: ...) but it does not exist or is not a directory.

It is because you did not check out the abseil project in your repo manifest. The Python script that generates Makefile / Kbuild relies on abseil. Check it out by adding an entry in your repo manifest, e.g.

<project path="external/python/absl-py" name="platform/external/python/absl-py" />

Then running repo sync.

See change 2127786 for an example.

Refer to repo Manifest Format if you have multiple remotes.

Appendix

Query appropriate ddk_headers targets to use

Example: The following query shows all ddk_headers targets in //common that includes common/include/linux/compiler-version.h, and visible to the target //common-modules/virtual-device:x86_64/goldfish_drivers/goldfish_sync.

$ tools/bazel query \
  'visible(//common-modules/virtual-device:x86_64/goldfish_drivers/goldfish_sync,
           kind(ddk_headers,
                rdeps(//common:*,
                      //common:include/linux/compiler-version.h)))'

See Bazel query language.