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