From: Kevin Puetz Subject: [PATCH v2] winegcc: Implement -Wl,--out-implib Message-Id: <20201120172828.3795-1-PuetzKevinA@JohnDeere.com> Date: Fri, 20 Nov 2020 11:28:28 -0600 This allows a CMake toolchain (or other caller) to treat winegcc like MinGW, specifying that it produce a separate file for imports, e.g. set(CMAKE_IMPORT_LIBRARY_PREFIX lib) set(CMAKE_IMPORT_LIBRARY_SUFFIX .a) string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " -Wl,--out-implib,") Signed-off-by: Kevin Puetz --- Marvin tested it, but it's not showing at https://source.winehq.org/patches/ Resending after a pass through git format-patch just in case that's why. Sorry for the mix-up, I thought I'd sent quilt patches before. -- makedep.c isn't changed to use use this because the few cases in which wine currently uses #pragma implib (and thus winebuild --implib) involve putting some (but not all) of the object files into the libfoo.a as well. The motive is to fix our CMake toolchain for wineg++ to support using target_link_libraries to link other SHARED_LIBRARY targets in the project. This broke when wine-5.7 removed __wine_spec_init from winecrt0; the issue is that CMake links to with an absolute path to the .so (i.e. foo.dll.so). So we had been (unnnoticed until it quit working) getting an ELF DT_NEEDED instead of a PE import. This "worked" before, since __wine_spec_init would still register the builtin dll loaded in such a fashion. Now the dependency's own dllimports (from kernel32, etc) don't get loaded anymore. And I'm pretty sure it only worked before by happy accident. CMake supports windows-style DLL/implib separation, but it really wants the link rule to produce both artifacts (as MSVC/MinGW do) and the implib needs to be a file that can be passed to linking as an absolute path. And (for least surprise) it seems like that filename should work with -lfoo too, even though CMake will always pass a full path. libfoo.def doesn't, because winegcc sees libfoo.def as the spec_file (i.e. --export). The only way I could find to pass a libfoo.def file and have it be imports (besides having winegcc find it via -lfoo) was to conceal it in -Wb,libfoo.def, which feels rather hacky. Just forwarding the mingw-style -Wl,--out-implib to winebuild --implib seemed easy and MinGW-like (which winegcc often seems to aim for). add_undef_import is subtle, but it's already there (for #pragma implib) so I didn't see any a reason to prefer a libfoo.def over a libfoo.a, when the latter already works as a filename and as -lfoo. If I've overlooked some reason it's preferable to use .def files, perhaps there could be a distinct extension (.impdef, .a.def, or .lib ala MSVC?) which get_file_type treats as file_dll and guess_lib_type (also?) searches. Then --out-implib could check the extension and use winebuild --def vs winebuild --implib accordingly (like how winegcc already reacts to the extension of -o to decide between generate_app_loader, --fake, etc). Signed-off-by in the sense that I think this is correct and adequate, but I'm happy to take feedback if there's other use-cases an upstream submission should try to address... --- tools/winegcc/winegcc.c | 28 +++++++++++++++++++++++++++- tools/winegcc/winegcc.man.in | 3 +++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 9268a5dfd1d..887f58a6dc3 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -231,6 +231,7 @@ struct options const char* entry_point; const char* prelink; const char* debug_file; + const char* out_implib; strarray* prefix; strarray* lib_dirs; strarray* args; @@ -1085,7 +1086,7 @@ static void add_library( struct options *opts, strarray *lib_dirs, strarray *fil static void build(struct options* opts) { strarray *lib_dirs, *files; - strarray *spec_args, *link_args, *tool; + strarray *spec_args, *link_args, *implib_args, *tool; char *output_file, *output_path; const char *spec_o_name, *libgcc = NULL; const char *output_name, *spec_file, *lang; @@ -1460,6 +1461,26 @@ static void build(struct options* opts) strarray_free(tool); } + if(opts->out_implib) + { + if (!spec_file) + error("--out-implib requires a .spec or .def file\n"); + + implib_args = get_winebuild_args( opts ); + if ((tool = build_tool_name( opts, TOOL_CC ))) strarray_add( implib_args, strmake( "--cc-cmd=%s", strarray_tostring( tool, " " ))); + if ((tool = build_tool_name( opts, TOOL_LD ))) strarray_add( implib_args, strmake( "--ld-cmd=%s", strarray_tostring( tool, " " ))); + + strarray_add(implib_args, "--implib"); + strarray_add(implib_args, "-o"); + strarray_add(implib_args, opts->out_implib); + strarray_add(implib_args, "--export"); + strarray_add(implib_args, spec_file); + strarray_addall(implib_args, opts->winebuild_args); + + spawn(opts->prefix, implib_args, 0); + strarray_free (implib_args); + } + /* set the base address with prelink if linker support is not present */ if (opts->prelink && !opts->target) { @@ -1972,6 +1993,11 @@ int main(int argc, char **argv) strarray_add( opts.files, strmake( "-Wl,%s", Wl->base[j] )); continue; } + if (!strcmp(Wl->base[j], "--out-implib")) + { + opts.out_implib = strdup( Wl->base[++j] ); + continue; + } if (!strcmp(Wl->base[j], "-static")) linking = -1; strarray_add(opts.linker_args, strmake("-Wl,%s",Wl->base[j])); } diff --git a/tools/winegcc/winegcc.man.in b/tools/winegcc/winegcc.man.in index 8a14dd59fd1..5364e177c7d 100644 --- a/tools/winegcc/winegcc.man.in +++ b/tools/winegcc/winegcc.man.in @@ -72,6 +72,9 @@ Do not add the winecrt0 library when linking. .IP \fB-Wb,\fIoption\fR Pass an option to winebuild. If \fIoption\fR contains commas, it is split into multiple options at the commas. +.IP "\fB-b,--target \fItarget\fR" +.IP "\fB-Wl,--out-implib,\fIlib.a\fR" +This option should be used while linking a dll, and is implemented for compatibility with MinGW-gcc. A \fIlib.spec\fR or \fIlib.def\fR must also be provided. Despite the name, it is actually forwarded to \fBwinebuild --implib -o \fIlib.a\fR rather than to the linker. .SH ENVIRONMENT .TP .B WINEBUILD