From c4847167addffd5b294628b731e320a3d751c7b8 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 9 Mar 2010 17:11:41 +0200 Subject: Implement ODB compiler driver --- odb/odb.cxx | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 odb/odb.cxx (limited to 'odb/odb.cxx') diff --git a/odb/odb.cxx b/odb/odb.cxx new file mode 100644 index 0000000..70fc8f2 --- /dev/null +++ b/odb/odb.cxx @@ -0,0 +1,282 @@ +// file : odb/odb.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include // getenv +#include // strerror +#include // stat, execvp +#include // stat +#include // stat + +#include +#include +#include // size_t +#include + +using namespace std; + +static string +plugin_path (string const& driver); + +int +main (int argc, char* argv[]) +{ + typedef vector strings; + + string file; + strings args; + bool v (false); + + // Find the plugin. It should be in the same directory as the + // driver. + // + string plugin (plugin_path (argv[0])); + + if (plugin.empty ()) + { + cerr << argv[0] << ": error: unable to locate ODB plugin" << endl; + cerr << argv[0] << ": info: make sure '" << argv[0] << ".so' is in " + << "the same directory as '" << argv[0] << "'" << endl; + return 1; + } + + // The first argument points to the program name, which is + // g++ by default. + // + args.push_back ("g++"); + + // Default options. + // + args.push_back ("-x"); + args.push_back ("c++"); + args.push_back ("-S"); + args.push_back ("-fplugin=" + plugin); + + for (int i = 1; i < argc; ++i) + { + string a (argv[i]); + size_t n (a.size ()); + + // -v + // + if (a == "-v") + { + v = true; + args.push_back (a); + } + // -x + // + else if (a == "-x") + { + if (++i == argc || argv[i][0] == '\0') + { + cerr << argv[0] << ": error: expected argument for the -x option" + << endl; + return 1; + } + + a = argv[i]; + + if (a[0] == '-') + args.push_back (a); + else + { + // This must be the g++ executable name. Update the first + // argument with it. + // + args[0] = a; + } + } + // -I + // + else if (n > 1 && a[0] == '-' && a[1] == 'I') + { + args.push_back (a); + + if (n == 2) // -I /path + { + if (++i == argc || argv[i][0] == '\0') + { + cerr << argv[0] << ": error: expected argument for the -I option" + << endl; + return 1; + } + + args.push_back (argv[i]); + } + } + // -D + // + else if (n > 1 && a[0] == '-' && a[1] == 'D') + { + args.push_back (a); + + if (n == 2) // -D macro + { + if (++i == argc || argv[i][0] == '\0') + { + cerr << argv[0] << ": error: expected argument for the -D option" + << endl; + return 1; + } + + args.push_back (argv[i]); + } + } + // -U + // + else if (n > 1 && a[0] == '-' && a[1] == 'U') + { + args.push_back (a); + + if (n == 2) // -U macro + { + if (++i == argc || argv[i][0] == '\0') + { + cerr << argv[0] << ": error: expected argument for the -U option" + << endl; + return 1; + } + + args.push_back (argv[i]); + } + } + // Everything else except the last argument (file to compile) is passed + // to the plugin. + // + else + { + if (n > 1 && a[0] == '-') + { + string k, v; + + if (n > 2 && a[1] == '-') + k = string (a, 2); // long format + else + k = string (a, 1); // short format + + // If the next argument is not the last, then we may have a + // value. + // + if (i + 2 < argc) + { + a = argv[i + 1]; + n = a.size (); + + if (n > 1 && a[0] != '-') + { + v = a; + ++i; + } + } + + string o ("-fplugin-arg-odb-"); + o += k; + + if (!v.empty ()) + { + o += '='; + o += v; + } + + args.push_back (o); + } + else + { + if (file.empty ()) + file = a; + else + { + cerr << argv[0] << ": error: second input file specified: '" + << a << "'" << endl; + return 1; + } + } + } + } + + if (file.empty ()) + { + cerr << argv[0] << ": error: input file expected" << endl; + return 1; + } + + args.push_back (file); + + // Create an execvp-compatible argument array. + // + vector exec_args; + + for (strings::const_iterator i (args.begin ()), e (args.end ()); + i != e; ++i) + { + exec_args.push_back (i->c_str ()); + + if (v) + cerr << *i << ' '; + } + + if (v) + cerr << endl; + + exec_args.push_back (0); + + if (execvp (exec_args[0], const_cast (&exec_args[0])) < 0) + { + cerr << exec_args[0] << ": error: " << strerror (errno) << endl; + return 1; + } +} + +static string +plugin_path (string const& drv) +{ + size_t p (drv.rfind ('/')); + + if (p != string::npos) + return drv + ".so"; + + // Search the PATH environment variable. + // + string paths; + + // If there is no PATH in environment then the default search + // path is the current directory. + // + if (char const* s = getenv ("PATH")) + paths = s; + else + paths = ":"; + + for (size_t b (0), e (paths.find (':')); b != string::npos;) + { + string p (paths, b, e - b); + + // Empty path (i.e., a double colon or a colon at the beginning + // or end of PATH) means search in the current dirrectory. + // + if (p.empty ()) + p = "."; + + string dp (p + (p[p.size () - 1] == '/' ? "" : "/") + drv); + + // Just check that the file exist without checking for + // permissions, etc. + // + struct stat info; + if (stat (dp.c_str (), &info) == 0 && S_ISREG (info.st_mode)) + return dp + ".so"; + + if (e == string::npos) + b = e; + else + { + b = e + 1; + e = paths.find (':', b); + } + } + + return ""; +} -- cgit v1.1