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@JohnDeere.com --- 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
Hi Kevin,
On 20.11.2020 18:28, Kevin Puetz wrote:
- 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);
- }
I think that we still want linker to take care of import lib on windows targets (mostly mingw). Linker can do better job than winebuild (by supporting dllexport attributes, for example).
Also, ideally, we'd take care of removing that import library on error. See output_debug_file for an example.
Thanks,
Jacek
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@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... --- tools/winegcc/winegcc.c | 39 +++++++++++++++++++++++++++++++++++- tools/winegcc/winegcc.man.in | 3 +++ 2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 9268a5dfd1d..e9707a73774 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -141,6 +141,7 @@ static const char* app_loader_template =
static const char *output_file_name; static const char *output_debug_file; +static const char *output_implib; static int keep_generated = 0; static strarray* tmp_files; #ifdef HAVE_SIGSET_T @@ -231,6 +232,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; @@ -273,6 +275,7 @@ static void cleanup_output_files(void) { if (output_file_name) unlink( output_file_name ); if (output_debug_file) unlink( output_debug_file ); + if (output_implib) unlink( output_implib ); }
static void clean_temp_files(void) @@ -522,6 +525,9 @@ static strarray *get_link_args( struct options *opts, const char *output_name ) if (opts->debug_file && strendswith(opts->debug_file, ".pdb")) strarray_add(link_args, strmake("-Wl,-pdb,%s", opts->debug_file));
+ if (opts->out_implib) + strarray_add(link_args, strmake("-Wl,--out-implib,%s", opts->out_implib)); + if (!try_link( opts->prefix, link_args, "-Wl,--file-alignment,0x1000" )) strarray_add( link_args, strmake( "-Wl,--file-alignment,%s", opts->file_align ? opts->file_align : "0x1000" )); @@ -554,6 +560,10 @@ static strarray *get_link_args( struct options *opts, const char *output_name ) strarray_add(link_args, "-Wl,-debug"); strarray_add(link_args, strmake("-Wl,-pdb:%s", opts->debug_file)); } + + if (opts->out_implib) + strarray_add(link_args, strmake("-Wl,-implib:%s", opts->out_implib)); + else if (!opts->strip) strarray_add(link_args, "-Wl,-debug:dwarf"); strarray_add( link_args, strmake( "-Wl,-filealign:%s", opts->file_align ? opts->file_align : "0x1000" )); @@ -1085,7 +1095,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; @@ -1430,6 +1440,7 @@ static void build(struct options* opts)
output_file_name = output_path; output_debug_file = opts->debug_file; + output_implib = opts->out_implib; atexit( cleanup_output_files );
spawn(opts->prefix, link_args, 0); @@ -1460,6 +1471,26 @@ static void build(struct options* opts) strarray_free(tool); }
+ if (opts->out_implib && !is_pe) + { + 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 +2003,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])); } @@ -2056,5 +2092,6 @@ int main(int argc, char **argv)
output_file_name = NULL; output_debug_file = NULL; + output_implib = NULL; return 0; } diff --git a/tools/winegcc/winegcc.man.in b/tools/winegcc/winegcc.man.in index 8a14dd59fd1..5ee1456fed9 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. \fBwinebuild --implib\fR is used for non-PE targets whose linker does not natively have such an option, so a \fIlib.spec\fR or \fIlib.def\fR is required. .SH ENVIRONMENT .TP .B WINEBUILD
Signed-off-by: Jacek Caban jacek@codeweavers.com