source: rtems-tools/linkers/rtems-ra.cpp @ 40fd7a0

4.104.115
Last change on this file since 40fd7a0 was 40fd7a0, checked in by Chris Johns <chrisj@…>, on Sep 1, 2014 at 3:26:47 AM

rld: Split the file into a path module for path specific functions.

This allows resued for other parts of the system not dependent on
objcet files or archives.

  • Property mode set to 100644
File size: 17.1 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            << " -c cflags : C compiler flags (also --cflags)" << std::endl
103            << " -S        : do not include file details (also --rap-strip)" << std::endl
104            << " -R        : include file paths (also --rpath)" << std::endl
105            << " -A        : Add rap files (also --Add-rap)" << std::endl
106            << " -r        : replace rap files (also --replace-rap)" << std::endl
107            << " -d        : delete rap files (also --delete-rap)" << std::endl
108            << " -Wl,opts  : link compatible flags, ignored" << std::endl
109            << "Output Formats:" << std::endl
110            << " ra      - RTEMS archive container of rap files" << std::endl;
111  ::exit (exit_code);
112}
113
114static void
115fatal_signal (int signum)
116{
117  signal (signum, SIG_DFL);
118
119  rld::process::temporaries_clean_up ();
120
121  /*
122   * Get the same signal again, this time not handled, so its normal effect
123   * occurs.
124   */
125  kill (getpid (), signum);
126}
127
128static void
129setup_signals (void)
130{
131  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
132    signal (SIGINT, fatal_signal);
133#ifdef SIGHUP
134  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
135    signal (SIGHUP, fatal_signal);
136#endif
137  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
138    signal (SIGTERM, fatal_signal);
139#ifdef SIGPIPE
140  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
141    signal (SIGPIPE, fatal_signal);
142#endif
143#ifdef SIGCHLD
144  signal (SIGCHLD, SIG_DFL);
145#endif
146}
147
148int
149main (int argc, char* argv[])
150{
151  int ec = 0;
152
153  setup_signals ();
154
155  try
156  {
157    rld::path::paths        libpaths;
158    rld::path::paths        libs;
159    rld::path::paths        libraries;
160    rld::path::paths        outra;
161    rld::path::paths        raps_add;
162    rld::path::paths        raps_replace;
163    rld::path::paths        raps_delete;
164    std::string             cc_name;
165    std::string             entry;
166    std::string             exit;
167    std::string             output_path = "./";
168    std::string             output = "a.ra";
169    bool                    standard_libs = true;
170    bool                    exec_prefix_set = false;
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                    << std::endl;
188          ::exit (0);
189          break;
190
191        case 'v':
192          rld::verbose_inc ();
193          break;
194
195        case 'l':
196          libs.push_back (optarg);
197          break;
198
199        case 'A':
200          /*
201           * Add rap files to ra file.
202           */
203          raps_add.push_back (optarg);
204          convert = false;
205          break;
206
207        case 'r':
208          /*
209           * replace rap files to ra file.
210           */
211          raps_replace.push_back (optarg);
212          convert = false;
213          break;
214
215        case 'd':
216          /*
217           * delete rap files to ra file.
218           */
219          raps_delete.push_back (optarg);
220          convert = false;
221          break;
222
223        case 'L':
224          if ((optarg[::strlen (optarg) - 1] == '/') ||
225              (optarg[::strlen (optarg) - 1] == '\\'))
226            optarg[::strlen (optarg) - 1] = '\0';
227          libpaths.push_back (optarg);
228          break;
229
230        case 'n':
231          standard_libs = false;
232          break;
233
234        case 'p':
235          std::cout << "Output path: " << optarg << std::endl;
236          output_path = optarg;
237          break;
238
239        case 'o':
240          output = optarg;
241          break;
242
243        case 'C':
244          if (exec_prefix_set == true)
245            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
246          rld::cc::cc = optarg;
247          break;
248
249        case 'E':
250          exec_prefix_set = true;
251          rld::cc::exec_prefix = optarg;
252          break;
253
254        case 'c':
255          rld::cc::cflags = optarg;
256          break;
257
258        case 'S':
259          rld::rap::add_obj_details = false;
260          break;
261
262        case 'R':
263          rld::rap::rpath += optarg;
264          rld::rap::rpath += '\0';
265          break;
266
267        case 'W':
268          /* ignore linker compatiable flags */
269          break;
270
271        case '?':
272          usage (3);
273          break;
274
275        case 'h':
276          usage (0);
277          break;
278      }
279    }
280
281    argc -= optind;
282    argv += optind;
283
284    if (rld::verbose ())
285      std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl;
286
287    /*
288     * libs can be elf archive and rap archive
289     */
290    while (argc--)
291      libs.push_back (*argv++);
292
293    /*
294     * If the full path to CC is not provided and the exec-prefix is not set by
295     * the command line see if it can be detected from the object file
296     * types. This must be after we have added the object files because they
297     * are used when detecting.
298     */
299    if (rld::cc::cc.empty () && !exec_prefix_set)
300      rld::cc::exec_prefix = rld::elf::machine_type ();
301
302    if (convert)
303    {
304      /*
305       * Get the standard library paths
306       */
307      if (standard_libs)
308        rld::cc::get_standard_libpaths (libpaths);
309      /*
310       * Get the command line libraries.
311       */
312      rld::files::find_libraries (libraries, libpaths, libs);
313
314      /*
315       * Are we to load standard libraries ?
316       */
317      if (standard_libs)
318        rld::cc::get_standard_libs (libraries, libpaths);
319
320     /*
321      * Convert ar file to ra file
322      */
323      for (rld::path::paths::iterator p = libraries.begin (); p != libraries.end (); ++p)
324      {
325        rld::path::paths    library;
326        rld::symbols::table symbols;
327        rld::files::cache*  cache = new rld::files::cache ();
328
329        library.clear ();
330        library.push_back (*p);
331
332        /*
333        * Open the cache.
334        */
335        cache->open ();
336
337        /*
338         * Load the library to the cache.
339         */
340        cache->add_libraries (library);
341
342        cache->load_symbols (symbols);
343
344        try
345        {
346
347          rld::files::objects& objs = cache->get_objects ();
348          rld::path::paths     raobjects;
349
350          int pos = -1;
351          std::string rap_name;
352          for (rld::files::objects::iterator obi = objs.begin ();
353              obi != objs.end ();
354              ++obi)
355          {
356            rld::files::object* obj = (*obi).second;
357
358            dependents.clear ();
359
360            rap_name = obj->name ().oname ();
361
362            pos = obj->name ().oname ().rfind ('.', rap_name.length ());
363            if (pos != -1)
364            {
365              rap_name.erase (pos, rap_name.length ());
366            }
367
368            rap_name += ".rap";
369
370            dependents.push_back (obj);
371
372            raobjects.push_back (rap_name);
373
374            /* Todo: include absolute name for rap_name */
375
376            rld::outputter::application (rap_name, entry, exit,
377                                         dependents, *cache, symbols,
378                                         true);
379          }
380
381          dependents.clear ();
382          for (rld::path::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni)
383          {
384            rld::files::object* obj = new rld::files::object (*ni);
385            dependents.push_back (obj);
386          }
387
388          bool              ra_rap = true;
389          bool              ra_exist = false;
390          rld::files::cache cachera;
391          std::string       raname = *p;
392
393          pos = -1;
394          pos = raname.rfind ('/', raname.length ());
395          if (pos != -1)
396          {
397            raname.erase (0, pos);
398          }
399
400          pos = -1;
401          pos = raname.rfind ('.', raname.length ());
402          if (pos != -1)
403          {
404            raname.erase (pos, raname.length ());
405          }
406          raname += ".ra";
407
408          raname = output_path + raname;
409
410          rld::outputter::archivera (raname, dependents, cachera,
411                                     ra_exist, ra_rap);
412          std::cout << "Generated: " << raname << std::endl;
413
414
415          for (rld::files::object_list::iterator oi = dependents.begin ();
416               oi != dependents.end ();
417               ++oi)
418          {
419            rld::files::object& obj = *(*oi);
420            ::unlink (obj.name ().oname ().c_str ());
421          }
422        }
423        catch (...)
424        {
425          cache->archives_end ();
426          throw;
427        }
428
429        cache->archives_end ();
430        delete cache;
431      }
432    }
433    else
434    {
435     /*
436      * Add, replace, delete files from the ra file.
437      */
438      for (rld::path::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl)
439      {
440        rld::path::paths   library;
441        rld::files::cache* cache = new rld::files::cache ();
442
443        library.clear ();
444        library.push_back (*pl);
445
446        /*
447        * Open the cache.
448        */
449        cache->open ();
450
451        /*
452         * Load the library to the cache.
453         */
454        cache->add_libraries (library);
455
456        rld::files::objects& objs = cache->get_objects ();
457        rld::path::paths     raobjects;
458
459        std::string rap_name;
460        bool        rap_delete = false;
461
462        dependents.clear ();
463        /*
464         * Delete rap files in ra file.
465         */
466        for (rld::files::objects::iterator obi = objs.begin ();
467            obi != objs.end ();
468            ++obi)
469        {
470          rld::files::object* obj = (*obi).second;
471
472          rap_name = obj->name ().oname ();
473          rap_delete = false;
474
475          for (rld::path::paths::iterator pa = raps_delete.begin ();
476               pa != raps_delete.end ();
477               ++pa)
478          {
479            if (*pa == rap_name)
480            {
481              rap_delete = true;
482              break;
483            }
484          }
485
486          if (!rap_delete)
487            dependents.push_back (obj);
488        }
489
490        /*
491         * Add rap files into ra file, add supports replace.
492         */
493        rld::path::paths rap_objects;
494        bool             rap_exist = false;
495
496        for (rld::path::paths::iterator pa = raps_add.begin ();
497             pa != raps_add.end ();
498             ++pa)
499        {
500          rap_exist = false;
501
502          for (rld::files::object_list::iterator oi = dependents.begin ();
503               oi != dependents.end ();
504               ++oi)
505          {
506            rld::files::object& obj = *(*oi);
507            if (*pa == obj.name ().oname ())
508            {
509              rap_exist = true;
510              raps_replace.push_back (*pa);
511              break;
512            }
513          }
514
515          if (!rap_exist)
516            rap_objects.push_back (*pa);
517        }
518
519        for (rld::path::paths::iterator pa = rap_objects.begin ();
520             pa != rap_objects.end ();
521             ++pa)
522        {
523          rld::files::object* obj = new rld::files::object (*pa);
524          if (!obj->name ().exists ())
525          {
526            delete obj;
527            throw rld::error ("file not exist", "rap-add");
528          }
529          else dependents.push_back (obj);
530        }
531
532        /*
533         * Replace rap files in ra file
534         */
535        rld::files::cache cachera;
536        bool              rap_replace = false;
537
538        rap_objects.clear ();
539        cachera.open ();
540
541        for (rld::path::paths::iterator pa = raps_replace.begin ();
542             pa != raps_replace.end ();
543             ++pa)
544        {
545          rap_replace = false;
546
547          for (rld::files::object_list::iterator oi = dependents.begin ();
548               oi != dependents.end ();
549               )
550          {
551            rld::files::object& obj = *(*oi);
552            if (*pa == obj.name ().oname ())
553            {
554              rap_replace = true;
555              dependents.erase (oi++);
556              break;
557            }
558            ++oi;
559          }
560
561          if (rap_replace)
562            rap_objects.push_back (*pa);
563        }
564
565        for (rld::path::paths::iterator pa = rap_objects.begin ();
566             pa != rap_objects.end ();
567             ++pa)
568        {
569          rld::files::object* obj = new rld::files::object (*pa);
570          if (!obj->name ().exists ())
571          {
572            delete obj;
573            throw rld::error ("file not exist", "rap-add");
574          }
575          else dependents.push_back (obj);
576        }
577
578        rld::outputter::archivera (*pl, dependents, cachera,
579                                   true, true);
580        std::cout << "End" << std::endl;
581
582        cache->archives_end ();
583        delete cache;
584      }
585    }
586  }
587  catch (rld::error re)
588  {
589    std::cerr << "error: "
590              << re.where << ": " << re.what
591              << std::endl;
592    ec = 10;
593  }
594  catch (std::exception e)
595  {
596    int   status;
597    char* realname;
598    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
599    std::cerr << "error: exception: " << realname << " [";
600    ::free (realname);
601    const std::type_info &ti = typeid (e);
602    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
603    std::cerr << realname << "] " << e.what () << std::endl << std::flush;
604    ::free (realname);
605    ec = 11;
606  }
607  catch (...)
608  {
609    /*
610     * Helps to know if this happens.
611     */
612    std::cerr << "error: unhandled exception" << std::endl;
613    ec = 12;
614  }
615
616  return ec;
617}
Note: See TracBrowser for help on using the repository browser.