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