Skip to content

Commit a07b135

Browse files
committed
[Driver][gcov] Derive .gcno .gcda file names from -o and -dumpdir
Resolve a FIXME. When -ftest-profile, -fprofile-arcs, or --coverage is specified and the driver performs both compilation and linking phases, derive the .gcno & .gcda file names from -o and -dumpdir. `clang --coverage d/a.c d/b.c -o e/x && e/x` will now emit `e/x-[ab].gc{no,da}` like GCC. For -fprofile-dir=, we make the deliberate decision to not mangle the input filename if relative. The following script demonstrates the .gcno and .gcda filenames. ``` PATH=/tmp/Rel/bin:$PATH # adapt according to your build directory mkdir -p d e f echo 'int main() {}' > d/a.c echo > d/b.c a() { rm $@ || exit 1; } clang --coverage d/a.c d/b.c && ./a.out a a-[ab].gc{no,da} clang --coverage d/a.c d/b.c -o e/x && e/x a e/x-[ab].gc{no,da} clang --coverage d/a.c d/b.c -o e/x -dumpdir f/ && e/x a f/[ab].gc{no,da} clang --coverage -fprofile-dir=f d/a.c d/b.c -o e/x && e/x a e/x-[ab].gcno f/e/x-[ab].gcda clang -c --coverage d/a.c d/b.c && clang --coverage a.o b.o && ./a.out a [ab].gc{no,da} clang -c --coverage -fprofile-dir=f d/a.c d/b.c && clang --coverage a.o b.o && ./a.out a [ab].gcno f/[ab].gcda clang -c --coverage d/a.c -o e/xa.o && clang --coverage e/xa.o && ./a.out a e/xa.gc{no,da} clang -c --coverage d/a.c -o e/xa.o -dumpdir f/g && clang --coverage e/xa.o && ./a.out a f/ga.gc{no,da} ``` The gcov code accidentally claims -c and -S, so -fsyntax-only -c/-S and -E -c/-S don't lead to a -Wunused-command-line-argument warning. Keep the unintended code for now.
1 parent 286cefc commit a07b135

File tree

3 files changed

+53
-31
lines changed

3 files changed

+53
-31
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,10 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
705705
}
706706

707707
static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
708-
const Driver &D, const InputInfo &Output,
708+
const JobAction &JA, const InputInfo &Output,
709709
const ArgList &Args, SanitizerArgs &SanArgs,
710710
ArgStringList &CmdArgs) {
711-
711+
const Driver &D = TC.getDriver();
712712
auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
713713
options::OPT_fprofile_generate_EQ,
714714
options::OPT_fno_profile_generate);
@@ -911,32 +911,39 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
911911
Args.hasArg(options::OPT_coverage))
912912
FProfileDir = Args.getLastArg(options::OPT_fprofile_dir);
913913

914-
// Put the .gcno and .gcda files (if needed) next to the object file or
915-
// bitcode file in the case of LTO.
916-
// FIXME: There should be a simpler way to find the object file for this
917-
// input, and this code probably does the wrong thing for commands that
918-
// compile and link all at once.
919-
if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
920-
(EmitCovNotes || EmitCovData) && Output.isFilename()) {
921-
SmallString<128> OutputFilename;
922-
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo))
923-
OutputFilename = FinalOutput->getValue();
924-
else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
925-
OutputFilename = FinalOutput->getValue();
926-
else
927-
OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
928-
SmallString<128> CoverageFilename = OutputFilename;
929-
if (llvm::sys::path::is_relative(CoverageFilename))
930-
(void)D.getVFS().makeAbsolute(CoverageFilename);
914+
// TODO: Don't claim -c/-S to warn about -fsyntax-only -c/-S, -E -c/-S,
915+
// like we warn about -fsyntax-only -E.
916+
(void)(Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S));
917+
918+
// Put the .gcno and .gcda files (if needed) next to the primary output file,
919+
// or fall back to a file in the current directory for `clang -c --coverage
920+
// d/a.c` in the absence of -o.
921+
if (EmitCovNotes || EmitCovData) {
922+
SmallString<128> CoverageFilename;
923+
if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) {
924+
// Form ${dumpdir}${basename}.gcno. Note that dumpdir may not end with a
925+
// path separator.
926+
CoverageFilename = DumpDir->getValue();
927+
CoverageFilename += llvm::sys::path::filename(Output.getBaseInput());
928+
} else if (Arg *FinalOutput =
929+
C.getArgs().getLastArg(options::OPT__SLASH_Fo)) {
930+
CoverageFilename = FinalOutput->getValue();
931+
} else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) {
932+
CoverageFilename = FinalOutput->getValue();
933+
} else {
934+
CoverageFilename = llvm::sys::path::filename(Output.getBaseInput());
935+
}
931936
llvm::sys::path::replace_extension(CoverageFilename, "gcno");
932-
933-
CmdArgs.push_back("-coverage-notes-file");
934-
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
937+
if (EmitCovNotes) {
938+
CmdArgs.push_back("-coverage-notes-file");
939+
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
940+
}
935941

936942
if (EmitCovData) {
937943
if (FProfileDir) {
944+
SmallString<128> Gcno = std::move(CoverageFilename);
938945
CoverageFilename = FProfileDir->getValue();
939-
llvm::sys::path::append(CoverageFilename, OutputFilename);
946+
llvm::sys::path::append(CoverageFilename, Gcno);
940947
}
941948
llvm::sys::path::replace_extension(CoverageFilename, "gcda");
942949
CmdArgs.push_back("-coverage-data-file");
@@ -5760,7 +5767,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
57605767
// for sampling, overhead of call arc collection is way too high and there's
57615768
// no way to collect the output.
57625769
if (!Triple.isNVPTX() && !Triple.isAMDGCN())
5763-
addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs);
5770+
addPGOAndCoverageFlags(TC, C, JA, Output, Args, SanitizeArgs, CmdArgs);
57645771

57655772
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
57665773

clang/test/Driver/coverage.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
// RUN: %clang -### -S -ftest-coverage -fno-test-coverage %s 2>&1 | FileCheck --check-prefix=NO-TEST-COVERAGE %s
33

44
// TEST-COVERAGE: "-ftest-coverage"
5-
// TEST-COVERAGE: "-coverage-notes-file" "{{.*}}{{/|\\\\}}coverage.gcno"
5+
// TEST-COVERAGE: "-coverage-notes-file" "coverage.gcno"
66
// NO-TEST-COVERAGE-NOT: "-coverage-notes-file"
77

88
// RUN: %clang -### -S -fprofile-arcs %s 2>&1 | FileCheck --check-prefix=PROFILE-ARCS %s
99
// RUN: %clang -### -S -fprofile-arcs -fno-profile-arcs %s 2>&1 | FileCheck --check-prefix=NO-PROFILE-ARCS %s
1010

11+
// NO-PROFILE-ARCS-NOT: "-coverage-notes-file"
1112
// PROFILE-ARCS: "-fprofile-arcs"
12-
// PROFILE-ARCS: "-coverage-notes-file" "{{.*}}{{/|\\\\}}coverage.c"
13-
// NO-PROFILE-ARCS-NOT: "-ftest-coverage"
13+
// PROFILE-ARCS: "-coverage-data-file" "coverage.gcda"
1414

15-
// RUN: %clang -### -S -fprofile-arcs %s -o /foo/bar.o 2>&1 | FileCheck --check-prefix=GCNO-LOCATION %s
15+
// RUN: %clang -### -S -ftest-coverage %s -o /foo/bar.o 2>&1 | FileCheck --check-prefix=GCNO-LOCATION %s
1616
// RUN: %clang_cl -### /c --coverage /Fo/foo/bar.obj -- %s 2>&1 | FileCheck --check-prefix=GCNO-LOCATION %s
17-
// RUN: %clang -### -c -fprofile-arcs %s -o foo/bar.o 2>&1 | FileCheck --check-prefix=GCNO-LOCATION-REL %s
17+
// RUN: %clang -### -c -ftest-coverage %s -o foo/bar.o 2>&1 | FileCheck --check-prefix=GCNO-LOCATION-REL %s
1818

1919
// GCNO-LOCATION: "-coverage-notes-file" "{{.*}}/foo/bar.gcno"
20-
// GCNO-LOCATION-REL: "-coverage-notes-file" "{{.*}}{{/|\\\\}}foo/bar.gcno"
20+
// GCNO-LOCATION-REL: "-coverage-notes-file" "foo/bar.gcno"
2121

2222
/// Don't warn -Wunused-command-line-argument.
2323
// RUN: %clang -E -Werror --coverage -ftest-coverage -fprofile-arcs %s
@@ -35,3 +35,18 @@
3535
// RUN: %clang -### -c %s 2>&1 | FileCheck --check-prefix=NO-COV %s
3636
// NO-COV-NOT: "-coverage-notes-file"
3737
// NO-COV-NOT: "-coverage-data-file"
38+
39+
// RUN: rm -rf %t && mkdir %t && cd %t
40+
// RUN: mkdir d e f && cp %s d/a.c && touch d/b.c
41+
42+
// RUN: %clang -### --coverage d/a.c d/b.c -o e/x 2>&1 | FileCheck %s --check-prefix=LINK1
43+
// LINK1: -cc1{{.*}} "-coverage-notes-file" "e/x-a.gcno" "-coverage-data-file" "e/x-a.gcda"
44+
// LINK1: -cc1{{.*}} "-coverage-notes-file" "e/x-b.gcno" "-coverage-data-file" "e/x-b.gcda"
45+
46+
// RUN: %clang -### --coverage d/a.c d/b.c -o e/x -dumpdir f/g 2>&1 | FileCheck %s --check-prefix=LINK2
47+
// LINK2: -cc1{{.*}} "-coverage-notes-file" "f/ga.gcno" "-coverage-data-file" "f/ga.gcda"
48+
// LINK2: -cc1{{.*}} "-coverage-notes-file" "f/gb.gcno" "-coverage-data-file" "f/gb.gcda"
49+
50+
// RUN: %clang -### --coverage d/a.c d/b.c -o e/x -fprofile-dir=f 2>&1 | FileCheck %s --check-prefix=LINK3
51+
// LINK3: -cc1{{.*}} "-coverage-notes-file" "e/x-a.gcno" "-coverage-data-file" "f{{/|\\\\}}e/x-a.gcda"
52+
// LINK3: -cc1{{.*}} "-coverage-notes-file" "e/x-b.gcno" "-coverage-data-file" "f{{/|\\\\}}e/x-b.gcda"

clang/test/Driver/working-directory.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66

77
// CHECK_NO_FILE: no such file or directory: 'no_such_file.cpp'
88

9-
// CHECK_WORKS: "-coverage-notes-file" "{{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs{{/|\\\\}}pchfile.gcno"
9+
// CHECK_WORKS: "-coverage-notes-file" "pchfile.gcno"
1010
// CHECK_WORKS: "-working-directory" "{{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs"
1111
// CHECK_WORKS: "-fdebug-compilation-dir={{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs"

0 commit comments

Comments
 (0)