Enhanced foreign-language binding
Version | 1 |
Created | 2016-01-21 |
Status | Draft |
Last modified | -- |
Author | Anon |
Abstract
This DIP proposes a unified foreign language binding and name mangling syntax, to extend/replace existing approaches.
Rationale
Currently, D has a mixed bag approach to binding symbols from other languages, each with their own functionality:
-
pragma(mangle, "foo")
Changes only the symbol mangling, not the calling convention. Mostly useful for binding C symbols that share a name with a D keyword.
-
extern(LinkageType)
Changes mangling and calling convention, but does not support binding to a name that is a D keyword.
-
@selector("foo")
For Objective-C support. Does most of what this proposal aims to do, but is custom built for Objective-C, instead of being a multi-purpose tool.
-
extern(C++, ns)
Supports mangling C++ symbols in namespaces. Also introduces the namespaces as symbols, which is not well loved by the community. Cannot bind symbols that share a name with a D keyword.
This proposal aims to replace all of these with a single, extendable, uniform syntax. This solves some of the current woes with binding C and C++, while opening up possibilities for adding additional language support in future without further breaking changes.
Description
-
Deprecate
{.D} pragma(mangle, "foo")
,
@selector("foo")
, and
extern(C++, ns)
-
Change LinkageAttribute in the grammar to:\ \ extern ( LinkageType [, StringLiteral ] ) \ \ Which has the following semantics:
- Functions will be called with appropriate calling convention.
- Symbols will be mangled according to the expectations of LinkageType
-
The name sent to the mangler is the concatenation of all the string parameters given to
{.D} extern()
.
-
A symbol inside an
{.D} extern(LinkageType)
block implicitly gains LinkageType, and it is an error have multiple
extern()
s on one symbol with different LinkageTypes
- The exact formatting of the string parameter is specific to each LinkageType, and should be sensible for the language being bound.
- A symbol inside a struct, class, or similar inherits the LinkageType of its parent, and appends any needed separator automatically.
-
Add LinkageType
{.D} auto
, which infers LinkageType from containing blocks, and defaults to D if there are none.
Usage
// Still works
// Mangles as "foo"
extern(C) int foo();
// No more pragma(mangle)
// Mangles as "body"
extern(C, "body") int body_();
// cppMangle("foo")
extern(C++) int foo();
// cppMangle("ns::foo")
extern(C++, "ns::foo") int foo();
// NB: Mangles as if it didn't have a module, and is a breaking change.
// "_D3fooFZi"
extern(D) int foo();
// "_D4bodyFZi"
extern(D, "body") int body_();
// Namespace block, does *not* introduce any symbols on its own
extern(C++, "ns::")
{
// No extern() directly on the symbol, so it appends its own name
// cppMangle("ns::foo")
int foo();
// auto to infer LinkageType from previous extern()
// cppMangle("ns::body")
extern(auto, "body") int body_();
// It is a good idea to not use auto on blocks
extern(C++, "sub::")
{
// cppMangle("ns::sub::foo")
int foo();
}
}
// Maintains current behavior, does not add to the symbol's mangled name
extern(C++)
{
// cppMangle("foo")
int foo();
}
// Extend same behavior to other languages
extern(C, "SDL_")
{
// "SDL_init"
void init();
}
// Even D
extern(D, "std.ascii.")
{
// std.ascii.isAlphaNum.mangleof
bool isAlphaNum(dchar) pure nothrow @nogc @safe;
}
// Nested symbols (those inside other symbols) append any
// needed separator for the mangler automatically.
extern(C++, "Object")
interface Object_
{
// cppMangleOf("Object::foo")
int foo();
}
// NB: The Objective-C mangler must add missing parameters
// the same way selector generation currently does.
extern(Objective-C)
class SomeClass
{
// selector: "length"
// mangle: "_i_SomeClass_length"
int length();
// selector: "moveTo_f:f:"
// mangle: "_i_SomeClass_moveTo_f_f_"
void moveTo(float x, float y);
// selector: "myMoveTo:d:"
// mangle: "_i_SomeClass_myMoveTo_d_"
extern(auto, "myMoveTo:") void moveTo(double x, double y);
}
Backwards Compatibility
Code that currently uses
pragma(mangle)
,
extern(C++, ns)
,
extern(D)
, or
@selector
would need to be updated.
There no longer would be a way to get
extern(D)
’s currently functionality explicitly, which may be detrimental to some generic code. However, simply omitting
extern(D)
entirely gives the current behavior.
There no longer would be a way to change a symbol’s mangling without also changing its calling convention, but that might be a good thing.
Binding C++ namespaces would no longer introduce the namespace as a symbol, leaving scoping to D’s module system. Again, this is believed to be a good thing.
Copyright
This document has been placed in the Public Domain.