From d1ad30f7a517e69bc87d1347224f1c9ab38493b3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 25 Oct 2012 10:35:36 +0200 Subject: Static multi-database support Add new options (--multi-database, --default-database). Generate common code to -odb.?xx files and database-specific to -odb-.?xx. --- odb/odb.cxx | 658 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 346 insertions(+), 312 deletions(-) (limited to 'odb/odb.cxx') diff --git a/odb/odb.cxx b/odb/odb.cxx index e18feeb..b80f577 100644 --- a/odb/odb.cxx +++ b/odb/odb.cxx @@ -123,6 +123,7 @@ profile_paths (strings const& args, char const* name); static char const* const db_macro[] = { + "-DODB_DATABASE_COMMON", "-DODB_DATABASE_MSSQL", "-DODB_DATABASE_MYSQL", "-DODB_DATABASE_ORACLE", @@ -491,7 +492,9 @@ main (int argc, char* argv[]) oi[1].option = "-p"; oi[2].option = "--profile"; - database db; + vector dbs; + bool show_sloc; + size_t sloc_limit; { oi[1].search_func = &profile_search_ignore; oi[2].search_func = &profile_search_ignore; @@ -527,14 +530,24 @@ main (int argc, char* argv[]) // Check that required options were specifed. // - if (!ops.database_specified ()) + dbs = ops.database (); + + if (dbs.empty ()) { e << argv[0] << ": error: no database specified with the --database " << "option" << endl; return 1; } - db = ops.database (); + if (dbs.size () > 1 && !ops.multi_database_specified ()) + { + e << argv[0] << ": error: --multi-database option required when " << + "multiple databases are specified"<< endl; + return 1; + } + + show_sloc = ops.show_sloc (); + sloc_limit = ops.sloc_limit_specified () ? ops.sloc_limit () : 0; // Translate some ODB options to GCC options. // @@ -566,26 +579,15 @@ main (int argc, char* argv[]) e << " " << *i << endl; } - // Second parse. + // Pass profile search paths (svc-path option). // - profile_data pd (prof_paths, db, argv[0]); - oi[1].search_func = &profile_search; - oi[2].search_func = &profile_search; - oi[1].arg = &pd; - oi[2].arg = &pd; - - cli::argv_file_scanner scan (ac, &av[0], oi, 3); - options ops (scan); - - size_t end (scan.end () - 1); // We have one less in plugin_args. - - if (end == plugin_args.size ()) + for (paths::const_iterator i (prof_paths.begin ()); + i != prof_paths.end (); ++i) { - e << argv[0] << ": error: input file expected" << endl; - return 1; + args.push_back (encode_plugin_option ("svc-path", i->string ())); } - // Add ODB macros. + // Add common ODB macros. // args.push_back ("-DODB_COMPILER"); @@ -595,396 +597,428 @@ main (int argc, char* argv[]) args.push_back ("-DODB_COMPILER_VERSION=" + ostr.str ()); } - args.push_back (db_macro[ops.database ()]); - - // Encode plugin options. + // Compile for each database. // - cli::options const& desc (options::description ()); - for (size_t i (0); i < end; ++i) + size_t sloc_total (0); + + for (vector::iterator i (dbs.begin ()); i != dbs.end (); ++i) { - string k, v; - string a (plugin_args[i]); + database db (*i); + strings db_args (args); - // Ignore certain options. + // Add database-specific ODB macro. // - if (a == "--") - { - // Ignore the option seperator since GCC doesn't understand it. - // - continue; - } - else if (a == "--std") - { - // Translated to GCC -std=. - // - ++i; - continue; - } + db_args.push_back (db_macro[db]); + + // Second parse. + // + profile_data pd (prof_paths, db, argv[0]); + oi[1].search_func = &profile_search; + oi[2].search_func = &profile_search; + oi[1].arg = &pd; + oi[2].arg = &pd; - cli::options::const_iterator it (desc.find (a)); + cli::argv_file_scanner scan (ac, &av[0], oi, 3); + options ops (scan); - if (it == desc.end ()) + size_t end (scan.end () - 1); // We have one less in plugin_args. + + if (end == plugin_args.size ()) { - e << argv[0] << ": ice: unexpected option '" << a << "'" << endl; + e << argv[0] << ": error: input file expected" << endl; return 1; } - if (a.size () > 2 && a[0] == '-' && a[1] == '-') - k = string (a, 2); // long format - else - k = string (a, 1); // short format - - // If there are more arguments then we may have a value. + // Encode plugin options. // - if (!it->flag ()) + cli::options const& desc (options::description ()); + for (size_t i (0); i < end; ++i) { - if (i + 1 == end) + string k, v; + string a (plugin_args[i]); + + // Ignore certain options. + // + if (a == "--") { - e << argv[0] << ": ice: expected argument for '" << a << "'" << endl; - return 1; + // Ignore the option seperator since GCC doesn't understand it. + // + continue; + } + else if (a == "--std") + { + // Translated to GCC -std=. + // + ++i; + continue; + } + else if (a == "-d" || a == "--databse") + { + // Ignore all other databases. + // + if (plugin_args[i + 1] != db.string ()) + { + ++i; + continue; + } } - v = plugin_args[++i]; - } - - args.push_back (encode_plugin_option (k, v)); - } - - // Pass profile search paths (svc-path option). - // - for (paths::const_iterator i (prof_paths.begin ()); - i != prof_paths.end (); ++i) - { - args.push_back (encode_plugin_option ("svc-path", i->string ())); - } - - // Reserve space for and remember the position of the svc-file - // option. - // - size_t svc_file_pos (args.size ()); - args.push_back (""); - - // If compiling multiple input files at once, pass them also with - // the --svc-file option. - // - bool at_once (ops.at_once () && plugin_args.size () - end > 1); - if (at_once) - { - if (ops.output_name ().empty ()) - { - e << "error: --output-name required when compiling multiple " << - "input files at once (--at-once)" << endl; - return 1; - } - - for (size_t i (end); i < plugin_args.size (); ++i) - args.push_back (encode_plugin_option ("svc-file", plugin_args[i])); - } + cli::options::const_iterator it (desc.find (a)); - // Create an execvp-compatible argument array. - // - typedef vector cstrings; - cstrings exec_args; + if (it == desc.end ()) + { + e << argv[0] << ": ice: unexpected option '" << a << "'" << endl; + return 1; + } - for (strings::const_iterator i (args.begin ()), end (args.end ()); - i != end; ++i) - { - exec_args.push_back (i->c_str ()); - } + if (a.size () > 2 && a[0] == '-' && a[1] == '-') + k = string (a, 2); // long format + else + k = string (a, 1); // short format - exec_args.push_back ("-"); // Compile stdin. - exec_args.push_back (0); + // If there are more arguments then we may have a value. + // + if (!it->flag ()) + { + if (i + 1 == end) + { + e << argv[0] << ": ice: expected argument for '" << a << "'" + << endl; + return 1; + } - // Iterate over the input files and compile each of them. - // - size_t sloc_total (0); + v = plugin_args[++i]; + } - for (; end < plugin_args.size (); ++end) - { - string name (at_once ? ops.output_name () : plugin_args[end]); + db_args.push_back (encode_plugin_option (k, v)); + } - // Set the --svc-file option. + // Reserve space for and remember the position of the svc-file + // option. // - args[svc_file_pos] = encode_plugin_option ("svc-file", name); - exec_args[svc_file_pos] = args[svc_file_pos].c_str (); + size_t svc_file_pos (db_args.size ()); + db_args.push_back (""); + // If compiling multiple input files at once, pass them also with + // the --svc-file option. // - // - ifstream ifs; - - if (!at_once) + bool at_once (ops.at_once () && plugin_args.size () - end > 1); + if (at_once) { - ifs.open (name.c_str (), ios_base::in | ios_base::binary); - - if (!ifs.is_open ()) + if (ops.output_name ().empty ()) { - e << name << ": error: unable to open in read mode" << endl; + e << "error: --output-name required when compiling multiple " << + "input files at once (--at-once)" << endl; return 1; } - } - if (v) - { - e << "Compiling " << name << endl; - for (cstrings::const_iterator i (exec_args.begin ()); - i != exec_args.end (); ++i) - { - if (*i != 0) - e << *i << (*(i + 1) != 0 ? ' ' : '\n'); - } + for (size_t i (end); i < plugin_args.size (); ++i) + db_args.push_back ( + encode_plugin_option ("svc-file", plugin_args[i])); } - process_info pi (start_process (&exec_args[0], argv[0], false, true)); + // Create an execvp-compatible argument array. + // + typedef vector cstrings; + cstrings exec_args; + for (strings::const_iterator i (db_args.begin ()), end (db_args.end ()); + i != end; ++i) { - __gnu_cxx::stdio_filebuf fb ( - pi.out_fd, ios_base::out | ios_base::binary); - ostream os (&fb); + exec_args.push_back (i->c_str ()); + } - if (!ops.trace ()) - { - // Add the standard prologue. - // - os << "#line 1 \"\"" << endl; + exec_args.push_back ("-"); // Compile stdin. + exec_args.push_back (0); - // Make sure ODB compiler and libodb versions are compatible. - // - os << "#include " << endl - << endl - << "#if ODB_VERSION != " << ODB_VERSION << endl - << "# error incompatible ODB compiler and runtime " << - "versions" << endl - << "#endif" << endl - << endl; - - // Add ODB compiler metaprogramming tests. - // - os << "namespace odb" << endl - << "{" << endl - << "namespace compiler" << endl - << "{" << endl; + // Iterate over the input files and compile each of them. + // + for (; end < plugin_args.size (); ++end) + { + string name (at_once ? ops.output_name () : plugin_args[end]); - // operator< test, used in validator. - // - os << "template " << endl - << "bool" << endl - << "has_lt_operator (const T& x, const T& y)" << endl - << "{" << endl - << "bool r (x < y);" << endl - << "return r;" << endl - << "}" << endl; - - os << "}" << endl - << "}" << endl; - } + // Set the --svc-file option. + // + db_args[svc_file_pos] = encode_plugin_option ("svc-file", name); + exec_args[svc_file_pos] = db_args[svc_file_pos].c_str (); - // Add custom prologue if any. // - // NOTE: if you change the format, you also need to update code - // in include.cxx // - strings const& pro (ops.odb_prologue ()); - for (size_t i (0); i < pro.size (); ++i) - { - os << "#line 1 \"\"" << endl - << pro[i] - << endl; - } + ifstream ifs; - strings const& prof (ops.odb_prologue_file ()); - for (size_t i (0); i < prof.size (); ++i) + if (!at_once) { - os << "#line 1 \"\"" - << endl; - - ifstream ifs (prof[i].c_str (), ios_base::in | ios_base::binary); + ifs.open (name.c_str (), ios_base::in | ios_base::binary); if (!ifs.is_open ()) { - e << prof[i] << ": error: unable to open in read mode" << endl; - fb.close (); - wait_process (pi, argv[0]); + e << name << ": error: unable to open in read mode" << endl; return 1; } + } - if (!(os << ifs.rdbuf ())) + if (v) + { + e << "Compiling " << name << endl; + for (cstrings::const_iterator i (exec_args.begin ()); + i != exec_args.end (); ++i) { - e << prof[i] << ": error: io failure" << endl; - fb.close (); - wait_process (pi, argv[0]); - return 1; + if (*i != 0) + e << *i << (*(i + 1) != 0 ? ' ' : '\n'); } - - os << endl; } - if (at_once) - { - // Include all the input files (no need to escape). - // - os << "#line 1 \"\"" << endl; + process_info pi (start_process (&exec_args[0], argv[0], false, true)); - bool b (ops.include_with_brackets ()); - char op (b ? '<' : '"'), cl (b ? '>' : '"'); - - for (; end < plugin_args.size (); ++end) - os << "#include " << op << plugin_args[end] << cl << endl; - } - else { - // Write the synthesized translation unit to stdout. - // - os << "#line 1 \"" << escape_path (name) << "\"" << endl; + __gnu_cxx::stdio_filebuf fb ( + pi.out_fd, ios_base::out | ios_base::binary); + ostream os (&fb); - if (!(os << ifs.rdbuf ())) + if (!ops.trace ()) { - e << name << ": error: io failure" << endl; - fb.close (); - wait_process (pi, argv[0]); - return 1; + // Add the standard prologue. + // + os << "#line 1 \"\"" << endl; + + // Make sure ODB compiler and libodb versions are compatible. + // + os << "#include " << endl + << endl + << "#if ODB_VERSION != " << ODB_VERSION << endl + << "# error incompatible ODB compiler and runtime " << + "versions" << endl + << "#endif" << endl + << endl; + + // Add ODB compiler metaprogramming tests. + // + os << "namespace odb" << endl + << "{" << endl + << "namespace compiler" << endl + << "{" << endl; + + // operator< test, used in validator. + // + os << "template " << endl + << "bool" << endl + << "has_lt_operator (const T& x, const T& y)" << endl + << "{" << endl + << "bool r (x < y);" << endl + << "return r;" << endl + << "}" << endl; + + os << "}" << endl + << "}" << endl; } - // Add a new line in case the input file doesn't end with one. + // Add custom prologue if any. // - os << endl; - } + // NOTE: if you change the format, you also need to update code + // in include.cxx + // + strings const& pro (ops.odb_prologue ()); + for (size_t i (0); i < pro.size (); ++i) + { + os << "#line 1 \"\"" << endl + << pro[i] << endl; + } - // Add custom epilogue if any. - // - // NOTE: if you change the format, you also need to update code - // in include.cxx - // - strings const& epi (ops.odb_epilogue ()); - for (size_t i (0); i < epi.size (); ++i) - { - os << "#line 1 \"\"" << endl - << epi[i] - << endl; - } + strings const& prof (ops.odb_prologue_file ()); + for (size_t i (0); i < prof.size (); ++i) + { + os << "#line 1 \"\"" + << endl; - strings const& epif (ops.odb_epilogue_file ()); - for (size_t i (0); i < epif.size (); ++i) - { - os << "#line 1 \"\"" - << endl; + ifstream ifs (prof[i].c_str (), ios_base::in | ios_base::binary); - ifstream ifs (epif[i].c_str (), ios_base::in | ios_base::binary); + if (!ifs.is_open ()) + { + e << prof[i] << ": error: unable to open in read mode" << endl; + fb.close (); + wait_process (pi, argv[0]); + return 1; + } - if (!ifs.is_open ()) - { - e << epif[i] << ": error: unable to open in read mode" << endl; - fb.close (); - wait_process (pi, argv[0]); - return 1; + if (!(os << ifs.rdbuf ())) + { + e << prof[i] << ": error: io failure" << endl; + fb.close (); + wait_process (pi, argv[0]); + return 1; + } + + os << endl; } - if (!(os << ifs.rdbuf ())) + if (at_once) { - e << epif[i] << ": error: io failure" << endl; - fb.close (); - wait_process (pi, argv[0]); - return 1; + // Include all the input files (no need to escape). + // + os << "#line 1 \"\"" << endl; + + bool b (ops.include_with_brackets ()); + char op (b ? '<' : '"'), cl (b ? '>' : '"'); + + for (; end < plugin_args.size (); ++end) + os << "#include " << op << plugin_args[end] << cl << endl; } + else + { + // Write the synthesized translation unit to stdout. + // + os << "#line 1 \"" << escape_path (name) << "\"" << endl; - os << endl; - } + if (!(os << ifs.rdbuf ())) + { + e << name << ": error: io failure" << endl; + fb.close (); + wait_process (pi, argv[0]); + return 1; + } - if (!ops.trace ()) - { - // Add the standard epilogue at the end so that we see all - // the declarations. - // - os << "#line 1 \"\"" << endl; + // Add a new line in case the input file doesn't end with one. + // + os << endl; + } - // Includes for standard smart pointers. The Boost TR1 header - // may or may not delegate to the GCC implementation. In either - // case, the necessary declarations will be provided so we don't - // need to do anything. + // Add custom epilogue if any. // - os << "#include " << endl - << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl - << "# include " << endl - << "#endif" << endl; - - // Standard wrapper traits. + // NOTE: if you change the format, you also need to update code + // in include.cxx // - os << "#include " << endl - << "#include " << endl; + strings const& epi (ops.odb_epilogue ()); + for (size_t i (0); i < epi.size (); ++i) + { + os << "#line 1 \"\"" << endl + << epi[i] << endl; + } - // Standard pointer traits. - // - os << "#include " << endl - << "#include " << endl; + strings const& epif (ops.odb_epilogue_file ()); + for (size_t i (0); i < epif.size (); ++i) + { + os << "#line 1 \"\"" + << endl; - // Standard container traits. - // - os << "#include " << endl; - } - } + ifstream ifs (epif[i].c_str (), ios_base::in | ios_base::binary); - // Filter the output stream looking for communication from the - // plugin. - // - { - __gnu_cxx::stdio_filebuf fb (pi.in_ofd, ios_base::in); - istream is (&fb); + if (!ifs.is_open ()) + { + e << epif[i] << ": error: unable to open in read mode" << endl; + fb.close (); + wait_process (pi, argv[0]); + return 1; + } - for (bool first (true); !is.eof (); ) - { - string line; - getline (is, line); + if (!(os << ifs.rdbuf ())) + { + e << epif[i] << ": error: io failure" << endl; + fb.close (); + wait_process (pi, argv[0]); + return 1; + } - if (is.fail () && !is.eof ()) + os << endl; + } + + if (!ops.trace ()) { - e << argv[0] << ": error: io failure while parsing output" << endl; - wait_process (pi, argv[0]); - return 1; + // Add the standard epilogue at the end so that we see all + // the declarations. + // + os << "#line 1 \"\"" << endl; + + // Includes for standard smart pointers. The Boost TR1 header + // may or may not delegate to the GCC implementation. In either + // case, the necessary declarations will be provided so we don't + // need to do anything. + // + os << "#include " << endl + << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl + << "# include " << endl + << "#endif" << endl; + + // Standard wrapper traits. + // + os << "#include " << endl + << "#include " << endl; + + // Standard pointer traits. + // + os << "#include " << endl + << "#include " << endl; + + // Standard container traits. + // + os << "#include " << endl; } + } - if (line.compare (0, 9, "odb:sloc:") == 0) + // Filter the output stream looking for communication from the + // plugin. + // + { + __gnu_cxx::stdio_filebuf fb (pi.in_ofd, ios_base::in); + istream is (&fb); + + for (bool first (true); !is.eof (); ) { - if (ops.show_sloc () || ops.sloc_limit_specified ()) + string line; + getline (is, line); + + if (is.fail () && !is.eof ()) { - size_t n; - istringstream is (string (line, 9, string::npos)); + e << argv[0] << ": error: io failure while parsing output" + << endl; + wait_process (pi, argv[0]); + return 1; + } - if (!(is >> n && is.eof ())) + if (line.compare (0, 9, "odb:sloc:") == 0) + { + if (show_sloc || sloc_limit != 0) { - e << argv[0] << ": error: invalid odb:sloc value" << endl; - wait_process (pi, argv[0]); - return 1; + size_t n; + istringstream is (string (line, 9, string::npos)); + + if (!(is >> n && is.eof ())) + { + e << argv[0] << ": error: invalid odb:sloc value" << endl; + wait_process (pi, argv[0]); + return 1; + } + + sloc_total += n; } - sloc_total += n; + continue; } - continue; - } - - if (first) - first = false; - else - cout << endl; + if (first) + first = false; + else + cout << endl; - cout << line; + cout << line; + } } - } - if (!wait_process (pi, argv[0])) - return 1; - } + if (!wait_process (pi, argv[0])) + return 1; + } // End input file loop. + } // End database loop. // Handle SLOC. // - if (ops.show_sloc ()) + if (show_sloc) e << "total: " << sloc_total << endl; - if (ops.sloc_limit_specified () && ops.sloc_limit () < sloc_total) + if (sloc_limit != 0 && sloc_limit < sloc_total) { - e << argv[0] << ": error: SLOC limit of " << ops.sloc_limit () - << " lines has been exceeded" << endl; + e << argv[0] << ": error: SLOC limit of " << sloc_limit << " lines " << + "has been exceeded" << endl; - if (!ops.show_sloc ()) + if (!show_sloc) e << argv[0] << ": info: use the --show-sloc option to see the " << "current total" << endl; -- cgit v1.1