1fdd4f30fSDmitri Gribenko //===- BuildSystem.cpp - Utilities for use by build systems ---------------===// 2fdd4f30fSDmitri Gribenko // 3fdd4f30fSDmitri Gribenko // The LLVM Compiler Infrastructure 4fdd4f30fSDmitri Gribenko // 5fdd4f30fSDmitri Gribenko // This file is distributed under the University of Illinois Open Source 6fdd4f30fSDmitri Gribenko // License. See LICENSE.TXT for details. 7fdd4f30fSDmitri Gribenko // 8fdd4f30fSDmitri Gribenko //===----------------------------------------------------------------------===// 9fdd4f30fSDmitri Gribenko // 10fdd4f30fSDmitri Gribenko // This file implements various utilities for use by build systems. 11fdd4f30fSDmitri Gribenko // 12fdd4f30fSDmitri Gribenko //===----------------------------------------------------------------------===// 13fdd4f30fSDmitri Gribenko 14fdd4f30fSDmitri Gribenko #include "clang-c/BuildSystem.h" 15*0b9682efSArgyrios Kyrtzidis #include "CXString.h" 16*0b9682efSArgyrios Kyrtzidis #include "llvm/ADT/ArrayRef.h" 17*0b9682efSArgyrios Kyrtzidis #include "llvm/ADT/SmallString.h" 18*0b9682efSArgyrios Kyrtzidis #include "llvm/Support/Path.h" 19*0b9682efSArgyrios Kyrtzidis #include "llvm/Support/raw_ostream.h" 20fdd4f30fSDmitri Gribenko #include "llvm/Support/TimeValue.h" 21fdd4f30fSDmitri Gribenko 22*0b9682efSArgyrios Kyrtzidis using namespace clang; 23*0b9682efSArgyrios Kyrtzidis using namespace llvm::sys; 24*0b9682efSArgyrios Kyrtzidis 25fdd4f30fSDmitri Gribenko unsigned long long clang_getBuildSessionTimestamp(void) { 26fdd4f30fSDmitri Gribenko return llvm::sys::TimeValue::now().toEpochTime(); 27fdd4f30fSDmitri Gribenko } 28fdd4f30fSDmitri Gribenko 29*0b9682efSArgyrios Kyrtzidis struct CXVirtualFileOverlayImpl { 30*0b9682efSArgyrios Kyrtzidis std::vector<std::pair<std::string, std::string> > Mappings; 31*0b9682efSArgyrios Kyrtzidis }; 32*0b9682efSArgyrios Kyrtzidis 33*0b9682efSArgyrios Kyrtzidis CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) { 34*0b9682efSArgyrios Kyrtzidis return new CXVirtualFileOverlayImpl(); 35*0b9682efSArgyrios Kyrtzidis } 36*0b9682efSArgyrios Kyrtzidis 37*0b9682efSArgyrios Kyrtzidis enum CXErrorCode 38*0b9682efSArgyrios Kyrtzidis clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO, 39*0b9682efSArgyrios Kyrtzidis const char *virtualPath, 40*0b9682efSArgyrios Kyrtzidis const char *realPath) { 41*0b9682efSArgyrios Kyrtzidis if (!VFO || !virtualPath || !realPath) 42*0b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 43*0b9682efSArgyrios Kyrtzidis if (!path::is_absolute(virtualPath)) 44*0b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 45*0b9682efSArgyrios Kyrtzidis if (!path::is_absolute(realPath)) 46*0b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 47*0b9682efSArgyrios Kyrtzidis 48*0b9682efSArgyrios Kyrtzidis for (path::const_iterator 49*0b9682efSArgyrios Kyrtzidis PI = path::begin(virtualPath), 50*0b9682efSArgyrios Kyrtzidis PE = path::end(virtualPath); PI != PE; ++PI) { 51*0b9682efSArgyrios Kyrtzidis StringRef Comp = *PI; 52*0b9682efSArgyrios Kyrtzidis if (Comp == "." || Comp == "..") 53*0b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 54*0b9682efSArgyrios Kyrtzidis } 55*0b9682efSArgyrios Kyrtzidis 56*0b9682efSArgyrios Kyrtzidis VFO->Mappings.push_back(std::make_pair(virtualPath, realPath)); 57*0b9682efSArgyrios Kyrtzidis return CXError_Success; 58*0b9682efSArgyrios Kyrtzidis } 59*0b9682efSArgyrios Kyrtzidis 60*0b9682efSArgyrios Kyrtzidis namespace { 61*0b9682efSArgyrios Kyrtzidis struct EntryTy { 62*0b9682efSArgyrios Kyrtzidis std::string VPath; 63*0b9682efSArgyrios Kyrtzidis std::string RPath; 64*0b9682efSArgyrios Kyrtzidis 65*0b9682efSArgyrios Kyrtzidis friend bool operator < (const EntryTy &LHS, const EntryTy &RHS) { 66*0b9682efSArgyrios Kyrtzidis return LHS.VPath < RHS.VPath; 67*0b9682efSArgyrios Kyrtzidis } 68*0b9682efSArgyrios Kyrtzidis }; 69*0b9682efSArgyrios Kyrtzidis 70*0b9682efSArgyrios Kyrtzidis class JSONVFSPrinter { 71*0b9682efSArgyrios Kyrtzidis llvm::raw_ostream &OS; 72*0b9682efSArgyrios Kyrtzidis 73*0b9682efSArgyrios Kyrtzidis public: 74*0b9682efSArgyrios Kyrtzidis JSONVFSPrinter(llvm::raw_ostream &OS) : OS(OS) {} 75*0b9682efSArgyrios Kyrtzidis 76*0b9682efSArgyrios Kyrtzidis /// Entries must be sorted. 77*0b9682efSArgyrios Kyrtzidis void print(ArrayRef<EntryTy> Entries) { 78*0b9682efSArgyrios Kyrtzidis OS << "{\n" 79*0b9682efSArgyrios Kyrtzidis " 'version': 0,\n" 80*0b9682efSArgyrios Kyrtzidis " 'roots': [\n"; 81*0b9682efSArgyrios Kyrtzidis printDirNodes(Entries, "", 4); 82*0b9682efSArgyrios Kyrtzidis OS << " ]\n" 83*0b9682efSArgyrios Kyrtzidis "}\n"; 84*0b9682efSArgyrios Kyrtzidis } 85*0b9682efSArgyrios Kyrtzidis 86*0b9682efSArgyrios Kyrtzidis private: 87*0b9682efSArgyrios Kyrtzidis ArrayRef<EntryTy> printDirNodes(ArrayRef<EntryTy> Entries, 88*0b9682efSArgyrios Kyrtzidis StringRef ParentPath, 89*0b9682efSArgyrios Kyrtzidis unsigned Indent) { 90*0b9682efSArgyrios Kyrtzidis while (!Entries.empty()) { 91*0b9682efSArgyrios Kyrtzidis const EntryTy &Entry = Entries.front(); 92*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "{\n"; 93*0b9682efSArgyrios Kyrtzidis Indent += 2; 94*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'type': 'directory',\n"; 95*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'name': \""; 96*0b9682efSArgyrios Kyrtzidis StringRef DirName = containedPart(ParentPath, 97*0b9682efSArgyrios Kyrtzidis path::parent_path(Entry.VPath)); 98*0b9682efSArgyrios Kyrtzidis OS.write_escaped(DirName) << "\",\n"; 99*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'contents': [\n"; 100*0b9682efSArgyrios Kyrtzidis Entries = printContents(Entries, Indent + 2); 101*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "]\n"; 102*0b9682efSArgyrios Kyrtzidis Indent -= 2; 103*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << '}'; 104*0b9682efSArgyrios Kyrtzidis if (Entries.empty()) { 105*0b9682efSArgyrios Kyrtzidis OS << '\n'; 106*0b9682efSArgyrios Kyrtzidis break; 107*0b9682efSArgyrios Kyrtzidis } 108*0b9682efSArgyrios Kyrtzidis StringRef NextVPath = Entries.front().VPath; 109*0b9682efSArgyrios Kyrtzidis if (!containedIn(ParentPath, NextVPath)) { 110*0b9682efSArgyrios Kyrtzidis OS << '\n'; 111*0b9682efSArgyrios Kyrtzidis break; 112*0b9682efSArgyrios Kyrtzidis } 113*0b9682efSArgyrios Kyrtzidis OS << ",\n"; 114*0b9682efSArgyrios Kyrtzidis } 115*0b9682efSArgyrios Kyrtzidis return Entries; 116*0b9682efSArgyrios Kyrtzidis } 117*0b9682efSArgyrios Kyrtzidis 118*0b9682efSArgyrios Kyrtzidis ArrayRef<EntryTy> printContents(ArrayRef<EntryTy> Entries, 119*0b9682efSArgyrios Kyrtzidis unsigned Indent) { 120*0b9682efSArgyrios Kyrtzidis while (!Entries.empty()) { 121*0b9682efSArgyrios Kyrtzidis const EntryTy &Entry = Entries.front(); 122*0b9682efSArgyrios Kyrtzidis Entries = Entries.slice(1); 123*0b9682efSArgyrios Kyrtzidis StringRef ParentPath = path::parent_path(Entry.VPath); 124*0b9682efSArgyrios Kyrtzidis StringRef VName = path::filename(Entry.VPath); 125*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "{\n"; 126*0b9682efSArgyrios Kyrtzidis Indent += 2; 127*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'type': 'file',\n"; 128*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'name': \""; 129*0b9682efSArgyrios Kyrtzidis OS.write_escaped(VName) << "\",\n"; 130*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'external-contents': \""; 131*0b9682efSArgyrios Kyrtzidis OS.write_escaped(Entry.RPath) << "\"\n"; 132*0b9682efSArgyrios Kyrtzidis Indent -= 2; 133*0b9682efSArgyrios Kyrtzidis OS.indent(Indent) << '}'; 134*0b9682efSArgyrios Kyrtzidis if (Entries.empty()) { 135*0b9682efSArgyrios Kyrtzidis OS << '\n'; 136*0b9682efSArgyrios Kyrtzidis break; 137*0b9682efSArgyrios Kyrtzidis } 138*0b9682efSArgyrios Kyrtzidis StringRef NextVPath = Entries.front().VPath; 139*0b9682efSArgyrios Kyrtzidis if (!containedIn(ParentPath, NextVPath)) { 140*0b9682efSArgyrios Kyrtzidis OS << '\n'; 141*0b9682efSArgyrios Kyrtzidis break; 142*0b9682efSArgyrios Kyrtzidis } 143*0b9682efSArgyrios Kyrtzidis OS << ",\n"; 144*0b9682efSArgyrios Kyrtzidis if (path::parent_path(NextVPath) != ParentPath) { 145*0b9682efSArgyrios Kyrtzidis Entries = printDirNodes(Entries, ParentPath, Indent); 146*0b9682efSArgyrios Kyrtzidis } 147*0b9682efSArgyrios Kyrtzidis } 148*0b9682efSArgyrios Kyrtzidis return Entries; 149*0b9682efSArgyrios Kyrtzidis } 150*0b9682efSArgyrios Kyrtzidis 151*0b9682efSArgyrios Kyrtzidis bool containedIn(StringRef Parent, StringRef Path) { 152*0b9682efSArgyrios Kyrtzidis return Path.startswith(Parent); 153*0b9682efSArgyrios Kyrtzidis } 154*0b9682efSArgyrios Kyrtzidis 155*0b9682efSArgyrios Kyrtzidis StringRef containedPart(StringRef Parent, StringRef Path) { 156*0b9682efSArgyrios Kyrtzidis assert(containedIn(Parent, Path)); 157*0b9682efSArgyrios Kyrtzidis if (Parent.empty()) 158*0b9682efSArgyrios Kyrtzidis return Path; 159*0b9682efSArgyrios Kyrtzidis return Path.slice(Parent.size()+1, StringRef::npos); 160*0b9682efSArgyrios Kyrtzidis } 161*0b9682efSArgyrios Kyrtzidis }; 162*0b9682efSArgyrios Kyrtzidis } 163*0b9682efSArgyrios Kyrtzidis 164*0b9682efSArgyrios Kyrtzidis enum CXErrorCode 165*0b9682efSArgyrios Kyrtzidis clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, 166*0b9682efSArgyrios Kyrtzidis unsigned, CXString *out_buffer) { 167*0b9682efSArgyrios Kyrtzidis if (!VFO || !out_buffer) 168*0b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 169*0b9682efSArgyrios Kyrtzidis 170*0b9682efSArgyrios Kyrtzidis llvm::SmallVector<EntryTy, 16> Entries; 171*0b9682efSArgyrios Kyrtzidis for (unsigned i = 0, e = VFO->Mappings.size(); i != e; ++i) { 172*0b9682efSArgyrios Kyrtzidis EntryTy Entry; 173*0b9682efSArgyrios Kyrtzidis Entry.VPath = VFO->Mappings[i].first; 174*0b9682efSArgyrios Kyrtzidis Entry.RPath = VFO->Mappings[i].second; 175*0b9682efSArgyrios Kyrtzidis Entries.push_back(Entry); 176*0b9682efSArgyrios Kyrtzidis } 177*0b9682efSArgyrios Kyrtzidis 178*0b9682efSArgyrios Kyrtzidis // FIXME: We should add options to determine if the paths are case sensitive 179*0b9682efSArgyrios Kyrtzidis // or not. The following assumes that if paths are case-insensitive the caller 180*0b9682efSArgyrios Kyrtzidis // did not mix cases in the virtual paths it provided. 181*0b9682efSArgyrios Kyrtzidis 182*0b9682efSArgyrios Kyrtzidis std::sort(Entries.begin(), Entries.end()); 183*0b9682efSArgyrios Kyrtzidis 184*0b9682efSArgyrios Kyrtzidis llvm::SmallString<256> Buf; 185*0b9682efSArgyrios Kyrtzidis llvm::raw_svector_ostream OS(Buf); 186*0b9682efSArgyrios Kyrtzidis JSONVFSPrinter Printer(OS); 187*0b9682efSArgyrios Kyrtzidis Printer.print(Entries); 188*0b9682efSArgyrios Kyrtzidis 189*0b9682efSArgyrios Kyrtzidis *out_buffer = cxstring::createDup(OS.str()); 190*0b9682efSArgyrios Kyrtzidis return CXError_Success; 191*0b9682efSArgyrios Kyrtzidis } 192*0b9682efSArgyrios Kyrtzidis 193*0b9682efSArgyrios Kyrtzidis void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) { 194*0b9682efSArgyrios Kyrtzidis delete VFO; 195*0b9682efSArgyrios Kyrtzidis } 196