source: rtems-tools/linkers/rtems-ra.cpp @ e5165d2

4.104.115
Last change on this file since e5165d2 was e5165d2, checked in by Peng Fan <Peng.Fan@…>, on Aug 9, 2014 at 12:32:50 PM

Fix getopt_long usage

When passing shorhand options, getopt_long sometimes does not handle
them correctly.

Signed-off-by: Peng Fan <Peng.Fan@…>

  • Property mode set to 100644
File size: 17.2 KB
Line 
1/*
2 * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/**
17 * @file
18 *
19 * @ingroup rtems_rld
20 *
21 * @brief RTEMS RA Linker Main manages opions, sequence of operations and exceptions.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <iostream>
30
31#include <cxxabi.h>
32#include <signal.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37#include <getopt.h>
38
39#include <rld.h>
40#include <rld-cc.h>
41#include <rld-rap.h>
42#include <rld-outputter.h>
43#include <rld-process.h>
44#include <rld-resolver.h>
45
46#ifndef HAVE_KILL
47#define kill(p,s) raise(s)
48#endif
49
50/**
51 * RTEMS Linker options. This needs to be rewritten to be like cc where only a
52 * single '-' and long options is present.
53 */
54static struct option rld_opts[] = {
55  { "help",        no_argument,            NULL,           'h' },
56  { "version",     no_argument,            NULL,           'V' },
57  { "verbose",     no_argument,            NULL,           'v' },
58  { "output-path", required_argument,      NULL,           'p' },
59  { "output",      required_argument,      NULL,           'o' },
60  { "lib-path",    required_argument,      NULL,           'L' },
61  { "lib",         required_argument,      NULL,           'l' },
62  { "no-stdlibs",  no_argument,            NULL,           'n' },
63  { "cc",          required_argument,      NULL,           'C' },
64  { "exec-prefix", required_argument,      NULL,           'E' },
65  { "march",       required_argument,      NULL,           'a' },
66  { "mcpu",        required_argument,      NULL,           'c' },
67  { "rap-strip",   no_argument,            NULL,           'S' },
68  { "rpath",       required_argument,      NULL,           'R' },
69  { "add-rap",     required_argument,      NULL,           'A' },
70  { "replace-rap", required_argument,      NULL,           'r' },
71  { "delete-rap",  required_argument,      NULL,           'd' },
72  { NULL,          0,                      NULL,            0 }
73};
74
75#if TO_BE_USED_FOR_THE_UNDEFINES
76void
77split_on_equals (const std::string& opt, std::string& left, std::string& right)
78{
79  std::string::size_type eq = opt.find_first_of('=');
80}
81#endif
82
83void
84usage (int exit_code)
85{
86  std::cout << "rtems-ra [options] objects" << std::endl
87            << "Options and arguments:" << std::endl
88            << " -h        : help (also --help)" << std::endl
89            << " -V        : print linker version number and exit (also --version)" << std::endl
90            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
91            << "             to increase verbosity (also --verbose)" << std::endl
92            << " -o name   : linker output, this options is just" << std::endl
93            << "             for waf, it will not output to file (also --output)" << std::endl
94            << " -p path   : output path (also --output-path)" << std::endl
95            << " -L path   : path to a library, add multiple for more than" << std::endl
96            << "             one path (also --lib-path)" << std::endl
97            << " -l lib    : add lib to the libraries searched, add multiple" << std::endl
98            << "             for more than one library (also --lib)" << std::endl
99            << " -n        : do not search standard libraries (also --no-stdlibs)" << std::endl
100            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
101            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
102            << " -a march  : machine architecture (also --march)" << std::endl
103            << " -c cpu    : machine architecture's CPU (also --mcpu)" << std::endl
104            << " -S        : do not include file details (also --rap-strip)" << std::endl
105            << " -R        : include file paths (also --rpath)" << std::endl
106            << " -A        : Add rap files (also --Add-rap)" << std::endl
107            << " -r        : replace rap files (also --replace-rap)" << std::endl
108            << " -d        : delete rap files (also --delete-rap)" << std::endl
109            << " -Wl,opts  : link compatible flags, ignored" << std::endl
110            << "Output Formats:" << std::endl
111            << " ra      - RTEMS archive container of rap files" << std::endl;
112  ::exit (exit_code);
113}
114
115static void
116fatal_signal (int signum)
117{
118  signal (signum, SIG_DFL);
119
120  rld::process::temporaries_clean_up ();
121
122  /*
123   * Get the same signal again, this time not handled, so its normal effect
124   * occurs.
125   */
126  kill (getpid (), signum);
127}
128
129static void
130setup_signals (void)
131{
132  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
133    signal (SIGINT, fatal_signal);
134#ifdef SIGHUP
135  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
136    signal (SIGHUP, fatal_signal);
137#endif
138  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
139    signal (SIGTERM, fatal_signal);
140#ifdef SIGPIPE
141  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
142    signal (SIGPIPE, fatal_signal);
143#endif
144#ifdef SIGCHLD
145  signal (SIGCHLD, SIG_DFL);
146#endif
147}
148
149int
150main (int argc, char* argv[])
151{
152  int ec = 0;
153
154  setup_signals ();
155
156  try
157  {
158    rld::files::paths       libpaths;
159    rld::files::paths       libs;
160    rld::files::paths       libraries;
161    rld::files::paths       outra;
162    rld::files::paths       raps_add;
163    rld::files::paths       raps_replace;
164    rld::files::paths       raps_delete;
165    std::string             cc_name;
166    std::string             entry;
167    std::string             exit;
168    std::string             output_path = "./";
169    std::string             output = "a.ra";
170    bool                    standard_libs = true;
171    bool                    exec_prefix_set = false;
172    bool                    convert = true;
173    rld::files::object_list dependents;
174
175    libpaths.push_back (".");
176    dependents.clear ();
177
178    while (true)
179    {
180      int opt = ::getopt_long (argc, argv, "hVvnSa:p:L:l:o:C:E:c:R:W:A:r:d:", rld_opts, NULL);
181      if (opt < 0)
182        break;
183
184      switch (opt)
185      {
186        case 'V':
187          std::cout << "rtems-ra (RTEMS Linker) " << rld::version ()
188                    << std::endl;
189          ::exit (0);
190          break;
191
192        case 'v':
193          rld::verbose_inc ();
194          break;
195
196        case 'l':
197          libs.push_back (optarg);
198          break;
199
200        case 'A':
201          /*
202           * Add rap files to ra file.
203           */
204          raps_add.push_back (optarg);
205          convert = false;
206          break;
207
208        case 'r':
209          /*
210           * replace rap files to ra file.
211           */
212          raps_replace.push_back (optarg);
213          convert = false;
214          break;
215
216        case 'd':
217          /*
218           * delete rap files to ra file.
219           */
220          raps_delete.push_back (optarg);
221          convert = false;
222          break;
223
224        case 'L':
225          if ((optarg[::strlen (optarg) - 1] == '/') ||
226              (optarg[::strlen (optarg) - 1] == '\\'))
227            optarg[::strlen (optarg) - 1] = '\0';
228          libpaths.push_back (optarg);
229          break;
230
231        case 'n':
232          standard_libs = false;
233          break;
234
235        case 'p':
236          std::cout << "Output path: " << optarg << std::endl;
237          output_path = optarg;
238          break;
239
240        case 'o':
241          output = optarg;
242          break;
243
244        case 'C':
245          if (exec_prefix_set == true)
246            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
247          rld::cc::cc = optarg;
248          break;
249
250        case 'E':
251          exec_prefix_set = true;
252          rld::cc::exec_prefix = optarg;
253          break;
254
255        case 'a':
256          rld::cc::march = optarg;
257          break;
258
259        case 'c':
260          rld::cc::mcpu = optarg;
261          break;
262
263        case 'S':
264          rld::rap::add_obj_details = false;
265          break;
266
267        case 'R':
268          rld::rap::rpath += optarg;
269          rld::rap::rpath += '\0';
270          break;
271
272        case 'W':
273          /* ignore linker compatiable flags */
274          break;
275
276        case '?':
277          usage (3);
278          break;
279
280        case 'h':
281          usage (0);
282          break;
283      }
284    }
285
286    argc -= optind;
287    argv += optind;
288
289    if (rld::verbose ())
290      std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl;
291
292    /*
293     * libs can be elf archive and rap archive
294     */
295    while (argc--)
296      libs.push_back (*argv++);
297
298    /*
299     * If the full path to CC is not provided and the exec-prefix is not set by
300     * the command line see if it can be detected from the object file
301     * types. This must be after we have added the object files because they
302     * are used when detecting.
303     */
304    if (rld::cc::cc.empty () && !exec_prefix_set)
305      rld::cc::exec_prefix = rld::elf::machine_type ();
306
307    if (convert)
308    {
309      /*
310       * Get the standard library paths
311       */
312      if (standard_libs)
313        rld::cc::get_standard_libpaths (libpaths);
314      /*
315       * Get the command line libraries.
316       */
317      rld::files::find_libraries (libraries, libpaths, libs);
318
319      /*
320       * Are we to load standard libraries ?
321       */
322      if (standard_libs)
323        rld::cc::get_standard_libs (libraries, libpaths);
324
325     /*
326      * Convert ar file to ra file
327      */
328      for (rld::files::paths::iterator p = libraries.begin (); p != libraries.end (); ++p)
329      {
330        rld::files::paths    library;
331        rld::symbols::table  symbols;
332        rld::files::cache*   cache = new rld::files::cache ();
333
334        library.clear ();
335        library.push_back (*p);
336
337        /*
338        * Open the cache.
339        */
340        cache->open ();
341
342        /*
343         * Load the library to the cache.
344         */
345        cache->add_libraries (library);
346
347        cache->load_symbols (symbols);
348
349        try
350        {
351
352          rld::files::objects& objs = cache->get_objects ();
353          rld::files::paths    raobjects;
354
355          int pos = -1;
356          std::string rap_name;
357          for (rld::files::objects::iterator obi = objs.begin ();
358              obi != objs.end ();
359              ++obi)
360          {
361            rld::files::object* obj = (*obi).second;
362
363            dependents.clear ();
364
365            rap_name = obj->name ().oname ();
366
367            pos = obj->name ().oname ().rfind ('.', rap_name.length ());
368            if (pos != -1)
369            {
370              rap_name.erase (pos, rap_name.length ());
371            }
372
373            rap_name += ".rap";
374
375            dependents.push_back (obj);
376
377            raobjects.push_back (rap_name);
378
379            /* Todo: include absolute name for rap_name */
380
381            rld::outputter::application (rap_name, entry, exit,
382                                         dependents, *cache, symbols,
383                                         true);
384          }
385
386          dependents.clear ();
387          for (rld::files::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni)
388          {
389            rld::files::object* obj = new rld::files::object (*ni);
390            dependents.push_back (obj);
391          }
392
393          bool ra_rap = true;
394          bool ra_exist = false;
395          rld::files::cache cachera;
396          std::string raname = *p;
397
398          pos = -1;
399          pos = raname.rfind ('/', raname.length ());
400          if (pos != -1)
401          {
402            raname.erase (0, pos);
403          }
404
405          pos = -1;
406          pos = raname.rfind ('.', raname.length ());
407          if (pos != -1)
408          {
409            raname.erase (pos, raname.length ());
410          }
411          raname += ".ra";
412
413          raname = output_path + raname;
414
415          rld::outputter::archivera (raname, dependents, cachera,
416                                     ra_exist, ra_rap);
417          std::cout << "Generated: " << raname << std::endl;
418
419
420          for (rld::files::object_list::iterator oi = dependents.begin ();
421               oi != dependents.end ();
422               ++oi)
423          {
424            rld::files::object& obj = *(*oi);
425            ::unlink (obj.name ().oname ().c_str ());
426          }
427        }
428        catch (...)
429        {
430          cache->archives_end ();
431          throw;
432        }
433
434        cache->archives_end ();
435        delete cache;
436      }
437    }
438    else
439    {
440     /*
441      * Add, replace, delete files from the ra file.
442      */
443      for (rld::files::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl)
444      {
445        rld::files::paths    library;
446        rld::files::cache*   cache = new rld::files::cache ();
447
448        library.clear ();
449        library.push_back (*pl);
450
451        /*
452        * Open the cache.
453        */
454        cache->open ();
455
456        /*
457         * Load the library to the cache.
458         */
459        cache->add_libraries (library);
460
461        rld::files::objects& objs = cache->get_objects ();
462        rld::files::paths    raobjects;
463
464        std::string rap_name;
465        bool rap_delete = false;
466
467        dependents.clear ();
468        /*
469         * Delete rap files in ra file.
470         */
471        for (rld::files::objects::iterator obi = objs.begin ();
472            obi != objs.end ();
473            ++obi)
474        {
475          rld::files::object* obj = (*obi).second;
476
477          rap_name = obj->name ().oname ();
478          rap_delete = false;
479
480          for (rld::files::paths::iterator pa = raps_delete.begin ();
481               pa != raps_delete.end ();
482               ++pa)
483          {
484            if (*pa == rap_name)
485            {
486              rap_delete = true;
487              break;
488            }
489          }
490
491          if (!rap_delete)
492            dependents.push_back (obj);
493        }
494
495        /*
496         * Add rap files into ra file, add supports replace.
497         */
498        bool rap_exist = false;
499        rld::files::paths rap_objects;
500        for (rld::files::paths::iterator pa = raps_add.begin ();
501             pa != raps_add.end ();
502             ++pa)
503        {
504          rap_exist = false;
505
506          for (rld::files::object_list::iterator oi = dependents.begin ();
507               oi != dependents.end ();
508               ++oi)
509          {
510            rld::files::object& obj = *(*oi);
511            if (*pa == obj.name ().oname ())
512            {
513              rap_exist = true;
514              raps_replace.push_back (*pa);
515              break;
516            }
517          }
518
519          if (!rap_exist)
520            rap_objects.push_back (*pa);
521        }
522
523        for (rld::files::paths::iterator pa = rap_objects.begin ();
524             pa != rap_objects.end ();
525             ++pa)
526        {
527          rld::files::object* obj = new rld::files::object (*pa);
528          if (!obj->name ().exists ())
529          {
530            delete obj;
531            throw rld::error ("file not exist", "rap-add");
532          }
533          else dependents.push_back (obj);
534        }
535
536        /*
537         * Replace rap files in ra file
538         */
539        bool rap_replace = false;
540        rld::files::cache cachera;
541
542        rap_objects.clear ();
543        cachera.open ();
544
545        for (rld::files::paths::iterator pa = raps_replace.begin ();
546             pa != raps_replace.end ();
547             ++pa)
548        {
549          rap_replace = false;
550
551          for (rld::files::object_list::iterator oi = dependents.begin ();
552               oi != dependents.end ();
553               )
554          {
555            rld::files::object& obj = *(*oi);
556            if (*pa == obj.name ().oname ())
557            {
558              rap_replace = true;
559              dependents.erase (oi++);
560              break;
561            }
562            ++oi;
563          }
564
565          if (rap_replace)
566            rap_objects.push_back (*pa);
567        }
568
569        for (rld::files::paths::iterator pa = rap_objects.begin ();
570             pa != rap_objects.end ();
571             ++pa)
572        {
573          rld::files::object* obj = new rld::files::object (*pa);
574          if (!obj->name ().exists ())
575          {
576            delete obj;
577            throw rld::error ("file not exist", "rap-add");
578          }
579          else dependents.push_back (obj);
580        }
581
582        rld::outputter::archivera (*pl, dependents, cachera,
583                                   true, true);
584        std::cout << "End" << std::endl;
585
586        cache->archives_end ();
587        delete cache;
588      }
589    }
590  }
591  catch (rld::error re)
592  {
593    std::cerr << "error: "
594              << re.where << ": " << re.what
595              << std::endl;
596    ec = 10;
597  }
598  catch (std::exception e)
599  {
600    int   status;
601    char* realname;
602    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
603    std::cerr << "error: exception: " << realname << " [";
604    ::free (realname);
605    const std::type_info &ti = typeid (e);
606    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
607    std::cerr << realname << "] " << e.what () << std::endl << std::flush;
608    ::free (realname);
609    ec = 11;
610  }
611  catch (...)
612  {
613    /*
614     * Helps to know if this happens.
615     */
616    std::cerr << "error: unhandled exception" << std::endl;
617    ec = 12;
618  }
619
620  return ec;
621}
Note: See TracBrowser for help on using the repository browser.