Home / Alt manpages / modularize-20(1)

  • modularize-20(1)
  • User command
  • linux

Build and Check a Clang Module Map with modularize-20

Ubuntu's modularize-20 checks a batch of C or C++ headers for modularisation problems and can draft a starting module.modulemap for you. The command does not rewrite your headers. Allow 15 to 30 minutes for a small header set, plus time to fix any diagnostics it finds.

This guide uses clang-tools-20 version 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139 and the installed executable reports LLVM 20.1.8. You need readable headers, a shell, and compiler-style arguments that let Clang parse them. The checks are normally unprivileged; use sudo only to read files that your account genuinely cannot access.

1. Make a header list

Create a plain text file with one header per line. Blank lines and lines beginning with # are ignored. A header can be followed by a colon and space-separated dependency names on the same line. Relative names are resolved relative to the list file unless you supply --prefix.

mkdir -p /tmp/modularize-demo/include
cat > /tmp/modularize-demo/include/widget.h <<'EOF'
#ifndef WIDGET_H
#define WIDGET_H
int widget_value;
#endif
EOF
cat > /tmp/modularize-demo/headers.list <<'EOF'
include/widget.h
EOF

The commands above create disposable test material. For a real project, keep the list beside the source tree or in a build directory that is easy to review.

2. Check that headers compile on their own

Run the list with the front-end arguments after it. The -x c++ argument tells Clang how to interpret the header; the tool otherwise assumes C++ for .h files. Pass -I for directories needed while checking includes.

modularize-20 /tmp/modularize-demo/headers.list \
  -x c++ -I /tmp/modularize-demo/include

A clean run is quiet and returns status zero. Check the status immediately if you are testing a script:

printf '%s\n' "$?"
0

Checkpoint

If the command prints a compiler diagnostic, fix the include path, language mode, macro definitions, or header itself before moving on. Do not hide a real parse error with --no-coverage-check; that option controls a different check.

3. Separate good and problem files

For a larger list, add --display-file-lists. The tool prints headers with no detected errors, headers with possible errors, and a combined list. In the combined list, a leading # marks a problem file.

modularize-20 --display-file-lists \
  /tmp/modularize-demo/headers.list \
  -x c++ -I /tmp/modularize-demo/include

This is a useful triage pass, not a proof that a header is safe in every build configuration. Header behaviour can depend on macros, target options and include order. Preserve the reported list, then repeat the check with the same front-end arguments used by your project.

4. Generate a module map

Use --module-map-path when you want the tool to act as a module-map assistant. It skips the normal modularisation checks and writes a generated file from the header list.

modularize-20 \
  --module-map-path=/tmp/modularize-demo/module.modulemap \
  --root-module=demo \
  /tmp/modularize-demo/headers.list \
  -x c++ -I /tmp/modularize-demo/include

sed -n '1,120p' /tmp/modularize-demo/module.modulemap

For the example, expect a module named demo containing a submodule for the listed header and an export * line. The generated file is a starting point: inspect its paths, module names, visibility and dependencies before putting it into a build.

Warning

--module-map-path overwrites the named output. Choose a new path while experimenting, or make a backup first:

cp --preserve=all /path/to/module.modulemap /path/to/module.modulemap.bak
modularize-20 --module-map-path=/path/to/module.modulemap /path/to/headers.list \
  -x c++

If the generated result is wrong, restore the backup with mv. Do not delete the backup until the replacement has been reviewed.

5. Check coverage when a module map already exists

If the header list contains a module map, the normal run performs a coverage check using the include paths supplied with -I. To run only that part, use --coverage-check-only:

modularize-20 --coverage-check-only \
  /path/to/headers.list -I /path/to/include -x c++

Use --no-coverage-check only when you deliberately want to skip coverage. These switches do not repair a module map and do not change compiler include paths.

6. Diagnose the common traps

  • Missing header. Usually means the list path or -I path is wrong. Test the exact file with test -r /path/to/header.h before changing the module map.
  • Works from one directory, fails from another. A list entry with a relative path can break after a script changes directory. Use absolute names or keep the list and its relative headers in a stable layout.
  • Wrong language mode. Headers written in C need -x c; headers using project macros may need matching -DNAME=value arguments. Copy the relevant arguments from the real compile command.
  • Zero exit status is not a guarantee. It means this invocation found no detected problem, not that every target platform, macro combination or downstream build rule is safe.

Done means

  • Header list is right. It contains the intended files and dependencies.
  • Check passes. It ran clean with the project's language, include and macro arguments.
  • Problem files reviewed. Anything --display-file-lists flagged has been looked at, not ignored.
  • Module map checked. It was generated to a reviewed path and its contents were checked manually.
  • Backup taken. Any existing module map was backed up before an intentional overwrite.