From 77d6727eddc64a95ccbdf87984e22270fce61b35 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 28 Nov 2012 13:47:35 +0200 Subject: Add support for DLL exporting of generated code New options: --export-symbol, --extern-symbol. --- NEWS | 3 + odb/common-query.cxx | 335 ++++++++++++++++++++++++++++++---------------- odb/common-query.hxx | 25 +++- odb/context.cxx | 37 +++++ odb/context.hxx | 11 ++ odb/generator.cxx | 2 +- odb/header.cxx | 30 +++-- odb/options.cli | 19 +++ odb/relational/header.cxx | 16 ++- odb/relational/header.hxx | 29 ++-- odb/relational/source.hxx | 4 +- odb/source.cxx | 2 +- 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 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 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 t (c, true_); + bool false_ (false); + instance 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 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 t (c, false_); + instance 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 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 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 ("object-count")); view_objects& objs (c.get ("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 ("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 ("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 ("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 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 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_; + instance query_columns_type_inst_; instance 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 + { + "", + "Insert 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 + { + "", + "If 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_; + instance query_columns_type_inst_; instance 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) { } -- cgit v1.1