Problem using a user-defined class on Mac OS X.
Dear all, I seem to be having a problem with unarchiving a user-defined class on Mac OS X. The problem is that the static member class_info<registered_class_options>::first is (besides inside the GiNaC dynamic library) also created within my executable. This second version is then used when registering my own class, so that my own class does not appear in the linked list of which *(class_info<registered_class_options>::first) is the first element. I debugged this by printing both the address of first and the name of the class being registered from the constructor of class_info and the for my own class the address of first turned out to be different. The consequence of this is that members of my own class cannot be unarchived. The problem does not occur on Linux. Anyone any bright ideas? Should this be considered a bug GiNaC? Does anyone know a combination of linker flags that can prevent this? Best wishes, Chris
Hello again,
I seem to be having a problem [...] the static member class_info<registered_class_options>::first is (besides inside the GiNaC dynamic library) also created within my executable.
I now solved this by creating a file class_info.cpp (given below). Shall I add this file to the CVS? I'm really rather ignorant on linker issues. Best wishes, Chris #include "class_info.h" #include "registrar.h" namespace GiNaC { template <> class_info<registered_class_options> *class_info<registered_class_options>::first = NULL; template <> bool class_info<registered_class_options>::parents_identified = false; template <> class_info<print_context_options> *class_info<print_context_options>::first = NULL; template <> bool class_info<print_context_options>::parents_identified = false; }
On Tue, Apr 03, 2007 at 11:27:54AM +0200, Chris.Dams@mi.infn.it wrote:
I seem to be having a problem [...] the static member class_info<registered_class_options>::first is (besides inside the GiNaC dynamic library) also created within my executable.
I now solved this by creating a file class_info.cpp (given below).
Interesting. There are template <class OPT> class_info<OPT> *class_info<OPT>::first = NULL; template <class OPT> bool class_info<OPT>::parents_identified = false; in class_info.h. So I wonder why explicit specialization makes any difference...
Shall I add this file to the CVS?
I think we should understand how it works first. Best regards, Alexei -- All science is either physics or stamp collecting.
Dear Alexei,
There are
template <class OPT> class_info<OPT> *class_info<OPT>::first = NULL; template <class OPT> bool class_info<OPT>::parents_identified = false;
in class_info.h. So I wonder why explicit specialization makes any difference...
Oh well, I should have said that I also removed these two. Obviously, if these static members weren't templated it would just have been wrong for the initializations to be in the header file. It would simply give an error complaining about symbols being defined more than once. The linker on the Mac does not seem to have a problem, creating the same mangled name multiple times, though :-(. Apparently the linker on Linux is smart enough to only keep one single instance of this variable and on Mac it is still smart enough if it only has to create the dynamic library but not if this is to be linked with an executable that also contains this same symbol. Highly inconvenient. You might be right that it could be a bug somewhere in the toolchain. Also, the Mac has gcc 3.3 while the Linux that I use has gcc 4.0.2.
Shall I add this file to the CVS?
I think we should understand how it works first.
You have a point there. Maybe I will go and try to hunt for some linker flags that make it behave properly. Best wishes, Chris
On Tue, Apr 03, 2007 at 11:27:54AM +0200, Chris.Dams@mi.infn.it wrote:
I seem to be having a problem [...] the static member class_info<registered_class_options>::first is (besides inside the GiNaC dynamic library) also created within my executable.
I now solved this by creating a file class_info.cpp (given below).
Interesting. There are
template <class OPT> class_info<OPT> *class_info<OPT>::first = NULL; template <class OPT> bool class_info<OPT>::parents_identified = false;
in class_info.h. So I wonder why explicit specialization makes any difference...
Shall I add this file to the CVS?
I think we should understand how it works first.
Hi, I may be jumping in a bit late, and without having looked through the source, but are we looking at a violation of the basic one-definition-rule (ODR)? whereby a specialization is providing a definition that is otherwise expected from a primary template? (For the record, which version are we looking at, so I may check it out?) Fang David Fang Computer Systems Laboratory Electrical & Computer Engineering Cornell University http://www.csl.cornell.edu/~fang/ -- (2400 baud? Netscape 3.0?? lynx??? No problem!)
On Tue, Apr 03, 2007 at 07:42:46PM -0400, David Fang wrote:
I may be jumping in a bit late, and without having looked through the source, but are we looking at a violation of the basic one-definition-rule (ODR)?
No. There are no multiple definitions. Only one specialization (which provides best match) is selected by the compiler.
whereby a specialization is providing a definition that is otherwise expected from a primary template?
C++ standard allows this (see e.g. 14.7.3). So, this is OK: template<typename T> class foo { static T data; }; template<typename T> class foo<T*> { static void* data; }; template<typename T> T foo<T>::data = T(1); template<typename T> void* foo<T*>::data = 0;
(For the record, which version are we looking at, so I may check it out?)
CVS HEAD. Best regards, Alexei -- All science is either physics or stamp collecting.
I may be jumping in a bit late, and without having looked through the source, but are we looking at a violation of the basic one-definition-rule (ODR)?
No. There are no multiple definitions. Only one specialization (which provides best match) is selected by the compiler.
whereby a specialization is providing a definition that is otherwise expected from a primary template?
C++ standard allows this (see e.g. 14.7.3).
So, this is OK:
template<typename T> class foo { static T data; };
template<typename T> class foo<T*> { static void* data; };
template<typename T> T foo<T>::data = T(1);
template<typename T> void* foo<T*>::data = 0;
Hi, This alone doesn't exhibit the issue in the original example. What you've written above is just a plain partial specialization, no violation at all. Now, suppose that the last definition above (foo<T*>::data) was replaced in a *different* translation unit with: template <> void* foo<void*>::data = &something_else; which is similar to the original code in this thread. The instantiation of foo<void*>::data can now be different-valued. (Is this analogous to the GiNaC source or proposed patch in question?) If I'm reading the following correctly (?): 14.6.4.1/7 "Point of instantiation" [temp.point]: A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required. ... says that points of instantiation that result in different meanings is ill-formed. The issue here is that one instantiation uses the primary template definition, while another uses the [partial] specialization. (Now if their separate definitions *happen* to be equivalent, I don't know if that makes it well-formed again.)
(For the record, which version are we looking at, so I may check it out?)
CVS HEAD.
Fang David Fang Computer Systems Laboratory Electrical & Computer Engineering Cornell University http://www.csl.cornell.edu/~fang/ -- (2400 baud? Netscape 3.0?? lynx??? No problem!)
Hello, On Wed, Apr 04, 2007 at 09:34:24PM -0400, David Fang wrote:
C++ standard allows this (see e.g. 14.7.3).
So, this is OK:
template<typename T> class foo { static T data; };
template<typename T> class foo<T*> { static void* data; };
template<typename T> T foo<T>::data = T(1);
template<typename T> void* foo<T*>::data = 0;
Hi, This alone doesn't exhibit the issue in the original example. What you've written above is just a plain partial specialization, no violation at all.
IMHO the patch in question is just explicit specialization, no violations either.
Now, suppose that the last definition above (foo<T*>::data) was replaced in a *different* translation unit with:
template <> void* foo<void*>::data = &something_else;
which is similar to the original code in this thread. The instantiation of foo<void*>::data can now be different-valued. (Is this analogous to the GiNaC source or proposed patch in question?)
That's a different story. What we have is _equivalent_ explicit specialization, like template<typename T> class bar { static void* data; }; template<typename T> bar<T>::data = 0; struct baz { }; // in a different translation unit: template<> bar<baz>::data = 0; So there should be no any difference. But... Apparently compiler generates different code: // With explicit specialization $ nm -B -C build/ginac/ginac/.libs/libginac.so | grep -e '::first' 0032bc8c B GiNaC::class_info<GiNaC::print_context_options>::first 0032bc84 B GiNaC::class_info<GiNaC::registered_class_options>::first // _Without_ explicit specialization nm -B -C build/ginac/ginac/.libs/libginac.so | grep -e '::first' 002611d0 V GiNaC::class_info<GiNaC::print_context_options>::first 00261168 V GiNaC::class_info<GiNaC::registered_class_options>::first I need to re-read the standard to understand what's going on... Best regards, Alexei -- All science is either physics or stamp collecting.
Hi again,
template <> void* foo<void*>::data = &something_else;
which is similar to the original code in this thread. The instantiation of foo<void*>::data can now be different-valued. (Is this analogous to the GiNaC source or proposed patch in question?)
That's a different story. What we have is _equivalent_ explicit specialization, like
template<typename T> class bar { static void* data; };
template<typename T> bar<T>::data = 0;
struct baz { };
// in a different translation unit:
template<> bar<baz>::data = 0;
So there should be no any difference. But... Apparently compiler generates different code:
The difference is that the former definition is a template, and thus symbols created by its instantiations are given weak-extern linkage, i.e. there may be multiple instantiations in different translation units, the linker will just pick any one for reference resolution purposes. The latter (full specialization) is no longer a template and given non-weak-external linkage. (Enforcing the ODR is one way to avoid this problem.) Hence, you see different linkage classifications shown by nm. Someone correct me if I'm wrong.
// With explicit specialization $ nm -B -C build/ginac/ginac/.libs/libginac.so | grep -e '::first' 0032bc8c B GiNaC::class_info<GiNaC::print_context_options>::first 0032bc84 B GiNaC::class_info<GiNaC::registered_class_options>::first
// _Without_ explicit specialization nm -B -C build/ginac/ginac/.libs/libginac.so | grep -e '::first' 002611d0 V GiNaC::class_info<GiNaC::print_context_options>::first 00261168 V GiNaC::class_info<GiNaC::registered_class_options>::first
I need to re-read the standard to understand what's going on...
It is not fun reading material. :) Fang David Fang Computer Systems Laboratory Electrical & Computer Engineering Cornell University http://www.csl.cornell.edu/~fang/ -- (2400 baud? Netscape 3.0?? lynx??? No problem!)
That's a different story. What we have is _equivalent_ explicit specialization, like
template<typename T> class bar { static void* data; };
template<typename T> bar<T>::data = 0;
struct baz { };
// in a different translation unit:
template<> bar<baz>::data = 0;
So there should be no any difference. But... Apparently compiler generates different code:
The difference is that the former definition is a template, and thus symbols created by its instantiations are given weak-extern linkage, i.e.
I should qualify that as *implicit* instantiations. Explicit instantiations might be non-weak, IIRC -- explicit and redundant instantiations will resut in 'multiply-defined' link diagnostics.
there may be multiple instantiations in different translation units, the linker will just pick any one for reference resolution purposes. The latter (full specialization) is no longer a template and given non-weak-external linkage. (Enforcing the ODR is one way to avoid this problem.) Hence, you see different linkage classifications shown by nm. Someone correct me if I'm wrong.
Fang David Fang Computer Systems Laboratory Electrical & Computer Engineering Cornell University http://www.csl.cornell.edu/~fang/ -- (2400 baud? Netscape 3.0?? lynx??? No problem!)
Hello, On Tue, Apr 03, 2007 at 10:18:35AM +0200, Chris.Dams@mi.infn.it wrote:
I seem to be having a problem with unarchiving a user-defined class on Mac OS X. [snipped]
The problem does not occur on Linux. Anyone any bright ideas? Should this be considered a bug GiNaC?
This is not a bright idea, but... there are no platform-specific code in GiNaC. So I'm inclined to think it's a toolchain bug. Best regards, Alexei -- All science is either physics or stamp collecting.
participants (4)
-
Alexei Sheplyakov
-
Chris.Dams@mi.infn.it
-
David Fang
-
varg@theor.jinr.ru