|
| 1 | +- Feature Name: export-executable-symbols |
| 2 | +- Start Date: 2019-12-28 |
| 3 | +- RFC PR: [rust-lang/rfcs#2841](https://github.com/rust-lang/rfcs/pull/2841) |
| 4 | +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Add the ability to export symbols from executables, not just dylibs, via a new |
| 10 | +compiler flag: `-C export-executable-symbols`. |
| 11 | + |
| 12 | +# Motivation |
| 13 | +[motivation]: #motivation |
| 14 | + |
| 15 | +Java and C# can't statically link against C/Rust code. Both require dylib |
| 16 | +symbols for their common native interop solution. Which is fine if you let |
| 17 | +their executables call your dylib, but is a problem if you want your Rust |
| 18 | +executable to load a JVM instance, and let it call back into your executable. |
| 19 | +You might want to do this to allow you to: |
| 20 | +* Load multiple language runtimes into the same process (Rust + C# + Java + Lua anyone? Only one of them can be the entry executable...) |
| 21 | +* Display user-friendly error messages if language runtimes are missing (maybe even a download link!) |
| 22 | +* [#[test] Java/Rust interop via cargo test.](https://github.com/MaulingMonkey/jerk/blob/04250c9d1b6ccc292eb27663f70919345c31007f/example-hello-world-jar/src/Global.rs) |
| 23 | + |
| 24 | +For this last case, I |
| 25 | +[manually export](https://github.com/MaulingMonkey/jerk/blob/04250c9d1b6ccc292eb27663f70919345c31007f/example-hello-world-jar/exports.def) |
| 26 | +executable symbols via |
| 27 | +[LINK](https://github.com/MaulingMonkey/jerk/blob/04250c9d1b6ccc292eb27663f70919345c31007f/example-hello-world-jar/build.rs#L4). |
| 28 | +This is ugly, brittle, and rustc |
| 29 | +[already knows](https://github.com/rust-lang/rust/blob/a916ac22b9f7f1f0f7aba0a41a789b3ecd765018/src/librustc_codegen_ssa/back/linker.rs#L706-L717) |
| 30 | +how to do this automatically, across more platforms, and better. |
| 31 | + |
| 32 | +# Guide-level explanation |
| 33 | +[guide-level-explanation]: #guide-level-explanation |
| 34 | + |
| 35 | +https://doc.rust-lang.org/rustc/codegen-options/index.html could gain: |
| 36 | + |
| 37 | +```md |
| 38 | +## export-executable-symbols |
| 39 | + |
| 40 | +This flag causes `rustc` to export symbols from executables, as if they were dynamic libraries. |
| 41 | + |
| 42 | +You might use this to allow the JVM or MSCLR to call back into your executable's |
| 43 | +Rust code from Java/C# when embedding their runtimes into your Rust executable. |
| 44 | +``` |
| 45 | + |
| 46 | +`rustc -C help` could gain: |
| 47 | + |
| 48 | +``` |
| 49 | + -C export-executable-symbols -- export symbols from executables, as if they were dynamic libraries. |
| 50 | +``` |
| 51 | + |
| 52 | +My Java interop [Quick Start](https://github.com/MaulingMonkey/jerk/blob/master/Readme.md#quick-start) |
| 53 | +would start recommending a `.cargo/config` with: |
| 54 | +```toml |
| 55 | +[build] |
| 56 | +rustflags = ["-C", "export-executable-symbols"] |
| 57 | +``` |
| 58 | + |
| 59 | +# Reference-level explanation |
| 60 | +[reference-level-explanation]: #reference-level-explanation |
| 61 | + |
| 62 | +On a technical level, this just involves preventing an early bailout when |
| 63 | +calling `fn export_symbols` on executables with MSVC or GNU linker backends. |
| 64 | +Other linker backends (EmLinker, WasmLd, PtxLinker) do not have this early |
| 65 | +bailout in the first place, and remain unaffected. |
| 66 | + |
| 67 | +# Drawbacks |
| 68 | +[drawbacks]: #drawbacks |
| 69 | + |
| 70 | +* Options bloat |
| 71 | +* The burden of supporting a niche use-case in hideously platform specific code |
| 72 | + |
| 73 | +# Rationale and alternatives |
| 74 | +[rationale-and-alternatives]: #rationale-and-alternatives |
| 75 | + |
| 76 | +This is *very* simple to implement, leverages existing code to enable it to do exactly what it was meant to do, and has few drawbacks. |
| 77 | + |
| 78 | +Alternatives: |
| 79 | + |
| 80 | +- Unconditionally export symbols from executables instead of introducing a new compiler flag. |
| 81 | +- Introduce a crate-level attribute instead of a compiler flag (`#![export_all_symbols]`? `#![export_symbols]`?) |
| 82 | +- Write *yet another* cargo subcommand to install/remember for interop testing instead of using cargo test. |
| 83 | +- Write interop tests exclusively as integration tests, in an entirely separate crate, that can load the testee as a dylib. |
| 84 | +- Continue abusing LINK, writing a tool to auto-generate .defs via build scripts - possibly by reading metadata from other tools. |
| 85 | +- Use nightly link-args instead of LINK, but still write a .def generator. |
| 86 | +- Remember to always cargo build a dylib copy of a crate manually before cargo test ing, and load that instead. |
| 87 | + (That would also add a whole second copy of all functions and static vars in the same unit test process!) |
| 88 | + |
| 89 | +# Prior art |
| 90 | +[prior-art]: #prior-art |
| 91 | + |
| 92 | +C and C++ compilers can already do this via `__declspec(dllexport)` annotations. |
| 93 | +Most people don't really notice it, for good or for ill. |
| 94 | + |
| 95 | +# Unresolved questions |
| 96 | +[unresolved-questions]: #unresolved-questions |
| 97 | + |
| 98 | +- Is this a good name for it? |
| 99 | +- Should it be more general and export when limit_rdylib_exports or crate_type == ProcMacro? |
| 100 | + |
| 101 | +# Future possibilities |
| 102 | +[future-possibilities]: #future-possibilities |
| 103 | + |
| 104 | +We could introduce a new source annotation, `#[export]`. For backwards |
| 105 | +compatibility with current behavior, `#[no_mangle]` symbols could be exported |
| 106 | +by default - and possibly disabled with `#[export(false)]`. This would |
| 107 | +reduce the need to hide this change to compiler/linker behavior behind a |
| 108 | +compiler flag or crate annotation. |
| 109 | + |
| 110 | +Maybe other options to control what symbols get exported? Although I'd fear |
| 111 | +turning rustc into yet another linker script implementation, so maybe not. |
| 112 | + |
| 113 | +My own building atop this in the wider language ecosystem would be for improved |
| 114 | +Java/Rust interop/testing, with the eventual goal of improved Android API |
| 115 | +support for Rust. Many APIs are only exposed via Java, and I'd like said APIs |
| 116 | +to be usable in a safe and sound fashion. |
0 commit comments