version and extern problems
Mike Parker
aldacron71 at yahoo.com
Sat Jul 7 22:07:38 PDT 2007
Walter Bright wrote:
> Bug 1311 http://d.puremagic.com/issues/show_bug.cgi?id=1311
> is about using version declarations to control part of a following
> declaration (or series of declarations):
>
> -------------------------
> version(Windows)
> extern(Windows):
> else
> extern(C):
>
> typedef void function() foo;
> --------------------------
>
> This does not work now, and it was a bug that it ever did appear to
> work. The issue is that version declarations can only affect entire
> declarations, not parts of them. An extern statement with a : is
> implicitly the same as:
>
> ----------------
> extern(Windows):
> int a;
> int b;
> -----is same as---
> extern(Windows)
> {
> int a;
> int b;
> }
> -----------------
Right. But since version doesn't create a new scope, what's the problem?
>
> That cannot be split up with a version declaration; it would be like
> trying to make:
>
> version (Windows)
> int
> else
> long
> x;
>
> work. The old behavior of dmd contained a serious (unreported) bug where
> such constructs would cause forward references to behave unpredictably.
Then I misunderstood the usage of version. I was under the impression
that it's a form of conditional compilation, i.e. on Windows the final
result would be
int x;
Is that not possible?
>
> So, the question is how to get the same effect? The alternatives are:
>
> 1.
> version(Windows)
> {
> extern(Windows):
> typedef void function() foo;
> }
> else
> {
> extern(C):
> typedef void function() foo;
> }
>
> Yes, that means doing a cut & paste on the code in the braces. Not
> thrilling, but it works.
I implemented it as I did to avoid this. Using multiple declarations is
error prone and a maintenance nightmare, particularly for the number of
declarations I'm dealing with.
>
> 2. Stop using extern(Windows). The Windows calling convention is only
> necessary when a) calling Win32 API functions (which don't exist on
> Linux anyway) and b) calling someone else's C code that pointlessly and
> spuriously uses the Windows calling convention, and cannot be fixed.
> There is no reason in new C/C++ code to ever use the Windows calling
> convention.
Unfortunately, I have no choice. This is not new D code, but bindings to
existing cross-platform C libraries (namely OpenGL and DevIL). On
Windows, these libraries all use the stdcall calling convention.
Declaring them as extern(C) causes crashes. On other platforms, the
libraries use the C calling convention, so they can't be declared
extern(Windows) there.
Every D OpenGL binding I have seen uses this technique. That's how I
first learned it. For example, all of Kenta Cho's D games
(http://www.asahi-net.or.jp/~cs8k-cyu/index_e.html) use an OpenGL module
with this at the top:
version (Win32) {
private import std.c.windows.windows;
extern(Windows):
}
else {
extern(C):
}
followed by the function declarations. Most of his code already won't
compile on newer versions without modification anyway. But still, now
all of the D OpenGL bindings are broken.
>
> 3. Create two source files, one for the extern(Windows) and the other
> for the extern(C). Have your makefile automatically copy one to the
> other, using sed to edit that one line. Import one under Windows, the
> other under Linux.
Yuck! :)
>
> 4. Wait for the future 2.0 macro feature, which should be able to deal
> with this nicely:
>
> macro Foo()
> {
> typedef void function() foo;
> }
> version(Windows)
> { extern(Windows): Foo(); }
> else
> { extern(C): Foo(); }
That will be nice when it gets here, but there are already a lot of
people using this library who aren't going to be willing to wait.
>
> 5. Do the same as (4) using string mixins:
>
> const string Foo =
> "
> typedef void function() foo;
> ";
> version(Windows)
> { extern(Windows): mixin(Foo); }
> else
> { extern(C): mixin(Foo); }
>
>
> 6. Use template mixins:
>
> template Foo()
> {
> typedef void function() foo;
> }
> version(Windows)
> { extern(Windows): mixin Foo; }
> else
> { extern(C): mixin Foo; }
It looks like one of these is going to be the best alternative. More
typing, but at least it keeps the declarations in one place.
More information about the Digitalmars-d
mailing list