arphaman created this revision.
arphaman added reviewers: Bigcheese, jkorous, dexonsmith.
Herald added a project: clang.
This patch adds a new option called `-gen-cdb-fragment-path` to the driver,
which can be used to specify a directory path to which clang can emit a
fragment of a CDB for each compilation it needs to invoke.
The CDB fragment is emitted into a unique file in the specified directory. It
contains the `-cc1` clang invocation in its command. The file itself is
actually a valid standalone CDB (if you disregard the not yet well supported
`-cc1` innovation by the CDB, which I'll fix). To load the full CDB that can be
emitted during a build, I'm going to add a new CDB reader from a directory that
reads all fragments and aggregates them into one CDB in a follow-up patch.
This is useful to setup verification infrastructure for `clang-scan-deps` for
some projects that don't have a way of constructing a CDB from their build.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D66555
Files:
clang/include/clang/Driver/Driver.h
clang/include/clang/Driver/Job.h
clang/include/clang/Driver/Options.td
clang/lib/Driver/Compilation.cpp
clang/lib/Driver/Driver.cpp
clang/test/Driver/gen-cdb-fragment.c
Index: clang/test/Driver/gen-cdb-fragment.c
===================================================================
--- /dev/null
+++ clang/test/Driver/gen-cdb-fragment.c
@@ -0,0 +1,18 @@
+// REQUIRES: x86-registered-target
+// RUN: rm -rf %t.cdb
+// RUN: %clang -target x86_64-apple-macos10.15 -c %s -o - -gen-cdb-fragment-path %t.cdb
+// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s
+// CHECK-LS: gen-cdb-fragment.c.{{.*}}.json
+
+// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK %s
+// CHECK: [{
+// CHECK-NEXT: "directory":"{{.*}}",
+// CHECK-NEXT: "command":"{{.*}} -cc1 -triple x86_64-apple-macosx10.15.0 {{.*}}",
+// CHECK-NEXT: "file":"{{.*}}gen-cdb-fragment.c"
+// CHECK: }]
+
+// RUN: rm -rf %t.cdb
+// RUN: mkdir %t.cdb
+// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s
+// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb
+// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -1040,6 +1040,8 @@
GenReproducer = Args.hasFlag(options::OPT_gen_reproducer,
options::OPT_fno_crash_diagnostics,
!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"));
+ if (const Arg *A = Args.getLastArg(options::OPT_gen_cdb_fragment_path))
+ PathToCDBFragmentDir = A->getValue();
// FIXME: TargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
if (IsCLMode()) {
@@ -4862,3 +4864,46 @@
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false);
}
+
+void Driver::emitCompilationDatabaseFragment(StringRef DestDir,
+ StringRef Executable,
+ StringRef Filename,
+ const ArgStringList &Args) const {
+ auto CWD = getVFS().getCurrentWorkingDirectory();
+ if (!CWD)
+ return;
+
+ SmallString<256> Path = DestDir;
+ getVFS().makeAbsolute(Path);
+ auto Err = llvm::sys::fs::create_directory(Path, /*IgnoreExisting=*/true);
+ if (Err)
+ return;
+
+ llvm::sys::path::append(Path, Twine(llvm::sys::path::filename(Filename)) +
+ ".%%%%.json");
+ int FD;
+ SmallString<256> TempPath;
+ Err = llvm::sys::fs::createUniqueFile(Path, FD, TempPath);
+ if (Err)
+ return;
+
+ llvm::raw_fd_ostream OS(FD, /*ShouldClose=*/true);
+ OS << "[{\n";
+ OS << R"("directory":")" << *CWD << "\",\n";
+ OS << R"("command":")";
+ auto EmitCommandLineFragment = [&OS](StringRef Arg) {
+ for (char C : Arg) {
+ if (C == ' ' || C == '\'' || C == '"' || C == '\\')
+ OS << '\\';
+ OS << C;
+ }
+ };
+ EmitCommandLineFragment(Executable);
+ for (const auto &Arg : Args) {
+ OS << ' ';
+ EmitCommandLineFragment(Arg);
+ }
+ OS << "\",\n";
+ OS << R"("file":")" << Filename << "\"\n";
+ OS << "}]";
+}
Index: clang/lib/Driver/Compilation.cpp
===================================================================
--- clang/lib/Driver/Compilation.cpp
+++ clang/lib/Driver/Compilation.cpp
@@ -176,6 +176,14 @@
C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
}
+ if (auto CDBOutputDir = getDriver().getPathToCDBFragmentDir()) {
+ if (isa<AssembleJobAction>(C.getSource()) ||
+ isa<BackendJobAction>(C.getSource())) {
+ for (const auto &F : C.getInputFilenames())
+ getDriver().emitCompilationDatabaseFragment(
+ *CDBOutputDir, C.getExecutable(), F, C.getArguments());
+ }
+ }
std::string Error;
bool ExecutionFailed;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -280,6 +280,8 @@
Flags<[CC1Option]>;
def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt,
HelpText<"Auto-generates preprocessed source files and a reproduction script">;
+def gen_cdb_fragment_path: Separate<["-"], "gen-cdb-fragment-path">, InternalDebugOpt,
+ HelpText<"Emit a compilation database fragment to the specified directory">;
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
Index: clang/include/clang/Driver/Job.h
===================================================================
--- clang/include/clang/Driver/Job.h
+++ clang/include/clang/Driver/Job.h
@@ -125,6 +125,10 @@
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
+ const llvm::opt::ArgStringList &getInputFilenames() const {
+ return InputFilenames;
+ }
+
/// Print a command argument, and optionally quote it.
static void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote);
Index: clang/include/clang/Driver/Driver.h
===================================================================
--- clang/include/clang/Driver/Driver.h
+++ clang/include/clang/Driver/Driver.h
@@ -226,7 +226,20 @@
/// jobs.
unsigned CheckInputsExist : 1;
+ /// The directory to which the driver should write out a compilation database
+ /// fragment for its invocation.
+ std::string PathToCDBFragmentDir;
+
public:
+ /// Returns the directory to which a compilation database fragment should be
+ /// written out for its invocation, or \c None if the fragments should not be
+ /// saved.
+ Optional<StringRef> getPathToCDBFragmentDir() const {
+ if (PathToCDBFragmentDir.empty())
+ return None;
+ return StringRef(PathToCDBFragmentDir);
+ }
+
/// Force clang to emit reproducer for driver invocation. This is enabled
/// indirectly by setting FORCE_CLANG_DIAGNOSTICS_CRASH environment variable
/// or when using the -gen-reproducer driver flag.
@@ -606,6 +619,13 @@
MutableArrayRef<unsigned> Digits);
/// Compute the default -fmodule-cache-path.
static void getDefaultModuleCachePath(SmallVectorImpl<char> &Result);
+
+ /// Emits a compilation database fragment to the given directory, that
+ /// contains an entry for the specified filename and arguments.
+ void
+ emitCompilationDatabaseFragment(StringRef DestDir, StringRef Executable,
+ StringRef Filename,
+ const llvm::opt::ArgStringList &Args) const;
};
/// \return True if the last defined optimization level is -Ofast.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits