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

Windows: Static libraries should end with .a not .lib when using MinGW/GCC #43749

Closed
stuij opened this issue Aug 8, 2017 · 22 comments
Closed
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@stuij
Copy link

stuij commented Aug 8, 2017

It looks like there might be a regression on Windows, where Rust static libraries built with/for MinGW have the MSVC naming, instead of GCC naming. So the shared library has a .lib suffix, and isn't prepended with 'lib'. This seems to be the reverse of issue #29508.

My pared down test case was the rust-ffi-examples code, which because of this is currently broken for an MSYS2 setup (I hope I have done something wrong):

$ rustup show
Default host: i686-pc-windows-gnu

installed toolchains
--------------------

stable-i686-pc-windows-gnu
nightly-i686-pc-windows-gnu (default)

active toolchain
----------------

nightly-i686-pc-windows-gnu (default)
rustc 1.21.0-nightly (dd53dd5f9 2017-08-01)

user@DESKTOP-LL841I9 MINGW32 ~/rust-ffi-examples/c-to-rust
$ make
cargo build
   Compiling c-to-rust v0.1.0 (file:///C:/msys32/home/zeno/rust-ffi-examples/c-to-rust)
note: link against the following native artifacts when linking against this static library
 
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
 
note: library: advapi32
 
note: library: ws2_32
 
note: library: userenv
 
note: library: shell32
 
note: library: gcc_eh
 
note: library: pthread
 
    Finished dev [unoptimized + debuginfo] target(s) in 1.7 secs
cc -o target/double target/main.o target/debug/libdouble_input.a -lws2_32 -luserenv
cc.exe: error: target/debug/libdouble_input.a: No such file or directory
make: *** [Makefile:14: target/double] Error 1
 
user@DESKTOP-LL841I9 MINGW32 ~/rust-ffi-examples/c-to-rust
$ ls target/debug
build  deps  double_input.d  double_input.lib  examples  incremental  native
@Mark-Simulacrum Mark-Simulacrum added C-feature-request Category: A feature request, i.e: not implemented / a PR. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Aug 10, 2017
@alexcrichton
Copy link
Member

Oh dear thanks for the report @stuij! cc @retep998 for the regression from #29520

@alexcrichton
Copy link
Member

Also cc @vadimcn, do you think we could change this back for MinGW?

@vadimcn
Copy link
Contributor

vadimcn commented Aug 15, 2017

Doesn't look like a regression to me. It's been this way for quite some time (2 years?).

The immediate cause seems to be this line in example's Makefile, which assumes that the output library will use Unix naming convention. I'm not sure what would be the proper way of writing that Makefile: -L target/debug -ldouble_input should take care of linking, but how do we let make know the name of the dependency? Maybe target/double: target/main.o target/debug/*double_input*?

@stuij
Copy link
Author

stuij commented Aug 15, 2017

@vadimcn: I'd think changing to .a for gcc would be fitting for two reasons:

  1. As I understand on Windows a .a file is similar but not actually the same as a .lib file. So it's not really about convention in that case, but seems like an error. Unless the output is actually in a .lib format. I honestly don't know too much about this all, so I could be completely misunderstanding things.

  2. On the convention side, as the ffi-example shows, these makefiles are not just for one platform. It seems like a more elegant solution to output the static library name in a format that gcc expects across platforms, so that not every cross-platform makefile needs to resort to unspecific wildcards, which feel a bit hacky to me.

@retep998
Copy link
Member

retep998 commented Aug 15, 2017

My PR made it follow whatever the target options for that target were. For some obscure reason the windows gnu targets were configured to use .lib for their staticlibs, but that didn't have any effect until my PR made staticlib outputs actually respect that. It was probably not my intention to make MinGW output foo.lib for staticlibs.

I have absolutely no issue with changing the windows gnu target specification to use libfoo.a as the staticlib style instead of foo.lib since that would follow the MinGW conventions.

@vadimcn
Copy link
Contributor

vadimcn commented Aug 15, 2017

@stuij: .a and .lib files are exactly equivalent, it's just a different naming convention.

AFAIR, the idea of the original PR was to follow the platform convention. MinGW itself sort of sits on both chairs, because given -lname it will find both libname.a and name.lib libraries.

We could change it, but that still leaves -msvc toolchain, which arguably should follow MSVC convention.
Personally, I am of the oppinion that the Makefile should be fixed, not the compiler.

@stuij
Copy link
Author

stuij commented Aug 15, 2017

@vadimcn: and now I'm confused. According to the internets, .lib and .a files, although similar, are not the same format. And there are tools to convert the one into the other. Could you clarify for me how this relates to the format that Rust outputs?

@vadimcn
Copy link
Contributor

vadimcn commented Aug 15, 2017

@stuij: Can you please provide a link? As far as I know, they are the same.

@stuij
Copy link
Author

stuij commented Aug 15, 2017

@vadimcn: you're right about the format. The binary format for both seems to be COFF object files wrapped in ar archives. Although I couldn't find any definite proof for MinGW. I think why people have been writing/finding that they're incompatible is because they've been created by different toolchains.

The closest that I've managed to get to a stance/an advice is this mingw thread, which basically says: don't mix artifacts from different toolchains. Also plain C ABI files might work, but it might also not. 64-bit definitely won't work apparently. I don't understand why:
https://sourceforge.net/p/mingw-w64/mailman/message/32027366/

I still feel that moving to .a naming makes sense. why not follow MinGW conventions for MinGW and follow the MSVC conventions for MSVC? It will confuse people less. You shouldn't actually mix the two. You don't have to have to put hackish things in makefiles. What are the upsides of sticking with the current situation?

@vadimcn
Copy link
Contributor

vadimcn commented Aug 15, 2017

@stuij, what people are talking about is C++ ABI compatibility, and it's true - you can't link g++ object files to VC++ ones. Plain C ABI, on the other hand, is 100% compatible, as far as I know.

why not follow MinGW conventions for MinGW and follow the MSVC conventions for MSVC?

"When on Windows, do as Microsoft does". We wanted to have platform-native feel for Windows Rust port, and that means using name.lib convention. Some Windows-native tools might not support libname.a format at all.

It will confuse people less.

That's debatable. I would argue that it's less confusing to have our two Windows toolchains behave similarly.

What are the upsides of sticking with the current situation?

Not disturbing workflows and tools that people had built around the current way of doing things?

@retep998
Copy link
Member

The C ABI is compatible between MinGW and MSVC when it comes to the .dll boundary. It is not compatible when it comes to linking together object files and static libraries. There's a lot of C runtime bits that are different between MinGW and MSVC and trying to statically link them together will only end in sadness.

I have never seen the foo.lib naming convention used with MinGW and I actually prefer that MinGW uses libfoo.a because when you see a library you immediately know which toolchain it is for just based on the naming. Anybody who uses MinGW is used to libfoo.a and I really doubt that anyone would be confused by Rust's gnu staticlibs following gnu naming conventions instead of msvc naming conventions.

Besides, gnu makefiles aren't going to be written for msvc, so the choice isn't between having a special case for Windows or a special case for MSVC, it is a choice between having a special case at all and no special case.

That said, the fact that this change has been sitting around for nearly two years makes me wonder about what code out there would be broken by us reverting back to libfoo.a for MinGW targets (if anyone wants to find examples, by all means). If we really wanted to avoid breaking anything, we could just duplicate the static library so both foo.lib and libfoo.a are produced.

@alexcrichton
Copy link
Member

@vadim ah yes sorry, but to clarify this was a 1.7.0 -> 1.8.0 regression (wow that's old!). In 1.7.0 we'd create libfoo.a whereas in 1.8.0 we'd create foo.lib, due to #29520.

It sounds like though we agree that *.a and *.lib in this circumstance is equivalent in terms of binary compatibility, so to me this is a question of defaults now. I think that libfoo.a is more idiomatic on MinGW because that's the same format as all the /mingw64/lib libraries and such. That being said, I believe that the -l flag for gcc (and presumably the ld linker too) will detect both foo.lib and libfoo.a. (rustc has hardcoded logic for this but I didn't know whether it was also in MinGW)

In that sense I think I'd personally advocate for not changing the current state of affairs. It'd be another unfortunate breaking change this time to switch the output name (which may go noticed this time!). @stuij for you, though, does @vadimcn's original suggestion work for implemented a "cross platform makefile"?

@stuij
Copy link
Author

stuij commented Aug 22, 2017

@alexcrichton I resolved it in autoconf during makefile generation, although @vadimcn's idea is a bit more convenient.

@alexcrichton
Copy link
Member

Ok good to know! If that's the case then I'm going to go ahead and close this as while a bug and indeed a historical regression, at this point we're probably unlikely to fix it due to the more regressions it'd cause to fix.

@stuij
Copy link
Author

stuij commented Aug 24, 2017

Cool. Thanks all, for exploring this.

@mati865
Copy link
Contributor

mati865 commented Jun 18, 2019

@alexcrichton This bug is causing real issues when creating static libraries for *-pc-windows-gnu.

To workaround it build systems have to create *.lib and then rename it to *.a which looks very hacky. Maybe some kind of option or environment variable could be introduced that build systems could switch to get proper .a extension?

Downstream issues:
https://gitlab.gnome.org/GNOME/librsvg/issues/474
msys2/MINGW-packages#5544

@spieglt
Copy link

spieglt commented Jun 19, 2019

I'd like to echo the desire for cargo to produce libsomething.a files when targeting stable-x86_64-pc-windows-gnu. I'm trying to compile a static lib for use in a program linked to a static build of Qt, which means I have to use MinGW, and I didn't know how to add my library as cargo didn't produce a .a file and Qt Creator seemed to expect it. If I hadn't seen the recent comment from @mati865 in this thread, I wouldn't have known to just change the filename (which seems to be working).

@alexcrichton
Copy link
Member

@mati865 this issue is nearly 2 years old and I'm only very tangentially related to this. I think it's probably best if a new issue were opened up instead of reviving a long-closed issue.

@spieglt
Copy link

spieglt commented Jun 19, 2019

@alexcrichton Out of curiosity, what is the advantage of opening a new issue that would lack all of the above background information? I found it to be very valuable.

@alexcrichton
Copy link
Member

This issue is years old and has lots of outdated information. A new issue serves to provide refreshed view of the world and ensure it's accurate and up to date. You can even link to this issue and take excerpts from it if it's still true today.

@adamski
Copy link

adamski commented Oct 23, 2019

I hit this issue today. I am using CMake and got around it by changing the expected filename of the target to be linked, which is a static library.

@Keith-Cancel
Copy link

Ran into this myself, and yea quite confusing.

belijzajac added a commit to grandinetech/rust-kzg that referenced this issue Jun 4, 2023
We're using MinGW compiler to cross-compile to Windows which will produce static libraries ending with .a extention
Here's an interesting read about it: rust-lang/rust#43749 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants