@@ -13,6 +13,7 @@ Date: June 2006
1313
1414#include " compile.h"
1515
16+ #include < cstring>
1617#include < fstream>
1718#include < sstream>
1819#include < iostream>
@@ -135,56 +136,114 @@ bool compilet::doit()
135136 warnings_before;
136137}
137138
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)
141151{
142152 // 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 (' .' );
151158
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 ());
153161
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" )
155166 {
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;
160168 }
161169
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))
176192 {
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:
177210 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 ;
178222 }
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
186223
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);
188247
189248 if (tstr==" " )
190249 {
@@ -193,7 +252,6 @@ bool compilet::add_input_file(const std::string &file_name)
193252 }
194253
195254 tmp_dirs.push_back (tstr);
196- std::stringstream cmd (" " );
197255 if (chdir (tmp_dirs.back ().c_str ())!=0 )
198256 {
199257 error () << " Cannot switch to temporary directory" << eom;
@@ -203,76 +261,47 @@ bool compilet::add_input_file(const std::string &file_name)
203261 // unpack now
204262 cmd << " ar x " << concat_dir_file (working_directory, file_name);
205263
206- FILE *stream;
207-
208264 stream=popen (cmd.str ().c_str (), " r" );
209265 pclose (stream);
210266
211267 cmd.clear ();
212268 cmd.str (" " );
269+ }
213270
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);
232273
233- stream= popen (cmd.str ().c_str (), " r" );
274+ stream = popen (cmd.str ().c_str (), " r" );
234275
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)
236281 {
237- std::string line;
238- int ch; // fgetc returns an int, not char
239- while ((ch=fgetc (stream))!=EOF)
282+ if (ch != ' \n ' )
240283 {
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);
259285 }
286+ else
287+ {
288+ std::string t = concat_dir_file (tstr, line);
260289
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;
263294
264- cmd.str (" " );
295+ line = " " ;
296+ }
297+ }
265298
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);
274300 }
275301
302+ if (!thin_archive && chdir (working_directory.c_str ()) != 0 )
303+ error () << " Could not change back to working directory" << eom;
304+
276305 return false ;
277306}
278307
@@ -302,41 +331,24 @@ bool compilet::find_library(const std::string &name)
302331 {
303332 std::string libname=tmp+name+" .so" ;
304333
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))
308335 {
336+ case file_typet::GOTO_BINARY:
337+ return !add_input_file (libname);
338+
339+ case file_typet::ELF_OBJECT:
309340 warning () << " Warning: Cannot read ELF library " << libname << eom;
310341 return warning_is_fatal;
342+
343+ default :
344+ break ;
311345 }
312346 }
313347 }
314348
315349 return false ;
316350}
317351
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-
340352// / parses object files and links them
341353// / \return true on error, false otherwise
342354bool compilet::link ()
0 commit comments