From 09469993e4e291f2ebfc8e898e6fa12e897e123d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 30 Aug 2013 21:42:58 +0800 Subject: Implement a new tool 'rtems-ra' rtems-ra supports converting an elf archive file into a rap archive file. It also support add, replace and delete rap files from the rap archive file. --- rld-outputter.cpp | 24 ++- rld-outputter.h | 3 +- rtems-ld.cpp | 2 +- rtems-ra.cpp | 621 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wscript | 13 ++ 5 files changed, 653 insertions(+), 10 deletions(-) create mode 100644 rtems-ra.cpp diff --git a/rld-outputter.cpp b/rld-outputter.cpp index 87e74f0..e00fbae 100644 --- a/rld-outputter.cpp +++ b/rld-outputter.cpp @@ -194,7 +194,8 @@ namespace rld archivera (const std::string& name, const files::object_list& dependents, files::cache& cache, - bool ra_exist) + bool ra_exist, + bool ra_rap) { files::object_list dep_copy (dependents); files::object_list objects; @@ -210,9 +211,12 @@ namespace rld { files::object& object = *(*oli); - if (object.get_archive ()) - { + if (ra_rap) objects.push_back (&object); + else + { + if (object.get_archive ()) + objects.push_back (&object); } } @@ -231,15 +235,19 @@ namespace rld * Replace the elf object file in ra file with elf object file * in collected object files, if exist. */ - for (oli = objects.begin (); oli != objects.end (); ++oli) + if (!ra_rap) { - files::object& object = *(*oli); - if (obj->name ().oname () == object.name ().oname ()) + for (oli = objects.begin (); oli != objects.end (); ++oli) { - exist = true; - break; + files::object& object = *(*oli); + if (obj->name ().oname () == object.name ().oname ()) + { + exist = true; + break; + } } } + if (!exist) objects_tmp.push_back (obj); } diff --git a/rld-outputter.h b/rld-outputter.h index 8b052e6..7fe52b2 100644 --- a/rld-outputter.h +++ b/rld-outputter.h @@ -65,7 +65,8 @@ namespace rld void archivera (const std::string& name, const files::object_list& dependents, files::cache& cache, - bool ra_exist); + bool ra_exist, + bool ra_rap); /** * Output the object file list as a script. diff --git a/rtems-ld.cpp b/rtems-ld.cpp index 6216f04..a7453cb 100644 --- a/rtems-ld.cpp +++ b/rtems-ld.cpp @@ -490,7 +490,7 @@ main (int argc, char* argv[]) } rld::outputter::archivera (outra, dependents, cachera, - !ra_exist); + !ra_exist, false); } } else diff --git a/rtems-ra.cpp b/rtems-ra.cpp new file mode 100644 index 0000000..07d2f00 --- /dev/null +++ b/rtems-ra.cpp @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS RA Linker Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like cc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "output-path", required_argument, NULL, 'p' }, + { "output", required_argument, NULL, 'o' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { "rap-strip", no_argument, NULL, 'S' }, + { "rpath", required_argument, NULL, 'R' }, + { "add-rap", required_argument, NULL, 'A' }, + { "replace-rap", required_argument, NULL, 'r' }, + { "delete-rap", required_argument, NULL, 'd' }, + { NULL, 0, NULL, 0 } +}; + +#if TO_BE_USED_FOR_THE_UNDEFINES +void +split_on_equals (const std::string& opt, std::string& left, std::string& right) +{ + std::string::size_type eq = opt.find_first_of('='); +} +#endif + +void +usage (int exit_code) +{ + std::cout << "rtems-ra [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -o name : linker output, this options is just" << std::endl + << " for waf, it will not output to file (also --output)" << std::endl + << " -p path : output path (also --output-path)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -S : do not include file details (also --rap-strip)" << std::endl + << " -R : include file paths (also --rpath)" << std::endl + << " -A : Add rap files (also --Add-rap)" << std::endl + << " -r : replace rap files (also --replace-rap)" << std::endl + << " -d : delete rap files (also --delete-rap)" << std::endl + << " -Wl,opts : link compatible flags, ignored" << std::endl + << "Output Formats:" << std::endl + << " ra - RTEMS archive container of rap files" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths libraries; + rld::files::paths outra; + rld::files::paths raps_add; + rld::files::paths raps_replace; + rld::files::paths raps_delete; + std::string cc_name; + std::string entry; + std::string exit; + std::string output_path = "./"; + std::string output = "a.ra"; + bool standard_libs = true; + bool exec_prefix_set = false; + bool convert = true; + rld::files::object_list dependents; + + libpaths.push_back ("."); + dependents.clear (); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hVvnS:a:p:L:l:o:C:E:c:R:W:A:r:d", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-ra (RTEMS Linker) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'l': + libs.push_back (optarg); + break; + + case 'A': + /* + * Add rap files to ra file. + */ + raps_add.push_back (optarg); + convert = false; + break; + + case 'r': + /* + * replace rap files to ra file. + */ + raps_replace.push_back (optarg); + convert = false; + break; + + case 'd': + /* + * delete rap files to ra file. + */ + raps_delete.push_back (optarg); + convert = false; + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'n': + standard_libs = false; + break; + + case 'p': + std::cout << "Output path: " << optarg << std::endl; + output_path = optarg; + break; + + case 'o': + output = optarg; + break; + + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case 'S': + rld::rap::add_obj_details = false; + break; + + case 'R': + rld::rap::rpath += optarg; + rld::rap::rpath += '\0'; + break; + + case 'W': + /* ignore linker compatiable flags */ + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + if (rld::verbose ()) + std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl; + + /* + * libs can be elf archive and rap archive + */ + while (argc--) + libs.push_back (*argv++); + + /* + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. + */ + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); + + if (convert) + { + /* + * Get the standard library paths + */ + if (standard_libs) + rld::cc::get_standard_libpaths (libpaths); + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::cc::get_standard_libs (libraries, libpaths); + + /* + * Convert ar file to ra file + */ + for (rld::files::paths::iterator p = libraries.begin (); p != libraries.end (); ++p) + { + rld::files::paths library; + rld::symbols::table symbols; + rld::files::cache* cache = new rld::files::cache (); + + library.clear (); + library.push_back (*p); + + /* + * Open the cache. + */ + cache->open (); + + /* + * Load the library to the cache. + */ + cache->add_libraries (library); + + cache->load_symbols (symbols); + + try + { + + rld::files::objects& objs = cache->get_objects (); + rld::files::paths raobjects; + + int pos = -1; + std::string rap_name; + for (rld::files::objects::iterator obi = objs.begin (); + obi != objs.end (); + ++obi) + { + rld::files::object* obj = (*obi).second; + + dependents.clear (); + + rap_name = obj->name ().oname (); + + pos = obj->name ().oname ().rfind ('.', rap_name.length ()); + if (pos != -1) + { + rap_name.erase (pos, rap_name.length ()); + } + + rap_name += ".rap"; + + dependents.push_back (obj); + + raobjects.push_back (rap_name); + + /* Todo: include absolute name for rap_name */ + + rld::outputter::application (rap_name, entry, exit, + dependents, *cache, symbols, + true); + } + + dependents.clear (); + for (rld::files::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni) + { + rld::files::object* obj = new rld::files::object (*ni); + dependents.push_back (obj); + } + + bool ra_rap = true; + bool ra_exist = false; + rld::files::cache cachera; + std::string raname = *p; + + pos = -1; + pos = raname.rfind ('/', raname.length ()); + if (pos != -1) + { + raname.erase (0, pos); + } + + pos = -1; + pos = raname.rfind ('.', raname.length ()); + if (pos != -1) + { + raname.erase (pos, raname.length ()); + } + raname += ".ra"; + + raname = output_path + raname; + + rld::outputter::archivera (raname, dependents, cachera, + ra_exist, ra_rap); + std::cout << "Generated: " << raname << std::endl; + + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + ::unlink (obj.name ().oname ().c_str ()); + } + } + catch (...) + { + cache->archives_end (); + throw; + } + + cache->archives_end (); + delete cache; + } + } + else + { + /* + * Add, replace, delete files from the ra file. + */ + for (rld::files::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl) + { + rld::files::paths library; + rld::files::cache* cache = new rld::files::cache (); + + library.clear (); + library.push_back (*pl); + + /* + * Open the cache. + */ + cache->open (); + + /* + * Load the library to the cache. + */ + cache->add_libraries (library); + + rld::files::objects& objs = cache->get_objects (); + rld::files::paths raobjects; + + std::string rap_name; + bool rap_delete = false; + + dependents.clear (); + /* + * Delete rap files in ra file. + */ + for (rld::files::objects::iterator obi = objs.begin (); + obi != objs.end (); + ++obi) + { + rld::files::object* obj = (*obi).second; + + rap_name = obj->name ().oname (); + rap_delete = false; + + for (rld::files::paths::iterator pa = raps_delete.begin (); + pa != raps_delete.end (); + ++pa) + { + if (*pa == rap_name) + { + rap_delete = true; + break; + } + } + + if (!rap_delete) + dependents.push_back (obj); + } + + /* + * Add rap files into ra file, add supports replace. + */ + bool rap_exist = false; + rld::files::paths rap_objects; + for (rld::files::paths::iterator pa = raps_add.begin (); + pa != raps_add.end (); + ++pa) + { + rap_exist = false; + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + if (*pa == obj.name ().oname ()) + { + rap_exist = true; + raps_replace.push_back (*pa); + break; + } + } + + if (!rap_exist) + rap_objects.push_back (*pa); + } + + for (rld::files::paths::iterator pa = rap_objects.begin (); + pa != rap_objects.end (); + ++pa) + { + rld::files::object* obj = new rld::files::object (*pa); + if (!obj->name ().exists ()) + { + delete obj; + throw rld::error ("file not exist", "rap-add"); + } + else dependents.push_back (obj); + } + + /* + * Replace rap files in ra file + */ + bool rap_replace = false; + rld::files::cache cachera; + + rap_objects.clear (); + cachera.open (); + + for (rld::files::paths::iterator pa = raps_replace.begin (); + pa != raps_replace.end (); + ++pa) + { + rap_replace = false; + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ) + { + rld::files::object& obj = *(*oi); + if (*pa == obj.name ().oname ()) + { + rap_replace = true; + dependents.erase (oi++); + break; + } + ++oi; + } + + if (rap_replace) + rap_objects.push_back (*pa); + } + + for (rld::files::paths::iterator pa = rap_objects.begin (); + pa != rap_objects.end (); + ++pa) + { + rld::files::object* obj = new rld::files::object (*pa); + if (!obj->name ().exists ()) + { + delete obj; + throw rld::error ("file not exist", "rap-add"); + } + else dependents.push_back (obj); + } + + rld::outputter::archivera (*pl, dependents, cachera, + true, true); + std::cout << "End" << std::endl; + + cache->archives_end (); + delete cache; + } + } + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl << std::flush; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cerr << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/wscript b/wscript index 6b3b70d..a7cfb96 100644 --- a/wscript +++ b/wscript @@ -127,6 +127,19 @@ def build(bld): linkflags = bld.linkflags, use = modules) + # + # Build the ra linker. + # + bld.program(target = 'rtems-ra', + source = ['rtems-ra.cpp', + 'pkgconfig.cpp'] + rld_source, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + # # Build the symbols. # -- cgit v1.2.3