[llvm-bugs] [Bug 49836] New: "fatal error: cannot open file" with relative -I paths and compile commands with different working directories
via llvm-bugs
llvm-bugs at lists.llvm.org
Sun Apr 4 09:16:21 PDT 2021
https://bugs.llvm.org/show_bug.cgi?id=49836
Bug ID: 49836
Summary: "fatal error: cannot open file" with relative -I paths
and compile commands with different working
directories
Product: clang
Version: trunk
Hardware: PC
OS: Linux
Status: NEW
Severity: normal
Priority: P
Component: Tooling
Assignee: unassignedclangbugs at nondot.org
Reporter: matt at correctcomputation.com
CC: llvm-bugs at lists.llvm.org
Created attachment 24718
--> https://bugs.llvm.org/attachment.cgi?id=24718&action=edit
Test case
When a LibTooling-based tool is run on several source files whose compile
commands (from the compilation database) have different working directories and
have -I options with relative paths, the tool may incorrectly report "fatal
error: cannot open file '...': No such file or directory" when processing an
`#include` directive.
See the attached test case, which uses clang-check as a simple example
LibTooling-based tool and requires Bear to generate the compilation database.
I get the following output on the LLVM monorepo main branch as of this writing
(7ca168dd5adabcc01e957fb8486ddf2e22dd37d7):
$ LLVM_OBJ="$HOME/llvm-main-test.wt/build" ./test.sh
+ make clean
rm -f sub1/foo1.o sub2/foo2.o
+ bear make CC=/home/matt/llvm-main-test.wt/build/bin/clang
cd sub1 && /home/matt/llvm-main-test.wt/build/bin/clang -Iinc1 -Iinc2 -c -o
foo1.o foo1.c
cd sub2 && /home/matt/llvm-main-test.wt/build/bin/clang -Iinc1 -Iinc2 -c -o
foo2.o foo2.c
+ /home/matt/llvm-main-test.wt/build/bin/clang-check -p compile_commands.json
sub1/foo1.c sub2/foo2.c
foo2.c:1:10: fatal error: cannot open file 'inc1/foo.h': No such file or
directory
#include "foo.h"
^
1 error generated.
Error while processing
/home/matt/test/libtooling-working-directory/libtooling-relative-include-dir-testcase.work/sub2/foo2.c.
+ /home/matt/llvm-main-test.wt/build/bin/clang-check -p compile_commands.json
sub1/foo1.c
+ /home/matt/llvm-main-test.wt/build/bin/clang-check -p compile_commands.json
sub2/foo2.c
+ make clean
rm -f sub1/foo1.o sub2/foo2.o
+ bear make USE_ABSOLUTE_INCLUDE_DIRS=1
CC=/home/matt/llvm-main-test.wt/build/bin/clang
cd sub1 && /home/matt/llvm-main-test.wt/build/bin/clang -I$PWD/inc1 -I$PWD/inc2
-c -o foo1.o foo1.c
cd sub2 && /home/matt/llvm-main-test.wt/build/bin/clang -I$PWD/inc1 -I$PWD/inc2
-c -o foo2.o foo2.c
+ /home/matt/llvm-main-test.wt/build/bin/clang-check -p compile_commands.json
sub1/foo1.c sub2/foo2.c
Note that the problem does not occur when clang-check is run on one source file
at a time (so only one compile command working directory is involved) or when
the -I paths are absolute.
My theory of the problem: FileManager caches the existence of files based on
path, and it does nothing to prevent these paths from being relative, in which
case the OS resolves them relative to the process working directory at the time
a given file is requested. Thus, FileManager is effectively assuming that the
process working directory does not change over the lifetime of the FileManager
instance. But LibTooling violates this assumption by using a single
FileManager for all of the tool invocations and calling
`OverlayFileSystem->setCurrentWorkingDirectory` (which boils down to an OS
`chdir`) for each tool invocation. It looks like LibTooling tries to make some
paths (in particular, the source file paths) absolute in advance to avoid this
kind of problem, but it doesn't do this for the -I paths (and possibly other
relevant paths: I haven't looked). Using an -I directory with a relative path
seems to be the most obvious way to get the tool (in this case, the
preprocessor) to request a relative path from the FileManager and trigger the
problem.
However, I am no expert on the design of LibTooling, so I cannot rule out that
there is another mechanism that tries to avoid the problem but fails in this
case. Or maybe the LibTooling-based tool is supposed to be responsible for
avoiding the problem (e.g., by making -I paths absolute via an argument
adjuster), but if so, the fact that the canonical example LibTooling-based tool
(clang-check) doesn't do this would suggest that it is inadequately documented.
For a real-world example of the problem, we originally saw it when we ran our
custom LibTooling-based whole-program static analysis tool on Icecast
(https://icecast.org/). Icecast has an autoconf-based "recursive make" build
system, which uses both relative -I paths and different working directories for
different compile commands. I found some other problem reports that looked
possibly related:
https://lists.llvm.org/pipermail/cfe-dev/2013-December/033883.html
https://lists.llvm.org/pipermail/cfe-users/2015-April/000681.html
but not an existing bug report here.
Since it would probably be at least a year before our project could incorporate
any fix from upstream Clang (it is a derivative of another Clang-based project
and we don't control the schedule for upgrading the Clang baseline), we'd
welcome any ideas for workarounds to use in the meantime. As I suggested, we
might be able to use an argument adjuster to make the -I paths absolute, but
maybe there are better workarounds.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210404/d558d433/attachment-0001.html>
More information about the llvm-bugs
mailing list