Wine MinGW system libraries
Hello all, I'm a contributor to the Wine project. To summarize the following mail, Wine needs special versions of some of its normal dependencies, such as libfreetype and libgnutls, built using the MinGW cross-compiler, and I'm sending out a mail to major distributions in order to get some feedback from our packagers on how these should be built and packaged. For a long time Wine has built all of its Win32 libraries (DLLs and EXEs) as ELF binaries. For various reasons related to application compatibility, we have started building our binaries as PE instead, using the MinGW cross-compiler. It is our intent to expand this to some of our dependencies as well. The list of dependencies that we intend to build using MinGW is not quite fixed yet, but we expect it to include and be mostly limited to the following: * libvkd3d * libFAudio * libgnutls * zlib (currently included via manual source import) * libmpg123 * libgsm * libpng * libjpeg-turbo * libtiff * libfreetype * liblcms2 * jxrlib and dependencies of the above packages (not including CRT dependencies, which Wine provides). There is currently some internal discussion about how these dependencies should be built and linked. There are essentially three questions I see that need to be resolved, and while these resolutions have a significant impact on the Wine building and development process, they also have an impact on distributions, and accordingly I'd like to get input from our packagers to ensure that their considerations are accurately taken into account. (1) Should we build via source import, or link statically, or dynamically? Static linking and source imports are dispreferred by openSUSE [1] [2], on the grounds that they make it harder to handle security updates. They also take up more space on disk, and make building and bisecting harder. Note however that if they are linked dynamically, we need to make sure that we load our packages instead of MinGW builds of open-source libraries with applications ship with. There's some internal discussion about whether this is possible while using "stock" builds of MinGW libraries, but, due to the way the Win32 loader works, we will probably need to compile each library, and its dependencies, with a separate, wine-specific name, e.g. "libwinefreetype-6.dll" and "libwineharfbuzz.dll". For a detailed explantion see footnote [3]. Note that all we actually need to change is the name; we don't need to patch the source. Accordingly, although static linking and source imports are generally disprefered, it may quite likely be preferable in our case. We don't get the benefits of on-disk deduplication, since Wine is essentially the only piece of software which needs these libraries. (2) If we use dynamic libraries, should dependencies be included in the main wine package, or packaged separately? This is mostly a question for packagers, although it also relates to (3). (3) If dependencies are packaged separately, should Wine build them as part of its build tree (e.g. using submodules), or find and link (statically or dynamically) to existing binaries? Linking to existing binaries is generally preferable: it avoids duplication on disk; it reduces compile times when compiling a single package from source (especially the first time). However, we aren't going to benefit from on-disk duplication. And, most importantly, unlike with ELF dependencies, there is no standardized way to locate MinGW libraries—especially if it comes to Wine-specific libraries. There is a MinGW version of pkg-config shipped by many distributions, which lets us find libraries, but there's no standardized way to find them at runtime. (Also, as far as I can tell, openSUSE doesn't build MinGW pkg-config? I couldn't seem to find it anywhere. That could be trivially solved, though.) For what it's worth, the current proposed solution (which has the support of the Wine maintainer) involves source imports and submodules. There's probably room for changing our approach even after things are committed, but I'd still like to get early feedback from distributions, and make sure that their interests are accurately represented, before we commit. ἔρρωσθε, Zebediah [1] https://en.opensuse.org/openSUSE:Packaging_guidelines#Bundling_of_multiple_p... [2] https://en.opensuse.org/openSUSE:Packaging_guidelines#Static_Libraries [3] The basic problem is that applications can and often do ship with PE builds of cross-platform libraries. These libraries can be ahead of Wine's system libraries, behind them, or even built with custom patches. Accordingly we really don't want to load "our" freetype in place of "their" freetype, or "theirs" in place of "ours". But because of the way the Win32 loader works, you can generally only have one DLL of a given name loaded in a process, and further attempts to dlopen() [as it were] "libfreetype-6.dll" will return the handle to the already loaded library, potentially breaking either Wine or the application. There *may* be ways we can hack around this internally, but it's not clear that it's feasible yet, and so it's probably best to assume that we'll need special builds of dynamic libraries.
On Mon, Sep 6, 2021 at 7:37 PM Zebediah Figura <zfigura@codeweavers.com> wrote:
Hello all,
I'm a contributor to the Wine project. To summarize the following mail, Wine needs special versions of some of its normal dependencies, such as libfreetype and libgnutls, built using the MinGW cross-compiler, and I'm sending out a mail to major distributions in order to get some feedback from our packagers on how these should be built and packaged.
For a long time Wine has built all of its Win32 libraries (DLLs and EXEs) as ELF binaries. For various reasons related to application compatibility, we have started building our binaries as PE instead, using the MinGW cross-compiler. It is our intent to expand this to some of our dependencies as well. The list of dependencies that we intend to build using MinGW is not quite fixed yet, but we expect it to include and be mostly limited to the following:
* libvkd3d * libFAudio * libgnutls * zlib (currently included via manual source import) * libmpg123 * libgsm * libpng * libjpeg-turbo * libtiff * libfreetype * liblcms2 * jxrlib
and dependencies of the above packages (not including CRT dependencies, which Wine provides).
There is currently some internal discussion about how these dependencies should be built and linked. There are essentially three questions I see that need to be resolved, and while these resolutions have a significant impact on the Wine building and development process, they also have an impact on distributions, and accordingly I'd like to get input from our packagers to ensure that their considerations are accurately taken into account.
(1) Should we build via source import, or link statically, or dynamically?
Static linking and source imports are dispreferred by openSUSE [1] [2], on the grounds that they make it harder to handle security updates. They also take up more space on disk, and make building and bisecting harder.
Note however that if they are linked dynamically, we need to make sure that we load our packages instead of MinGW builds of open-source libraries with applications ship with. There's some internal discussion about whether this is possible while using "stock" builds of MinGW libraries, but, due to the way the Win32 loader works, we will probably need to compile each library, and its dependencies, with a separate, wine-specific name, e.g. "libwinefreetype-6.dll" and "libwineharfbuzz.dll". For a detailed explantion see footnote [3]. Note that all we actually need to change is the name; we don't need to patch the source.
Accordingly, although static linking and source imports are generally disprefered, it may quite likely be preferable in our case. We don't get the benefits of on-disk deduplication, since Wine is essentially the only piece of software which needs these libraries.
(2) If we use dynamic libraries, should dependencies be included in the main wine package, or packaged separately?
This is mostly a question for packagers, although it also relates to (3).
(3) If dependencies are packaged separately, should Wine build them as part of its build tree (e.g. using submodules), or find and link (statically or dynamically) to existing binaries?
Linking to existing binaries is generally preferable: it avoids duplication on disk; it reduces compile times when compiling a single package from source (especially the first time). However, we aren't going to benefit from on-disk duplication. And, most importantly, unlike with ELF dependencies, there is no standardized way to locate MinGW libraries—especially if it comes to Wine-specific libraries. There is a MinGW version of pkg-config shipped by many distributions, which lets us find libraries, but there's no standardized way to find them at runtime. (Also, as far as I can tell, openSUSE doesn't build MinGW pkg-config? I couldn't seem to find it anywhere. That could be trivially solved, though.)
We switched to pkgconf some years ago... I wonder if the folks maintaining the MinGW stack switched over to using pkgconf's "personality" feature to support requesting various targets from pkgconf. If they did, then that would explain the lack of MinGW build of pkgconfig. -- 真実はいつも一つ!/ Always, there's only one truth!
On Tuesday 2021-09-07 01:36, Zebediah Figura wrote:
[3] But because of the way the Win32 loader works, you can generally only have one DLL of a given name loaded in a process. [...] further attempts to dlopen() [as it were] "libfreetype-6.dll" will return the handle to the already loaded library
"generally" is a vague word. Generally, ld.so behaves quite similar, so there is no problem. Outside the generality, one can load two libs with the same basename, so there is also no problem.
[A library like libfreetype] can be ahead of Wine's system libraries, behind them, or even built with custom patches. Accordingly we really don't want to load "our" freetype in place of "their" freetype, or "theirs" in place of "ours".
(1) Should we build via source import, or link statically, or dynamically?
Anything that is static can not be overridden. But overriding is at the heart of your operation AIUI.
Note however that if they are linked dynamically, we need to make sure that we load our packages instead of MinGW builds of open-source libraries with applications ship with. [...] We will probably need to compile each library, and its dependencies, with a separate, wine-specific name, e.g. "libwinefreetype-6.dll"
Not a big deal. If game.exe can load its own freetype.dll in favor of wine's freetype.dll, then wine can load its own freetype.dll in favor of mingw's freetype.dll. And that works best if they do have the same filename.
On 9/7/21 3:04 AM, Jan Engelhardt wrote:
On Tuesday 2021-09-07 01:36, Zebediah Figura wrote:
[3] But because of the way the Win32 loader works, you can generally only have one DLL of a given name loaded in a process. [...] further attempts to dlopen() [as it were] "libfreetype-6.dll" will return the handle to the already loaded library
"generally" is a vague word. Generally, ld.so behaves quite similar, so there is no problem. Outside the generality, one can load two libs with the same basename, so there is also no problem.
The Win32 loader is capable of it, yeah. But it's not exactly common. There's some concern that because applications have been known to trawl the internal loader state, or even call public functions like EnumProcessModules(), they'll break in creative ways when they see two identically named libraries loaded in their process.
[A library like libfreetype] can be ahead of Wine's system libraries, behind them, or even built with custom patches. Accordingly we really don't want to load "our" freetype in place of "their" freetype, or "theirs" in place of "ours".
(1) Should we build via source import, or link statically, or dynamically?
Anything that is static can not be overridden. But overriding is at the heart of your operation AIUI.
Sorry, I'm not sure I understand. Overriding what exactly? We don't want to override their libfreetype with ours, or vice versa. We want to give the application the libfreetype it expects, and we want to load the libfreetype we expect. There are many reasons things can break otherwise, but the most realistic is that one of them is older than the other, and is missing some API that either the application or Wine needs.
Note however that if they are linked dynamically, we need to make sure that we load our packages instead of MinGW builds of open-source libraries with applications ship with. [...] We will probably need to compile each library, and its dependencies, with a separate, wine-specific name, e.g. "libwinefreetype-6.dll"
Not a big deal. If game.exe can load its own freetype.dll in favor of wine's freetype.dll, then wine can load its own freetype.dll in favor of mingw's freetype.dll. And that works best if they do have the same filename.
Hello, On Tue, 7 Sep 2021, Zebediah Figura wrote:
[A library like libfreetype] can be ahead of Wine's system libraries, behind them, or even built with custom patches. Accordingly we really don't want to load "our" freetype in place of "their" freetype, or "theirs" in place of "ours".
(1) Should we build via source import, or link statically, or dynamically?
Anything that is static can not be overridden. But overriding is at the heart of your operation AIUI.
Sorry, I'm not sure I understand. Overriding what exactly?
We don't want to override their libfreetype with ours, or vice versa. We want to give the application the libfreetype it expects, and we want to load the libfreetype we expect. There are many reasons things can break otherwise, but the most realistic is that one of them is older than the other, and is missing some API that either the application or Wine needs.
Well, if you're fearing that, then you should also fear symbol clashes, right? I.e. you not only need to rename the lib basename, but also all exported symbols from your version. (After all, programs could also crawl the export lists). At that point it all becomes cumbersome. How do deal with that problem currently? Why would that change with the file format of your helper libs? Why should the libfreetype that wine is using for internal purposes be loaded visibly into the process image at all? After all the whole purpose of an emulator is to, well, emulate the target as faithfully as possible, and one of those things would be to provide the target process with only the list of loaded DLLs it would also see on a normal Windows system. I.e. one without freetype or any other libs that you mentioned. The code and data of those libs can of course be loaded if you need them in-target-process, but all the meta data of it should not be readily linked into the normal data structures available to the target process. Ciao, Michael.
On 9/8/21 8:50 AM, Michael Matz wrote:
Hello,
On Tue, 7 Sep 2021, Zebediah Figura wrote:
[A library like libfreetype] can be ahead of Wine's system libraries, behind them, or even built with custom patches. Accordingly we really don't want to load "our" freetype in place of "their" freetype, or "theirs" in place of "ours".
(1) Should we build via source import, or link statically, or dynamically?
Anything that is static can not be overridden. But overriding is at the heart of your operation AIUI.
Sorry, I'm not sure I understand. Overriding what exactly?
We don't want to override their libfreetype with ours, or vice versa. We want to give the application the libfreetype it expects, and we want to load the libfreetype we expect. There are many reasons things can break otherwise, but the most realistic is that one of them is older than the other, and is missing some API that either the application or Wine needs.
Well, if you're fearing that, then you should also fear symbol clashes, right? I.e. you not only need to rename the lib basename, but also all exported symbols from your version. (After all, programs could also crawl the export lists). At that point it all becomes cumbersome.
How do deal with that problem currently? Why would that change with the file format of your helper libs? Why should the libfreetype that wine is using for internal purposes be loaded visibly into the process image at all? After all the whole purpose of an emulator is to, well, emulate the target as faithfully as possible, and one of those things would be to provide the target process with only the list of loaded DLLs it would also see on a normal Windows system. I.e. one without freetype or any other libs that you mentioned. The code and data of those libs can of course be loaded if you need them in-target-process, but all the meta data of it should not be readily linked into the normal data structures available to the target process.
Like any problem of emulation, it's a matter of trying to figure out what's "good enough". And the root of the problem here, what we're concerned about, is that the amount of work required to make dynamic libraries "good enough"—by our estimation—is a lot more than it is for static libraries. Currently host libraries are loaded in ELF format, and they're stored somewhere in wine internals. win32 code can see them, if they knew how to look for them, but of course they don't. The idea with PE libraries is that, since we of course already have a PE loader, we just use it for the code we can. There's some solutions that have been proposed internally that would allow us to use system dynamic libraries unmodified. They require doing some hacks to the PE loader. The hacks get worse if we try to remove system libraries from the "known" win32 data structures and put them in our own private ones. It's not clear that these hacks would be acceptable for Wine, and it's not clear that programs wouldn't break anyway for one reason or another. So while we *might* be able to use system libraries unmodified, I didn't really want to present the situation to distributions as if we were sure. But I'm sure that I can at least take this as a sign that openSUSE would like us to use its dynamic libraries if at all possible. It's certainly not alone in that :-)
Hello, On Wed, 8 Sep 2021, Zebediah Figura wrote:
Well, if you're fearing that, then you should also fear symbol clashes, right? I.e. you not only need to rename the lib basename, but also all exported symbols from your version. (After all, programs could also crawl the export lists). At that point it all becomes cumbersome.
How do deal with that problem currently? Why would that change with the file format of your helper libs? Why should the libfreetype that wine is using for internal purposes be loaded visibly into the process image at all? After all the whole purpose of an emulator is to, well, emulate the target as faithfully as possible, and one of those things would be to provide the target process with only the list of loaded DLLs it would also see on a normal Windows system. I.e. one without freetype or any other libs that you mentioned. The code and data of those libs can of course be loaded if you need them in-target-process, but all the meta data of it should not be readily linked into the normal data structures available to the target process.
Like any problem of emulation, it's a matter of trying to figure out what's "good enough".
True.
And the root of the problem here, what we're concerned about, is that the amount of work required to make dynamic libraries "good enough"—by our estimation—is a lot more than it is for static libraries.
I might see that, but is it really the case? You're saying static libs would work for you. That means static ELF libs linked into the wine executable. They aren't seen by the target PE process then, and whatever makes use of the code in those static libs (i.e. code in wine itself) also directly refers to symbols within them with the link editor resolving those references. I.e. I assume that you don't expose any of those symbols to the target process (would require trampolines and custom loader code when you link statically). Now, for some reason that I don't see right now you don't want to use dynamic ELF libs anymore. What is that reason? Linking the wine executable(s) dynamically to the system ELF libs that are static above and would be dynamic then (or are already) has exactly the same properties: symbols and lib metadata stays internal to the wine executable and isn't exposed directly to the target process, which is exactly what you should want. Your solution to this wish of avoiding ELF libs is to instead create and load PE libs into the wine executable. That immediately creates the problem you're worried about, namely namespace pollution for the target process. Now, you also don't want to adjust your PE loader to support something like an internal namespace for those wine-internal libs, because of complexity (I wouldn't call such internal namespace a hack, btw). But it seems all this complexity only comes from your wish of loading PE libs when that doesn't seem necessary. My normal answer to that would be "don't do that then". It also avoids the need to actually create PE libs with a mingw toolchain and the necessary maintenance of everything needed to cross compile those libraries. Think of it this way: assume for a moment the target process is a different architecture, i.e. that wine wouldn't only be an API emulator but also a CPU emulator, say for aarch64 with wine running on x86_64. Now your idea would be equivalent to compiling libfreetype for aarch64, and then implementing all kinds of complexity within wine to actually run that code on x86_64 just to make use of the facilities provided by libfreetype for wine purposes, instead of just using a libfreetype compiled for x86_64 to start with. Your current train of thoughts seems to go from a working and natural solution (link against system libs in host format for the host executables) to complex and unnatural solutions (create host code in target file format, but load it into the host program with the target loader but also somewhat hide it from the target process). So, what, _exactly_ is the reason that you don't want to link against ELF system libraries for the wine executables that are ELF files themself? I clearly must be missing something of the picture to see why going through these hoops even occurred to you :-)
Currently host libraries are loaded in ELF format, and they're stored somewhere in wine internals. win32 code can see them, if they knew how to look for them, but of course they don't. The idea with PE libraries is that, since we of course already have a PE loader, we just use it for the code we can.
But why? You also have an ELF loader that you don't even need to maintain yourself (in ld.so), why would you want to use the target object loader (PE) for the host binaries (the wine code) when you can load host files perfectly fine already? Ciao, Michael.
Am 07.09.21 um 01:36 schrieb Zebediah Figura: > For a long time Wine has built all of its Win32 libraries (DLLs and > EXEs) as ELF binaries. Wait, so I have two directories with libraries: * /usr/lib64/wine/x86_64-unix/ containing according to "file": "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked". * /usr/lib64/wine/x86_64-windows/ containing according to "file": "PE32+ executable (DLL) (console) x86-64, for MS Windows" plus some non-libraries. So I assume we're only talking about the <arch>-unix directory, right? > The list of dependencies that we intend to build using MinGW is no > quite fixed yet, but we expect it to include and be mostly limited> to the following: > > * libvkd3d > * libFAudio > * libgnutls > * zlib (currently included via manual source import) > * libmpg123 > * libgsm > * libpng > * libjpeg-turbo > * libtiff > * libfreetype > * liblcms2 > * jxrlib What puts a dependency on this list? Wine will typically also use the graphics stack, typically provided by Mesa. Why is that not included? Here is my very limited understanding of Wine: the <arch>-windows directory provides DLLs that a Windows application might need. These are regular PE libraries so that Windows applications don't get confused. Internally some of these libraries load libraries from <arch>-unix, but these aren't exposed to the Windows application. So they can be ELF executables, which in turn enables them to link system libraries, including those from the above list. That seems like a pretty clean design, although I don't know which problems it might produce. Now let's say we have something like libfreetype as PE, hence also most, if not all libraries in <arch>-unix. Then we could use a unified loader, but applications might see all these implementation details. Additionally, you'll likely still need to load ELF libraries at some point, because I don't think you'll want to build your own Mesa, LLVM, and all that comes with it. Best regards, Aaron
On 9/8/21 11:07 AM, Michael Matz wrote:
Hello,
On Wed, 8 Sep 2021, Zebediah Figura wrote:
Well, if you're fearing that, then you should also fear symbol clashes, right? I.e. you not only need to rename the lib basename, but also all exported symbols from your version. (After all, programs could also crawl the export lists). At that point it all becomes cumbersome.
How do deal with that problem currently? Why would that change with the file format of your helper libs? Why should the libfreetype that wine is using for internal purposes be loaded visibly into the process image at all? After all the whole purpose of an emulator is to, well, emulate the target as faithfully as possible, and one of those things would be to provide the target process with only the list of loaded DLLs it would also see on a normal Windows system. I.e. one without freetype or any other libs that you mentioned. The code and data of those libs can of course be loaded if you need them in-target-process, but all the meta data of it should not be readily linked into the normal data structures available to the target process.
Like any problem of emulation, it's a matter of trying to figure out what's "good enough".
True.
And the root of the problem here, what we're concerned about, is that the amount of work required to make dynamic libraries "good enough"—by our estimation—is a lot more than it is for static libraries.
I might see that, but is it really the case? You're saying static libs would work for you. That means static ELF libs linked into the wine executable. They aren't seen by the target PE process then, and whatever makes use of the code in those static libs (i.e. code in wine itself) also directly refers to symbols within them with the link editor resolving those references. I.e. I assume that you don't expose any of those symbols to the target process (would require trampolines and custom loader code when you link statically).
Now, for some reason that I don't see right now you don't want to use dynamic ELF libs anymore. What is that reason? Linking the wine executable(s) dynamically to the system ELF libs that are static above and would be dynamic then (or are already) has exactly the same properties: symbols and lib metadata stays internal to the wine executable and isn't exposed directly to the target process, which is exactly what you should want.
Your solution to this wish of avoiding ELF libs is to instead create and load PE libs into the wine executable. That immediately creates the problem you're worried about, namely namespace pollution for the target process. Now, you also don't want to adjust your PE loader to support something like an internal namespace for those wine-internal libs, because of complexity (I wouldn't call such internal namespace a hack, btw). But it seems all this complexity only comes from your wish of loading PE libs when that doesn't seem necessary. My normal answer to that would be "don't do that then". It also avoids the need to actually create PE libs with a mingw toolchain and the necessary maintenance of everything needed to cross compile those libraries.
Think of it this way: assume for a moment the target process is a different architecture, i.e. that wine wouldn't only be an API emulator but also a CPU emulator, say for aarch64 with wine running on x86_64. Now your idea would be equivalent to compiling libfreetype for aarch64, and then implementing all kinds of complexity within wine to actually run that code on x86_64 just to make use of the facilities provided by libfreetype for wine purposes, instead of just using a libfreetype compiled for x86_64 to start with.
Your current train of thoughts seems to go from a working and natural solution (link against system libs in host format for the host executables) to complex and unnatural solutions (create host code in target file format, but load it into the host program with the target loader but also somewhat hide it from the target process).
So, what, _exactly_ is the reason that you don't want to link against ELF system libraries for the wine executables that are ELF files themself? I clearly must be missing something of the picture to see why going through these hoops even occurred to you :-)
Currently host libraries are loaded in ELF format, and they're stored somewhere in wine internals. win32 code can see them, if they knew how to look for them, but of course they don't. The idea with PE libraries is that, since we of course already have a PE loader, we just use it for the code we can.
But why? You also have an ELF loader that you don't even need to maintain yourself (in ld.so), why would you want to use the target object loader (PE) for the host binaries (the wine code) when you can load host files perfectly fine already?
Right, I omitted the explanation for the sake of simplicity (not that it helped very much, my mail still ended up very long). Let me try to explain in detail; please feel free to ask for further clarification if necessary. The basic reason is that Wine is essentially trying to split itself into "PE" and "Unix" parts. The idea is that all of the "user" code is built in PE format, and only calls into unix code by making a sort of fake "syscall". The "kernel" code is built in ELF format (or whatever the host system loads). There are a few basic reasons for doing this: * Many applications, mostly anti-cheat and anti-tamper engines, depend on our libraries actually being in PE format on disk, and matching that in memory. We used to have "fake" DLLs for this, but they weren't verisimilar enough. This by itself basically only matters for actual Windows libraries (and in practice applications mostly only care about ones they expect to be tampered with, which isn't that many.) However... * Some of the important hosts for Wine have dropped support for 32-bit libraries or are going to drop it. Mac is the obvious example here, but many commercial Linux distributions also want to drop support. By limiting the surface through which code can transition between PE and Unix code, it becomes feasible to do 32-to-64 translation, where previously this was quite infeasible. * There's some demand for running Win32 debuggers under wine. These have always worked more than a little tenuously, but a couple of them are causing problems when they try to break in and unwind from Unix code. By acting like we're making actual syscalls, things work much better. Of the several dozen modules we have that currently call into Unix libraries, about half of them aren't going to use PE dependencies. Most of these have already been fully split into PE and Unix parts, including things like the socket layer and winegstreamer. As you point out, we could just call into the Unix parts for the other half as well. There are a few reasons we don't want to do this: * Making fake syscalls is, like real syscalls, not cheap. It involves a full context switch into and out of Unix code. * Making callbacks from Unix code is difficult, and not cheap either. Some libraries don't do callbacks, and so this doesn't matter, but others do, and it makes things ugly. * Writing the wrappers between Unix and PE code involves some nontrivial work in itself. The smaller the interface is, the easier things are for us. ἔρρωσθε, Zebediah
On 9/8/21 6:35 PM, Aaron Puchert wrote: > Am 07.09.21 um 01:36 schrieb Zebediah Figura: >> For a long time Wine has built all of its Win32 libraries (DLLs and >> EXEs) as ELF binaries. > Wait, so I have two directories with libraries: > * /usr/lib64/wine/x86_64-unix/ containing according to "file": "ELF > 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked". > * /usr/lib64/wine/x86_64-windows/ containing according to "file": "PE32+ > executable (DLL) (console) x86-64, for MS Windows" plus some non-libraries. > > So I assume we're only talking about the <arch>-unix directory, right? Sort of. I'm mainly trying to give historical context in explaining why there are even PE-format DLLs, but I didn't explain well enough. Let me try to clarify. It used to be that all libraries were built in ELF format, and sort of converted to PE format in memory on the fly. They have an export table identical to their Windows counterpart, and are named with a ".dll.so" suffix. For reasons described in [1] from this thread, we started converting these DLLs into actual PE format, by compiling them with the MinGW cross-compiler, and loading them into memory the same way we load PE DLLs. Cross-compiled DLLs have the sufix ".dll". Most such DLLs could use Wine's CRT libraries (msvcrt.dll) and didn't need to call into Unix code. Some did need to call into Unix code (most of the core parts of the Windows kernel, but also stuff like GStreamer or 3D acceleration libraries). We can't just call Unix code from a DLL (for reasons I'll try to explain below) so these got split into two pieces, one ending in ".dll" and one ending in ".so". In this case the DLL loads the .so through some internal APIs and does what are essentially fake syscalls to it. Currently most, but not all, libraries have been converted or split in this way. The x86_64-unix directory holds both the libraries that haven't been split, and the .so parts of the libraries that have. I.e. it holds both .dll.so and .so files. The x86_64-windows directory holds the PE parts of the libraries that have been converted or split, i.e. it holds the .dll files. The PE system dependency question is what stands in the way of converting most of the libraries that haven't been split yet. [1] https://lists.opensuse.org/archives/list/factory@lists.opensuse.org/thread/2M5KSB3W22X6T5VLGHPEOWJC2X7SF3KW/ > >> The list of dependencies that we intend to build using MinGW is no > quite fixed yet, but we expect it to include and be mostly limited> > to the following: >> >> * libvkd3d >> * libFAudio >> * libgnutls >> * zlib (currently included via manual source import) >> * libmpg123 >> * libgsm >> * libpng >> * libjpeg-turbo >> * libtiff >> * libfreetype >> * liblcms2 >> * jxrlib > What puts a dependency on this list? Wine will typically also use the > graphics stack, typically provided by Mesa. Why is that not included? > > Here is my very limited understanding of Wine: the <arch>-windows > directory provides DLLs that a Windows application might need. These are > regular PE libraries so that Windows applications don't get confused. > Internally some of these libraries load libraries from <arch>-unix, but > these aren't exposed to the Windows application. So they can be ELF > executables, which in turn enables them to link system libraries, > including those from the above list. That seems like a pretty clean > design, although I don't know which problems it might produce. > > Now let's say we have something like libfreetype as PE, hence also most, > if not all libraries in <arch>-unix. Then we could use a unified loader, > but applications might see all these implementation details. > Additionally, you'll likely still need to load ELF libraries at some > point, because I don't think you'll want to build your own Mesa, LLVM, > and all that comes with it. Yes, we still need to load actual ELF code. The determining questions are something like: (1) Is it easy to compile in PE format? (2) Does it need to interact with the host system, say, in terms of configuration files? (3) Does it need to call down into the OS at some level, in ways that Windows can't replicate? So anything that interacts with devices is right out (Mesa, audio libraries,
(Sorry, I accidentally hit send before I was done composing...) On 9/8/21 6:35 PM, Aaron Puchert wrote:
The list of dependencies that we intend to build using MinGW is no > quite fixed yet, but we expect it to include and be mostly limited> to the following:
* libvkd3d * libFAudio * libgnutls * zlib (currently included via manual source import) * libmpg123 * libgsm * libpng * libjpeg-turbo * libtiff * libfreetype * liblcms2 * jxrlib What puts a dependency on this list? Wine will typically also use the graphics stack, typically provided by Mesa. Why is that not included?
Here is my very limited understanding of Wine: the <arch>-windows directory provides DLLs that a Windows application might need. These are regular PE libraries so that Windows applications don't get confused. Internally some of these libraries load libraries from <arch>-unix, but these aren't exposed to the Windows application. So they can be ELF executables, which in turn enables them to link system libraries, including those from the above list. That seems like a pretty clean design, although I don't know which problems it might produce.
Now let's say we have something like libfreetype as PE, hence also most, if not all libraries in <arch>-unix. Then we could use a unified loader, but applications might see all these implementation details. Additionally, you'll likely still need to load ELF libraries at some point, because I don't think you'll want to build your own Mesa, LLVM, and all that comes with it.
Yes, we still need to load actual ELF code. The determining questions are something like: (1) Is it easy to compile in PE format? (2) Does it need to interact with the host system, say, in terms of configuration files? (3) Does it need to call down into the OS at some level, in ways that Windows can't replicate? So anything that interacts with devices is right out (Mesa, audio libraries, libusb, udev, libSDL as used for gamepads, v4l2, gphoto2, cups, sane ...). fontconfig can be built PE (and I've seen applications in the wild use it) but we need it to detect *host* fonts. GStreamer can be built PE, but we want to use host codecs where possible (also, Wine will probably end up shipping statically compiled libraries if only as a fallback, and I think we don't want to distribute patent-encumbered codecs.)
Hello, On Thu, 9 Sep 2021, Zebediah Figura wrote:
But why? You also have an ELF loader that you don't even need to maintain yourself (in ld.so), why would you want to use the target object loader (PE) for the host binaries (the wine code) when you can load host files perfectly fine already?
Right, I omitted the explanation for the sake of simplicity (not that it helped very much, my mail still ended up very long). Let me try to explain in detail; please feel free to ask for further clarification if necessary.
The basic reason is that Wine is essentially trying to split itself into "PE" and "Unix" parts. The idea is that all of the "user" code is built in PE format, and only calls into unix code by making a sort of fake "syscall". The "kernel" code is built in ELF format (or whatever the host system loads).
Okay, define "user" code then. From your initial list of libs:
* libvkd3d * libFAudio * libgnutls * zlib (currently included via manual source import) * libmpg123 * libgsm * libpng * libjpeg-turbo * libtiff * libfreetype * liblcms2 * jxrlib
Why is, for instance, libpng or libfreetype such user code? No Windows program will make use of facilities of these libraries (and if they do, they have an explicit dependency on a self-provided freetype.dll). So it seems your definition of user code extends to something beyond just the emulated windows program. I could imagine one thing: you have (of course) code that is part of some existing PE libs which really are intentionally loaded visibly into the target process (like any of the well known MS DLLs), but the implemention of functions in them actually makes use of facilities of the above libraries (like decoding PNGs). Is that it? If so, your argument about the unix<->PE border makes sense, and I see how one would like to build the above helper libs such that they can be included from your existing PE libs. (Either by statically including the code within the PE libs, or by making the above libs be themself PE DLLs) But I don't see how much a distro can help here. Especially the requirement about providing libfoo as PE DLL, but not named libfoo, but rather libfoo-for-wine-internals, to not overtly pollute the targets namespace, makes the whole thing fairly specific and un-distro-like. An extension to the PE loader of wine to support an internal namespace would help with that: a distro could provide a libfoo PE DLL package without strange renaming. (And such internal namespace would also help with some of the raison d'être for the whole stunt: not exposing the libs metadata to the process would make anti-cheaters not tripp over non matching memory/disk). Such PE DLL package could then theoretically be used in other packages that want to build PE executables that directly make use of e.g. libpng.dll . But it's still a stretch: you understandably want to use libraries that exist on the system for 3rdparty stuff you depend on. But the very act of building it as PE files already makes it non-system-provided. Nothing on the system except wine would use these files, so the usual arguments of why system libs are better (heavy testing, quicker updates for bugs) become weak quickly. If the source code between libfoo.rpm/deb and libfoo-dll.rpm/deb would be shared (i.e. they fall out of the same package source container) then at least you would benefit from quick bug fixes, but I think it's questionable if packagers are happy to have to provide for a cross compiled libpng package when they actually need to care for the system libs. Hmm, rock and hard place? :-) I don't have a good suggestion. What would be your preference or idea? (Well, I do have a crazy idea: automatically wrap an ELF file into an PE file and generate the glue automatically during wine build or even on the fly during load. You then would "properly" load the PE file into the target process, and that it happens to contain a large blob of bytes that happens to look like an ELF file is just a random little fun fact. The ABI switching glue isn't too terrible. But of course that still leaves the 32bit vs. 64bit problem: the system ELF libs will most often be 64bit, but you could depend on and wrap the -32bit variants as well if they exist) Ciao, Michael.
On 9/9/21 10:42 AM, Michael Matz wrote:
Hello,
On Thu, 9 Sep 2021, Zebediah Figura wrote:
But why? You also have an ELF loader that you don't even need to maintain yourself (in ld.so), why would you want to use the target object loader (PE) for the host binaries (the wine code) when you can load host files perfectly fine already?
Right, I omitted the explanation for the sake of simplicity (not that it helped very much, my mail still ended up very long). Let me try to explain in detail; please feel free to ask for further clarification if necessary.
The basic reason is that Wine is essentially trying to split itself into "PE" and "Unix" parts. The idea is that all of the "user" code is built in PE format, and only calls into unix code by making a sort of fake "syscall". The "kernel" code is built in ELF format (or whatever the host system loads).
Okay, define "user" code then. From your initial list of libs:
* libvkd3d * libFAudio * libgnutls * zlib (currently included via manual source import) * libmpg123 * libgsm * libpng * libjpeg-turbo * libtiff * libfreetype * liblcms2 * jxrlib
Why is, for instance, libpng or libfreetype such user code? No Windows program will make use of facilities of these libraries (and if they do, they have an explicit dependency on a self-provided freetype.dll). So it seems your definition of user code extends to something beyond just the emulated windows program.
I could imagine one thing: you have (of course) code that is part of some existing PE libs which really are intentionally loaded visibly into the target process (like any of the well known MS DLLs), but the implemention of functions in them actually makes use of facilities of the above libraries (like decoding PNGs). Is that it?
Basically, yeah. For example, libpng is used in Wine by windowscodecs.dll (which has support for decoding and encoding a bunch of different image formats) and by user32.dll (which contains most of the core windowing code, including the ability to decode and paint PNG window icons.) Both of those are of course 100% user-mode on Windows. It makes things easier for us if they are on Wine as well.
If so, your argument about the unix<->PE border makes sense, and I see how one would like to build the above helper libs such that they can be included from your existing PE libs. (Either by statically including the code within the PE libs, or by making the above libs be themself PE DLLs)
But I don't see how much a distro can help here. Especially the requirement about providing libfoo as PE DLL, but not named libfoo, but rather libfoo-for-wine-internals, to not overtly pollute the targets namespace, makes the whole thing fairly specific and un-distro-like.
An extension to the PE loader of wine to support an internal namespace would help with that: a distro could provide a libfoo PE DLL package without strange renaming. (And such internal namespace would also help with some of the raison d'être for the whole stunt: not exposing the libs metadata to the process would make anti-cheaters not tripp over non matching memory/disk). Such PE DLL package could then theoretically be used in other packages that want to build PE executables that directly make use of e.g. libpng.dll .
But it's still a stretch: you understandably want to use libraries that exist on the system for 3rdparty stuff you depend on. But the very act of building it as PE files already makes it non-system-provided. Nothing on the system except wine would use these files, so the usual arguments of why system libs are better (heavy testing, quicker updates for bugs) become weak quickly. If the source code between libfoo.rpm/deb and libfoo-dll.rpm/deb would be shared (i.e. they fall out of the same package source container) then at least you would benefit from quick bug fixes, but I think it's questionable if packagers are happy to have to provide for a cross compiled libpng package when they actually need to care for the system libs.
Hmm, rock and hard place? :-)
I don't have a good suggestion. What would be your preference or idea?
Yeah, it's awkward :-( There's been a lot of internal discussion about this, and there's a lot of people who are ready to assume that distributions just don't want to deal with our nonsense, and that we should build everything using submodules (and probably link it all statically). Actually, this assumption has been made even without considering the whole renaming-dynamic-libraries problem (after all, what possible users could there even be for MinGW libraries in the first place?) Part of my goal with these mails is to clarify what it is distributions *actually* want. Some seem quite willing to deal with adding MinGW packages for us, although none so far has been happy about the concept of using Wine-specific build script hacks for dynamic libraries. Even in the absence of any other reason to separate dependencies, there is still the concept of updating things independently (updating gnutls on the same schedule, etc.) Granted, I expect most distributions these days have facilities for tracking static library dependencies and updating them to match, though obviously that's not ideal either. Of course, the other bit is, *maybe* it's possible to use unmodified dynamic libraries. There's been ideas proposed and we're still trying to work out the kinks and figure out if it's actually plausible. In a sense I kind of want to ask "assuming we can, what do you want, and assuming we can't, what do you want". As for what Wine wants, well... there's disagreement within the project; some of us would like to see dynamic libraries and out-of-tree development (because it makes development easier), and some would like to see static libraries plus submodules or source imports (because it's easier to write). The Wine maintainer favors the latter.
(Well, I do have a crazy idea: automatically wrap an ELF file into an PE file and generate the glue automatically during wine build or even on the fly during load. You then would "properly" load the PE file into the target process, and that it happens to contain a large blob of bytes that happens to look like an ELF file is just a random little fun fact. The ABI switching glue isn't too terrible. But of course that still leaves the 32bit vs. 64bit problem: the system ELF libs will most often be 64bit, but you could depend on and wrap the -32bit variants as well if they exist)
This would I think get ugly really quickly, not to mention fragile :-/
On Thursday 2021-09-09 18:23, Zebediah Figura (she/her) wrote:
[The] assumption has been made even without considering the whole renaming-dynamic-libraries problem (after all, what possible users could there even be for MinGW libraries in the first place?)
The downstream uses for mingw libraries are - the WSL loader for our distro - other mingw packages (usually more libraries) - to build other kinds of software that do not participate in openSUSE anymore (i.e. some application you're trying to ship to a customer with native Windows) In that sense, the mingw stack's importance ranks a little below that of dmd/fpc.
Of course, the other bit is, *maybe* it's possible to use unmodified dynamic libraries. There's been ideas proposed and we're still trying to work out the kinks and figure out if it's actually plausible. In a sense I kind of want to ask "assuming we can, what do you want, and assuming we can't, what do you want".
Un-bundling is high on the list, even if the code is only ever used by one entity. Think of an extreme like chromium, which currently tries to compile 40000-ish source files from one source tarball. If one fails, the entire RPM build aborts naturally, and it has to painstakingly restart from zero after the build recipe was modified in any way. In short, the metric "source files compiled per .spec" should not be too large. (Think back to when Xorg 7.x was being split up into libxcb, libX11, libXwhatever. Though we now have 20+ more spec files, the turnaround time is _so_ much better than what it once was.)
On Thu, Sep 9, 2021 at 3:06 PM Jan Engelhardt <jengelh@inai.de> wrote:
On Thursday 2021-09-09 18:23, Zebediah Figura (she/her) wrote:
[The] assumption has been made even without considering the whole renaming-dynamic-libraries problem (after all, what possible users could there even be for MinGW libraries in the first place?)
The downstream uses for mingw libraries are
- the WSL loader for our distro - other mingw packages (usually more libraries) - to build other kinds of software that do not participate in openSUSE anymore (i.e. some application you're trying to ship to a customer with native Windows)
In that sense, the mingw stack's importance ranks a little below that of dmd/fpc.
Of course, the other bit is, *maybe* it's possible to use unmodified dynamic libraries. There's been ideas proposed and we're still trying to work out the kinks and figure out if it's actually plausible. In a sense I kind of want to ask "assuming we can, what do you want, and assuming we can't, what do you want".
Un-bundling is high on the list, even if the code is only ever used by one entity. Think of an extreme like chromium, which currently tries to compile 40000-ish source files from one source tarball. If one fails, the entire RPM build aborts naturally, and it has to painstakingly restart from zero after the build recipe was modified in any way. In short, the metric "source files compiled per .spec" should not be too large.
(Think back to when Xorg 7.x was being split up into libxcb, libX11, libXwhatever. Though we now have 20+ more spec files, the turnaround time is _so_ much better than what it once was.)
Chromium gives me nightmares. Whenever I have to work on that codebase, it *sucks*. -- 真実はいつも一つ!/ Always, there's only one truth!
On Thu, 2021-09-09 at 15:42 +0000, Michael Matz wrote:
If the source code between libfoo.rpm/deb and libfoo-dll.rpm/deb would be shared (i.e. they fall out of the same package source container) then at least you would benefit from quick bug fixes, but I think it's questionable if packagers are happy to have to provide for a cross compiled libpng package when they actually need to care for the system libs.
I'd actually love to see some investment in being able to build libraries built against mingw from the same source and spec file. (maybe similar to the baselibs for 32bit) Because most if not all libraries in windows:mingw:win{32,64} are outdated and using the same source and spec files for them would result in not having to do work twice. Right now I always use a Fedora container to build PE binaries, because they have up to date packages for mingw gtk+. I'd love to do so on on my openSUSE host. Cheers, Florian "sp1rit" -- $\int_\text{now}^{+\infty}\text{Keep trying}$ Matrix: @sp1rit:tchncs.de <sp1rit@disroot.org> D248BF2F4C6A82A1E0569D897D8C1CD573166D09 <sp1rit@national.shitposting.agency> BBDE032EAAFBFC627FB7E635B1F4055D8460CE34
On Thu, Sep 9, 2021 at 6:26 PM sp1rit <sp1rit@national.shitposting.agency> wrote:
On Thu, 2021-09-09 at 15:42 +0000, Michael Matz wrote:
If the source code between libfoo.rpm/deb and libfoo-dll.rpm/deb would be shared (i.e. they fall out of the same package source container) then at least you would benefit from quick bug fixes, but I think it's questionable if packagers are happy to have to provide for a cross compiled libpng package when they actually need to care for the system libs.
I'd actually love to see some investment in being able to build libraries built against mingw from the same source and spec file. (maybe similar to the baselibs for 32bit) Because most if not all libraries in windows:mingw:win{32,64} are outdated and using the same source and spec files for them would result in not having to do work twice.
Right now I always use a Fedora container to build PE binaries, because they have up to date packages for mingw gtk+. I'd love to do so on on my openSUSE host.
There's been some effort in the Fedora MinGW SIG to develop macros for transitioning to that model, it's just tricky because of how different everything has to be (including how debuginfo subpackage generation works). -- 真実はいつも一つ!/ Always, there's only one truth!
* Many applications, mostly anti-cheat and anti-tamper engines, [...] Oh well.... This by itself basically only matters for actual Windows libraries (and in practice applications mostly only care about ones they expect to be tampered with, which isn't that many.) I don't know much about anti-cheat, but wouldn't the graphics stack be of importance here, which you wrote is off limits? (Thinking about
* Some of the important hosts for Wine have dropped support for 32-bit libraries or are going to drop it. Mac is the obvious example here, but many commercial Linux distributions also want to drop support. By limiting the surface through which code can transition between PE and Unix code, it becomes feasible to do 32-to-64 translation, where previously this was quite infeasible. So the Unix code lives in a different process? Couldn't that result in
Am 09.09.21 um 07:13 schrieb Zebediah Figura: things like transparency cheats in FPS games, not sure if that's still something to worry about.) performance issues with games that heavily exercise graphics, sound, input libraries?
* Making fake syscalls is, like real syscalls, not cheap. It involves a full context switch into and out of Unix code. Exactly. I'm not sure at all if that's going to be an issue, but obviously one needs to be careful when introducing a process boundary, and make sure there aren't too many context switches. So here I have to agree with Michael: loading ELF libraries into the same process but "hiding" them from Windows code sounds like something I'd be less worried about. In the end it's up to you though.
From a distribution point of view (in addition to what Jan wrote about un-bundling): right now it's hard to say if we'll want to use our own sources, but staying close to upstream would be appreciated, to keep that option open for later. We have quite a few packages that have started bundling things and let that diverge to a point where using upstream code (or our package) seems ever unlikelier. Best regards, Aaron
On 9/9/21 6:54 PM, Aaron Puchert wrote:
* Many applications, mostly anti-cheat and anti-tamper engines, [...] Oh well.... This by itself basically only matters for actual Windows libraries (and in practice applications mostly only care about ones they expect to be tampered with, which isn't that many.) I don't know much about anti-cheat, but wouldn't the graphics stack be of importance here, which you wrote is off limits? (Thinking about
Am 09.09.21 um 07:13 schrieb Zebediah Figura: things like transparency cheats in FPS games, not sure if that's still something to worry about.)
Honestly we'd like to be able to cut the unix boundary for the graphics stack lower. The problem is that it's really hard when your graphics stack is Mesa, and impossible when it's proprietary.
* Some of the important hosts for Wine have dropped support for 32-bit libraries or are going to drop it. Mac is the obvious example here, but many commercial Linux distributions also want to drop support. By limiting the surface through which code can transition between PE and Unix code, it becomes feasible to do 32-to-64 translation, where previously this was quite infeasible. So the Unix code lives in a different process? Couldn't that result in performance issues with games that heavily exercise graphics, sound, input libraries?
It lives in the same process; we use an ljmp (far jump) to cross segment boundaries. Obviously it requires support from the host OS to still give us a 32-bit segment.
* Making fake syscalls is, like real syscalls, not cheap. It involves a full context switch into and out of Unix code. Exactly. I'm not sure at all if that's going to be an issue, but obviously one needs to be careful when introducing a process boundary, and make sure there aren't too many context switches. So here I have to agree with Michael: loading ELF libraries into the same process but "hiding" them from Windows code sounds like something I'd be less worried about. In the end it's up to you though.
From a distribution point of view (in addition to what Jan wrote about un-bundling): right now it's hard to say if we'll want to use our own sources, but staying close to upstream would be appreciated, to keep that option open for later. We have quite a few packages that have started bundling things and let that diverge to a point where using upstream code (or our package) seems ever unlikelier.
Best regards, Aaron
On 9/9/21 2:05 PM, Jan Engelhardt wrote:
On Thursday 2021-09-09 18:23, Zebediah Figura (she/her) wrote:
[The] assumption has been made even without considering the whole renaming-dynamic-libraries problem (after all, what possible users could there even be for MinGW libraries in the first place?)
The downstream uses for mingw libraries are
- the WSL loader for our distro - other mingw packages (usually more libraries) - to build other kinds of software that do not participate in openSUSE anymore (i.e. some application you're trying to ship to a customer with native Windows)
In that sense, the mingw stack's importance ranks a little below that of dmd/fpc.
Sorry, what are dmd/fpc?
Of course, the other bit is, *maybe* it's possible to use unmodified dynamic libraries. There's been ideas proposed and we're still trying to work out the kinks and figure out if it's actually plausible. In a sense I kind of want to ask "assuming we can, what do you want, and assuming we can't, what do you want".
Un-bundling is high on the list, even if the code is only ever used by one entity. Think of an extreme like chromium, which currently tries to compile 40000-ish source files from one source tarball. If one fails, the entire RPM build aborts naturally, and it has to painstakingly restart from zero after the build recipe was modified in any way. In short, the metric "source files compiled per .spec" should not be too large.
(Think back to when Xorg 7.x was being split up into libxcb, libX11, libXwhatever. Though we now have 20+ more spec files, the turnaround time is _so_ much better than what it once was.)
Sure, makes sense. Although honestly the size of Wine's dependencies is not particularly comparable to the size of Wine itself (not that that's great either, but, well.)
On Fri, Sep 10, 2021 at 12:16 PM Zebediah Figura <zfigura@codeweavers.com> wrote:
On 9/9/21 2:05 PM, Jan Engelhardt wrote:
On Thursday 2021-09-09 18:23, Zebediah Figura (she/her) wrote:
[The] assumption has been made even without considering the whole renaming-dynamic-libraries problem (after all, what possible users could there even be for MinGW libraries in the first place?)
The downstream uses for mingw libraries are
- the WSL loader for our distro - other mingw packages (usually more libraries) - to build other kinds of software that do not participate in openSUSE anymore (i.e. some application you're trying to ship to a customer with native Windows)
In that sense, the mingw stack's importance ranks a little below that of dmd/fpc.
Sorry, what are dmd/fpc?
DMD is the Digital Mars D compiler. FPC is the FreePascal Compiler. -- 真実はいつも一つ!/ Always, there's only one truth!
participants (7)
-
Aaron Puchert
-
Jan Engelhardt
-
Michael Matz
-
Neal Gompa
-
sp1rit
-
Zebediah Figura
-
Zebediah Figura (she/her)