From 4eb47d2965ca832243ed80f4140c34cfbed96863 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 2 Sep 2010 22:24:55 +0200 Subject: Various portability and path handling changes --- odb/odb.cxx | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 10 deletions(-) diff --git a/odb/odb.cxx b/odb/odb.cxx index a99fd83..d801e1f 100644 --- a/odb/odb.cxx +++ b/odb/odb.cxx @@ -10,6 +10,10 @@ #include // stat #include // stat +#ifdef _WIN32 +# include // _spawnvp +#endif + #include #include #include // size_t @@ -18,11 +22,21 @@ #include #include +#ifdef HAVE_CONFIG_H +# include +#endif + using namespace std; static string +driver_path (string const& driver); + +static string plugin_path (string const& driver); +inline size_t +rfind_slash (string const&); + static char const* const db_macro[] = { "-DODB_MYSQL", @@ -39,7 +53,13 @@ main (int argc, char* argv[]) // Find the plugin. It should be in the same directory as the // driver. // +#ifndef STATIC_PLUGIN string plugin (plugin_path (argv[0])); +#else + // Use a dummy name if the plugin is linked into the compiler. + // + string plugin ("odb"); +#endif if (plugin.empty ()) { @@ -56,7 +76,21 @@ main (int argc, char* argv[]) // g++ by default. // #ifdef GXX_NAME - args.push_back (GXX_NAME); + string gxx (GXX_NAME); + + // If the g++ name is a relative path (starts with '.'), then use + // our own path as base. + // + if (!gxx.empty () && gxx[0] == '.') + { + string path (driver_path (argv[0])); + size_t p (rfind_slash (path)); + + if (p != string::npos) + gxx = string (path, 0, p + 1) + gxx; + } + + args.push_back (gxx); #else args.push_back ("g++"); #endif @@ -304,20 +338,55 @@ main (int argc, char* argv[]) exec_args.push_back (0); +#ifdef _WIN32 + intptr_t r (_spawnvp (_P_WAIT, exec_args[0], &exec_args[0])); + + if (r == (intptr_t)(-1)) + { + e << exec_args[0] << ": error: " << strerror (errno) << endl; + return 1; + } + + return r == 0 ? 0 : 1; +#else if (execvp (exec_args[0], const_cast (&exec_args[0])) < 0) { e << exec_args[0] << ": error: " << strerror (errno) << endl; return 1; } +#endif +} + +// +// Path manipulation. +// + +#ifdef _WIN32 +const char dir_sep = '\\'; +const char path_sep = ';'; +#else +const char dir_sep = '/'; +const char path_sep = ':'; +#endif + +inline size_t +rfind_slash (string const& s) +{ + size_t r (s.rfind ('/')); + + if (r == string::npos) + r = s.rfind ('\\'); + + return r; } static string -plugin_path (string const& drv) +driver_path (string const& drv) { - size_t p (drv.rfind ('/')); + size_t p (rfind_slash (drv)); if (p != string::npos) - return drv + ".so"; + return drv; // Search the PATH environment variable. // @@ -329,9 +398,17 @@ plugin_path (string const& drv) if (char const* s = getenv ("PATH")) paths = s; else - paths = ":"; + paths = path_sep; + + // On Windows also check the current directory. + // +#ifdef _WIN32 + paths += path_sep; +#endif - for (size_t b (0), e (paths.find (':')); b != string::npos;) + struct stat info; + + for (size_t b (0), e (paths.find (path_sep)); b != string::npos;) { string p (paths, b, e != string::npos ? e - b : e); @@ -341,21 +418,84 @@ plugin_path (string const& drv) if (p.empty ()) p = "."; - string dp (p + (p[p.size () - 1] == '/' ? "" : "/") + drv); + string dp (p); + + char l (p[p.size () - 1]); + if (l != '/' && l != '\\') + dp += dir_sep; + + dp += 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"; + return dp; + + // On Windows also try the path with the .exe extension. + // +#ifdef _WIN32 + dp += ".exe"; + + if (stat (dp.c_str (), &info) == 0 && S_ISREG (info.st_mode)) + return dp; +#endif if (e == string::npos) b = e; else { b = e + 1; - e = paths.find (':', b); + e = paths.find (path_sep, b); + } + } + + return ""; +} + +static string +plugin_path (string const& drv) +{ + string path (driver_path (drv)); + + if (!path.empty ()) + { + // If the driver name starts with 'lt-', then we are running thought + // the libtool script. Strip this prefix -- the shared object should + // be in the same directory. + // + { + size_t p (rfind_slash (path)); + p = p != string::npos ? p + 1 : 0; + + if (p + 2 < path.size () && + path[p] == 'l' && path[p + 1] == 't' && path[p + 2] == '-') + { + path = (p != 0 ? string (path, 0, p) : string ()) + + string (path, p + 3, string::npos); + } + + } + + struct stat info; + + string so (path + ".so"); + if (stat (so.c_str (), &info) == 0) + return so; + + string la (path + ".la"); + if (stat (la.c_str (), &info) == 0) + { + size_t p (rfind_slash (path)); + + if (p != string::npos) + { + string so (path, 0, p + 1); + so += string (".libs") + dir_sep + string (path, p + 1) + ".so"; + + if (stat (so.c_str (), &info) == 0) + return so; + } } } -- cgit v1.1