source: rtems-tools/linkers/main.cpp @ aef6d90

4.104.115
Last change on this file since aef6d90 was aef6d90, checked in by Chris Johns <chrisj@…>, on Sep 16, 2012 at 11:37:29 PM

Update the help to something useful.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1/*
2 * Copyright (c) 2011, 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 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-gcc.h>
41#include <rld-outputter.h>
42#include <rld-process.h>
43#include <rld-resolver.h>
44
45#ifndef HAVE_KILL
46#define kill(p,s) raise(s)
47#endif
48
49/**
50 * RTEMS Linker options. This needs to be rewritten to be like gcc where only a
51 * single '-' and long options is present.
52 */
53static struct option rld_opts[] = {
54  { "help",        no_argument,            NULL,           'h' },
55  { "version",     no_argument,            NULL,           'V' },
56  { "verbose",     no_argument,            NULL,           'v' },
57  { "warn",        no_argument,            NULL,           'w' },
58  { "map",         no_argument,            NULL,           'M' },
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  { "exec-prefix", required_argument,      NULL,           'E' },
64  { "march",       required_argument,      NULL,           'a' },
65  { "mcpu",        required_argument,      NULL,           'c' },
66  { "entry",       required_argument,      NULL,           'e' },
67  { "define",      required_argument,      NULL,           'd' },
68  { "undefined",   required_argument,      NULL,           'u' },
69  { "base",        required_argument,      NULL,           'b' },
70  { "script",      no_argument,            NULL,           'S' },
71  { NULL,          0,                      NULL,            0 }
72};
73
74#if TO_BE_USED_FOR_THE_UNDEFINES
75void
76split_on_equals (const std::string& opt, std::string& left, std::string& right)
77{
78  std::string::size_type eq = opt.find_first_of('=');
79}
80#endif
81
82void
83usage (int exit_code)
84{
85  std::cout << "rtems-ld [options] objects" << std::endl
86            << "Options and arguments:" << std::endl
87            << " -h        : help (also --help)" << std::endl
88            << " -V        : print linker version number and exit (also --version)" << std::endl
89            << " -v        : verbose (trace import parts), can be supply multiple times" << std::endl
90            << "             to increase verbosity (also --verbose)" << std::endl
91            << " -w        : generate warnings (also --warn)" << std::endl
92            << " -M        : generate map output (also --map)" << std::endl
93            << " -o file   : linker output is written to file (also --output)" << std::endl
94            << " -L path   : path to a library, add multiple for more than" << std::endl
95            << "             one path (also --lib-path)" << std::endl
96            << " -l lib    : add lib to the libraries searched, add multiple" << std::endl
97            << "             for more than one library (also --lib)" << std::endl
98            << " -n        : do not search standard libraries (also --no-stdlibs)" << std::endl
99            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
100            << " -a march  : machine architecture (also --march)" << std::endl
101            << " -c cpu    : machine architecture's CPU (also --mcpu)" << std::endl
102            << " -e entry  : entry point symbol (also --entry)" << std::endl
103            << " -d sym    : add the symbol definition, add multiple with" << std::endl
104            << "             more than one define (also --define)" << std::endl
105            << " -u sym    : add the undefined symbol definition, add multiple" << std::endl
106            << "             for more than one undefined symbol (also --undefined)" << std::endl
107            << " -b elf    : read the ELF file symbols as the base RTEMS kernel" << std::endl
108            << "             image (also --base)" << std::endl
109            << " -S script : linker output is a script file (also --script)" << std::endl;
110  ::exit (exit_code);
111}
112
113static void
114fatal_signal (int signum)
115{
116  signal (signum, SIG_DFL);
117
118  rld::process::temporaries.clean_up ();
119
120  /*
121   * Get the same signal again, this time not handled, so its normal effect
122   * occurs.
123   */
124  kill (getpid (), signum);
125}
126
127static void
128setup_signals (void)
129{
130  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
131    signal (SIGINT, fatal_signal);
132#ifdef SIGHUP
133  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
134    signal (SIGHUP, fatal_signal);
135#endif
136  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
137    signal (SIGTERM, fatal_signal);
138#ifdef SIGPIPE
139  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
140    signal (SIGPIPE, fatal_signal);
141#endif
142#ifdef SIGCHLD
143  signal (SIGCHLD, SIG_DFL);
144#endif
145}
146
147int
148main (int argc, char* argv[])
149{
150  int ec = 0;
151
152  setup_signals ();
153
154  try
155  {
156    rld::files::cache   cache;
157    rld::files::cache   base;
158    rld::files::paths   libpaths;
159    rld::files::paths   libs;
160    rld::files::paths   objects;
161    rld::files::paths   libraries;
162    rld::symbols::table base_symbols;
163    rld::symbols::table symbols;
164    rld::symbols::table undefined;
165    std::string         entry;
166    std::string         output = "a.out";
167    std::string         base_name;
168    bool                script = false;
169    bool                standard_libs = true;
170    bool                exec_prefix_set = false;
171    bool                map = false;
172    bool                warnings = false;
173
174    libpaths.push_back (".");
175
176    while (true)
177    {
178      int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:", rld_opts, NULL);
179      if (opt < 0)
180        break;
181
182      switch (opt)
183      {
184        case 'V':
185          std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
186                    << std::endl;
187          ::exit (0);
188          break;
189
190        case 'v':
191          rld::verbose_inc ();
192          break;
193
194        case 'M':
195          map = true;
196          break;
197
198        case 'w':
199          warnings = true;
200          break;
201
202        case 'o':
203          if (output.size () != 0)
204            std::cerr << "error: output already set" << std::endl;
205          output = optarg;
206          break;
207
208        case 'S':
209          script = true;
210          break;
211
212        case 'l':
213          /*
214           * The order is important. It is the search order.
215           */
216          libs.push_back (optarg);
217          break;
218
219        case 'L':
220          if ((optarg[::strlen (optarg) - 1] == '/') ||
221              (optarg[::strlen (optarg) - 1] == '\\'))
222            optarg[::strlen (optarg) - 1] = '\0';
223          libpaths.push_back (optarg);
224          break;
225
226        case 'n':
227          standard_libs = false;
228          break;
229
230        case 'E':
231          exec_prefix_set = true;
232          rld::gcc::exec_prefix = optarg;
233          break;
234
235        case 'a':
236          rld::gcc::march = optarg;
237          break;
238
239        case 'c':
240          rld::gcc::mcpu = optarg;
241          break;
242
243        case 'e':
244          entry = optarg;
245          break;
246
247        case 'd':
248          symbols[optarg] = rld::symbols::symbol (optarg);
249          break;
250
251        case 'u':
252          undefined[optarg] = rld::symbols::symbol (optarg);
253          break;
254
255        case 'b':
256          base_name = optarg;
257          break;
258
259        case '?':
260          usage (3);
261          break;
262
263        case 'h':
264          usage (0);
265          break;
266      }
267    }
268
269    argc -= optind;
270    argv += optind;
271
272    if (rld::verbose () || map)
273      std::cout << "RTEMS Linker " << rld::version () << std::endl;
274
275    /*
276     * If there are no object files there is nothing to link.
277     */
278    if ((argc == 0) && !map)
279      throw rld::error ("no object files", "options");
280
281    /*
282     * Load the remaining command line arguments into the cache as object
283     * files.
284     */
285    while (argc--)
286      objects.push_back (*argv++);
287
288    /*
289     * Add the object files to the cache.
290     */
291    cache.add (objects);
292
293    /*
294     * Open the cache.
295     */
296    cache.open ();
297
298    /*
299     * If the exec-prefix is not set by the command line see if it can be
300     * detected from the object file types. This must be after we have added
301     * the object files.
302     */
303    if (!exec_prefix_set)
304      rld::gcc::exec_prefix = rld::elf::machine_type ();
305
306    /*
307     * If we have a base image add it.
308     */
309    if (base_name.length ())
310    {
311      base.open ();
312      base.add (base_name);
313      base.load_symbols (base_symbols, true);
314    }
315
316    /*
317     * Get the standard library paths
318     */
319    rld::gcc::get_standard_libpaths (libpaths);
320
321    /*
322     * Get the command line libraries.
323     */
324    rld::files::find_libraries (libraries, libpaths, libs);
325
326    /*
327     * Are we to load standard libraries ?
328     */
329    if (standard_libs)
330      rld::gcc::get_standard_libs (libraries, libpaths);
331
332    /*
333     * Load the library to the cache.
334     */
335    cache.add_libraries (libraries);
336
337    /*
338     * Load the symbol table.
339     */
340    cache.load_symbols (symbols);
341
342    /*
343     * Map ?
344     */
345    if (map)
346    {
347      if (base_name.length ())
348        rld::map (base, base_symbols);
349      rld::map (cache, symbols);
350    }
351
352    if (cache.path_count ())
353    {
354      /*
355       * This structure allows us to add different operations with the same
356       * structure.
357       */
358      rld::files::object_list dependents;
359      rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined);
360
361      /**
362       * Output the file.
363       */
364      if (script)
365        rld::outputter::script (output, dependents, cache);
366      else
367        rld::outputter::archive (output, dependents, cache);
368
369      /**
370       * Check for warnings.
371       */
372      if (warnings)
373      {
374        rld::warn_unused_externals (dependents);
375      }
376    }
377  }
378  catch (rld::error re)
379  {
380    std::cerr << "error: "
381              << re.where << ": " << re.what
382              << std::endl;
383    ec = 10;
384  }
385  catch (std::exception e)
386  {
387    int   status;
388    char* realname;
389    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
390    std::cerr << "error: std::exception: " << realname << " [";
391    ::free (realname);
392    const std::type_info &ti = typeid (e);
393    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
394    std::cerr << realname << "] " << e.what () << std::endl;
395    ::free (realname);
396    ec = 11;
397  }
398  catch (...)
399  {
400    /*
401     * Helps to know if this happens.
402     */
403    std::cout << "error: unhandled exception" << std::endl;
404    ec = 12;
405  }
406
407  return ec;
408}
Note: See TracBrowser for help on using the repository browser.