Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -152,6 +152,9 @@ /// The version string to put into coverage files. char CoverageVersion[4]; + /// The directory all source files are relative to. + std::string SourceDir; + /// Enable additional debugging information. std::string DebugPass; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -870,6 +870,13 @@ Group, Flags<[CC1Option, CoreOption]>, HelpText<"Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">; +def fsource_dir : Separate<["-"], "fsource-dir">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, + HelpText<"The directory all source files are relative to.">; +def fsource_dir_EQ : Joined<["-"], "fsource-dir=">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, + Alias; + defm addrsig : OptInFFlag<"addrsig", "Emit", "Don't emit", " an address-significance table", [CoreOption]>; defm blocks : OptInFFlag<"blocks", "Enable the 'blocks' language feature", "", "", [CoreOption]>; def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group; Index: clang/include/clang/Lex/PreprocessorOptions.h =================================================================== --- clang/include/clang/Lex/PreprocessorOptions.h +++ clang/include/clang/Lex/PreprocessorOptions.h @@ -175,6 +175,9 @@ /// build it again. std::shared_ptr FailedModules; + /// The directory all source files are relative to. + std::string SourceDir; + /// A prefix map for __FILE__ and __BASE_FILE__. std::map> MacroPrefixMap; Index: clang/lib/CodeGen/CoverageMappingGen.h =================================================================== --- clang/lib/CodeGen/CoverageMappingGen.h +++ clang/lib/CodeGen/CoverageMappingGen.h @@ -94,6 +94,8 @@ std::vector FunctionNames; std::vector FunctionRecords; + std::string normalizeFilename(StringRef Filename); + /// Emit a function record. void emitFunctionMappingRecord(const FunctionInfo &Info, uint64_t FilenamesRef); Index: clang/lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- clang/lib/CodeGen/CoverageMappingGen.cpp +++ clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1368,13 +1368,6 @@ } }; -std::string normalizeFilename(StringRef Filename) { - llvm::SmallString<256> Path(Filename); - llvm::sys::fs::make_absolute(Path); - llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - return std::string(Path); -} - } // end anonymous namespace static void dump(llvm::raw_ostream &OS, StringRef FunctionName, @@ -1413,6 +1406,16 @@ SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); } +std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { + llvm::SmallString<256> Path(Filename); + llvm::sys::fs::make_absolute(Path); + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + StringRef SourceDir = CGM.getCodeGenOpts().SourceDir; + if (!SourceDir.empty() && Path.startswith(SourceDir)) + llvm::sys::path::make_relative(Path, SourceDir, Path); + return std::string(Path); +} + void CoverageMappingModuleGen::emitFunctionMappingRecord( const FunctionInfo &Info, uint64_t FilenamesRef) { llvm::LLVMContext &Ctx = CGM.getLLVMContext(); Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -5189,6 +5189,11 @@ if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); + if (Arg *A = Args.getLastArg(options::OPT_fsource_dir)) { + CmdArgs.push_back("-fsource-dir"); + CmdArgs.push_back(A->getValue()); + } + // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs, D.getVFS()); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1188,8 +1188,16 @@ } Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); + + SmallString<128> P(Args.getLastArgValue(OPT_fsource_dir)); + if (!P.empty() && !llvm::sys::path::is_absolute(P)) + llvm::sys::fs::make_absolute(P); + llvm::sys::path::remove_dots(P, /*remove_dot_dot=*/true); + Opts.SourceDir = std::string(P.str()); + Opts.DebugCompilationDir = std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir)); + for (auto *A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_builtin_bitcode)) { CodeGenOptions::BitcodeFileToLink F; @@ -3631,6 +3639,12 @@ for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); + SmallString<128> P(Args.getLastArgValue(OPT_fsource_dir)); + if (!P.empty() && !llvm::sys::path::is_absolute(P)) + llvm::sys::fs::make_absolute(P); + llvm::sys::path::remove_dots(P, /*remove_dot_dot=*/true); + Opts.SourceDir = std::string(P.str()); + for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) { auto Split = StringRef(A).split('='); Opts.MacroPrefixMap.insert( Index: clang/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1542,6 +1542,9 @@ FN += PLoc.getFilename(); } remapMacroPath(FN, PPOpts->MacroPrefixMap); + StringRef SourceDir = PPOpts->SourceDir; + if (!SourceDir.empty() && FN.startswith(SourceDir)) + llvm::sys::path::make_relative(FN, SourceDir, FN); Lexer::Stringify(FN); OS << '"' << FN << '"'; } Index: clang/test/CoverageMapping/source_dir.c =================================================================== --- /dev/null +++ clang/test/CoverageMapping/source_dir.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm %s -o - | FileCheck -check-prefix=ABSPATH %s + +// ABSPATH: @__llvm_coverage_mapping = {{.*}}"\01 +// ABSPATH: {{[/\\].*(/|\\\\)test(/|\\\\)CoverageMapping(/|\\\\)source_dir}}.c +// ABSPATH: " + +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -fsource-dir %S %s -o - | FileCheck -check-prefix=RELPATH %s + +// RELPATH: @__llvm_coverage_mapping = {{.*}}"\01 +// RELPATH: source_dir.c +// RELPATH: " + +void f1() {} Index: clang/test/Preprocessor/file_test.c =================================================================== --- clang/test/Preprocessor/file_test.c +++ clang/test/Preprocessor/file_test.c @@ -3,6 +3,7 @@ // RUN: %clang -E -fmacro-prefix-map=%p=/UNLIKELY_PATH/empty -c -o - %s | FileCheck %s // RUN: %clang -E -fmacro-prefix-map=%p=/UNLIKELY_PATH=empty -c -o - %s | FileCheck %s -check-prefix CHECK-EVIL // RUN: %clang -E -fmacro-prefix-map=%p/= -c -o - %s | FileCheck %s --check-prefix CHECK-REMOVE +// RUN: %clang -E -fsource-dir %S -c -o - %s | FileCheck %s --check-prefix CHECK-RELATIVE filename: __FILE__ #include "Inputs/include-file-test/file_test.h" @@ -21,3 +22,8 @@ // CHECK-REMOVE: filename: "Inputs/include-file-test/file_test.h" // CHECK-REMOVE: basefile: "file_test.c" // CHECK-REMOVE-NOT: filename: + +// CHECK-RELATIVE: filename: "file_test.c" +// CHECK-RELATIVE: filename: "Inputs/include-file-test/file_test.h" +// CHECK-RELATIVE: basefile: "file_test.c" +// CHECK-RELATIVE-NOT: filename: Index: llvm/include/llvm/Support/Path.h =================================================================== --- llvm/include/llvm/Support/Path.h +++ llvm/include/llvm/Support/Path.h @@ -514,6 +514,10 @@ bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false, Style style = Style::native); +/// Return a path that when appeneded to from resolves to the same as to. +void make_relative(StringRef from, StringRef to, SmallVectorImpl &result, + Style style = Style::native); + } // end namespace path } // end namespace sys } // end namespace llvm Index: llvm/lib/Support/Path.cpp =================================================================== --- llvm/lib/Support/Path.cpp +++ llvm/lib/Support/Path.cpp @@ -775,6 +775,22 @@ return true; } +void make_relative(StringRef from, StringRef to, SmallVectorImpl &result, + Style style) { + SmallString<256> buffer; + auto fromIt = begin(from, style), fromE = end(from); + auto toIt = begin(to, style), toE = end(to); + // Find a common base. + for (; fromIt != fromE && toIt != toE && *fromIt == *toIt; ++fromIt, ++toIt) + ; + // Navigate backwards to the base. + for (; toIt != toE; ++toIt) + if (*toIt != ".") + append(buffer, style, ".."); + append(buffer, fromIt, fromE, style); + result.swap(buffer); +} + } // end namespace path namespace fs { Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -1547,6 +1547,35 @@ EXPECT_EQ(Path, "C:\\old/foo\\bar"); } +static std::string make_relative(StringRef from, StringRef to, + path::Style style) { + SmallString<256> buffer; + path::make_relative(from, to, buffer, style); + return std::string(buffer.str()); +} + +TEST(Support, MakeRelative) { + EXPECT_EQ("", make_relative("/a/b/c/d", "/a/b/c/d", path::Style::posix)); + EXPECT_EQ("d", make_relative("/a/b/c/d", "/a/b/c", path::Style::posix)); + EXPECT_EQ("c/d", make_relative("/a/b/c/d", "/a/b", path::Style::posix)); + EXPECT_EQ("../../c/d", + make_relative("/a/b/c/d", "/a/b/e/f", path::Style::posix)); + EXPECT_EQ("../../../../a/b/c/d", + make_relative("/a/b/c/d", "/e/f/g/h", path::Style::posix)); + + EXPECT_EQ("", make_relative("C:\\a\\b\\c\\d", "C:\\a\\b\\c\\d", + path::Style::windows)); + EXPECT_EQ("d", make_relative("C:\\a\\b\\c\\d", "C:\\a\\b\\c", + path::Style::windows)); + EXPECT_EQ("c\\d", + make_relative("C:\\a\\b\\c\\d", "C:\\a\\b", path::Style::windows)); + EXPECT_EQ("..\\..\\c\\d", make_relative("C:\\a\\b\\c\\d", "C:\\a\\b\\e\\f", + path::Style::windows)); + EXPECT_EQ( + "..\\..\\..\\..\\a\\b\\c\\d", + make_relative("C:\\a\\b\\c\\d", "C:\\e\\f\\g\\h", path::Style::windows)); +} + TEST_F(FileSystemTest, OpenFileForRead) { // Create a temp file. int FileDescriptor;