]>
Commit | Line | Data |
---|---|---|
c1a9b12d SL |
1 | #include "rustllvm.h" |
2 | ||
3 | #include "llvm/Object/Archive.h" | |
c1a9b12d | 4 | #include "llvm/Object/ArchiveWriter.h" |
3b2f2976 | 5 | #include "llvm/Support/Path.h" |
c1a9b12d SL |
6 | |
7 | using namespace llvm; | |
8 | using namespace llvm::object; | |
9 | ||
5bcae85e | 10 | struct RustArchiveMember { |
32a655c1 SL |
11 | const char *Filename; |
12 | const char *Name; | |
13 | Archive::Child Child; | |
c1a9b12d | 14 | |
32a655c1 SL |
15 | RustArchiveMember() |
16 | : Filename(nullptr), Name(nullptr), | |
32a655c1 | 17 | Child(nullptr, nullptr, nullptr) |
32a655c1 SL |
18 | { |
19 | } | |
5bcae85e | 20 | ~RustArchiveMember() {} |
c1a9b12d SL |
21 | }; |
22 | ||
5bcae85e | 23 | struct RustArchiveIterator { |
32a655c1 SL |
24 | bool First; |
25 | Archive::child_iterator Cur; | |
26 | Archive::child_iterator End; | |
532ac7d7 XL |
27 | std::unique_ptr<Error> Err; |
28 | ||
29 | RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End, | |
30 | std::unique_ptr<Error> Err) | |
31 | : First(true), | |
32 | Cur(Cur), | |
33 | End(End), | |
34 | Err(std::move(Err)) {} | |
5bcae85e SL |
35 | }; |
36 | ||
37 | enum class LLVMRustArchiveKind { | |
32a655c1 SL |
38 | Other, |
39 | GNU, | |
32a655c1 SL |
40 | BSD, |
41 | COFF, | |
5bcae85e SL |
42 | }; |
43 | ||
32a655c1 SL |
44 | static Archive::Kind fromRust(LLVMRustArchiveKind Kind) { |
45 | switch (Kind) { | |
46 | case LLVMRustArchiveKind::GNU: | |
47 | return Archive::K_GNU; | |
32a655c1 SL |
48 | case LLVMRustArchiveKind::BSD: |
49 | return Archive::K_BSD; | |
50 | case LLVMRustArchiveKind::COFF: | |
51 | return Archive::K_COFF; | |
52 | default: | |
ff7c6d11 | 53 | report_fatal_error("Bad ArchiveKind."); |
5bcae85e SL |
54 | } |
55 | } | |
56 | ||
57 | typedef OwningBinary<Archive> *LLVMRustArchiveRef; | |
58 | typedef RustArchiveMember *LLVMRustArchiveMemberRef; | |
59 | typedef Archive::Child *LLVMRustArchiveChildRef; | |
60 | typedef Archive::Child const *LLVMRustArchiveChildConstRef; | |
61 | typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; | |
62 | ||
32a655c1 SL |
63 | extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) { |
64 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = | |
65 | MemoryBuffer::getFile(Path, -1, false); | |
66 | if (!BufOr) { | |
67 | LLVMRustSetLastError(BufOr.getError().message().c_str()); | |
68 | return nullptr; | |
69 | } | |
c1a9b12d | 70 | |
32a655c1 | 71 | Expected<std::unique_ptr<Archive>> ArchiveOr = |
32a655c1 | 72 | Archive::create(BufOr.get()->getMemBufferRef()); |
c1a9b12d | 73 | |
32a655c1 | 74 | if (!ArchiveOr) { |
32a655c1 | 75 | LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str()); |
32a655c1 SL |
76 | return nullptr; |
77 | } | |
c1a9b12d | 78 | |
32a655c1 SL |
79 | OwningBinary<Archive> *Ret = new OwningBinary<Archive>( |
80 | std::move(ArchiveOr.get()), std::move(BufOr.get())); | |
c1a9b12d | 81 | |
32a655c1 | 82 | return Ret; |
c1a9b12d SL |
83 | } |
84 | ||
32a655c1 SL |
85 | extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) { |
86 | delete RustArchive; | |
c1a9b12d SL |
87 | } |
88 | ||
5bcae85e | 89 | extern "C" LLVMRustArchiveIteratorRef |
32a655c1 SL |
90 | LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) { |
91 | Archive *Archive = RustArchive->getBinary(); | |
dfeec247 XL |
92 | #if LLVM_VERSION_GE(10, 0) |
93 | std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success()); | |
94 | #else | |
532ac7d7 | 95 | std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success()); |
dfeec247 | 96 | #endif |
532ac7d7 XL |
97 | auto Cur = Archive->child_begin(*Err); |
98 | if (*Err) { | |
99 | LLVMRustSetLastError(toString(std::move(*Err)).c_str()); | |
32a655c1 SL |
100 | return nullptr; |
101 | } | |
532ac7d7 XL |
102 | auto End = Archive->child_end(); |
103 | return new RustArchiveIterator(Cur, End, std::move(Err)); | |
c1a9b12d SL |
104 | } |
105 | ||
5bcae85e | 106 | extern "C" LLVMRustArchiveChildConstRef |
32a655c1 SL |
107 | LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) { |
108 | if (RAI->Cur == RAI->End) | |
109 | return nullptr; | |
110 | ||
111 | // Advancing the iterator validates the next child, and this can | |
112 | // uncover an error. LLVM requires that we check all Errors, | |
113 | // so we only advance the iterator if we actually need to fetch | |
114 | // the next child. | |
115 | // This means we must not advance the iterator in the *first* call, | |
116 | // but instead advance it *before* fetching the child in all later calls. | |
117 | if (!RAI->First) { | |
118 | ++RAI->Cur; | |
532ac7d7 XL |
119 | if (*RAI->Err) { |
120 | LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str()); | |
32a655c1 | 121 | return nullptr; |
5bcae85e | 122 | } |
32a655c1 SL |
123 | } else { |
124 | RAI->First = false; | |
125 | } | |
126 | ||
127 | if (RAI->Cur == RAI->End) | |
128 | return nullptr; | |
129 | ||
32a655c1 | 130 | const Archive::Child &Child = *RAI->Cur.operator->(); |
32a655c1 | 131 | Archive::Child *Ret = new Archive::Child(Child); |
7453a54e | 132 | |
32a655c1 | 133 | return Ret; |
c1a9b12d SL |
134 | } |
135 | ||
32a655c1 SL |
136 | extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) { |
137 | delete Child; | |
c1a9b12d SL |
138 | } |
139 | ||
32a655c1 SL |
140 | extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) { |
141 | delete RAI; | |
c1a9b12d SL |
142 | } |
143 | ||
32a655c1 SL |
144 | extern "C" const char * |
145 | LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { | |
32a655c1 SL |
146 | Expected<StringRef> NameOrErr = Child->getName(); |
147 | if (!NameOrErr) { | |
b7449926 | 148 | // rustc_codegen_llvm currently doesn't use this error string, but it might be |
32a655c1 SL |
149 | // useful in the future, and in the mean time this tells LLVM that the |
150 | // error was not ignored and that it shouldn't abort the process. | |
151 | LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str()); | |
152 | return nullptr; | |
153 | } | |
32a655c1 SL |
154 | StringRef Name = NameOrErr.get(); |
155 | *Size = Name.size(); | |
156 | return Name.data(); | |
c1a9b12d SL |
157 | } |
158 | ||
32a655c1 SL |
159 | extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child, |
160 | size_t *Size) { | |
161 | StringRef Buf; | |
32a655c1 SL |
162 | Expected<StringRef> BufOrErr = Child->getBuffer(); |
163 | if (!BufOrErr) { | |
164 | LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str()); | |
165 | return nullptr; | |
166 | } | |
32a655c1 SL |
167 | Buf = BufOrErr.get(); |
168 | *Size = Buf.size(); | |
169 | return Buf.data(); | |
c1a9b12d SL |
170 | } |
171 | ||
5bcae85e SL |
172 | extern "C" LLVMRustArchiveMemberRef |
173 | LLVMRustArchiveMemberNew(char *Filename, char *Name, | |
32a655c1 SL |
174 | LLVMRustArchiveChildRef Child) { |
175 | RustArchiveMember *Member = new RustArchiveMember; | |
176 | Member->Filename = Filename; | |
177 | Member->Name = Name; | |
178 | if (Child) | |
179 | Member->Child = *Child; | |
180 | return Member; | |
c1a9b12d SL |
181 | } |
182 | ||
32a655c1 SL |
183 | extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { |
184 | delete Member; | |
c1a9b12d SL |
185 | } |
186 | ||
5bcae85e | 187 | extern "C" LLVMRustResult |
32a655c1 | 188 | LLVMRustWriteArchive(char *Dst, size_t NumMembers, |
5bcae85e | 189 | const LLVMRustArchiveMemberRef *NewMembers, |
32a655c1 | 190 | bool WriteSymbtab, LLVMRustArchiveKind RustKind) { |
5bcae85e | 191 | |
5bcae85e | 192 | std::vector<NewArchiveMember> Members; |
32a655c1 | 193 | auto Kind = fromRust(RustKind); |
c1a9b12d | 194 | |
32a655c1 SL |
195 | for (size_t I = 0; I < NumMembers; I++) { |
196 | auto Member = NewMembers[I]; | |
197 | assert(Member->Name); | |
198 | if (Member->Filename) { | |
32a655c1 SL |
199 | Expected<NewArchiveMember> MOrErr = |
200 | NewArchiveMember::getFile(Member->Filename, true); | |
5bcae85e SL |
201 | if (!MOrErr) { |
202 | LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); | |
203 | return LLVMRustResult::Failure; | |
204 | } | |
3b2f2976 | 205 | MOrErr->MemberName = sys::path::filename(MOrErr->MemberName); |
5bcae85e | 206 | Members.push_back(std::move(*MOrErr)); |
c1a9b12d | 207 | } else { |
32a655c1 SL |
208 | Expected<NewArchiveMember> MOrErr = |
209 | NewArchiveMember::getOldMember(Member->Child, true); | |
5bcae85e SL |
210 | if (!MOrErr) { |
211 | LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); | |
212 | return LLVMRustResult::Failure; | |
213 | } | |
214 | Members.push_back(std::move(*MOrErr)); | |
c1a9b12d SL |
215 | } |
216 | } | |
0731742a | 217 | |
2c00a5a8 | 218 | auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); |
2c00a5a8 | 219 | if (!Result) |
5bcae85e | 220 | return LLVMRustResult::Success; |
2c00a5a8 | 221 | LLVMRustSetLastError(toString(std::move(Result)).c_str()); |
2c00a5a8 | 222 | |
5bcae85e | 223 | return LLVMRustResult::Failure; |
c1a9b12d | 224 | } |