clangDriver is the library implementing the compiler driver for Clang. It utilitizes LLVMOption to process command line options. As options are processed when required, as opposed to use a large switch, Clang gets the ability to detect unused options straightforwardly.
When an option is checked with APIs such as hasArg and
getLastArg, its "claimed" bit is set.
1 | template<typename ...OptSpecifiers> |
After all options are processed, Clang reports a
-Wunused-command-line-argument diagnostic for each
unclaimed option. There are multiple possible messages, but
argument unused during compilation is the most common one.
1 | % clang -c -ftime-trace a.s |
There are many heuristics to enhance the desirability of
-Wunused-command-line-argument, which can be rather
subjective. For instance, options that are relevant only during
compilation do not result in -Wunused-command-line-argument
diagnostics when linking is performed. This is necessary to support
linking actions that utilitize CFLAGS or
CXXFLAGS.
1 | % clang -faddrsig -fpic -march=generic a.o |
Default options
There is a tension between
-Wunused-command-line-argument and default options. Let's
consider a scenario where we specify
--rtlib=compiler-rt --unwindlib=libunwind in
CFLAGS and CXXFLAGS to utilize compiler-rt and
LLVM libunwind. ClangDriver claims --rtlib and
--unwindlib in the following code snippet:
1 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { |
However, if a build target employs -nostdlib or
-nodefaultlibs, options such as --rtlib,
--unwindlib, and many other linker options (e.g.
-static-libstdc++ and -pthread) will not be
claimed, resulting in unused argument diagnostics:
1 | % clang --rtlib=compiler-rt --unwindlib=libunwind -stdlib=libstdc++ -static-libstdc++ -pthread -nostdlib a.o |
While some options like -stdlib= do not trigger a
diagnostic, this seems more like a happenstance rather than a deliberate
design choice.
To suppress the diagnostics, we can utilitize --start-no-unused-arguments
and --end-no-unused-arguments (Clang 14) like the
following:
1 | % clang --start-no-unused-arguments --rtlib=compiler-rt --unwindlib=libunwind -stdlib=libstdc++ -static-libstdc++ -pthread --end-no-unused-arguments -nostdlib a.o |
There is also a heavy hammer -Qunused-arguments to
suppress -Wunused-command-line-argument diagnostics
regardless of options' positions:
1 | % clang -Qunused-arguments --rtlib=compiler-rt --unwindlib=libunwind -stdlib=libstdc++ -static-libstdc++ -pthread -nostdlib a.o |
Conveniently, options specified in a Clang configuration file are automatically claimed.
1 | cat >a.cfg <<e |
In the last command, I specify -no-canonical-prefixes so
that clang will find dirname(clang)/clang.cfg, otherwise
Clang would try to find
dirname(realname(clang))/clang.cfg.