if ensure that all binaries, libraries, and dependencies are compiled with the same rustc
build and flags, can guarantee ABI compatibility?
i don't think so, but if you compile an rlib once, you can then use it in an application and also a dynamically linked plugin. this is how rustc implements custom codegen backends.
As I understand it, if those "flags" also include eg. target platform, and resolutions of any environment variables, which should be the case in a reasonably standard setup, generally yes; but it's not actually guaranteed as things like deterministic struct layout are not guaranteed in general (consider a --randomize-layout
security hardening flag, for example)
Yes, this is how crate-type = "dylib"
works, you must have all crates compiled with the same version + compiler settings.
However, the ABI is NOT stable. You need to recompile and redistribute all crates simultaneously when the compiler is updated.
And you also need to recompile all dependent crates when a dependency changes.
Please correct me if I'm wrong, but that creates DLLs in Windows and their counterpart in other OS's. That would still be a C-ABI, not a Rust ABI.
Edit: I'm confused by the Rust Reference, which says it creates a Rust library, but also that it produces .so/.dll/*.dylib files
Dynamic libraries can contain symbols with Rust ABI or C ABI just like static libraries can contain symbols with Rust ABI or C ABI. The issues are around whether this is compatible with anything, not with whether the items can be put in the file.
Are you sure that isn't crate-type = "cdylib"
instead of crate-type = "dylib"
?
To hopefully clarify, a dll/so exports pretty much only names that point to a location in the file (handwaving some details that shouldn't be relevant here). An ABI is defining how source code is translated to those exports and what they point to, while most of the time an effort is made to do so in terms of C's ABI to increase compatibility it's neither required or always possible.
These file formats do not expect any single programming language's ABI, and can contain arbitrary machine code[1]. This is a bit similar to how an .mp4
file can contain an MPEG-4 movie as implied by its name, but can also contain other codecs.
No, as much as consumer OSes are stuck in legacy code, they are not that locked into C, in part because these OSes are designed back when even C was too high-level. ↩︎
First: thank you to all, who answered, but unfortunately, I'm still confused.
I'm seeing this from the Windows perspective, so let's forget about the other OS's.
As per my understanding, a dll is a binary file with some library code that follows whatever Microsoft defined to make it usable for whatever other program want to use it. That includes a defined ABI.
This is what I get from cdylib. I can create a dll with Rust (which was invented far later than the definition of a dll was made) and (if compiled as 32-bit code) use it in a dinosaur like Visual FoxPro.
When I look up cdylib in the Rust Reference I find
This output type will create
*.so
files on Linux,*.dylib
files on macOS, and*.dll
files on Windows.
and the world if fine for me.
But when I lookup dylib I also find
This output type will create
*.so
files on Linux,*.dylib
files on macOS, and*.dll
files on Windows.
and here my struggle starts. Does this also creates a dll, which I can use from elsewhere? If not, why is it called dll? It shouldn't. It's like I can rename a text file to dll and say I can produce dll's in Notepad.
The thing that makes a *.dll
a proper *.dll
is that it can be loaded into a process by Windows’ dynamic linker — it has a particular file format containing a symbol table giving names for code (or data) elsewhere in the file. The library file format says nothing about what the ABI of those symbols is.
There is no guarantee that an arbitrary DLL is useful to another program. A DLL with the wrong ABI for your language is unhelpful,[1] but also so is a DLL whose code doesn’t do anything you want.
though with sufficient effort and inline assembly, you could use it anyway ↩︎
Ok - I guess my misunderstanding comes from way back when I did Visual FoxPro. Binary libraries only usable by VFP were called FLL, not DLL - hence I assumed DLL's are only those, with the correct ABI and usable from whatever language.
And modern node native plugins are dlls renamed to .node
- extensions are mostly only convention not actually a format! (Node plugins must also export some metadata, you can't just use an arbitrary dll, so this reduces confusion)
It's best to think of dynamic libraries as being, (somewhat unsurprisingly) the dynamic version of static libraries, this is less true on Windows than Linux, but not by much.
Both are, essentially, chunks of bytes arranged into sections that define broad details about them (mostly memory protection and alignment), and a table of symbols: pretty much just names that each point to a particular location (static libraries are the most different here, adding a bunch of rules about which symbols win or remain visible when linked)
As an example of how you can use (abuse?) this, .net libraries are built to DLLs too, but all their symbols just point at type metadata or bytecode.
ABI is a lot more complicated: sometimes there is a platform ABI - this is mostly useful to be able to get a cross-language stack though, outside of calling convention it's mostly not applicable outside C. That still leaves metadata, name mangling (the symbol name for an exported declaration), structure layout, exceptions, and the actual mapping of language types to their C equivalent even if you stay within the platform ABI, let alone whatever else I'm forgetting about.
This very much doesn't include defined ABI. Open the Wikipedia and you'll find Microsoft fastcall, Microsoft vectorcall, Borland register and many other ABIs. Most of these are Windows. They all are supported and used, no Rust needed to have that zoo.
That was never the case. All compilers have to support stdcall convention used by NTDLL.DLL (an official entry point for Win32 API), but there were always many others.
It's a bit ironic, BTW: Windows is, pretty much, the only OS where all that zoo exists in C world. Most other OSes had one C compiler and thus one, fixed, C ABI – while Microsoft was, for years, not popular among the developers. Borland, Watcom, and many others were more popular.
Microsoft only managed to hire away compiler developers of other compilers (including, but limited, to Anders Hejlsberg) and consolidate its hold on developers tools near the beginning of XXI century (that's why Windows, like other OSes, only have one 64bit API).
Well there's also the fact that we have the internet now. GNU and Clang choose to follow Microsoft's lead instead of their own in Windows.
We were pretty close to only one convention, but at least both are fairly similar.