winegcc: Implement -Wl,--out-implib

Kevin Puetz PuetzKevinA at JohnDeere.com
Fri Nov 20 09:44:45 CST 2020


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,<TARGET_IMPLIB>")

Signed-off-by: Kevin Puetz <PuetzKevinA at JohnDeere.com>

---
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...

Index: wine/tools/winegcc/winegcc.c
===================================================================
--- wine.orig/tools/winegcc/winegcc.c
+++ wine/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
 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;
@@ -1454,6 +1455,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)
     {
@@ -1966,6 +1987,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]));
                         }
Index: wine/tools/winegcc/winegcc.man.in
===================================================================
--- wine.orig/tools/winegcc/winegcc.man.in
+++ wine/tools/winegcc/winegcc.man.in
@@ -72,6 +72,9 @@ Do not add the winecrt0 library when lin
 .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



More information about the wine-devel mailing list