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" 150b9682efSArgyrios Kyrtzidis #include "CXString.h" 160b9682efSArgyrios Kyrtzidis #include "llvm/ADT/ArrayRef.h" 170b9682efSArgyrios Kyrtzidis #include "llvm/ADT/SmallString.h" 180b9682efSArgyrios Kyrtzidis #include "llvm/Support/Path.h" 19fdd4f30fSDmitri Gribenko #include "llvm/Support/TimeValue.h" 20*757fcd6dSChandler Carruth #include "llvm/Support/raw_ostream.h" 21fdd4f30fSDmitri Gribenko 220b9682efSArgyrios Kyrtzidis using namespace clang; 230b9682efSArgyrios Kyrtzidis using namespace llvm::sys; 240b9682efSArgyrios Kyrtzidis 25fdd4f30fSDmitri Gribenko unsigned long long clang_getBuildSessionTimestamp(void) { 26fdd4f30fSDmitri Gribenko return llvm::sys::TimeValue::now().toEpochTime(); 27fdd4f30fSDmitri Gribenko } 28fdd4f30fSDmitri Gribenko 290b9682efSArgyrios Kyrtzidis struct CXVirtualFileOverlayImpl { 300b9682efSArgyrios Kyrtzidis std::vector<std::pair<std::string, std::string> > Mappings; 310b9682efSArgyrios Kyrtzidis }; 320b9682efSArgyrios Kyrtzidis 330b9682efSArgyrios Kyrtzidis CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) { 340b9682efSArgyrios Kyrtzidis return new CXVirtualFileOverlayImpl(); 350b9682efSArgyrios Kyrtzidis } 360b9682efSArgyrios Kyrtzidis 370b9682efSArgyrios Kyrtzidis enum CXErrorCode 380b9682efSArgyrios Kyrtzidis clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO, 390b9682efSArgyrios Kyrtzidis const char *virtualPath, 400b9682efSArgyrios Kyrtzidis const char *realPath) { 410b9682efSArgyrios Kyrtzidis if (!VFO || !virtualPath || !realPath) 420b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 430b9682efSArgyrios Kyrtzidis if (!path::is_absolute(virtualPath)) 440b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 450b9682efSArgyrios Kyrtzidis if (!path::is_absolute(realPath)) 460b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 470b9682efSArgyrios Kyrtzidis 480b9682efSArgyrios Kyrtzidis for (path::const_iterator 490b9682efSArgyrios Kyrtzidis PI = path::begin(virtualPath), 500b9682efSArgyrios Kyrtzidis PE = path::end(virtualPath); PI != PE; ++PI) { 510b9682efSArgyrios Kyrtzidis StringRef Comp = *PI; 520b9682efSArgyrios Kyrtzidis if (Comp == "." || Comp == "..") 530b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 540b9682efSArgyrios Kyrtzidis } 550b9682efSArgyrios Kyrtzidis 560b9682efSArgyrios Kyrtzidis VFO->Mappings.push_back(std::make_pair(virtualPath, realPath)); 570b9682efSArgyrios Kyrtzidis return CXError_Success; 580b9682efSArgyrios Kyrtzidis } 590b9682efSArgyrios Kyrtzidis 600b9682efSArgyrios Kyrtzidis namespace { 610b9682efSArgyrios Kyrtzidis struct EntryTy { 620b9682efSArgyrios Kyrtzidis std::string VPath; 630b9682efSArgyrios Kyrtzidis std::string RPath; 640b9682efSArgyrios Kyrtzidis 650b9682efSArgyrios Kyrtzidis friend bool operator < (const EntryTy &LHS, const EntryTy &RHS) { 660b9682efSArgyrios Kyrtzidis return LHS.VPath < RHS.VPath; 670b9682efSArgyrios Kyrtzidis } 680b9682efSArgyrios Kyrtzidis }; 690b9682efSArgyrios Kyrtzidis 700b9682efSArgyrios Kyrtzidis class JSONVFSPrinter { 710b9682efSArgyrios Kyrtzidis llvm::raw_ostream &OS; 720b9682efSArgyrios Kyrtzidis 730b9682efSArgyrios Kyrtzidis public: 740b9682efSArgyrios Kyrtzidis JSONVFSPrinter(llvm::raw_ostream &OS) : OS(OS) {} 750b9682efSArgyrios Kyrtzidis 760b9682efSArgyrios Kyrtzidis /// Entries must be sorted. 770b9682efSArgyrios Kyrtzidis void print(ArrayRef<EntryTy> Entries) { 780b9682efSArgyrios Kyrtzidis OS << "{\n" 790b9682efSArgyrios Kyrtzidis " 'version': 0,\n" 800b9682efSArgyrios Kyrtzidis " 'roots': [\n"; 810b9682efSArgyrios Kyrtzidis printDirNodes(Entries, "", 4); 820b9682efSArgyrios Kyrtzidis OS << " ]\n" 830b9682efSArgyrios Kyrtzidis "}\n"; 840b9682efSArgyrios Kyrtzidis } 850b9682efSArgyrios Kyrtzidis 860b9682efSArgyrios Kyrtzidis private: 870b9682efSArgyrios Kyrtzidis ArrayRef<EntryTy> printDirNodes(ArrayRef<EntryTy> Entries, 880b9682efSArgyrios Kyrtzidis StringRef ParentPath, 890b9682efSArgyrios Kyrtzidis unsigned Indent) { 900b9682efSArgyrios Kyrtzidis while (!Entries.empty()) { 910b9682efSArgyrios Kyrtzidis const EntryTy &Entry = Entries.front(); 920b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "{\n"; 930b9682efSArgyrios Kyrtzidis Indent += 2; 940b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'type': 'directory',\n"; 950b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'name': \""; 960b9682efSArgyrios Kyrtzidis StringRef DirName = containedPart(ParentPath, 970b9682efSArgyrios Kyrtzidis path::parent_path(Entry.VPath)); 980b9682efSArgyrios Kyrtzidis OS.write_escaped(DirName) << "\",\n"; 990b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'contents': [\n"; 1000b9682efSArgyrios Kyrtzidis Entries = printContents(Entries, Indent + 2); 1010b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "]\n"; 1020b9682efSArgyrios Kyrtzidis Indent -= 2; 1030b9682efSArgyrios Kyrtzidis OS.indent(Indent) << '}'; 1040b9682efSArgyrios Kyrtzidis if (Entries.empty()) { 1050b9682efSArgyrios Kyrtzidis OS << '\n'; 1060b9682efSArgyrios Kyrtzidis break; 1070b9682efSArgyrios Kyrtzidis } 1080b9682efSArgyrios Kyrtzidis StringRef NextVPath = Entries.front().VPath; 1090b9682efSArgyrios Kyrtzidis if (!containedIn(ParentPath, NextVPath)) { 1100b9682efSArgyrios Kyrtzidis OS << '\n'; 1110b9682efSArgyrios Kyrtzidis break; 1120b9682efSArgyrios Kyrtzidis } 1130b9682efSArgyrios Kyrtzidis OS << ",\n"; 1140b9682efSArgyrios Kyrtzidis } 1150b9682efSArgyrios Kyrtzidis return Entries; 1160b9682efSArgyrios Kyrtzidis } 1170b9682efSArgyrios Kyrtzidis 1180b9682efSArgyrios Kyrtzidis ArrayRef<EntryTy> printContents(ArrayRef<EntryTy> Entries, 1190b9682efSArgyrios Kyrtzidis unsigned Indent) { 1200b9682efSArgyrios Kyrtzidis while (!Entries.empty()) { 1210b9682efSArgyrios Kyrtzidis const EntryTy &Entry = Entries.front(); 1220b9682efSArgyrios Kyrtzidis Entries = Entries.slice(1); 1230b9682efSArgyrios Kyrtzidis StringRef ParentPath = path::parent_path(Entry.VPath); 1240b9682efSArgyrios Kyrtzidis StringRef VName = path::filename(Entry.VPath); 1250b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "{\n"; 1260b9682efSArgyrios Kyrtzidis Indent += 2; 1270b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'type': 'file',\n"; 1280b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'name': \""; 1290b9682efSArgyrios Kyrtzidis OS.write_escaped(VName) << "\",\n"; 1300b9682efSArgyrios Kyrtzidis OS.indent(Indent) << "'external-contents': \""; 1310b9682efSArgyrios Kyrtzidis OS.write_escaped(Entry.RPath) << "\"\n"; 1320b9682efSArgyrios Kyrtzidis Indent -= 2; 1330b9682efSArgyrios Kyrtzidis OS.indent(Indent) << '}'; 1340b9682efSArgyrios Kyrtzidis if (Entries.empty()) { 1350b9682efSArgyrios Kyrtzidis OS << '\n'; 1360b9682efSArgyrios Kyrtzidis break; 1370b9682efSArgyrios Kyrtzidis } 1380b9682efSArgyrios Kyrtzidis StringRef NextVPath = Entries.front().VPath; 1390b9682efSArgyrios Kyrtzidis if (!containedIn(ParentPath, NextVPath)) { 1400b9682efSArgyrios Kyrtzidis OS << '\n'; 1410b9682efSArgyrios Kyrtzidis break; 1420b9682efSArgyrios Kyrtzidis } 1430b9682efSArgyrios Kyrtzidis OS << ",\n"; 1440b9682efSArgyrios Kyrtzidis if (path::parent_path(NextVPath) != ParentPath) { 1450b9682efSArgyrios Kyrtzidis Entries = printDirNodes(Entries, ParentPath, Indent); 1460b9682efSArgyrios Kyrtzidis } 1470b9682efSArgyrios Kyrtzidis } 1480b9682efSArgyrios Kyrtzidis return Entries; 1490b9682efSArgyrios Kyrtzidis } 1500b9682efSArgyrios Kyrtzidis 1510b9682efSArgyrios Kyrtzidis bool containedIn(StringRef Parent, StringRef Path) { 1520b9682efSArgyrios Kyrtzidis return Path.startswith(Parent); 1530b9682efSArgyrios Kyrtzidis } 1540b9682efSArgyrios Kyrtzidis 1550b9682efSArgyrios Kyrtzidis StringRef containedPart(StringRef Parent, StringRef Path) { 1560b9682efSArgyrios Kyrtzidis assert(containedIn(Parent, Path)); 1570b9682efSArgyrios Kyrtzidis if (Parent.empty()) 1580b9682efSArgyrios Kyrtzidis return Path; 1590b9682efSArgyrios Kyrtzidis return Path.slice(Parent.size()+1, StringRef::npos); 1600b9682efSArgyrios Kyrtzidis } 1610b9682efSArgyrios Kyrtzidis }; 1620b9682efSArgyrios Kyrtzidis } 1630b9682efSArgyrios Kyrtzidis 1640b9682efSArgyrios Kyrtzidis enum CXErrorCode 16574c96c0cSArgyrios Kyrtzidis clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned, 16674c96c0cSArgyrios Kyrtzidis char **out_buffer_ptr, 16774c96c0cSArgyrios Kyrtzidis unsigned *out_buffer_size) { 16874c96c0cSArgyrios Kyrtzidis if (!VFO || !out_buffer_ptr || !out_buffer_size) 1690b9682efSArgyrios Kyrtzidis return CXError_InvalidArguments; 1700b9682efSArgyrios Kyrtzidis 1710b9682efSArgyrios Kyrtzidis llvm::SmallVector<EntryTy, 16> Entries; 1720b9682efSArgyrios Kyrtzidis for (unsigned i = 0, e = VFO->Mappings.size(); i != e; ++i) { 1730b9682efSArgyrios Kyrtzidis EntryTy Entry; 1740b9682efSArgyrios Kyrtzidis Entry.VPath = VFO->Mappings[i].first; 1750b9682efSArgyrios Kyrtzidis Entry.RPath = VFO->Mappings[i].second; 1760b9682efSArgyrios Kyrtzidis Entries.push_back(Entry); 1770b9682efSArgyrios Kyrtzidis } 1780b9682efSArgyrios Kyrtzidis 1790b9682efSArgyrios Kyrtzidis // FIXME: We should add options to determine if the paths are case sensitive 1800b9682efSArgyrios Kyrtzidis // or not. The following assumes that if paths are case-insensitive the caller 1810b9682efSArgyrios Kyrtzidis // did not mix cases in the virtual paths it provided. 1820b9682efSArgyrios Kyrtzidis 1830b9682efSArgyrios Kyrtzidis std::sort(Entries.begin(), Entries.end()); 1840b9682efSArgyrios Kyrtzidis 1850b9682efSArgyrios Kyrtzidis llvm::SmallString<256> Buf; 1860b9682efSArgyrios Kyrtzidis llvm::raw_svector_ostream OS(Buf); 1870b9682efSArgyrios Kyrtzidis JSONVFSPrinter Printer(OS); 1880b9682efSArgyrios Kyrtzidis Printer.print(Entries); 1890b9682efSArgyrios Kyrtzidis 19074c96c0cSArgyrios Kyrtzidis StringRef Data = OS.str(); 19174c96c0cSArgyrios Kyrtzidis *out_buffer_ptr = (char*)malloc(Data.size()); 19274c96c0cSArgyrios Kyrtzidis *out_buffer_size = Data.size(); 19374c96c0cSArgyrios Kyrtzidis memcpy(*out_buffer_ptr, Data.data(), Data.size()); 1940b9682efSArgyrios Kyrtzidis return CXError_Success; 1950b9682efSArgyrios Kyrtzidis } 1960b9682efSArgyrios Kyrtzidis 1970b9682efSArgyrios Kyrtzidis void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) { 1980b9682efSArgyrios Kyrtzidis delete VFO; 1990b9682efSArgyrios Kyrtzidis } 200d502a10cSArgyrios Kyrtzidis 201d502a10cSArgyrios Kyrtzidis 202d502a10cSArgyrios Kyrtzidis struct CXModuleMapDescriptorImpl { 203d502a10cSArgyrios Kyrtzidis std::string ModuleName; 204d502a10cSArgyrios Kyrtzidis std::string UmbrellaHeader; 205d502a10cSArgyrios Kyrtzidis }; 206d502a10cSArgyrios Kyrtzidis 207d502a10cSArgyrios Kyrtzidis CXModuleMapDescriptor clang_ModuleMapDescriptor_create(unsigned) { 208d502a10cSArgyrios Kyrtzidis return new CXModuleMapDescriptorImpl(); 209d502a10cSArgyrios Kyrtzidis } 210d502a10cSArgyrios Kyrtzidis 211d502a10cSArgyrios Kyrtzidis enum CXErrorCode 212d502a10cSArgyrios Kyrtzidis clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor MMD, 213d502a10cSArgyrios Kyrtzidis const char *name) { 214d502a10cSArgyrios Kyrtzidis if (!MMD || !name) 215d502a10cSArgyrios Kyrtzidis return CXError_InvalidArguments; 216d502a10cSArgyrios Kyrtzidis 217d502a10cSArgyrios Kyrtzidis MMD->ModuleName = name; 218d502a10cSArgyrios Kyrtzidis return CXError_Success; 219d502a10cSArgyrios Kyrtzidis } 220d502a10cSArgyrios Kyrtzidis 221d502a10cSArgyrios Kyrtzidis enum CXErrorCode 222d502a10cSArgyrios Kyrtzidis clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor MMD, 223d502a10cSArgyrios Kyrtzidis const char *name) { 224d502a10cSArgyrios Kyrtzidis if (!MMD || !name) 225d502a10cSArgyrios Kyrtzidis return CXError_InvalidArguments; 226d502a10cSArgyrios Kyrtzidis 227d502a10cSArgyrios Kyrtzidis MMD->UmbrellaHeader = name; 228d502a10cSArgyrios Kyrtzidis return CXError_Success; 229d502a10cSArgyrios Kyrtzidis } 230d502a10cSArgyrios Kyrtzidis 231d502a10cSArgyrios Kyrtzidis enum CXErrorCode 232d502a10cSArgyrios Kyrtzidis clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor MMD, unsigned, 233d502a10cSArgyrios Kyrtzidis char **out_buffer_ptr, 234d502a10cSArgyrios Kyrtzidis unsigned *out_buffer_size) { 235d502a10cSArgyrios Kyrtzidis if (!MMD || !out_buffer_ptr || !out_buffer_size) 236d502a10cSArgyrios Kyrtzidis return CXError_InvalidArguments; 237d502a10cSArgyrios Kyrtzidis 238d502a10cSArgyrios Kyrtzidis llvm::SmallString<256> Buf; 239d502a10cSArgyrios Kyrtzidis llvm::raw_svector_ostream OS(Buf); 240d502a10cSArgyrios Kyrtzidis OS << "framework module " << MMD->ModuleName << " {\n"; 241d502a10cSArgyrios Kyrtzidis OS << " umbrella header \""; 242d502a10cSArgyrios Kyrtzidis OS.write_escaped(MMD->UmbrellaHeader) << "\"\n"; 243d502a10cSArgyrios Kyrtzidis OS << '\n'; 244d502a10cSArgyrios Kyrtzidis OS << " export *\n"; 245d502a10cSArgyrios Kyrtzidis OS << " module * { export * }\n"; 246d502a10cSArgyrios Kyrtzidis OS << "}\n"; 247d502a10cSArgyrios Kyrtzidis 248d502a10cSArgyrios Kyrtzidis StringRef Data = OS.str(); 249d502a10cSArgyrios Kyrtzidis *out_buffer_ptr = (char*)malloc(Data.size()); 250d502a10cSArgyrios Kyrtzidis *out_buffer_size = Data.size(); 251d502a10cSArgyrios Kyrtzidis memcpy(*out_buffer_ptr, Data.data(), Data.size()); 252d502a10cSArgyrios Kyrtzidis return CXError_Success; 253d502a10cSArgyrios Kyrtzidis } 254d502a10cSArgyrios Kyrtzidis 255d502a10cSArgyrios Kyrtzidis void clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor MMD) { 256d502a10cSArgyrios Kyrtzidis delete MMD; 257d502a10cSArgyrios Kyrtzidis } 258