Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-export-metadata.h"
20 : #include "rust-hir-visitor.h"
21 : #include "rust-hir-full.h"
22 : #include "rust-hir-map.h"
23 : #include "rust-ast-dump.h"
24 : #include "rust-abi.h"
25 : #include "rust-item.h"
26 : #include "rust-macro.h"
27 : #include "rust-object-export.h"
28 :
29 : #include "md5.h"
30 : #include "rust-system.h"
31 :
32 : namespace Rust {
33 : namespace Metadata {
34 :
35 : static const std::string extension_path = ".rox";
36 :
37 4305 : ExportContext::ExportContext () : mappings (Analysis::Mappings::get ()) {}
38 :
39 4305 : ExportContext::~ExportContext () {}
40 :
41 : void
42 4305 : ExportContext::emit_crate (AST::Crate &c)
43 : {
44 4305 : std::stringstream oss;
45 4305 : using AST::Dump;
46 4305 : AST::Dump dumper (
47 : oss,
48 : Dump::Configuration{Dump::Configuration::InternalComment::Hide,
49 : Dump::Configuration::NodeDescription::Hide,
50 : Dump::Configuration::Comment::Hide,
51 : Dump::Configuration::Newline::Hide,
52 : Dump::Configuration::Indentation::None},
53 4305 : {});
54 4305 : dumper.process (c);
55 :
56 8610 : public_interface_buffer += oss.str ();
57 4305 : }
58 : void
59 3 : ExportContext::emit_macro (AST::MacroRulesDefinition ¯o)
60 : {
61 3 : std::stringstream oss;
62 3 : AST::Dump dumper (oss);
63 :
64 3 : dumper.go (macro);
65 :
66 6 : public_interface_buffer += oss.str ();
67 3 : }
68 :
69 : const std::string &
70 4305 : ExportContext::get_interface_buffer () const
71 : {
72 4305 : return public_interface_buffer;
73 : }
74 :
75 4305 : PublicInterface::PublicInterface (HIR::Crate &crate)
76 4305 : : crate (crate), mappings (Analysis::Mappings::get ()), context ()
77 4305 : {}
78 :
79 : void
80 0 : PublicInterface::Export (HIR::Crate &crate)
81 : {
82 0 : PublicInterface interface (crate);
83 0 : interface.gather_export_data ();
84 0 : interface.write_to_object_file ();
85 0 : }
86 :
87 : void
88 4305 : PublicInterface::ExportTo (HIR::Crate &crate, const std::string &output_path)
89 : {
90 4305 : PublicInterface interface (crate);
91 4305 : interface.gather_export_data ();
92 4305 : interface.write_to_path (output_path);
93 4305 : }
94 :
95 : void
96 4305 : PublicInterface::gather_export_data ()
97 : {
98 4305 : auto crate_num
99 4305 : = mappings.lookup_crate_num (crate.get_mappings ().get_nodeid ());
100 4305 : auto &ast_crate = mappings.get_ast_crate (crate_num.value ());
101 4305 : context.emit_crate (ast_crate);
102 :
103 4308 : for (auto ¯o : mappings.get_exported_macros ())
104 4308 : context.emit_macro (macro);
105 4305 : }
106 :
107 : void
108 0 : PublicInterface::write_to_object_file () const
109 : {
110 : // done
111 0 : const auto &buf = context.get_interface_buffer ();
112 0 : std::string size_buffer = std::to_string (buf.size ());
113 :
114 : // md5 this
115 0 : struct md5_ctx chksm;
116 0 : unsigned char checksum[16];
117 :
118 0 : md5_init_ctx (&chksm);
119 0 : md5_process_bytes (buf.c_str (), buf.size (), &chksm);
120 0 : md5_finish_ctx (&chksm, checksum);
121 :
122 : // MAGIC MD5 DLIM DLIM buffer-size DELIM contents
123 0 : const std::string current_crate_name = mappings.get_current_crate_name ();
124 :
125 : // extern void
126 0 : rust_write_export_data (kMagicHeader, sizeof (kMagicHeader));
127 0 : rust_write_export_data ((const char *) checksum, sizeof (checksum));
128 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
129 0 : rust_write_export_data (current_crate_name.c_str (),
130 0 : current_crate_name.size ());
131 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
132 0 : rust_write_export_data (size_buffer.c_str (), size_buffer.size ());
133 0 : rust_write_export_data (kSzDelim, sizeof (kSzDelim));
134 0 : rust_write_export_data (buf.c_str (), buf.size ());
135 0 : }
136 :
137 : void
138 4305 : PublicInterface::write_to_path (const std::string &path) const
139 : {
140 : // validate path contains correct extension
141 4305 : const std::string expected_file_name = expected_metadata_filename ();
142 4305 : const char *path_base_name = lbasename (path.c_str ());
143 4305 : if (strcmp (path_base_name, expected_file_name.c_str ()) != 0)
144 : {
145 0 : rust_error_at (UNDEF_LOCATION,
146 : "expected metadata-output path to have base file name of: "
147 : "%qs got %qs",
148 : expected_file_name.c_str (), path_base_name);
149 0 : return;
150 : }
151 :
152 : // done
153 4305 : const auto &buf = context.get_interface_buffer ();
154 4305 : std::string size_buffer = std::to_string (buf.size ());
155 :
156 : // md5 this
157 4305 : struct md5_ctx chksm;
158 4305 : unsigned char checksum[16];
159 :
160 4305 : md5_init_ctx (&chksm);
161 4305 : md5_process_bytes (buf.c_str (), buf.size (), &chksm);
162 4305 : md5_finish_ctx (&chksm, checksum);
163 :
164 : // MAGIC MD5 DLIM DLIM buffer-size DELIM contents
165 4305 : const std::string current_crate_name = mappings.get_current_crate_name ();
166 :
167 : // write to path
168 4305 : FILE *nfd = fopen (path.c_str (), "wb");
169 4305 : if (nfd == NULL)
170 : {
171 0 : rust_error_at (UNDEF_LOCATION, "failed to open file %qs for writing: %s",
172 0 : path.c_str (), xstrerror (errno));
173 0 : return;
174 : }
175 :
176 : // write data
177 4305 : if (fwrite (kMagicHeader, sizeof (kMagicHeader), 1, nfd) < 1)
178 : {
179 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
180 0 : path.c_str (), xstrerror (errno));
181 0 : fclose (nfd);
182 0 : return;
183 : }
184 :
185 4305 : if (fwrite (checksum, sizeof (checksum), 1, nfd) < 1)
186 : {
187 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
188 0 : path.c_str (), xstrerror (errno));
189 0 : fclose (nfd);
190 0 : return;
191 : }
192 :
193 4305 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
194 : {
195 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
196 0 : path.c_str (), xstrerror (errno));
197 0 : fclose (nfd);
198 0 : return;
199 : }
200 :
201 4305 : if (fwrite (current_crate_name.c_str (), current_crate_name.size (), 1, nfd)
202 : < 1)
203 : {
204 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
205 0 : path.c_str (), xstrerror (errno));
206 0 : fclose (nfd);
207 0 : return;
208 : }
209 :
210 4305 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
211 : {
212 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
213 0 : path.c_str (), xstrerror (errno));
214 0 : fclose (nfd);
215 0 : return;
216 : }
217 :
218 4305 : if (fwrite (size_buffer.c_str (), size_buffer.size (), 1, nfd) < 1)
219 : {
220 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
221 0 : path.c_str (), xstrerror (errno));
222 0 : fclose (nfd);
223 0 : return;
224 : }
225 :
226 4305 : if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1)
227 : {
228 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
229 0 : path.c_str (), xstrerror (errno));
230 0 : fclose (nfd);
231 0 : return;
232 : }
233 :
234 4305 : if (!buf.empty ())
235 4305 : if (fwrite (buf.c_str (), buf.size (), 1, nfd) < 1)
236 : {
237 0 : rust_error_at (UNDEF_LOCATION, "failed to write to file %qs: %s",
238 0 : path.c_str (), xstrerror (errno));
239 0 : fclose (nfd);
240 0 : return;
241 : }
242 :
243 : // done
244 4305 : fclose (nfd);
245 4305 : }
246 :
247 : bool
248 0 : PublicInterface::is_crate_public (const HIR::VisItem &item)
249 : {
250 0 : const HIR::Visibility &visibility = item.get_visibility ();
251 :
252 0 : bool is_public
253 0 : = visibility.get_vis_type () == HIR::Visibility::VisType::Public;
254 0 : bool has_path = !visibility.get_path ().is_error ();
255 :
256 : // FIXME this might be pub(crate)
257 : // Arthur magic required here
258 :
259 0 : return is_public && !has_path;
260 : }
261 :
262 : std::string
263 8610 : PublicInterface::expected_metadata_filename ()
264 : {
265 8610 : auto &mappings = Analysis::Mappings::get ();
266 :
267 8610 : const std::string current_crate_name = mappings.get_current_crate_name ();
268 8610 : return current_crate_name + extension_path;
269 8610 : }
270 :
271 : } // namespace Metadata
272 : } // namespace Rust
|