From: Alex Lorenz Date: Mon, 26 Aug 2019 17:59:41 +0000 (+0000) Subject: [driver] add a new option `-gen-cdb-fragment-path` to emit X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2116900d5c2aef64b09edd88f1fe895a30731ce8;p=clang [driver] add a new option `-gen-cdb-fragment-path` to emit a fragment of a compilation database for each compilation 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. This option emits the same CDB contents as -MJ, and will be ignored if -MJ is specified. Differential Revision: https://reviews.llvm.org/D66555 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369938 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index a50f881ee0..7cc0038488 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -280,6 +280,8 @@ def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">, 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">; diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 4f475b121f..49178b33b5 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -2013,13 +2013,14 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CompilationDatabase = std::move(File); } auto &CDB = *CompilationDatabase; - SmallString<128> Buf; - if (llvm::sys::fs::current_path(Buf)) - Buf = "."; - CDB << "{ \"directory\": \"" << escape(Buf) << "\""; + auto CWD = D.getVFS().getCurrentWorkingDirectory(); + if (!CWD) + CWD = "."; + CDB << "{ \"directory\": \"" << escape(*CWD) << "\""; CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; + SmallString<128> Buf; Buf = "-x"; Buf += types::getTypeName(Input.getType()); CDB << ", \"" << escape(Buf) << "\""; @@ -2037,6 +2038,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, // Skip writing dependency output and the compilation database itself. if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group) continue; + if (O.getID() == options::OPT_gen_cdb_fragment_path) + continue; // Skip inputs. if (O.getKind() == Option::InputClass) continue; @@ -2051,6 +2054,40 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CDB << ", \"" << escape(Buf) << "\"]},\n"; } +void Clang::DumpCompilationDatabaseFragmentToDir( + StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output, + const InputInfo &Input, const llvm::opt::ArgList &Args) const { + // If this is a dry run, do not create the compilation database file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + if (CompilationDatabase) + DumpCompilationDatabase(C, "", Target, Output, Input, Args); + + SmallString<256> Path = Dir; + const auto &Driver = C.getDriver(); + Driver.getVFS().makeAbsolute(Path); + auto Err = llvm::sys::fs::create_directory(Path, /*IgnoreExisting=*/true); + if (Err) { + Driver.Diag(diag::err_drv_compilationdatabase) << Dir << Err.message(); + return; + } + + llvm::sys::path::append( + Path, + Twine(llvm::sys::path::filename(Input.getFilename())) + ".%%%%.json"); + int FD; + SmallString<256> TempPath; + Err = llvm::sys::fs::createUniqueFile(Path, FD, TempPath); + if (Err) { + Driver.Diag(diag::err_drv_compilationdatabase) << Path << Err.message(); + return; + } + CompilationDatabase = + std::make_unique(FD, /*shouldClose=*/true); + DumpCompilationDatabase(C, "", Target, Output, Input, Args); +} + static void CollectArgsForIntegratedAssembler(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, @@ -3495,6 +3532,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) { DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args); Args.ClaimAllArgs(options::OPT_MJ); + } else if (const Arg *GenCDBFragment = + Args.getLastArg(options::OPT_gen_cdb_fragment_path)) { + DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C, + TripleStr, Output, Input, Args); + Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path); } if (IsCuda || IsHIP) { diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h index fc4f5ecdd2..8b6ac43ebd 100644 --- a/lib/Driver/ToolChains/Clang.h +++ b/lib/Driver/ToolChains/Clang.h @@ -95,6 +95,10 @@ private: const InputInfo &Output, const InputInfo &Input, const llvm::opt::ArgList &Args) const; + void DumpCompilationDatabaseFragmentToDir( + StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output, + const InputInfo &Input, const llvm::opt::ArgList &Args) const; + public: Clang(const ToolChain &TC); ~Clang() override; diff --git a/test/Driver/gen-cdb-fragment.c b/test/Driver/gen-cdb-fragment.c new file mode 100644 index 0000000000..553c349afc --- /dev/null +++ b/test/Driver/gen-cdb-fragment.c @@ -0,0 +1,37 @@ +// 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: { "directory": "{{.*}}", "file": "{{.*}}gen-cdb-fragment.c", "output": "-", "arguments": [{{.*}}, "--target=x86_64-apple-macos10.15"{{.*}}]}, +// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK-FLAG %s +// CHECK-FLAG-NOT: -gen-cdb-fragment-path + +// 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 + +// Empty path is equivalent to '.' +// RUN: rm -rf %t.cdb +// RUN: mkdir %t.cdb +// RUN: %clang -target x86_64-apple-macos10.15 -working-directory %t.cdb -c %s -o - -gen-cdb-fragment-path "" +// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s +// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK-CWD %s +// CHECK-CWD: "directory": "{{.*}}.cdb" + +// -### does not emit the CDB fragment +// RUN: rm -rf %t.cdb +// RUN: mkdir %t.cdb +// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb -### +// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s + +// -MJ is preferred over -gen-cdb-fragment-path +// RUN: rm -rf %t.cdb +// RUN: mkdir %t.cdb +// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb -MJ %t.out +// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s +// RUN: FileCheck %s < %t.out