Compile dynamic library crate to `.dylib` vs `.so`


Out of curiosity I’m wondering: Is it possible with Rust on OS X to force a dylib or cdylib crate to compile to .so rather than to .dylib?

I know for a fact it can be done with C on OS X, albeit with some finicking around with gcc/llvm CLI parameters.


Are you looking to generate a Linux-compatible ELF shared object, or a Mach-O dylib with a .so file extension?

(If you’re already using gcc, it might be useful to share the options you’re using. AFAIK Rust currently uses gcc to link on most platforms, so you might try passing the same option with -C link-args=...)


To avoid the X/Y problem I’ll explain my use case:

I need to load a dynamic lib in Emacs, which has become possible in Emacs 25.
However, it refuses to load a .dylib file and will accept only an .so, even on OS X.
There is a variable that holds the accepted extensions but modifying that has no actual effect on Emacs’ pickiness.

Right now I work around the problem by copying the .dylib produced by Cargo/RustC to the same stem but with .so as extension, and Emacs swallows that without complaints (so both dylib production and consumption are currently on OS X). But it turns my compilation CLI line from a cute little cargo build into a Lovecraftian cargo build && cp target/debug/libmy_module.dylib target/debug/ Which of course is scriptable, but this seems to me something Cargo somehow should be able to produce, with the right arguments.

Now the ideal solution is of course for Emacs to start accepting .dylib files on OS X (and if it doesn’t do so already, .dll on Windows). But given that I can’t easily hack that into Emacs, I’d like to be able to produce an .so file directly.

And no, I happen to not be using GCC. I’m trying to oxidize C code in this case :slight_smile:


Unfortunately cargo does currently not support post-build scripts or passing custom linker arguments automatically. If it did, that would make my life much easier too.


I think you are mistaken. AFAIK the only ways currently to link Rust code are to use gcc (or msvc, or the gcc-compatible clang wrapper that’s installed as “gcc” on recent versions of macOS).

rustflags might be useful for you.


Oh yeah, I forgot that exists, that only works on the root crate though, which is no good for my particular case.


To clarify, OS X used to have a type of Mach-O binary called “bundle” and sometimes given the .so extension, different from dylibs, but it’s been deprecated for about a decade. Since Emacs’ dynamic library support is new, I doubt it is using the deprecated APIs; it is probably using the standard POSIX dlopen/dlsym/etc. APIs that have long been the recommended choice on OS X, and just has broken filename handling that assumes dynamic libraries have a .so ending. I think those APIs will also load a bundle if you give it one, but there is no point. Renaming a dylib is the right thing to do, or fixing Emacs.

See also: Allow configuring name of generated shared library artifact

By the way, OS X also has “frameworks”, where the main file is just a dylib (nothing within the file itself to differentiate from Unix-style dylibs) but with no file extension, and placed in a specific directory structure (confusingly sometimes also referred to as a “bundle”, but entirely separate) along with header files and anything else needed by the library. Thus compatibility with buggy software is not the only use case for naming dylibs something other than libfoo.dylib, though I don’t have an opinion on whether Cargo itself should support it.


I guess I want not so much hard-coded renaming support as a feature in Cargo. Rather I’d like an option to include (turing-complete, yet DSL-less) post-processing with the results of cargo build or cargo build --release.
That would allow me to automate this admittedly somewhat odd use case within the confines of the Rust ecosystem: I have a strong dislike for using both a build tool and a build script on top of it, since it feels like a really ugly hack.

Build scripts in the form of approximate my use case with the fatal flaw that they cannot operate on the generated files in target/.