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

4.104.115
Last change on this file since 7461924 was 7461924, checked in by Chris Johns <chrisj@…>, on Sep 17, 2012 at 12:13:55 AM

Rename rld-gcc. Add -C option.

Add a -C (also --cc) option to allow the CC to be used when linking to be
provided by the user rather than using the path. This support allows user
who work with the full path to tools rather than the environment to make
use of the linker without them needing to play with environment table.

Rename rld-gcc.[h.cpp] to rld-cc.[h,cpp] because gcc may not be the
only compiler/linker used by the RTEMS project.

  • Property mode set to 100644
File size: 11.6 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 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-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 cc 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  { "script",      no_argument,            NULL,           'S' },
61  { "lib-path",    required_argument,      NULL,           'L' },
62  { "lib",         required_argument,      NULL,           'l' },
63  { "no-stdlibs",  no_argument,            NULL,           'n' },
64  { "entry",       required_argument,      NULL,           'e' },
65  { "define",      required_argument,      NULL,           'd' },
66  { "undefined",   required_argument,      NULL,           'u' },
67  { "base",        required_argument,      NULL,           'b' },
68  { "cc",          required_argument,      NULL,           'C' },
69  { "exec-prefix", required_argument,      NULL,           'E' },
70  { "march",       required_argument,      NULL,           'a' },
71  { "mcpu",        required_argument,      NULL,           'c' },
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-ld [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 be supply multiple times" << std::endl
91            << "             to increase verbosity (also --verbose)" << std::endl
92            << " -w        : generate warnings (also --warn)" << std::endl
93            << " -M        : generate map output (also --map)" << std::endl
94            << " -o file   : linker output is written to file (also --output)" << std::endl
95            << " -S script : linker output is a script file (also --script)" << 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            << " -e entry  : entry point symbol (also --entry)" << std::endl
102            << " -d sym    : add the symbol definition, add multiple with" << std::endl
103            << "             more than one define (also --define)" << std::endl
104            << " -u sym    : add the undefined symbol definition, add multiple" << std::endl
105            << "             for more than one undefined symbol (also --undefined)" << std::endl
106            << " -b elf    : read the ELF file symbols as the base RTEMS kernel" << std::endl
107            << "             image (also --base)" << std::endl
108            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
109            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
110            << " -a march  : machine architecture (also --march)" << std::endl
111            << " -c cpu    : machine architecture's CPU (also --mcpu)" << 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::cache   cache;
159    rld::files::cache   base;
160    rld::files::paths   libpaths;
161    rld::files::paths   libs;
162    rld::files::paths   objects;
163    rld::files::paths   libraries;
164    rld::symbols::table base_symbols;
165    rld::symbols::table symbols;
166    rld::symbols::table undefined;
167    std::string         entry;
168    std::string         output = "a.out";
169    std::string         base_name;
170    std::string         cc_name;
171    bool                script = false;
172    bool                standard_libs = true;
173    bool                exec_prefix_set = false;
174    bool                map = false;
175    bool                warnings = false;
176
177    libpaths.push_back (".");
178
179    while (true)
180    {
181      int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL);
182      if (opt < 0)
183        break;
184
185      switch (opt)
186      {
187        case 'V':
188          std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
189                    << std::endl;
190          ::exit (0);
191          break;
192
193        case 'v':
194          rld::verbose_inc ();
195          break;
196
197        case 'M':
198          map = true;
199          break;
200
201        case 'w':
202          warnings = true;
203          break;
204
205        case 'o':
206          if (output.size () != 0)
207            std::cerr << "error: output already set" << std::endl;
208          output = optarg;
209          break;
210
211        case 'S':
212          script = true;
213          break;
214
215        case 'l':
216          /*
217           * The order is important. It is the search order.
218           */
219          libs.push_back (optarg);
220          break;
221
222        case 'L':
223          if ((optarg[::strlen (optarg) - 1] == '/') ||
224              (optarg[::strlen (optarg) - 1] == '\\'))
225            optarg[::strlen (optarg) - 1] = '\0';
226          libpaths.push_back (optarg);
227          break;
228
229        case 'n':
230          standard_libs = false;
231          break;
232
233        case 'C':
234          if (exec_prefix_set == true)
235            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
236          rld::cc::cc = optarg;
237          break;
238
239        case 'E':
240          exec_prefix_set = true;
241          rld::cc::exec_prefix = optarg;
242          break;
243
244        case 'a':
245          rld::cc::march = optarg;
246          break;
247
248        case 'c':
249          rld::cc::mcpu = optarg;
250          break;
251
252        case 'e':
253          entry = optarg;
254          break;
255
256        case 'd':
257          symbols[optarg] = rld::symbols::symbol (optarg);
258          break;
259
260        case 'u':
261          undefined[optarg] = rld::symbols::symbol (optarg);
262          break;
263
264        case 'b':
265          base_name = optarg;
266          break;
267
268        case '?':
269          usage (3);
270          break;
271
272        case 'h':
273          usage (0);
274          break;
275      }
276    }
277
278    argc -= optind;
279    argv += optind;
280
281    if (rld::verbose () || map)
282      std::cout << "RTEMS Linker " << rld::version () << std::endl;
283
284    /*
285     * If there are no object files there is nothing to link.
286     */
287    if ((argc == 0) && !map)
288      throw rld::error ("no object files", "options");
289
290    /*
291     * Load the remaining command line arguments into the cache as object
292     * files.
293     */
294    while (argc--)
295      objects.push_back (*argv++);
296
297    /*
298     * Add the object files to the cache.
299     */
300    cache.add (objects);
301
302    /*
303     * Open the cache.
304     */
305    cache.open ();
306
307    /*
308     * If the full path to CC is not provided and the exec-prefix is not set by
309     * the command line see if it can be detected from the object file
310     * types. This must be after we have added the object files because they
311     * are used when detecting.
312     */
313    if (rld::cc::cc.empty () && !exec_prefix_set)
314      rld::cc::exec_prefix = rld::elf::machine_type ();
315
316    /*
317     * If we have a base image add it.
318     */
319    if (base_name.length ())
320    {
321      base.open ();
322      base.add (base_name);
323      base.load_symbols (base_symbols, true);
324    }
325
326    /*
327     * Get the standard library paths
328     */
329    rld::cc::get_standard_libpaths (libpaths);
330
331    /*
332     * Get the command line libraries.
333     */
334    rld::files::find_libraries (libraries, libpaths, libs);
335
336    /*
337     * Are we to load standard libraries ?
338     */
339    if (standard_libs)
340      rld::cc::get_standard_libs (libraries, libpaths);
341
342    /*
343     * Load the library to the cache.
344     */
345    cache.add_libraries (libraries);
346
347    /*
348     * Load the symbol table.
349     */
350    cache.load_symbols (symbols);
351
352    /*
353     * Map ?
354     */
355    if (map)
356    {
357      if (base_name.length ())
358        rld::map (base, base_symbols);
359      rld::map (cache, symbols);
360    }
361
362    if (cache.path_count ())
363    {
364      /*
365       * This structure allows us to add different operations with the same
366       * structure.
367       */
368      rld::files::object_list dependents;
369      rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined);
370
371      /**
372       * Output the file.
373       */
374      if (script)
375        rld::outputter::script (output, dependents, cache);
376      else
377        rld::outputter::archive (output, dependents, cache);
378
379      /**
380       * Check for warnings.
381       */
382      if (warnings)
383      {
384        rld::warn_unused_externals (dependents);
385      }
386    }
387  }
388  catch (rld::error re)
389  {
390    std::cerr << "error: "
391              << re.where << ": " << re.what
392              << std::endl;
393    ec = 10;
394  }
395  catch (std::exception e)
396  {
397    int   status;
398    char* realname;
399    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
400    std::cerr << "error: std::exception: " << realname << " [";
401    ::free (realname);
402    const std::type_info &ti = typeid (e);
403    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
404    std::cerr << realname << "] " << e.what () << std::endl;
405    ::free (realname);
406    ec = 11;
407  }
408  catch (...)
409  {
410    /*
411     * Helps to know if this happens.
412     */
413    std::cout << "error: unhandled exception" << std::endl;
414    ec = 12;
415  }
416
417  return ec;
418}
Note: See TracBrowser for help on using the repository browser.