aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-11-28 13:47:35 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-11-28 13:47:35 +0200
commit77d6727eddc64a95ccbdf87984e22270fce61b35 (patch)
tree8c119200e3e6c70c9a158a4212b4c93565a0bba9
parent9ad0acf37561de9bf359a561faed53de17c2ca3b (diff)
Add support for DLL exporting of generated code
New options: --export-symbol, --extern-symbol.
-rw-r--r--NEWS3
-rw-r--r--odb/common-query.cxx335
-rw-r--r--odb/common-query.hxx25
-rw-r--r--odb/context.cxx37
-rw-r--r--odb/context.hxx11
-rw-r--r--odb/generator.cxx2
-rw-r--r--odb/header.cxx30
-rw-r--r--odb/options.cli19
-rw-r--r--odb/relational/header.cxx16
-rw-r--r--odb/relational/header.hxx29
-rw-r--r--odb/relational/source.hxx4
-rw-r--r--odb/source.cxx2
12 files changed, 357 insertions, 156 deletions
diff --git a/NEWS b/NEWS
index 3ad3c8e..1636642 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ Version 2.2.0
refer to Section 4.5, "Prepared Queries" in the ODB manual as well as the
'prepared' example in the odb-examples package.
+ * New options, --export-symbol and --extern-symbol, allow DLL exporting
+ of the generated database support code.
+
* Support for early connection release. Now the database connection is
released when commit()/rollback() is called rather than when the
transaction instance goes out of scope.
diff --git a/odb/common-query.cxx b/odb/common-query.cxx
index ce07136..bbe5fe7 100644
--- a/odb/common-query.cxx
+++ b/odb/common-query.cxx
@@ -157,7 +157,7 @@ generate_decl (string const& tag, semantics::class_& c)
string const& fq_name (class_fq_name (c));
os << "template <>" << endl
- << "struct alias_traits<" << endl
+ << "struct " << exp << "alias_traits<" << endl
<< " " << fq_name << "," << endl
<< " id_" << db << "," << endl
<< " " << scope_ << "::" << tag << "_tag>"
@@ -207,8 +207,8 @@ generate_def (string const&, semantics::class_&, string const&)
//
query_columns_base::
-query_columns_base (semantics::class_& c, bool decl)
- : decl_ (decl)
+query_columns_base (semantics::class_& c, bool decl, bool inst)
+ : decl_ (decl), inst_ (inst)
{
string const& n (class_fq_name (c));
@@ -311,36 +311,17 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
<< endl;
}
}
+ else if (inst_)
+ {
+ generate_inst (m, c);
+ }
else
{
// Generate explicit template instantiation directive for the
// pointed-to pointer_query_columns.
//
if (multi_dynamic)
- {
- // If the pointed-to class has no pointers of its own then
- // pointer_query_columns just derives from query_columns and
- // that's what we need to instantiate.
- //
- bool has_ptr (has_a (c, test_pointer | include_base));
-
- string alias (scope_ + "::" + name + "_alias_");
-
- // Instantiate base [pointer_]query_columns.
- //
- {
- instance<query_columns_base_insts> b (has_ptr, alias);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- os << "template struct " << (has_ptr ? "pointer_" : "") <<
- "query_columns<" << endl
- << " " << fq_name << "," << endl
- << " id_" << db << "," << endl
- << " " << alias << " >;"
- << endl;
- }
+ generate_inst (m, c);
if (inv)
os << const_ << scope_ << "::" << name << "_type_" << endl
@@ -349,6 +330,35 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
}
}
+void query_columns_base::
+generate_inst (semantics::data_member& m, semantics::class_& c)
+{
+ string name (public_name (m));
+ string const& fq_name (class_fq_name (c));
+
+ // If the pointed-to class has no pointers of its own then
+ // pointer_query_columns just derives from query_columns and
+ // that's what we need to instantiate.
+ //
+ bool has_ptr (has_a (c, test_pointer | include_base));
+ string alias (scope_ + "::" + name + "_alias_");
+
+ // Instantiate base [pointer_]query_columns.
+ //
+ {
+ instance<query_columns_base_insts> b (has_ptr, inst_, alias);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ inst_header (inst_);
+ os << (has_ptr ? "pointer_" : "") << "query_columns<" << endl
+ << " " << fq_name << "," << endl
+ << " id_" << db << "," << endl
+ << " " << alias << " >;"
+ << endl;
+}
+
// query_columns
//
@@ -546,8 +556,8 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
<< name << "_pointer_type_;"
<< endl;
- os << "struct " << name << "_type_: " << name << "_pointer_type_, " <<
- name << "_column_type_"
+ os << "struct " << name << "_type_: " <<
+ name << "_pointer_type_, " << name << "_column_type_"
<< "{";
if (!const_.empty ())
@@ -596,8 +606,8 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
<< name << "_pointer_type_;"
<< endl;
- os << "struct " << name << "_type_: " << name << "_pointer_type_, " <<
- name << "_column_type_"
+ os << "struct " << name << "_type_: " <<
+ name << "_pointer_type_, " << name << "_column_type_"
<< "{";
column_ctor (type, name + "_type_", name + "_column_type_");
@@ -677,8 +687,8 @@ traverse (type& c)
//
query_columns_base_insts::
-query_columns_base_insts (bool ptr, string const& alias)
- : ptr_ (ptr), alias_ (alias)
+query_columns_base_insts (bool ptr, bool decl, string const& alias)
+ : ptr_ (ptr), decl_ (decl), alias_ (alias)
{
*this >> inherits_ >> *this;
}
@@ -686,7 +696,7 @@ query_columns_base_insts (bool ptr, string const& alias)
query_columns_base_insts::
query_columns_base_insts (query_columns_base_insts const& x)
: context (), // @@ -Wextra
- ptr_ (x.ptr_), alias_ (x.alias_)
+ ptr_ (x.ptr_), decl_ (x.decl_), alias_ (x.alias_)
{
*this >> inherits_ >> *this;
}
@@ -703,8 +713,8 @@ traverse (type& c)
//
inherits (c, inherits_);
- os << "template struct " <<
- (ptr_ ? "pointer_query_columns" : "query_columns") << "<" << endl
+ inst_header (decl_);
+ os << (ptr_ ? "pointer_query_columns" : "query_columns") << "<" << endl
<< " " << class_fq_name (c) << "," << endl
<< " id_" << db << "," << endl
<< " " << alias_ << " >;"
@@ -779,11 +789,13 @@ traverse (type& c)
// table alias (A) template argument.
//
os << "template <>" << endl
- << "struct query_columns_base< " << type << ", id_" << db << " >"
+ << "struct " << exp << "query_columns_base< " << type << ", " <<
+ "id_" << db << " >"
<< "{";
bool true_ (true); //@@ (im)perfect forwarding.
- instance<query_columns_base> t (c, true_);
+ bool false_ (false);
+ instance<query_columns_base> t (c, true_, false_);
t->traverse (c);
os << "};";
@@ -819,6 +831,30 @@ traverse (type& c)
generate_impl (c);
}
+ else if (inst_)
+ {
+ // If we have the extern symbol, generate extern template declarations.
+ //
+ if (!options.extern_symbol ().empty ())
+ {
+ os << "#ifdef " << options.extern_symbol () << endl
+ << endl;
+
+ if (has_a (c, test_pointer | exclude_base))
+ {
+ bool true_ (true); //@@ (im)perfect forwarding.
+ bool false_ (false);
+
+ instance<query_columns_base> t (c, false_, true_);
+ t->traverse (c);
+ }
+
+ generate_inst (c);
+
+ os << "#endif // " << options.extern_symbol () << endl
+ << endl;
+ }
+ }
else
{
bool has_ptr (has_a (c, test_pointer | exclude_base));
@@ -839,49 +875,14 @@ traverse (type& c)
if (has_ptr)
{
bool false_ (false); //@@ (im)perfect forwarding.
- instance<query_columns_base> t (c, false_);
+ instance<query_columns_base> t (c, false_, false_);
t->traverse (c);
}
- // Explicit template instantiations. Here is what we need to
- // instantiate
- //
- // 1. Reuse inheritance bases all the way to the ultimate base.
- // Unlike poly inheritance, reuse inheritance uses the table
- // alias of the derived type. Note that bases can have object
- // pointers of their own but their types have already been
- // instantiated by step 3 below performed for the base object.
- //
- // 2. Object pointers. Note that while object pointers cannot have
- // their own pointers, they can have reuse inheritance bases.
- //
- // 3. The query_columns class for the table itself.
+ // Explicit template instantiations.
//
if (multi_dynamic)
- {
- string alias ("access::object_traits_impl< " + type + ", id_" +
- db.string () + " >");
-
- // 1
- //
- {
- instance<query_columns_base_insts> b (false, alias);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- // 2: Handled by query_columns_base (which is where we generate
- // all the aliases for object pointers).
- //
-
- // 3
- //
- os << "template struct query_columns<" << endl
- << " " << type << "," << endl
- << " id_" << db << "," << endl
- << " " << alias << " >;"
- << endl;
- }
+ generate_inst (c);
}
}
@@ -890,7 +891,13 @@ generate_impl (type& c)
{
string guard;
- if (multi_dynamic)
+ // Exclude definitions (they will be explicitly instantiated once in
+ // the source file) unless we have the extern symbol. In this case
+ // the extern template declaration will make sure we don't get
+ // instantiations in multiple places and we will avoid the VC++
+ // warning C4661 (no definition provided).
+ //
+ if (multi_dynamic && options.extern_symbol ().empty ())
{
guard = make_guard ("ODB_" + db.string () + "_QUERY_COLUMNS_DEF");
@@ -906,6 +913,50 @@ generate_impl (type& c)
<< endl;
}
+void query_columns_type::
+generate_inst (type& c)
+{
+ string const& type (class_fq_name (c));
+
+ // Explicit template instantiations. Here is what we need to
+ // instantiate
+ //
+ // 1. Reuse inheritance bases all the way to the ultimate base.
+ // Unlike poly inheritance, reuse inheritance uses the table
+ // alias of the derived type. Note that bases can have object
+ // pointers of their own but their types have already been
+ // instantiated by step 3 below performed for the base object.
+ //
+ // 2. Object pointers. Note that while object pointers cannot have
+ // their own pointers, they can have reuse inheritance bases.
+ //
+ // 3. The query_columns class for the table itself.
+ //
+ string alias ("access::object_traits_impl< " + type + ", id_" +
+ db.string () + " >");
+
+ // 1
+ //
+ {
+ instance<query_columns_base_insts> b (false, inst_, alias);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ // 2: Handled by query_columns_base (which is where we generate
+ // all the aliases for object pointers).
+ //
+
+ // 3
+ //
+ inst_header (inst_);
+ os << "query_columns<" << endl
+ << " " << type << "," << endl
+ << " id_" << db << "," << endl
+ << " " << alias << " >;"
+ << endl;
+}
+
// view_query_columns_type
//
@@ -922,6 +973,7 @@ void view_query_columns_type::
generate_decl (type& c)
{
string const& type (class_fq_name (c));
+ size_t obj_count (c.get<size_t> ("object-count"));
view_objects& objs (c.get<view_objects> ("objects"));
// Generate alias_traits specializations.
@@ -950,10 +1002,27 @@ generate_decl (type& c)
}
}
- os << "struct access::view_traits_impl< " << type << ", id_" << db <<
- " >::query_columns";
+ // If we have the extern symbol, generate extern template declarations.
+ // Do it before query_columns since the inheritance will trigger
+ // instantiation and we won't be able to change visibility (GCC).
+ //
+ if (obj_count != 0 && multi_dynamic && !options.extern_symbol ().empty ())
+ {
+ os << "#ifdef " << options.extern_symbol () << endl
+ << endl;
+
+ generate_inst (c);
- if (c.get<size_t> ("object-count") > 1)
+ os << "#endif // " << options.extern_symbol () << endl
+ << endl;
+ }
+
+ // query_columns
+ //
+ os << "struct " << exp << "access::view_traits_impl< " << type << ", " <<
+ "id_" << db << " >::query_columns";
+
+ if (obj_count > 1)
{
os << "{";
@@ -1040,14 +1109,9 @@ generate_decl (type& c)
void view_query_columns_type::
generate_def (type& c)
{
- string const& type (class_fq_name (c));
view_objects& objs (c.get<view_objects> ("objects"));
- string traits ("access::view_traits_impl< " + type + ", id_" +
- db.string () + " >");
-
- // Generate alias_traits specializations and instantiate corresponding
- // [pointer_]query_columns.
+ // Generate alias_traits specializations.
//
{
bool false_ (false); //@@ (im)perfect forwarding
@@ -1073,40 +1137,75 @@ generate_def (type& c)
if (polymorphic (o) || t.qualified () || i->alias != t.uname ())
{
at->generate_def (i->alias, o, i->alias);
+ }
+ }
+ }
+
+ if (multi_dynamic)
+ generate_inst (c);
+}
+
+void view_query_columns_type::
+generate_inst (type& c)
+{
+ string const& type (class_fq_name (c));
+ view_objects& objs (c.get<view_objects> ("objects"));
+
+ string traits ("access::view_traits_impl< " + type + ", id_" +
+ db.string () + " >");
+
+ // Instantiate [pointer_]query_columns.
+ //
+ for (view_objects::const_iterator i (objs.begin ());
+ i < objs.end ();
+ ++i)
+ {
+ if (i->kind != view_object::object)
+ continue; // Skip tables.
+
+ if (i->alias.empty ())
+ continue;
+
+ semantics::class_& o (*i->obj);
+ qname const& t (table_name (o));
+
+ // Check that the alias is not the same as the table name
+ // (if this is a polymorphic object, then the alias is just
+ // a prefix).
+ //
+ if (polymorphic (o) || t.qualified () || i->alias != t.uname ())
+ {
+
+ string const& otype (class_fq_name (o));
- // The same code as in query_columns_base.
- //
- if (multi_dynamic)
- {
- string const& otype (class_fq_name (o));
-
- // If the pointed-to class has no pointers of its own then
- // pointer_query_columns just derives from query_columns and
- // that's what we need to instantiate.
- //
- bool has_ptr (has_a (o, test_pointer | include_base));
-
- string alias ("odb::alias_traits<\n"
- " " + otype + ",\n"
- " id_" + db.string () + ",\n"
- " " + traits + "::" + i->alias + "_tag>");
-
- // Instantiate base [pointer_]query_columns.
- //
- {
- instance<query_columns_base_insts> b (has_ptr, alias);
- traversal::inherits i (*b);
- inherits (o, i);
- }
-
- os << "template struct " << (has_ptr ? "pointer_" : "") <<
- "query_columns<" << endl
- << " " << otype << "," << endl
- << " id_" << db << "," << endl
- << " " << alias << " >;"
- << endl;
- }
+ // If the pointed-to class has no pointers of its own then
+ // pointer_query_columns just derives from query_columns and
+ // that's what we need to instantiate.
+ //
+ bool has_ptr (has_a (o, test_pointer | include_base));
+
+ string alias ("odb::alias_traits<\n"
+ " " + otype + ",\n"
+ " id_" + db.string () + ",\n"
+ " " + traits + "::" + i->alias + "_tag>");
+
+
+
+ // Instantiate base [pointer_]query_columns.
+ //
+ {
+ instance<query_columns_base_insts> b (has_ptr, decl_, alias);
+ traversal::inherits i (*b);
+ inherits (o, i);
}
+
+ inst_header (decl_);
+ os << (has_ptr ? "pointer_" : "") <<
+ "query_columns<" << endl
+ << " " << otype << "," << endl
+ << " id_" << db << "," << endl
+ << " " << alias << " >;"
+ << endl;
}
}
}
diff --git a/odb/common-query.hxx b/odb/common-query.hxx
index 4fa9fe1..f0418b1 100644
--- a/odb/common-query.hxx
+++ b/odb/common-query.hxx
@@ -79,7 +79,10 @@ struct query_columns_base: object_columns_base, virtual context
{
typedef query_columns_base base;
- query_columns_base (semantics::class_&, bool decl);
+ // If inst is true, then we generate extern template declarations
+ // in the header.
+ //
+ query_columns_base (semantics::class_&, bool decl, bool inst);
virtual void
traverse_object (semantics::class_&);
@@ -90,8 +93,12 @@ struct query_columns_base: object_columns_base, virtual context
virtual void
traverse_pointer (semantics::data_member&, semantics::class_&);
+ virtual void
+ generate_inst (semantics::data_member&, semantics::class_&);
+
protected:
bool decl_;
+ bool inst_;
string const_; // Const prefix or empty.
string scope_;
};
@@ -176,7 +183,7 @@ struct query_columns_base_insts: traversal::class_, virtual context
{
typedef query_columns_base_insts base;
- query_columns_base_insts (bool ptr, string const& alias);
+ query_columns_base_insts (bool ptr, bool decl, string const& alias);
query_columns_base_insts (query_columns_base_insts const&);
virtual void
@@ -184,6 +191,7 @@ struct query_columns_base_insts: traversal::class_, virtual context
private:
bool ptr_;
+ bool decl_;
string alias_;
traversal::inherits inherits_;
};
@@ -202,7 +210,11 @@ struct query_columns_type: traversal::class_, virtual context
// If decl is false then generate definitions (only needed for
// query_columns so ptr should be false).
//
- query_columns_type (bool ptr, bool decl): ptr_ (ptr), decl_ (decl) {}
+ // If inst if true, then generate extern template declarations
+ // in the header (ptr and decl should be false).
+ //
+ query_columns_type (bool ptr, bool decl, bool inst)
+ : ptr_ (ptr), decl_ (decl), inst_ (inst) {}
virtual void
traverse (type&);
@@ -210,9 +222,13 @@ struct query_columns_type: traversal::class_, virtual context
virtual void
generate_impl (type&);
+ virtual void
+ generate_inst (type&);
+
public:
bool ptr_;
bool decl_;
+ bool inst_;
};
// Generate the query_columns class for views.
@@ -232,6 +248,9 @@ struct view_query_columns_type: traversal::class_, virtual context
void
generate_def (type&);
+ void
+ generate_inst (type&);
+
public:
bool decl_;
};
diff --git a/odb/context.cxx b/odb/context.cxx
index 066287b..6ee8ad1 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -442,6 +442,7 @@ context (ostream& os_,
options (ops),
features (f),
db (options.database ()[0]),
+ exp (data_->exp_),
keyword_set (data_->keyword_set_),
include_regex (data_->include_regex_),
accessor_regex (data_->accessor_regex_),
@@ -460,6 +461,11 @@ context (ostream& os_,
assert (current_ == 0);
current_ = this;
+ // Export control.
+ //
+ if (!ops.export_symbol ().empty ())
+ exp = ops.export_symbol () + " ";
+
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
@@ -497,6 +503,7 @@ context ()
options (current ().options),
features (current ().features),
db (current ().db),
+ exp (current ().exp),
keyword_set (current ().keyword_set),
include_regex (current ().include_regex),
accessor_regex (current ().accessor_regex),
@@ -1872,6 +1879,36 @@ strlit (string const& str)
return strlit_ascii (str);
}
+void context::
+inst_header (bool decl)
+{
+ string const& ext (options.extern_symbol ());
+
+ if (decl && !ext.empty ())
+ os << ext << " ";
+
+ os << "template struct";
+
+ if (!exp.empty ())
+ {
+ // If we are generating an explicit instantiation directive rather
+ // than the extern template declaration, then omit the export symbol
+ // if we already have it in the header (i.e., extern symbol specified
+ // and defined). If we don't do that, then we get GCC warnings saying
+ // that the second set of visibility attributes is ignored.
+ //
+ if (!decl && !ext.empty ())
+ os << endl
+ << "#ifndef " << ext << endl
+ << options.export_symbol () << endl
+ << "#endif" << endl;
+ else
+ os << " " << exp;
+ }
+ else
+ os << " ";
+}
+
namespace
{
struct column_count_impl: object_members_base
diff --git a/odb/context.hxx b/odb/context.hxx
index fc1b3bd..7c7ca71 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -712,6 +712,13 @@ public:
static string
strlit (string const&);
+public:
+ // Generate explicit instantiation headers with all the necessary
+ // extern and export symbols.
+ //
+ void
+ inst_header (bool decl);
+
// Counts and other information.
//
public:
@@ -964,6 +971,8 @@ protected:
semantics::class_* top_object_;
semantics::class_* cur_object_;
+ string exp_;
+
keyword_set_type keyword_set_;
type_map_type type_map_;
@@ -984,6 +993,8 @@ public:
features_type& features;
database const db;
+ string& exp;
+
keyword_set_type const& keyword_set;
regex_mapping const& include_regex;
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 279017e..e95ba25 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -516,7 +516,7 @@ generate (options const& ops,
// Include query columns implementations for explicit instantiations.
//
string impl_guard;
- if (md == multi_database::dynamic)
+ if (md == multi_database::dynamic && ops.extern_symbol ().empty ())
{
impl_guard = ctx->make_guard (
"ODB_" + db.string () + "_QUERY_COLUMNS_DEF");
diff --git a/odb/header.cxx b/odb/header.cxx
index 1f02463..3259a6a 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -13,8 +13,8 @@ namespace header
struct class1: traversal::class_, virtual context
{
class1 ()
- : query_columns_type_ (false, true),
- pointer_query_columns_type_ (true, true) {}
+ : query_columns_type_ (false, true, false),
+ pointer_query_columns_type_ (true, true, false) {}
virtual void
traverse (type& c)
@@ -76,7 +76,7 @@ traverse_object (type& c)
// object_traits
//
os << "template <>" << endl
- << "class access::object_traits< " << type << " >"
+ << "class " << exp << "access::object_traits< " << type << " >"
<< "{"
<< "public:" << endl;
@@ -312,7 +312,7 @@ traverse_object (type& c)
// object_traits_impl
//
os << "template <>" << endl
- << "class access::object_traits_impl< " << type << ", " <<
+ << "class " << exp << "access::object_traits_impl< " << type << ", " <<
"id_common >:" << endl
<< " public access::object_traits< " << type << " >"
<< "{"
@@ -500,7 +500,7 @@ traverse_view (type& c)
// view_traits
//
os << "template <>" << endl
- << "class access::view_traits< " << type << " >"
+ << "class " << exp << "access::view_traits< " << type << " >"
<< "{"
<< "public:" << endl;
@@ -537,7 +537,8 @@ traverse_view (type& c)
// view_traits_impl
//
os << "template <>" << endl
- << "class access::view_traits_impl< " << type << ", id_common >:" << endl
+ << "class " << exp << "access::view_traits_impl< " << type << ", " <<
+ "id_common >:" << endl
<< " public access::view_traits< " << type << " >"
<< "{"
<< "public:" << endl;
@@ -606,7 +607,8 @@ namespace header
struct class2: traversal::class_, virtual context
{
class2 ()
- : query_columns_type_ (false, true),
+ : query_columns_type_ (false, true, false),
+ query_columns_type_inst_ (false, false, true),
view_query_columns_type_ (true)
{
}
@@ -631,6 +633,7 @@ namespace header
private:
instance<query_columns_type> query_columns_type_;
+ instance<query_columns_type> query_columns_type_inst_;
instance<view_query_columns_type> view_query_columns_type_;
};
}
@@ -640,19 +643,20 @@ traverse_object (type& c)
{
if (options.generate_query ())
{
- bool has_ptr (has_a (c, test_pointer | include_base));
-
- if (has_ptr)
- os << "// " << class_name (c) << endl
- << "//" << endl;
+ os << "// " << class_name (c) << endl
+ << "//" << endl;
// query_columns
//
// If we don't have any pointers, then query_columns is generated
// in pass 1 (see the comment in class1 for details).
//
- if (has_ptr)
+ if (has_a (c, test_pointer | include_base))
query_columns_type_->traverse (c);
+
+ // Generate extern template declarations.
+ //
+ query_columns_type_inst_->traverse (c);
}
// Move header comment out of if-block if adding any code here.
diff --git a/odb/options.cli b/odb/options.cli
index 3c7efa8..42acad7 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -230,6 +230,25 @@ class options
then you should include it into the prefix value."
};
+ // Export control.
+ //
+ std::string --export-symbol
+ {
+ "<symbol>",
+ "Insert <symbol> in places where DLL export/import control statements
+ (\cb{__declspec(dllexport/dllimport)}) are necessary. See also the
+ \cb{--extern-symbol} option below."
+ };
+
+ std::string --extern-symbol
+ {
+ "<symbol>",
+ "If <symbol> is defined, insert it in places where a template
+ instantiation must be declared \cb{extern}. This option is normally
+ used together with \cb{--export-symbol} when both multi-database
+ support and queries are enabled."
+ };
+
// Language.
//
cxx_version --std = cxx_version::cxx98
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index 543e1ac..ff2679e 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -52,8 +52,8 @@ traverse_object (type& c)
// object_traits_impl
//
os << "template <>" << endl
- << "class access::object_traits_impl< " << type << ", id_" << db <<
- " >:" << endl
+ << "class " << exp << "access::object_traits_impl< " << type << ", " <<
+ "id_" << db << " >:" << endl
<< " public access::object_traits< " << type << " >"
<< "{"
<< "public:" << endl;
@@ -680,8 +680,8 @@ traverse_view (type& c)
// view_traits_impl
//
os << "template <>" << endl
- << "class access::view_traits_impl< " << type << ", id_" <<
- db << " >:" << endl
+ << "class " << exp << "access::view_traits_impl< " << type << ", " <<
+ "id_" << db << " >:" << endl
<< " public access::view_traits< " << type << " >"
<< "{"
<< "public:" << endl;
@@ -834,9 +834,13 @@ traverse_composite (type& c)
os << "// " << class_name (c) << endl
<< "//" << endl;
+ // While composite_value_traits is not used directly by user code, we
+ // still need to export it if the generated code for the same database
+ // is split into several DLLs.
+ //
os << "template <>" << endl
- << "class access::composite_value_traits< " << type << ", " <<
- "id_" << db << " >"
+ << "class " << exp << "access::composite_value_traits< " << type <<
+ ", id_" << db << " >"
<< "{"
<< "public:" << endl;
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 89ef664..3e0480f 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -747,8 +747,8 @@ namespace relational
: id_image_member_ ("id_"),
version_image_member_ ("version_"),
discriminator_image_member_ ("discriminator_"),
- query_columns_type_ (false, true),
- pointer_query_columns_type_ (true, true)
+ query_columns_type_ (false, true, false),
+ pointer_query_columns_type_ (true, true, false)
{
}
@@ -758,8 +758,8 @@ namespace relational
id_image_member_ ("id_"),
version_image_member_ ("version_"),
discriminator_image_member_ ("discriminator_"),
- query_columns_type_ (false, true),
- pointer_query_columns_type_ (true, true)
+ query_columns_type_ (false, true, false),
+ pointer_query_columns_type_ (true, true, false)
{
}
@@ -823,7 +823,8 @@ namespace relational
typedef class2 base;
class2 ()
- : query_columns_type_ (false, true),
+ : query_columns_type_ (false, true, false),
+ query_columns_type_inst_ (false, false, true),
view_query_columns_type_ (true)
{
}
@@ -831,7 +832,8 @@ namespace relational
class2 (class_ const&)
: root_context (), //@@ -Wextra
context (),
- query_columns_type_ (false, true),
+ query_columns_type_ (false, true, false),
+ query_columns_type_inst_ (false, false, true),
view_query_columns_type_ (true)
{
}
@@ -855,19 +857,21 @@ namespace relational
{
if (options.generate_query ())
{
- bool has_ptr (has_a (c, test_pointer | include_base));
-
- if (has_ptr)
- os << "// " << class_name (c) << endl
- << "//" << endl;
+ os << "// " << class_name (c) << endl
+ << "//" << endl;
// query_columns
//
// If we don't have any pointers, then query_columns is generated
// in pass 1 (see the comment in class1 for details).
//
- if (has_ptr)
+ if (has_a (c, test_pointer | include_base))
query_columns_type_->traverse (c);
+
+ // Generate extern template declarations.
+ //
+ if (multi_dynamic)
+ query_columns_type_inst_->traverse (c);
}
// Move header comment out of if-block if adding any code here.
@@ -896,6 +900,7 @@ namespace relational
private:
instance<query_columns_type> query_columns_type_;
+ instance<query_columns_type> query_columns_type_inst_;
instance<view_query_columns_type> view_query_columns_type_;
};
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index ed5f0e3..610c545 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -3294,7 +3294,7 @@ namespace relational
typedef class_ base;
class_ ()
- : query_columns_type_ (false, false),
+ : query_columns_type_ (false, false, false),
view_query_columns_type_ (false),
grow_base_ (index_),
grow_member_ (index_),
@@ -3318,7 +3318,7 @@ namespace relational
class_ (class_ const&)
: root_context (), //@@ -Wextra
context (),
- query_columns_type_ (false, false),
+ query_columns_type_ (false, false, false),
view_query_columns_type_ (false),
grow_base_ (index_),
grow_member_ (index_),
diff --git a/odb/source.cxx b/odb/source.cxx
index a26adc7..5dd82ca 100644
--- a/odb/source.cxx
+++ b/odb/source.cxx
@@ -14,7 +14,7 @@ namespace source
struct class_: traversal::class_, virtual context
{
class_ ()
- : query_columns_type_ (false, false),
+ : query_columns_type_ (false, false, false),
view_query_columns_type_ (false)
{
}