@@ -13,6 +13,7 @@ Date: June 2006
13
13
14
14
#include " compile.h"
15
15
16
+ #include < cstring>
16
17
#include < fstream>
17
18
#include < sstream>
18
19
#include < iostream>
@@ -135,56 +136,114 @@ bool compilet::doit()
135
136
warnings_before;
136
137
}
137
138
138
- // / puts input file names into a list and does preprocessing for libraries.
139
- // / \return false on success, true on error.
140
- bool compilet::add_input_file (const std::string &file_name)
139
+ enum class file_typet
140
+ {
141
+ FAILED_TO_OPEN_FILE,
142
+ UNKNOWN,
143
+ SOURCE_FILE,
144
+ NORMAL_ARCHIVE,
145
+ THIN_ARCHIVE,
146
+ GOTO_BINARY,
147
+ ELF_OBJECT
148
+ };
149
+
150
+ static file_typet detect_file_type (const std::string &file_name)
141
151
{
142
152
// first of all, try to open the file
143
- {
144
- std::ifstream in (file_name);
145
- if (!in)
146
- {
147
- warning () << " failed to open file `" << file_name << " '" << eom;
148
- return warning_is_fatal; // generously ignore unless -Werror
149
- }
150
- }
153
+ std::ifstream in (file_name);
154
+ if (!in)
155
+ return file_typet::FAILED_TO_OPEN_FILE;
156
+
157
+ const std::string::size_type r = file_name.rfind (' .' );
151
158
152
- size_t r=file_name.rfind (' .' , file_name.length ()-1 );
159
+ const std::string ext =
160
+ r == std::string::npos ? " " : file_name.substr (r + 1 , file_name.length ());
153
161
154
- if (r==std::string::npos)
162
+ if (
163
+ ext == " c" || ext == " cc" || ext == " cp" || ext == " cpp" || ext == " CPP" ||
164
+ ext == " c++" || ext == " C" || ext == " i" || ext == " ii" || ext == " class" ||
165
+ ext == " jar" || ext == " jsil" )
155
166
{
156
- // a file without extension; will ignore
157
- warning () << " input file `" << file_name
158
- << " ' has no extension, not considered" << eom;
159
- return warning_is_fatal;
167
+ return file_typet::SOURCE_FILE;
160
168
}
161
169
162
- std::string ext = file_name.substr (r+1 , file_name.length ());
163
-
164
- if (ext==" c" ||
165
- ext==" cc" ||
166
- ext==" cp" ||
167
- ext==" cpp" ||
168
- ext==" CPP" ||
169
- ext==" c++" ||
170
- ext==" C" ||
171
- ext==" i" ||
172
- ext==" ii" ||
173
- ext==" class" ||
174
- ext==" jar" ||
175
- ext==" jsil" )
170
+ char hdr[8 ];
171
+ in.get (hdr, 8 );
172
+ if ((ext == " a" || ext == " o" ) && strncmp (hdr, " !<thin>" , 8 ) == 0 )
173
+ return file_typet::THIN_ARCHIVE;
174
+
175
+ if (ext == " a" )
176
+ return file_typet::NORMAL_ARCHIVE;
177
+
178
+ if (is_goto_binary (file_name))
179
+ return file_typet::GOTO_BINARY;
180
+
181
+ if (hdr[0 ] == 0x7f && memcmp (hdr + 1 , " ELF" , 3 ) == 0 )
182
+ return file_typet::ELF_OBJECT;
183
+
184
+ return file_typet::UNKNOWN;
185
+ }
186
+
187
+ // / puts input file names into a list and does preprocessing for libraries.
188
+ // / \return false on success, true on error.
189
+ bool compilet::add_input_file (const std::string &file_name)
190
+ {
191
+ switch (detect_file_type (file_name))
176
192
{
193
+ case file_typet::FAILED_TO_OPEN_FILE:
194
+ warning () << " failed to open file `" << file_name
195
+ << " ': " << std::strerror (errno) << eom;
196
+ return warning_is_fatal; // generously ignore unless -Werror
197
+
198
+ case file_typet::UNKNOWN:
199
+ // unknown extension, not a goto binary, will silently ignore
200
+ debug () << " unknown file type in `" << file_name << " '" << eom;
201
+ return false ;
202
+
203
+ case file_typet::ELF_OBJECT:
204
+ // ELF file without goto-cc section, silently ignore
205
+ debug () << " ELF object without goto-cc section: `" << file_name << " '"
206
+ << eom;
207
+ return false ;
208
+
209
+ case file_typet::SOURCE_FILE:
177
210
source_files.push_back (file_name);
211
+ return false ;
212
+
213
+ case file_typet::NORMAL_ARCHIVE:
214
+ return add_files_from_archive (file_name, false );
215
+
216
+ case file_typet::THIN_ARCHIVE:
217
+ return add_files_from_archive (file_name, true );
218
+
219
+ case file_typet::GOTO_BINARY:
220
+ object_files.push_back (file_name);
221
+ return false ;
178
222
}
179
- else if (ext==" a" )
180
- {
181
- #ifdef _WIN32
182
- char td[MAX_PATH+1 ];
183
- #else
184
- char td[] = " goto-cc.XXXXXX" ;
185
- #endif
186
223
187
- std::string tstr=get_temporary_directory (td);
224
+ UNREACHABLE;
225
+ }
226
+
227
+ // / extracts goto binaries from AR archive and add them as input files.
228
+ // / \return false on success, true on error.
229
+ bool compilet::add_files_from_archive (
230
+ const std::string &file_name,
231
+ bool thin_archive)
232
+ {
233
+ #ifdef _WIN32
234
+ char td[MAX_PATH + 1 ];
235
+ #else
236
+ char td[] = " goto-cc.XXXXXX" ;
237
+ #endif
238
+
239
+ std::stringstream cmd;
240
+ FILE *stream;
241
+
242
+ std::string tstr = working_directory;
243
+
244
+ if (!thin_archive)
245
+ {
246
+ tstr = get_temporary_directory (td);
188
247
189
248
if (tstr==" " )
190
249
{
@@ -193,7 +252,6 @@ bool compilet::add_input_file(const std::string &file_name)
193
252
}
194
253
195
254
tmp_dirs.push_back (tstr);
196
- std::stringstream cmd (" " );
197
255
if (chdir (tmp_dirs.back ().c_str ())!=0 )
198
256
{
199
257
error () << " Cannot switch to temporary directory" << eom;
@@ -203,76 +261,47 @@ bool compilet::add_input_file(const std::string &file_name)
203
261
// unpack now
204
262
cmd << " ar x " << concat_dir_file (working_directory, file_name);
205
263
206
- FILE *stream;
207
-
208
264
stream=popen (cmd.str ().c_str (), " r" );
209
265
pclose (stream);
210
266
211
267
cmd.clear ();
212
268
cmd.str (" " );
269
+ }
213
270
214
- // add the files from "ar t"
215
- #ifdef _WIN32
216
- if (file_name[0 ]!=' /' && file_name[1 ]!=' :' ) // NOLINT(readability/braces)
217
- #else
218
- if (file_name[0 ]!=' /' ) // NOLINT(readability/braces)
219
- #endif
220
- {
221
- cmd << " ar t " <<
222
- #ifdef _WIN32
223
- working_directory << " \\ " << file_name;
224
- #else
225
- working_directory << " /" << file_name;
226
- #endif
227
- }
228
- else
229
- {
230
- cmd << " ar t " << file_name;
231
- }
271
+ // add the files from "ar t"
272
+ cmd << " ar t " << concat_dir_file (working_directory, file_name);
232
273
233
- stream= popen (cmd.str ().c_str (), " r" );
274
+ stream = popen (cmd.str ().c_str (), " r" );
234
275
235
- if (stream!=nullptr )
276
+ if (stream != nullptr )
277
+ {
278
+ std::string line;
279
+ int ch; // fgetc returns an int, not char
280
+ while ((ch = fgetc (stream)) != EOF)
236
281
{
237
- std::string line;
238
- int ch; // fgetc returns an int, not char
239
- while ((ch=fgetc (stream))!=EOF)
282
+ if (ch != ' \n ' )
240
283
{
241
- if (ch!=' \n ' )
242
- {
243
- line+=static_cast <char >(ch);
244
- }
245
- else
246
- {
247
- std::string t;
248
- #ifdef _WIN32
249
- t = tmp_dirs.back () + ' \\ ' + line;
250
- #else
251
- t = tmp_dirs.back () + ' /' + line;
252
- #endif
253
-
254
- if (is_goto_binary (t))
255
- object_files.push_back (t);
256
-
257
- line = " " ;
258
- }
284
+ line += static_cast <char >(ch);
259
285
}
286
+ else
287
+ {
288
+ std::string t = concat_dir_file (tstr, line);
260
289
261
- pclose (stream);
262
- }
290
+ if (is_goto_binary (t))
291
+ object_files.push_back (t);
292
+ else
293
+ debug () << " Object file is not a goto binary: " << line << eom;
263
294
264
- cmd.str (" " );
295
+ line = " " ;
296
+ }
297
+ }
265
298
266
- if (chdir (working_directory.c_str ())!=0 )
267
- error () << " Could not change back to working directory" << eom;
268
- }
269
- else if (is_goto_binary (file_name))
270
- object_files.push_back (file_name);
271
- else
272
- {
273
- // unknown extension, not a goto binary, will silently ignore
299
+ pclose (stream);
274
300
}
275
301
302
+ if (!thin_archive && chdir (working_directory.c_str ()) != 0 )
303
+ error () << " Could not change back to working directory" << eom;
304
+
276
305
return false ;
277
306
}
278
307
@@ -302,41 +331,24 @@ bool compilet::find_library(const std::string &name)
302
331
{
303
332
std::string libname=tmp+name+" .so" ;
304
333
305
- if (is_goto_binary (libname))
306
- return !add_input_file (libname);
307
- else if (is_elf_file (libname))
334
+ switch (detect_file_type (libname))
308
335
{
336
+ case file_typet::GOTO_BINARY:
337
+ return !add_input_file (libname);
338
+
339
+ case file_typet::ELF_OBJECT:
309
340
warning () << " Warning: Cannot read ELF library " << libname << eom;
310
341
return warning_is_fatal;
342
+
343
+ default :
344
+ break ;
311
345
}
312
346
}
313
347
}
314
348
315
349
return false ;
316
350
}
317
351
318
- // / checking if we can load an object file
319
- // / \par parameters: file name
320
- // / \return true if the given file name exists and is an ELF file, false
321
- // / otherwise
322
- bool compilet::is_elf_file (const std::string &file_name)
323
- {
324
- std::fstream in;
325
-
326
- in.open (file_name, std::ios::in);
327
- if (in.is_open ())
328
- {
329
- char buf[4 ];
330
- for (std::size_t i=0 ; i<4 ; i++)
331
- buf[i]=static_cast <char >(in.get ());
332
- if (buf[0 ]==0x7f && buf[1 ]==' E' &&
333
- buf[2 ]==' L' && buf[3 ]==' F' )
334
- return true ;
335
- }
336
-
337
- return false ;
338
- }
339
-
340
352
// / parses object files and links them
341
353
// / \return true on error, false otherwise
342
354
bool compilet::link ()
0 commit comments