Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for DllExport on Windows #7196

Closed
kvanbere opened this issue Jun 17, 2013 · 11 comments · Fixed by #27416
Closed

Add support for DllExport on Windows #7196

kvanbere opened this issue Jun 17, 2013 · 11 comments · Fixed by #27416
Labels
A-codegen Area: Code generation O-windows Operating system: Windows

Comments

@kvanbere
Copy link

It currently does not seem to be possible to export a function from a DLL on Windows. It's not done as one would expect when building with --lib.

@kvanbere
Copy link
Author

It seems that rustc-hash.dll indeed contains exports on Windows, and therefore it must be possible to somehow build such that code is exported. The following method does not produce exports;

Crate:

// Crate linkage metadata
#[link(name = "thing", vers = "1.0", author = "who")];

// Make a library ("bin" is the default)
#[crate_type = "lib"];

// Load some modules from other files
mod test;

Module:

pub extern fn foo(a: int) -> int {
    1
}

Thoughts?

@kvanbere
Copy link
Author

mod test; -> pub mod test; works as intended. Sorry folks, closing.

@Aatch
Copy link
Contributor

Aatch commented Jun 17, 2013

Re-opening because the general idea is still sound. Adding a #[linkage] attribute for more exotic linkage types seems valid to me.

Also, I'm nominating this for production ready, based on the idea that dllimport/dllexport exist for a reason. Though I'm happy to be corrected here.

@Aatch Aatch reopened this Jun 17, 2013
@emberian
Copy link
Member

emberian commented Aug 5, 2013

Visiting for triage; nothing to add

@catamorphism
Copy link
Contributor

Accepted for feature-complete

@pnkfelix
Copy link
Member

Assigning P-low. Not 1.0.

@klutzy
Copy link
Contributor

klutzy commented May 28, 2014

We actually dllexports all public symbols:

// lib.rs
#![crate_type = "dylib"]
#![crate_id = "r"]
#[no_mangle] pub fn func1() {} // exported
#[no_mangle] fn func2() {}
pub fn func3() {} // exported
fn func4() {}
C:\home\stone\tmp>dumpbin /exports r-1437d9a7-0.0.dll
...
File Type: DLL

  Section contains the following exports for r-1437d9a7-0.0.dll

    00000000 characteristics
    538549CB time date stamp Wed May 28 11:28:27 2014
        0.00 version
           1 ordinal base
           4 number of functions
           4 number of names

    ordinal hint RVA      name

          1    0 000015F0 _ZN5func320h830e15bc5d49336cjaa4v0.0E
          2    1 0000162C __morestack
          3    2 000015B0 func1
          4    3 00004000 rust_metadata_r_0.0_ac1193c82740e58b

but just by accident! If we don't explicitly export anything, ld exports everything public.

The "unintended export" will not occur if we add some explicit dllexports in native code:

// c.c
__declspec(dllexport)
void func5(void) {}
$ gcc -c -o c.o c.c
$ ar rcs ext.lib c.o
// lib.rs
#![crate_type = "dylib"]
#![crate_id = "r"]

#[link(name = "ext", kind = "static")]
extern "C" {
    pub fn func5();
}

#[no_mangle] pub fn func1() {} // exported
#[no_mangle] fn func2() {}
fn func3() { unsafe { func5(); } } // use dllexported symbol
$ rustc lib.rs

C:\home\stone\tmp>dumpbin /exports r-1437d9a7-0.0.dll
...
  Section contains the following exports for r-1437d9a7-0.0.dll

    00000000 characteristics
    538552D1 time date stamp Wed May 28 12:06:57 2014
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 0000161C func5
// a.rs
extern crate r;

fn main() {
    r::func1();
}
$ rustc lib.rs
$ rustc a.rs -L .
error: linking with `gcc` failed: exit code: 1
...
note: a.o:(.text+0x1a): undefined reference to `func1'

This is bad. We have to export them explicitly in this case.

@steveklabnik
Copy link
Member

I'm pulling a massive triage effort to get us ready for 1.0. As part of this, I'm moving stuff that's wishlist-like to the RFCs repo, as that's where major new things should get discussed/prioritized.

This issue has been moved to the RFCs repo: rust-lang/rfcs#826

@klutzy
Copy link
Contributor

klutzy commented Feb 11, 2015

(Note that the missing export behavior is certainly a bug, which can be fixed without introducing dllexport syntax support. I'll open new issue for the one.)

@alexcrichton
Copy link
Member

Note that for MSVC targets the compiler now places dllexport on all exported functions from a library. It does not, however deal with dllimport at all, and in general the situation is unfortunately a bit of a mess.

I've written up a comment about this, but I'm going to use this bug to track a more proper implementation of using dllimport and dllexport, many of the concerns of which are outlined in that bug. @klutzy also probably knows enough about this to be a good liason to talk to!

I think this is more concretely actionable in this repo than the RFC repo for now, so I'm going to reopen this.

@alexcrichton alexcrichton reopened this May 29, 2015
@alexcrichton alexcrichton added T-tools and removed E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. P-low Low priority labels May 29, 2015
@retep998
Copy link
Member

I think we shouldn't indiscriminately put dllexport on all exported functions from a library, because if we statically link the library, then those functions still have dllexport and are thus exported from the resulting executable, even though the main crate doesn't publicly re-export them. I think this might be why link is failing to strip unreferenced functions.

bors added a commit that referenced this issue Aug 11, 2015
These two commits are aimed at "fixing" our usage of `dllexport` in the compiler. Currently we blanket apply this attribute to *everything* public in a crate, but this ends up with a few downsides:

* Executables are larger than the should be as a result of thinking they should export everything
* Native libraries aren't handled correctly because technically a statically included native library should be exported from a DLL in some cases.
* Symbols don't actually need to be exported if they never end up in a DLL.

The first commit adds a new unstable attribute, `#[linked_from]`, which is a way to tell the compiler what native library a block of symbols comes from. This is used to inform the compiler what set of native libraries are statically included in the rlib (or other output). This information is later used to export them from a DLL if necessary. Currently this is only used in a few places (such as the LLVM bindings) to get the compiler to link correctly.

The second commit stops adding `dllexport` to all items in LLVM and instead explicitly telling the linker what symbols should be exported. We only need to do this when building a dynamic library, and otherwise we can avoid adding `dllexport` or telling the linker about exported symbols.

As a testament to this change, the size of "Hello World" on MSVC drops from 1.2MB to 67KB as a result of this patch. This is because the linker can much more aggressively remove unused code.

These commits do not yet attempt to fix our story with `dllimport`, and I'll leave that to a future PR and issue, for now though I'm going to say that this

Closes #7196
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation O-windows Operating system: Windows
Projects
None yet
9 participants