diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h --- a/clang/include/clang/Tooling/Tooling.h +++ b/clang/include/clang/Tooling/Tooling.h @@ -360,6 +360,10 @@ /// turn this off when running on multiple threads to avoid the raciness. void setRestoreWorkingDir(bool RestoreCWD); + /// Sets whether the resource directory of the current binary should be + /// injected into the command lines. + void setInjectResourceDir(bool InjectResourceDir); + /// Sets whether an error message should be printed out if an action fails. By /// default, if an action fails, a message is printed out to stderr. void setPrintErrorMessage(bool PrintErrorMessage); @@ -390,6 +394,7 @@ DiagnosticConsumer *DiagConsumer = nullptr; bool RestoreCWD = true; + bool InjectResourceDir = true; bool PrintErrorMessage = true; }; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -316,6 +316,10 @@ tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files); Tool.clearArgumentsAdjusters(); Tool.setRestoreWorkingDir(false); + // A resource directory deduced from the current executable path is most + // likely not correct (e.g. when done from inside a shared library). Let the + // driver deduce it from the absolute compiler path in `CDB`. + Tool.setInjectResourceDir(false); Tool.setPrintErrorMessage(false); Tool.setDiagnosticConsumer(&DC); DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -553,15 +553,17 @@ CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename); assert(!CommandLine.empty()); - // Add the resource dir based on the binary of this tool. argv[0] in the - // compilation database may refer to a different compiler and we want to - // pick up the very same standard library that compiler is using. The - // builtin headers in the resource dir need to match the exact clang - // version the tool is using. - // FIXME: On linux, GetMainExecutable is independent of the value of the - // first argument, thus allowing ClangTool and runToolOnCode to just - // pass in made-up names here. Make sure this works on other platforms. - injectResourceDir(CommandLine, "clang_tool", &StaticSymbol); + if (InjectResourceDir) { + // Add the resource dir based on the binary of this tool. argv[0] in the + // compilation database may refer to a different compiler and we want to + // pick up the very same standard library that compiler is using. The + // builtin headers in the resource dir need to match the exact clang + // version the tool is using. + // FIXME: On linux, GetMainExecutable is independent of the value of the + // first argument, thus allowing ClangTool and runToolOnCode to just + // pass in made-up names here. Make sure this works on other platforms. + injectResourceDir(CommandLine, "clang_tool", &StaticSymbol); + } // FIXME: We need a callback mechanism for the tool writer to output a // customized message for each file. @@ -625,6 +627,10 @@ this->RestoreCWD = RestoreCWD; } +void ClangTool::setInjectResourceDir(bool InjectResourceDir) { + this->InjectResourceDir = InjectResourceDir; +} + void ClangTool::setPrintErrorMessage(bool PrintErrorMessage) { this->PrintErrorMessage = PrintErrorMessage; } diff --git a/clang/test/ClangScanDeps/Inputs/resource_directory/cdb_tu.json b/clang/test/ClangScanDeps/Inputs/resource_directory/cdb_tu.json new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/resource_directory/cdb_tu.json @@ -0,0 +1,7 @@ +[ + { + "directory": "DIR", + "command": "CLANG -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -c DIR/tu.c -o DIR/tu.o", + "file": "DIR/tu.c" + } +] diff --git a/clang/test/ClangScanDeps/Inputs/resource_directory/mod.h b/clang/test/ClangScanDeps/Inputs/resource_directory/mod.h new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/resource_directory/mod.h @@ -0,0 +1 @@ +// mod.h diff --git a/clang/test/ClangScanDeps/Inputs/resource_directory/module.modulemap b/clang/test/ClangScanDeps/Inputs/resource_directory/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/resource_directory/module.modulemap @@ -0,0 +1 @@ +module mod { header "mod.h" } diff --git a/clang/test/ClangScanDeps/Inputs/resource_directory/tu.c b/clang/test/ClangScanDeps/Inputs/resource_directory/tu.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/resource_directory/tu.c @@ -0,0 +1,3 @@ +// tu.c + +#include "mod.h" diff --git a/clang/test/ClangScanDeps/resource_directory.c b/clang/test/ClangScanDeps/resource_directory.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/resource_directory.c @@ -0,0 +1,9 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: cp %S/Inputs/resource_directory/* %t +// RUN: sed -e "s|CLANG|/our/custom/bin/clang|g" -e "s|DIR|%/t|g" %S/Inputs/resource_directory/cdb_tu.json > %t/cdb.json + +// RUN: clang-scan-deps -compilation-database %t/cdb.json --format experimental-full > result.json +// RUN: cat result.json | sed 's:\\\\\?:/:g' | FileCheck %s + +// CHECK: "-resource-dir" +// CHECK-NEXT: "/our/custom/{{.*}}"