aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-09-12 14:28:03 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-09-12 14:28:03 +0200
commitc0931400a1c5f02cf145c90fd7e34216836efd88 (patch)
tree5e13c5864e5f3c944a316f9189eb87976c8908c0
parentf01ad68661d62af62087b7b1ae29628f028e9eaa (diff)
Implement --output-name, --generate-schema-only, and --at-once options
-rw-r--r--NEWS13
-rw-r--r--odb/common.cxx2
-rw-r--r--odb/context.cxx25
-rw-r--r--odb/context.hxx8
-rw-r--r--odb/generator.cxx120
-rw-r--r--odb/generator.hxx5
-rw-r--r--odb/header.cxx8
-rw-r--r--odb/odb.cxx86
-rw-r--r--odb/option-functions.cxx6
-rw-r--r--odb/options.cli26
-rw-r--r--odb/plugin.cxx18
-rw-r--r--odb/relational/header.hxx4
-rw-r--r--odb/relational/inline.hxx2
-rw-r--r--odb/relational/model.hxx2
-rw-r--r--odb/relational/schema-source.hxx2
-rw-r--r--odb/relational/source.hxx2
-rw-r--r--odb/validator.cxx19
17 files changed, 236 insertions, 112 deletions
diff --git a/NEWS b/NEWS
index 1e06550..ad93c1f 100644
--- a/NEWS
+++ b/NEWS
@@ -68,6 +68,19 @@ Version 2.1.0
"PostgreSQL Type Mapping" and 17.1, "SQL Server Type Mapping" in the
ODB manual.
+ * New option, --output-name, specifies the alternative base name used to
+ construct the names of the generated files. Refer to the ODB compiler
+ command line interface documentation (man pages) for details.
+
+ * New option, --generate-schema-only, instructs the ODB compiler to
+ generate the database schema only. Refer to the ODB compiler command
+ line interface documentation (man pages) for details.
+
+ * New option, --at-once, triggers the generation of code for all the input
+ files as well as for all the files that they include at once. Refer to
+ the ODB compiler command line interface documentation (man pages) for
+ details.
+
* The id() pragma that was used to declare a persistent class without an
object id has been renamed to no_id.
diff --git a/odb/common.cxx b/odb/common.cxx
index 667afc0..be8e6c5 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -599,7 +599,7 @@ check (semantics::typedefs& t)
//
if (!included_)
{
- if (class_file (*ci) != unit.file ())
+ if (!options.at_once () && class_file (*ci) != unit.file ())
return false;
}
diff --git a/odb/context.cxx b/odb/context.cxx
index fab5432..099b10b 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -2100,28 +2100,3 @@ process_include_path (string const& ip, bool prefix, char open)
return r;
}
-
-// namespace
-//
-
-void namespace_::
-traverse (type& ns)
-{
- // Only traverse namespaces from the main file.
- //
- if (ns.file () == unit.file ())
- {
- string name (ns.name ());
-
- if (name.empty ())
- os << "namespace";
- else
- os << "namespace " << name;
-
- os << "{";
-
- traversal::namespace_::traverse (ns);
-
- os << "}";
- }
-}
diff --git a/odb/context.hxx b/odb/context.hxx
index dc5eb05..8ae110a 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -1050,12 +1050,4 @@ has (Y& y)
return false;
}
-// Standard namespace traverser.
-//
-struct namespace_: traversal::namespace_, context
-{
- virtual void
- traverse (type&);
-};
-
#endif // ODB_CONTEXT_HXX
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 26efedf..630d320 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -25,6 +25,7 @@ using namespace std;
using namespace cutl;
using semantics::path;
+typedef vector<path> paths;
namespace
{
@@ -67,7 +68,8 @@ void generator::
generate (options const& ops,
features& fts,
semantics::unit& unit,
- path const& p)
+ path const& p,
+ paths const& inputs)
{
try
{
@@ -95,7 +97,9 @@ generate (options const& ops,
// Output files.
//
- path file (p.leaf ());
+ path file (ops.output_name ().empty ()
+ ? p.leaf ()
+ : path (ops.output_name ()).leaf ());
string base (file.base ().string ());
fs::auto_removes auto_rm;
@@ -122,52 +126,69 @@ generate (options const& ops,
sql_path = dir / sql_path;
}
+ bool gen_cxx (!ops.generate_schema_only ());
+
//
//
- ofstream hxx (hxx_path.string ().c_str ());
+ ofstream hxx;
- if (!hxx.is_open ())
+ if (gen_cxx)
{
- cerr << "error: unable to open '" << hxx_path << "' in write mode"
- << endl;
- throw failed ();
- }
+ hxx.open (hxx_path.string ().c_str (), ios_base::out);
+
+ if (!hxx.is_open ())
+ {
+ cerr << "error: unable to open '" << hxx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
- auto_rm.add (hxx_path);
+ auto_rm.add (hxx_path);
+ }
//
//
- ofstream ixx (ixx_path.string ().c_str ());
+ ofstream ixx;
- if (!ixx.is_open ())
+ if (gen_cxx)
{
- cerr << "error: unable to open '" << ixx_path << "' in write mode"
- << endl;
- throw failed ();
- }
+ ixx.open (ixx_path.string ().c_str (), ios_base::out);
+
+ if (!ixx.is_open ())
+ {
+ cerr << "error: unable to open '" << ixx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
- auto_rm.add (ixx_path);
+ auto_rm.add (ixx_path);
+ }
//
//
- ofstream cxx (cxx_path.string ().c_str ());
+ ofstream cxx;
- if (!cxx.is_open ())
+ if (gen_cxx)
{
- cerr << "error: unable to open '" << cxx_path << "' in write mode"
- << endl;
- throw failed ();
- }
+ cxx.open (cxx_path.string ().c_str (), ios_base::out);
- auto_rm.add (cxx_path);
+ if (!cxx.is_open ())
+ {
+ cerr << "error: unable to open '" << cxx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (cxx_path);
+ }
//
//
- bool sql_schema (ops.generate_schema () &&
- ops.schema_format ().count (schema_format::sql));
+ bool gen_sql_schema (ops.generate_schema () &&
+ ops.schema_format ().count (schema_format::sql));
ofstream sql;
- if (sql_schema)
+ if (gen_sql_schema)
{
sql.open (sql_path.string ().c_str (), ios_base::out);
@@ -183,12 +204,13 @@ generate (options const& ops,
//
//
- bool sep_schema (ops.generate_schema () &&
- ops.schema_format ().count (schema_format::separate));
+ bool gen_sep_schema (gen_cxx &&
+ ops.generate_schema () &&
+ ops.schema_format ().count (schema_format::separate));
ofstream sch;
- if (sep_schema)
+ if (gen_sep_schema)
{
sch.open (sch_path.string ().c_str (), ios_base::out);
@@ -204,11 +226,14 @@ generate (options const& ops,
// Print C++ headers.
//
- hxx << file_header;
- ixx << file_header;
- cxx << file_header;
+ if (gen_cxx)
+ {
+ hxx << file_header;
+ ixx << file_header;
+ cxx << file_header;
+ }
- if (sep_schema)
+ if (gen_sep_schema)
sch << file_header;
typedef compiler::ostream_filter<compiler::cxx_indenter, char> ind_filter;
@@ -224,6 +249,7 @@ generate (options const& ops,
// HXX
//
+ if (gen_cxx)
{
auto_ptr<context> ctx (
create_context (hxx, unit, ops, fts, model.get ()));
@@ -257,15 +283,25 @@ generate (options const& ops,
<< "// End prologue." << endl
<< endl;
- hxx << "#include " << ctx->process_include_path (file.string ()) << endl
- << endl;
+ // Include main file(s).
+ //
+ for (paths::const_iterator i (inputs.begin ()); i != inputs.end (); ++i)
+ hxx << "#include " << ctx->process_include_path (i->string ()) << endl;
+
+ hxx << endl;
+
{
// We don't want to indent prologues/epilogues.
//
ind_filter ind (ctx->os);
- include::generate (true);
+ // There are no -odb.hxx includes if we are generating code for
+ // everything.
+ //
+ if (!ops.at_once ())
+ include::generate (true);
+
header::generate ();
switch (ops.database ())
@@ -307,6 +343,7 @@ generate (options const& ops,
// IXX
//
+ if (gen_cxx)
{
auto_ptr<context> ctx (
create_context (ixx, unit, ops, fts, model.get ()));
@@ -359,6 +396,7 @@ generate (options const& ops,
// CXX
//
+ if (gen_cxx)
{
auto_ptr<context> ctx (
create_context (cxx, unit, ops, fts, model.get ()));
@@ -385,7 +423,11 @@ generate (options const& ops,
//
ind_filter ind (ctx->os);
- include::generate (false);
+ // There are no -odb.hxx includes if we are generating code for
+ // everything.
+ //
+ if (!ops.at_once ())
+ include::generate (false);
switch (ops.database ())
{
@@ -420,7 +462,7 @@ generate (options const& ops,
// SCH
//
- if (sep_schema)
+ if (gen_sep_schema)
{
auto_ptr<context> ctx (
create_context (sch, unit, ops, fts, model.get ()));
@@ -482,7 +524,7 @@ generate (options const& ops,
// SQL
//
- if (sql_schema)
+ if (gen_sql_schema)
{
auto_ptr<context> ctx (
create_context (sql, unit, ops, fts, model.get ()));
diff --git a/odb/generator.hxx b/odb/generator.hxx
index 5a1bbdf..98454a3 100644
--- a/odb/generator.hxx
+++ b/odb/generator.hxx
@@ -5,6 +5,8 @@
#ifndef ODB_GENERATOR_HXX
#define ODB_GENERATOR_HXX
+#include <vector>
+
#include <odb/options.hxx>
#include <odb/features.hxx>
#include <odb/semantics/unit.hxx>
@@ -18,7 +20,8 @@ public:
generate (options const&,
features&,
semantics::unit&,
- semantics::path const&);
+ semantics::path const& file,
+ std::vector<semantics::path> const& inputs);
generator () {}
diff --git a/odb/header.cxx b/odb/header.cxx
index 8e6718d..8bf5453 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -17,8 +17,12 @@ namespace header
ostream& os (ctx.os);
os << "#include <memory>" << endl
- << "#include <cstddef>" << endl // std::size_t
- << endl;
+ << "#include <cstddef>" << endl; // std::size_t
+
+ if (ctx.features.polymorphic_object)
+ os << "#include <string>" << endl; // For discriminator.
+
+ os << endl;
os << "#include <odb/core.hxx>" << endl
<< "#include <odb/traits.hxx>" << endl
diff --git a/odb/odb.cxx b/odb/odb.cxx
index d89cd3e..4f48359 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -56,7 +56,7 @@ typedef vector<path> paths;
// Escape backslashes in the path.
//
static string
-escape_path (path const& p);
+escape_path (string const&);
// Search the PATH environment variable for the file.
//
@@ -664,6 +664,23 @@ main (int argc, char* argv[])
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]));
+ }
+
// Create an execvp-compatible argument array.
//
typedef vector<char const*> cstrings;
@@ -684,26 +701,31 @@ main (int argc, char* argv[])
for (; end < plugin_args.size (); ++end)
{
- path input (plugin_args[end]);
+ string name (at_once ? ops.output_name () : plugin_args[end]);
// Set the --svc-file option.
//
- args[svc_file_pos] = encode_plugin_option ("svc-file", input.string ());
+ args[svc_file_pos] = encode_plugin_option ("svc-file", name);
exec_args[svc_file_pos] = args[svc_file_pos].c_str ();
//
//
- ifstream ifs (input.string ().c_str (), ios_base::in | ios_base::binary);
+ ifstream ifs;
- if (!ifs.is_open ())
+ if (!at_once)
{
- e << input << ": error: unable to open in read mode" << endl;
- return 1;
+ ifs.open (name.c_str (), ios_base::in | ios_base::binary);
+
+ if (!ifs.is_open ())
+ {
+ e << name << ": error: unable to open in read mode" << endl;
+ return 1;
+ }
}
if (v)
{
- e << "Compiling " << input << endl;
+ e << "Compiling " << name << endl;
for (cstrings::const_iterator i (exec_args.begin ());
i != exec_args.end (); ++i)
{
@@ -796,21 +818,36 @@ main (int argc, char* argv[])
os << endl;
}
- // Write the synthesized translation unit to stdout.
- //
- os << "#line 1 \"" << escape_path (input) << "\"" << endl;
-
- if (!(os << ifs.rdbuf ()))
+ if (at_once)
{
- e << input << ": 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 \"<command-line>\"" << 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;
- // Add a new line in case the input file doesn't end with one.
- //
- os << endl;
+ if (!(os << ifs.rdbuf ()))
+ {
+ e << name << ": error: io failure" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
+
+ // Add a new line in case the input file doesn't end with one.
+ //
+ os << endl;
+ }
// Add custom epilogue if any.
//
@@ -1187,17 +1224,16 @@ profile_paths (strings const& sargs, char const* name)
//
static string
-escape_path (path const& p)
+escape_path (string const& p)
{
string r;
- string const& s (p.string ());
- for (size_t i (0); i < s.size (); ++i)
+ for (size_t i (0); i < p.size (); ++i)
{
- if (s[i] == '\\')
+ if (p[i] == '\\')
r += "\\\\";
else
- r += s[i];
+ r += p[i];
}
return r;
diff --git a/odb/option-functions.cxx b/odb/option-functions.cxx
index 6d6f948..6b7442e 100644
--- a/odb/option-functions.cxx
+++ b/odb/option-functions.cxx
@@ -11,6 +11,12 @@ using namespace std;
void
process_options (options& o)
{
+ // If --generate-schema-only was specified, then set --generate-schema
+ // as well.
+ //
+ if (o.generate_schema_only ())
+ o.generate_schema (true);
+
// Set the default schema format depending on the database.
//
if (o.generate_schema () && o.schema_format ().empty ())
diff --git a/odb/options.cli b/odb/options.cli
index 8705283..e9d76dd 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -81,6 +81,13 @@ class options
Use the \cb{--schema-format} option to alter the default schema format."
};
+ bool --generate-schema-only
+ {
+ "Generate only the database schema. Note that this option is only valid
+ when generating schema as a standalone SQL file (see \cb{--schema-format}
+ for details)."
+ };
+
std::set< ::schema_format> --schema-format
{
"<format>",
@@ -156,6 +163,18 @@ class options
profile."
};
+ bool --at-once
+ {
+ "Generate code for all the input files as well as for all the files that
+ they include at once. The result is a single set of source/schema files
+ that contain all the generated code. If more than one input file is
+ specified together with this option, then the \cb{--output-name} option
+ must also be specified in order to provide the base name for the output
+ files. In this case, the directory part of such a base name is used as
+ the location of the combined file. This can be important for the
+ \cb{#include} directive resolution."
+ };
+
qname --schema
{
"<schema>",
@@ -193,6 +212,13 @@ class options
"Write the generated files to <dir> instead of the current directory."
};
+ std::string --output-name
+ {
+ "<name>",
+ "Use <name> instead of the input file to construct the names of the
+ generated files."
+ };
+
std::string --odb-file-suffix = "-odb"
{
"<suffix>",
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 8920521..1d73b7f 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -37,7 +37,9 @@ typedef vector<path> paths;
int plugin_is_GPL_compatible;
auto_ptr<options const> options_;
paths profile_paths_;
-path file_; // File being compiled.
+path file_; // File being compiled.
+paths inputs_; // List of input files in at-once mode or just file_.
+
// A prefix of the _cpp_file struct. This struct is not part of the
// public interface so we have to resort to this technique (based on
@@ -136,7 +138,7 @@ gate_callback (void*, void*)
// Generate.
//
generator g;
- g.generate (*options_, f, *u, file_);
+ g.generate (*options_, f, *u, file_, inputs_);
}
catch (cutl::re::format const& e)
{
@@ -221,7 +223,14 @@ plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*)
if (strcmp (a.key, "svc-file") == 0)
{
- file_ = path (v);
+ // First is the main file. Subsequent are inputs in the at-once
+ // mode.
+ //
+ if (file_.empty ())
+ file_ = path (v);
+ else
+ inputs_.push_back (path (v));
+
continue;
}
@@ -238,6 +247,9 @@ plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*)
}
}
+ if (inputs_.empty ())
+ inputs_.push_back (file_);
+
// Two-phase options parsing, similar to the driver.
//
int argc (static_cast<int> (argv.size ()));
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index c7a7445..25f9480 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -970,7 +970,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
if (object (c))
@@ -1224,7 +1224,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
if (object (c))
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index ff97874..76c29f1 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -202,7 +202,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
context::top_object = context::cur_object = &c;
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index b3edd93..4245c91 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -659,7 +659,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
if (!object (c))
diff --git a/odb/relational/schema-source.hxx b/odb/relational/schema-source.hxx
index 82b7e71..925e914 100644
--- a/odb/relational/schema-source.hxx
+++ b/odb/relational/schema-source.hxx
@@ -21,7 +21,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
if (!object (c))
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 21954e0..1b5df6e 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -3340,7 +3340,7 @@ namespace relational
virtual void
traverse (type& c)
{
- if (class_file (c) != unit.file ())
+ if (!options.at_once () && class_file (c) != unit.file ())
return;
context::top_object = context::cur_object = &c;
diff --git a/odb/validator.cxx b/odb/validator.cxx
index 225a2a1..aba82a5 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -573,7 +573,7 @@ namespace
// Update features set based on this object.
//
- if (class_file (c) == unit.file ())
+ if (options.at_once () || class_file (c) == unit.file ())
{
if (poly_root != 0)
features.polymorphic_object = true;
@@ -706,7 +706,7 @@ namespace
// Update features set based on this view.
//
- if (class_file (c) == unit.file ())
+ if (options.at_once () || class_file (c) == unit.file ())
{
features.view = true;
}
@@ -1251,6 +1251,21 @@ validate (options const& ops,
unsigned short pass)
{
bool valid (true);
+
+ // Validate options.
+ //
+ if (ops.generate_schema_only () &&
+ (ops.schema_format ().size () != 1 ||
+ *ops.schema_format ().begin () != schema_format::sql))
+ {
+ cerr << "error: --generate-schema-only is only valid when generating " <<
+ "schema as a standalone SQL file" << endl;
+ valid = false;
+ }
+
+ if (!valid)
+ throw failed ();
+
auto_ptr<context> ctx (create_context (cerr, u, ops, f, 0));
if (pass == 1)