blob: e5caa5447ba1ce21fe7d006226d67f52a969007b [file] [log] [blame]
Dmitri Gribenkofdd4f302014-02-12 10:40:07 +00001//===- 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"
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000015#include "CXString.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000018#include "llvm/ADT/Optional.h"
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000019#include "llvm/Support/Path.h"
Dmitri Gribenkofdd4f302014-02-12 10:40:07 +000020#include "llvm/Support/TimeValue.h"
Chandler Carruth757fcd62014-03-04 10:05:20 +000021#include "llvm/Support/raw_ostream.h"
Ben Langmuira56071c52014-04-17 03:31:02 +000022#include "llvm/Support/YAMLParser.h"
Dmitri Gribenkofdd4f302014-02-12 10:40:07 +000023
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000024using namespace clang;
25using namespace llvm::sys;
26
Dmitri Gribenkofdd4f302014-02-12 10:40:07 +000027unsigned long long clang_getBuildSessionTimestamp(void) {
28 return llvm::sys::TimeValue::now().toEpochTime();
29}
Dmitri Gribenkofdd4f302014-02-12 10:40:07 +000030
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000031struct CXVirtualFileOverlayImpl {
32 std::vector<std::pair<std::string, std::string> > Mappings;
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000033 Optional<bool> IsCaseSensitive;
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000034};
35
36CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) {
37 return new CXVirtualFileOverlayImpl();
38}
39
40enum CXErrorCode
41clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO,
42 const char *virtualPath,
43 const char *realPath) {
44 if (!VFO || !virtualPath || !realPath)
45 return CXError_InvalidArguments;
46 if (!path::is_absolute(virtualPath))
47 return CXError_InvalidArguments;
48 if (!path::is_absolute(realPath))
49 return CXError_InvalidArguments;
50
51 for (path::const_iterator
52 PI = path::begin(virtualPath),
53 PE = path::end(virtualPath); PI != PE; ++PI) {
54 StringRef Comp = *PI;
55 if (Comp == "." || Comp == "..")
56 return CXError_InvalidArguments;
57 }
58
59 VFO->Mappings.push_back(std::make_pair(virtualPath, realPath));
60 return CXError_Success;
61}
62
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000063enum CXErrorCode
64clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay VFO,
65 int caseSensitive) {
66 if (!VFO)
67 return CXError_InvalidArguments;
68
69 VFO->IsCaseSensitive = caseSensitive;
70 return CXError_Success;
71}
72
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000073namespace {
74struct EntryTy {
75 std::string VPath;
76 std::string RPath;
77
78 friend bool operator < (const EntryTy &LHS, const EntryTy &RHS) {
79 return LHS.VPath < RHS.VPath;
80 }
81};
82
83class JSONVFSPrinter {
84 llvm::raw_ostream &OS;
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000085 CXVirtualFileOverlay VFO;
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000086
87public:
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000088 JSONVFSPrinter(llvm::raw_ostream &OS, CXVirtualFileOverlay VFO)
89 : OS(OS), VFO(VFO) {}
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +000090
91 /// Entries must be sorted.
92 void print(ArrayRef<EntryTy> Entries) {
93 OS << "{\n"
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +000094 " 'version': 0,\n";
95 if (VFO->IsCaseSensitive.hasValue()) {
96 OS << " 'case-sensitive': '";
97 if (VFO->IsCaseSensitive.getValue())
98 OS << "true";
99 else
100 OS << "false";
101 OS << "',\n";
102 }
103 OS << " 'roots': [\n";
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000104 printDirNodes(Entries, "", 4);
105 OS << " ]\n"
106 "}\n";
107 }
108
109private:
110 ArrayRef<EntryTy> printDirNodes(ArrayRef<EntryTy> Entries,
111 StringRef ParentPath,
112 unsigned Indent) {
113 while (!Entries.empty()) {
114 const EntryTy &Entry = Entries.front();
115 OS.indent(Indent) << "{\n";
116 Indent += 2;
117 OS.indent(Indent) << "'type': 'directory',\n";
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000118 StringRef DirName = containedPart(ParentPath,
119 path::parent_path(Entry.VPath));
Ben Langmuir5bf828d2014-05-16 01:38:59 +0000120 OS.indent(Indent)
121 << "'name': \"" << llvm::yaml::escape(DirName) << "\",\n";
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000122 OS.indent(Indent) << "'contents': [\n";
123 Entries = printContents(Entries, Indent + 2);
124 OS.indent(Indent) << "]\n";
125 Indent -= 2;
126 OS.indent(Indent) << '}';
127 if (Entries.empty()) {
128 OS << '\n';
129 break;
130 }
131 StringRef NextVPath = Entries.front().VPath;
132 if (!containedIn(ParentPath, NextVPath)) {
133 OS << '\n';
134 break;
135 }
136 OS << ",\n";
137 }
138 return Entries;
139 }
140
141 ArrayRef<EntryTy> printContents(ArrayRef<EntryTy> Entries,
142 unsigned Indent) {
143 while (!Entries.empty()) {
144 const EntryTy &Entry = Entries.front();
145 Entries = Entries.slice(1);
146 StringRef ParentPath = path::parent_path(Entry.VPath);
147 StringRef VName = path::filename(Entry.VPath);
148 OS.indent(Indent) << "{\n";
149 Indent += 2;
150 OS.indent(Indent) << "'type': 'file',\n";
Ben Langmuira56071c52014-04-17 03:31:02 +0000151 OS.indent(Indent) << "'name': \"" << llvm::yaml::escape(VName) << "\",\n";
152 OS.indent(Indent) << "'external-contents': \""
153 << llvm::yaml::escape(Entry.RPath) << "\"\n";
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000154 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
Argyrios Kyrtzidis74c96c02014-03-03 06:38:52 +0000187clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned,
188 char **out_buffer_ptr,
189 unsigned *out_buffer_size) {
190 if (!VFO || !out_buffer_ptr || !out_buffer_size)
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000191 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);
Argyrios Kyrtzidisa9ab4d42014-03-20 04:51:48 +0000209 JSONVFSPrinter Printer(OS, VFO);
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000210 Printer.print(Entries);
211
Argyrios Kyrtzidis74c96c02014-03-03 06:38:52 +0000212 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());
Argyrios Kyrtzidis0b9682e2014-02-25 03:59:23 +0000216 return CXError_Success;
217}
218
219void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) {
220 delete VFO;
221}
Argyrios Kyrtzidisd502a102014-03-03 07:41:45 +0000222
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}