source: rtems-tools/linkers/rtems-ra.cpp @ 3d2db56

5
Last change on this file since 3d2db56 was 3d2db56, checked in by Chris Johns <chrisj@…>, on 11/28/18 at 18:41:33

Fix warnings on Windows.

  • Property mode set to 100644
File size: 17.3 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#include <rld-rtems.h>
46
47#ifndef HAVE_KILL
48#define kill(p,s) raise(s)
49#endif
50
51/**
52 * RTEMS Linker options. This needs to be rewritten to be like cc where only a
53 * single '-' and long options is present.
54 */
55static struct option rld_opts[] = {
56  { "help",        no_argument,            NULL,           'h' },
57  { "version",     no_argument,            NULL,           'V' },
58  { "verbose",     no_argument,            NULL,           'v' },
59  { "output-path", required_argument,      NULL,           'p' },
60  { "output",      required_argument,      NULL,           'o' },
61  { "lib-path",    required_argument,      NULL,           'L' },
62  { "lib",         required_argument,      NULL,           'l' },
63  { "no-stdlibs",  no_argument,            NULL,           'n' },
64  { "cc",          required_argument,      NULL,           'C' },
65  { "exec-prefix", required_argument,      NULL,           'E' },
66  { "march",       required_argument,      NULL,           'a' },
67  { "mcpu",        required_argument,      NULL,           'c' },
68  { "rap-strip",   no_argument,            NULL,           'S' },
69  { "rpath",       required_argument,      NULL,           'R' },
70  { "add-rap",     required_argument,      NULL,           'A' },
71  { "replace-rap", required_argument,      NULL,           'r' },
72  { "delete-rap",  required_argument,      NULL,           'd' },
73  { NULL,          0,                      NULL,            0 }
74};
75
76#if TO_BE_USED_FOR_THE_UNDEFINES
77void
78split_on_equals (const std::string& opt, std::string& left, std::string& right)
79{
80  std::string::size_type eq = opt.find_first_of('=');
81}
82#endif
83
84void
85usage (int exit_code)
86{
87  std::cout << "rtems-ra [options] objects" << std::endl
88            << "Options and arguments:" << std::endl
89            << " -h        : help (also --help)" << std::endl
90            << " -V        : print linker version number and exit (also --version)" << std::endl
91            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
92            << "             to increase verbosity (also --verbose)" << std::endl
93            << " -o name   : linker output, this options is just" << std::endl
94            << "             for waf, it will not output to file (also --output)" << std::endl
95            << " -p path   : output path (also --output-path)" << std::endl
96            << " -L path   : path to a library, add multiple for more than" << std::endl
97            << "             one path (also --lib-path)" << std::endl
98            << " -l lib    : add lib to the libraries searched, add multiple" << std::endl
99            << "             for more than one library (also --lib)" << std::endl
100            << " -n        : do not search standard libraries (also --no-stdlibs)" << std::endl
101            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
102            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
103            << " -c cflags : C compiler flags (also --cflags)" << 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::path::paths        libpaths;
159    rld::path::paths        libs;
160    rld::path::paths        libraries;
161    rld::path::paths        outra;
162    rld::path::paths        raps_add;
163    rld::path::paths        raps_replace;
164    rld::path::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                    convert = true;
172    rld::files::object_list dependents;
173
174    libpaths.push_back (".");
175    dependents.clear ();
176
177    while (true)
178    {
179      int opt = ::getopt_long (argc, argv, "hVvnSa:p:L:l:o:C:E:c:R:W:A:r:d:", rld_opts, NULL);
180      if (opt < 0)
181        break;
182
183      switch (opt)
184      {
185        case 'V':
186          std::cout << "rtems-ra (RTEMS Linker) " << rld::version ()
187                    << ", RTEMS revision " << rld::rtems::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 (rld::cc::is_exec_prefix_set ())
246            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
247          rld::cc::set_cc (optarg);
248          break;
249
250        case 'E':
251          if (rld::cc::is_cc_set ())
252            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
253          rld::cc::set_exec_prefix (optarg);
254          break;
255
256        case 'c':
257          rld::cc::set_flags (optarg, rld::cc::ft_cflags);
258          break;
259
260        case 'S':
261          rld::rap::add_obj_details = false;
262          break;
263
264        case 'R':
265          rld::rap::rpath += optarg;
266          rld::rap::rpath += '\0';
267          break;
268
269        case 'W':
270          /* ignore linker compatiable flags */
271          break;
272
273        case '?':
274          usage (3);
275          break;
276
277        case 'h':
278          usage (0);
279          break;
280      }
281    }
282
283    argc -= optind;
284    argv += optind;
285
286    if (rld::verbose ())
287      std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl;
288
289    /*
290     * libs can be elf archive and rap archive
291     */
292    while (argc--)
293      libs.push_back (*argv++);
294
295    /*
296     * If the full path to CC is not provided and the exec-prefix is not set by
297     * the command line see if it can be detected from the object file
298     * types. This must be after we have added the object files because they
299     * are used when detecting.
300     */
301    if (!rld::cc::is_cc_set () && !rld::cc::is_exec_prefix_set ())
302      rld::cc::set_exec_prefix (rld::elf::machine_type ());
303
304    if (convert)
305    {
306      /*
307       * Get the standard library paths
308       */
309      if (standard_libs)
310        rld::cc::get_standard_libpaths (libpaths);
311      /*
312       * Get the command line libraries.
313       */
314      rld::files::find_libraries (libraries, libpaths, libs);
315
316      /*
317       * Are we to load standard libraries ?
318       */
319      if (standard_libs)
320        rld::cc::get_standard_libs (libraries, libpaths);
321
322     /*
323      * Convert ar file to ra file
324      */
325      for (rld::path::paths::iterator p = libraries.begin (); p != libraries.end (); ++p)
326      {
327        rld::path::paths    library;
328        rld::symbols::table symbols;
329        rld::files::cache*  cache = new rld::files::cache ();
330
331        library.clear ();
332        library.push_back (*p);
333
334        /*
335        * Open the cache.
336        */
337        cache->open ();
338
339        /*
340         * Load the library to the cache.
341         */
342        cache->add_libraries (library);
343
344        cache->load_symbols (symbols);
345
346        try
347        {
348
349          rld::files::objects& objs = cache->get_objects ();
350          rld::path::paths     raobjects;
351
352          int pos = -1;
353          std::string rap_name;
354          for (rld::files::objects::iterator obi = objs.begin ();
355              obi != objs.end ();
356              ++obi)
357          {
358            rld::files::object* obj = (*obi).second;
359
360            dependents.clear ();
361
362            rap_name = obj->name ().oname ();
363
364            pos = obj->name ().oname ().rfind ('.', rap_name.length ());
365            if (pos != -1)
366            {
367              rap_name.erase (pos, rap_name.length ());
368            }
369
370            rap_name += ".rap";
371
372            dependents.push_back (obj);
373
374            raobjects.push_back (rap_name);
375
376            /* Todo: include absolute name for rap_name */
377
378            rld::outputter::rap_application (rap_name, entry, exit,
379                                             dependents, *cache, symbols,
380                                             true);
381          }
382
383          dependents.clear ();
384          for (rld::path::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni)
385          {
386            rld::files::object* obj = new rld::files::object (*ni);
387            dependents.push_back (obj);
388          }
389
390          bool              ra_rap = true;
391          bool              ra_exist = false;
392          rld::files::cache cachera;
393          std::string       raname = *p;
394
395          pos = -1;
396          pos = raname.rfind ('/', raname.length ());
397          if (pos != -1)
398          {
399            raname.erase (0, pos);
400          }
401
402          pos = -1;
403          pos = raname.rfind ('.', raname.length ());
404          if (pos != -1)
405          {
406            raname.erase (pos, raname.length ());
407          }
408          raname += ".ra";
409
410          raname = output_path + raname;
411
412          rld::outputter::archivera (raname, dependents, cachera,
413                                     ra_exist, ra_rap);
414          std::cout << "Generated: " << raname << std::endl;
415
416
417          for (rld::files::object_list::iterator oi = dependents.begin ();
418               oi != dependents.end ();
419               ++oi)
420          {
421            rld::files::object& obj = *(*oi);
422            ::unlink (obj.name ().oname ().c_str ());
423          }
424        }
425        catch (...)
426        {
427          cache->archives_end ();
428          throw;
429        }
430
431        cache->archives_end ();
432        delete cache;
433      }
434    }
435    else
436    {
437     /*
438      * Add, replace, delete files from the ra file.
439      */
440      for (rld::path::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl)
441      {
442        rld::path::paths   library;
443        rld::files::cache* cache = new rld::files::cache ();
444
445        library.clear ();
446        library.push_back (*pl);
447
448        /*
449        * Open the cache.
450        */
451        cache->open ();
452
453        /*
454         * Load the library to the cache.
455         */
456        cache->add_libraries (library);
457
458        rld::files::objects& objs = cache->get_objects ();
459        rld::path::paths     raobjects;
460
461        std::string rap_name;
462        bool        rap_delete = false;
463
464        dependents.clear ();
465        /*
466         * Delete rap files in ra file.
467         */
468        for (rld::files::objects::iterator obi = objs.begin ();
469            obi != objs.end ();
470            ++obi)
471        {
472          rld::files::object* obj = (*obi).second;
473
474          rap_name = obj->name ().oname ();
475          rap_delete = false;
476
477          for (rld::path::paths::iterator pa = raps_delete.begin ();
478               pa != raps_delete.end ();
479               ++pa)
480          {
481            if (*pa == rap_name)
482            {
483              rap_delete = true;
484              break;
485            }
486          }
487
488          if (!rap_delete)
489            dependents.push_back (obj);
490        }
491
492        /*
493         * Add rap files into ra file, add supports replace.
494         */
495        rld::path::paths rap_objects;
496        bool             rap_exist = false;
497
498        for (rld::path::paths::iterator pa = raps_add.begin ();
499             pa != raps_add.end ();
500             ++pa)
501        {
502          rap_exist = false;
503
504          for (rld::files::object_list::iterator oi = dependents.begin ();
505               oi != dependents.end ();
506               ++oi)
507          {
508            rld::files::object& obj = *(*oi);
509            if (*pa == obj.name ().oname ())
510            {
511              rap_exist = true;
512              raps_replace.push_back (*pa);
513              break;
514            }
515          }
516
517          if (!rap_exist)
518            rap_objects.push_back (*pa);
519        }
520
521        for (rld::path::paths::iterator pa = rap_objects.begin ();
522             pa != rap_objects.end ();
523             ++pa)
524        {
525          rld::files::object* obj = new rld::files::object (*pa);
526          if (!obj->name ().exists ())
527          {
528            delete obj;
529            throw rld::error ("file not exist", "rap-add");
530          }
531          else dependents.push_back (obj);
532        }
533
534        /*
535         * Replace rap files in ra file
536         */
537        rld::files::cache cachera;
538        bool              rap_replace = false;
539
540        rap_objects.clear ();
541        cachera.open ();
542
543        for (rld::path::paths::iterator pa = raps_replace.begin ();
544             pa != raps_replace.end ();
545             ++pa)
546        {
547          rap_replace = false;
548
549          for (rld::files::object_list::iterator oi = dependents.begin ();
550               oi != dependents.end ();
551               )
552          {
553            rld::files::object& obj = *(*oi);
554            if (*pa == obj.name ().oname ())
555            {
556              rap_replace = true;
557              dependents.erase (oi++);
558              break;
559            }
560            ++oi;
561          }
562
563          if (rap_replace)
564            rap_objects.push_back (*pa);
565        }
566
567        for (rld::path::paths::iterator pa = rap_objects.begin ();
568             pa != rap_objects.end ();
569             ++pa)
570        {
571          rld::files::object* obj = new rld::files::object (*pa);
572          if (!obj->name ().exists ())
573          {
574            delete obj;
575            throw rld::error ("file not exist", "rap-add");
576          }
577          else dependents.push_back (obj);
578        }
579
580        rld::outputter::archivera (*pl, dependents, cachera,
581                                   true, true);
582        std::cout << "End" << std::endl;
583
584        cache->archives_end ();
585        delete cache;
586      }
587    }
588  }
589  catch (rld::error re)
590  {
591    std::cerr << "error: "
592              << re.where << ": " << re.what
593              << std::endl;
594    ec = 10;
595  }
596  catch (std::exception& e)
597  {
598    int   status;
599    char* realname;
600    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
601    std::cerr << "error: exception: " << realname << " [";
602    ::free (realname);
603    const std::type_info &ti = typeid (e);
604    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
605    std::cerr << realname << "] " << e.what () << std::endl << std::flush;
606    ::free (realname);
607    ec = 11;
608  }
609  catch (...)
610  {
611    /*
612     * Helps to know if this happens.
613     */
614    std::cerr << "error: unhandled exception" << std::endl;
615    ec = 12;
616  }
617
618  return ec;
619}
Note: See TracBrowser for help on using the repository browser.