Problem with stream classes in Visual Studio
Borland's Object Windows Library for the modern age
Brought to you by:
jogybl,
sebas_ledesma
Hello
I am trying to convert a large project from BCB++ 4.0 (OWL 2) to the OwlNext and Visual Studio 2003. I am using the latest OwlNext, 6.20.3 and OwlExt. OwlNext is simply installed by using installer from CodeGear website.
Most of the code now compiles, but I am stuck with compiler errors in geometry.h. I suppose it has something to do with new stream classes in OwlNext and/or namespaces, but have no idea how to solve it. VS Project defines are currently only: USE_OWLEXTLIB and OWL2_COMPAT.
Here are the compiler errors:
d:\OWL\include\owl\geometry.h(157) : error C2143: syntax error : missing ';' before '&'
d:\OWL\include\owl\geometry.h(157) : error C2501: 'ipstream' : missing storage-class or type specifiers
d:\OWL\include\owl\geometry.h(157) : error C2065: 'is' : undeclared identifier
d:\OWL\include\owl\geometry.h(157) : error C2065: 'p' : undeclared identifier
d:\OWL\include\owl\geometry.h(157) : error C2275: 'OWL::TPoint' : illegal use of this type as an expression
d:\OWL\include\owl\geometry.h(123) : see declaration of 'OWL::TPoint'
d:\OWL\include\owl\geometry.h(157) : warning C4229: anachronism used : modifiers on data are ignored
d:\OWL\include\owl\geometry.h(157) : error C2501: 'operator
>>'' : missing storage-class or type specifiers d:\OWL\include\owl\geometry.h(157) : error C2078: too many initializers d:\OWL\include\owl\geometry.h(158) : error C2365: 'OWL::operator>>'' : redefinition; previous definition was a 'data variable'd:\OWL\include\owl\geometry.h(157) : see declaration of 'OWL::operator`>>''
......................
Can anybody help?
Thanks in advance,
Goran Obradovic
Hi Vidar
Thank you very much for this comprehensive analysis. I already implemented similar solution as a quick-fix and it is working well.
Regards,
Goran Obradovic
Hi Goran,
Line 157 in <owl/geometry.h>:
_OWLCFUNC(ipstream&) operator >>(ipstream& is, TPoint& p);
after macro preprosessing (usually) expands to
ipstream& __cdecl operator >>(ipstream& is, TPoint& p);
The error messages you get indicate that "ipstream" is not yet defined. Normally "ipstream" should have already been declared in <owl/objstrm.h> which is included at line 21 in <owl/geometry.h>.
Is "UNIX" defined as a symbol in your project somewhere? This will prevent <owl/objstrm.h> from being included. (Sidebar: This seems nonsensical by OWLNext; there's no alternative handling for the "UNIX" symbol that makes the code compile, unless "__HPUX_SOURCE" is also defined, which includes <owl/objstrm.h> in a separate but identical include statement!).
Check out why <owl/objstrm.h> is not included. Running <owl/geometry.h> through the preprocessor and inspecting the output may help (use the same build configuration and defines).
Regards,
Vidar Hasfjord
Hi Vidar
Thank you for a quick answer.
Actually, I followed the same logic and, as a first step, removed all conditionals when including <owl/objstrm.h> from geometry.h. No success.
Then, I created a Test.cpp in my project, containing only one line, #include <owl/geometry.h>. Compiling this file brings the same errors. After adding #include <owl/defs.h> before #include <owl/geometry.h>, Test.cpp compiles without errors. So, it seems that geometry.h needs defs.h settings in order to compile. But, "geometry.h" contains only #include <owl/private/defs.h> instead. What is the role of headers in "private" directory?
Is there some article or examples for using OwlNext with VS 7?
Regards
Goran Obradovic
Hi Goran,
I've investigated this problem in depth now, and it looks like you've run into a design flaw in the OWLNext headers. There is an indirect circular dependency between <owl/geometry.h> and <owl/objstrm.h> (through <owl/defs.h> which includes <owl/wsyscls.h> which again depend on and include <owl/geometry.h>).
It seems some OWL developer circumvented the circular dependency problem by creating an awful loophole in the sentry guard in <owl/geometry.h>:
if !defined(OWL_GEOMETRY_H) || defined(WSYSCLS_ENTRY)
Note the second term. This exists just to allow <owl/wsyscls.h> a second pass through this header. Here is how it is set up in <owl/wsyscls.h> (some comments and blank lines removed for clarity):
define WSYSCLS_ENTRY
if !defined(OWL_GEOMETRY_H) || defined(WSYSCLS_ENTRY)
include <owl/geometry.h> // TPoint, et. al.
endif
undef WSYSCLS_ENTRY
In fact, the content of the whole <owl/geometry.h> header is not processed if not through this loophole. Below the includes in <owl/geometry.h> you'll find:
if defined(WSYSCLS_ENTRY)
define ENTRY
endif
if defined(ENTRY)
The rest of the file is encapsulated in that #if statement!
Unfortunately this is brittle and only solves the circular dependency in certain cases that is highly dependent on the order files are included. Basically the <owl/geometry.h> header is fundamentally broken; it is not self-sufficient. It only works properly when it's included from <owl/wsyscls.h>, i.e. you can only include <owl/geometry.h> via <owl/wsyscls.h> (directly or indirectly). Including <owl/geometry.h> explicitly will either fail (if <owl/wsyscls.h> has not already been included) or be a no-operation (in case <owl/wsyscls.h> has already been included, which means <owl/geometry.h> has already been included also).
Like you've already discovered you can circumvent the problem by including <owl/defs.h> (which includes <owl/wsyscls.h>) before <owl/geometry.h>:
include <owl/defs.h>
include <owl/geometry.h> // technically a no-op, but future-proof
While including <owl/geometry.h> here is technically a no-op, I still recommend doing so to be compatible with potential future OWLNext fixes to this problem. Including <owl/wsyscls.h> before <owl/geometry.h> will work as well, of course, but semantically less elegant; in the future this problem may be fixed and you then probably don't want the extra definition in <owl/wsyscls.h>.
Here's a proposal to fix this in OWLNext:
Remove the <owl/wsyscls.h> include from <owl/defs.h>. It is not needed in general by all OWL programs and doesn't belong in this header. Then close the sentry guard loophole in <owl/geometry.h> and remove the application of the loophole in <owl/wsyscls.h>. Add <owl/wsyscls.h> includes to only the headers in OWL that strictly need it; as far as I can tell, that is just <owl/module.h>.
I've applied this fix to my private OWLNext build, and my simple tests so far compile with no errors or warnings.
> What is the role of headers in "private" directory?
As far as I know, the "private" directory is for compiler/platform-specific code, but I think more code lives there as well; for no apparent reason.
Regards,
Vidar Hasfjord