Hi Damjan,

That really sounds great!
Although, personally it is easier for me to fire up a Windows VM... ;-)

Regarding Windows SDK 7.0: Yes, this needs to be replaced and every little step forward *is* a step forward.

Regards,

   Matthias

Am 15.02.25 um 18:40 schrieb Damjan Jovanovic:
Hi

Back in 2015, I heard how LibreOffice was cross-compiling its Windows build on Linux+Wine (https://www.winehq.org/), so I decided to try that too.

I tried it a few times before and couldn't get very far. Our Windows build uses Cygwin, and Cygwin didn't work on Wine for a long time (very old versions of Cygwin work, but as Cygwin added new features using Windows APIs that Wine doesn't implement yet, it broke). But after fixing some bugs (eg. https://bugs.winehq.org/show_bug.cgi?id=48891) and other Wine improvements, on recent Wine versions Cygwin is functional enough. A .NET 2 installation deadlock on FreeBSD (https://bugs.winehq.org/show_bug.cgi?id=52447) also discouraged me from trying it for a long time, but that was fixed in newer Wine versions when I tested last year.

And so I tried to set up a clean WINEPREFIX, and in it installed Cygwin, .NET 2, Windows SDK, Java, Ant, NASM, the usual minimal build environment for Windows. Then started Cygwin with Wine in an XFCE terminal, and followed the usual Windows build steps, and lo and behold, it actually started building!

The build then broke in a number of places, but I was able to fix or work around the issues.

-----------------------
Bugs in Wine
-----------------------
1. curl build failed with some error like "1: invalid command". Wine's cmd.exe had a bug where a "2<&1" redirection in Curl's build script was getting parsed incorrectly. I fixed it and my patch to Wine was merged (https://bugs.winehq.org/show_bug.cgi?id=57795).

2. libxml2 build failed. It turned out that the build does "cscript configure.js", and configure.js calls "vf.WriteBlankLines(1)" which fails because Wine's scrrun.dll doesn't implement ITextStream::WriteBlankLines(), so it returns the COM E_NOTIMPL error code, which becomes an exception that causes the script to fail. I fixed that too and it's been merged (https://bugs.winehq.org/show_bug.cgi?id=57810).

3. stoc build failed because xml2cmp crashed, and shell build failed because lngconvex crashed, both due to the same reason: those tools find the size of a file by seeking to the end, reading the current offset, and then seeking back to the beginning (did they never learn how the stat(2) system call lets you find a file's size easier and faster?), but Wine's msvcp90.dll has a bug where ::std::ifstream::seekg() crashes. I initially worked around that in AOO by calling seekg(0, ::std::ios::beg) instead, but also reported it to Wine, and a few days ago other Wine developers fixed it (https://bugs.winehq.org/show_bug.cgi?id=57817). It was a bug in Wine's msvcp90.dll where a wrong structure field alignment caused the wrong calling convention to be used for the function call.

4. postprocess build experienced 2 crashes in rebase due to an unimplemented function in Wine.
---snip---
rebase -i ../wntmsci12.pro/misc/coffbase.txt <http://wntmsci12.pro/misc/coffbase.txt>  -e 10000 -l ../wntmsci12.pro/misc/rebase_log.txt <http://wntmsci12.pro/misc/rebase_log.txt> -R C:/AOO/main/solver/450/wntmsci12.pro/bin <http://wntmsci12.pro/bin> -N no_rebase.txt  -v @../wntmsci12.pro/misc/rebase_again.txt <http://wntmsci12.pro/misc/rebase_again.txt> wine: Call from 7BD748A5 to unimplemented function imagehlp.dll.ReBaseImage64, aborting wine: Unimplemented function imagehlp.dll.ReBaseImage64 called at address 7BD748A5 (thread 0688), starting debugger...
---snip---
However this does not break the build: when you close the popup dialog, it continues building.

5. instsetoo_native build broke due to missing makecab.exe. Strictly speaking, this is a Wine bug, because makecab.exe is a standard part of Windows, so Wine should supply its own implementation of it. However reading the Perl script where this is called, I saw this is only necessary in some types of packaging (eg. MSI), yet the script fails even when using "--with-package-format=installed" which doesn't need it. Therefore, for now, I hacked the script to not check for it (attached).

6. insetstoo_native also breaks the first time it's run, due to some kind of memory depletion:      12 [main] perl 1440 child_copy: user heap read copy failed, 0x20000000..0x24390000, done 0, windows pid 1440, Win32 error 8     550 [main] perl 1440 child_copy: data read copy failed, 0x402000..0x402044, done 0, windows pid 1440, Win32 error 5

To work around this and complete the build, Cygwin has to be exited, "wineserver -k" run to kill all Wine instances, and then Cygwin has to be started up again, and that module cleaned and rebuilt:
cd /cygdrive/c/AOO/main/instsetoo_native
rm -rf wntmsci12.pro <http://wntmsci12.pro>
build --from instsetoo_native
This needs further investigation.

----------------------
Bugs in AOO
----------------------
I was doing a Win32 build of the windows-amd64 branch (with some extra changes I haven't pushed yet), because I wanted to check if my Windows/AMD64 changes caused any regressions in the Win32 build. And indeed, I found and fixed some AOO regressions in that branch:

1. connectivity build of drivers/ado failed:
---snip---
[ build CXX ] connectivity/source/drivers/ado/AResultSet
AResultSet.cxx
c:/AOO/main/connectivity/source/drivers/ado/AResultSet.cxx(278) : error C2664: 'Recordset15::get_AbsolutePosition' : cannot convert parameter 1 from 'sal_IntPtr *' to 'PositionEnum_Param *'         Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
---snip---

Fixed that in commit 3f8f95abcd8c826bf60b52dcebad0438358a3937 by changing the variable type to PositionEnum_Param in 2 places. The stupid data type is an integer on Win64, and an enum on Win32, go figure.

2. scp2 build broke because it couldn't find ssl3.dll and crypto3.dll (from OpenSSL). The issue there was that my scp2 changes expect the processor type to be added to SCPDEFS, but the makefile never did so. When I fixed that in commit ceb9a1253b970a2e0a3eb6c1810f24dfbb12ce38, it started using the correct names, libssl-3.dll and libcrypto-3.dll.

-------------
Results
-------------
And after the above fixes and workarounds, the build finished successfully! The resulting AOO binaries run in Wine, run on Windows, documents load, unit tests pass, and it all works!

The build works reasonably well. Wine prints out some harmless warnings, such as:
---snip---
01d8:fixme:heap:RtlSetHeapInformation HEAP_INFORMATION_CLASS 1 not implemented!
03e0:fixme:msvcrt:__clean_type_info_names_internal (7B93C39C) stub
043c:fixme:file:NtSetInformationFile Unsupported class (16)
---snip---
because Cygwin and/or Microsoft's tools use the Windows API in dirty ways, calling undocumented NTDLL functions, which Wine doesn't fully support. But this doesn't cause any problems, and these warnings can be hidden by setting the environment variable WINEDEBUG="fixme-all".

I hoped that the build would be faster, because the NTFS filesystem is slow with many small files. Unfortunately that's not the case, "time" shows it's even slower:
real    880m47.204s
user    176m38.196s
sys     212m19.741s
which is almost 15 hours, on a build without precompiled headers (and other sub-optimal conditions).

--------------------------
Reflection
--------------------------
While making these fixes I kept wondering, why am I having these issues? Back when LibreOffice did this, surely they would have submitted these bug fixes to Wine? Did they avoid the Wine bugs somehow, such as by porting curl and libxml2 to gbuild, which could be building them differently? Also surely back in 2015 Wine was even less complete and more buggy?

I went and had a look at the original email where I read about LibreOffice using Wine, and realized I misunderstood. The exact words in the email were "according to past FOSDEM talk, LibreOffice developers cross-compile Win32 version of LibreOffice on Linux and test on Wine." That sounds more like LibreOffice was only getting tested on Wine, not compiled on Wine. We've now gone even further, and can both compile and test on Wine ;-).

And how is building on Wine useful?
- For those of us that develop on *nix (Linux, FreeBSD, possibly macOS), it is much easier to build Windows versions. No separate machine necessary, no extra memory and storage necessary, no separate operating system to maintain. - The build runs in a native terminal and supports native keyboard shortcuts, not that annoying Cygwin window where you have to Ctrl+Insert to copy and Shirt+Insert to paste. - You should even be able to use the same source tree to build both *nix and Windows binaries - they just go to different subdirectories (eg. main/solver/450/wntmsci12.pro <http://wntmsci12.pro> and main/solver/450/unxlngx6.pro <http://unxlngx6.pro>). - It is already so accurately emulating Windows APIs that it has helped to find and fix bugs in the Windows build. - Wine's very design makes deployment and administration of Windows applications easier. Each WINEPREFIX directory fully contains all the state of all the applications installed in it, with its own "Windows registry" in .inf files, its own "C:" drive directory, etc. So just that one WINEPREFIX directory can be copied, moved, backed up, etc., and all the applications will go with it. - When using cloud computing, it could be cheaper, eg. Github charges more money for Windows VMs than Linux VMs.

Compared to other cross-compilation approaches, this is a "purer" build than other ways of cross-compiling to Windows, much more representative of what the build would do on real Windows: - Both mingw-w64 and Clang can compile Windows binaries on *nix, but they don't use the original Microsoft header files, and may lack DirectX, ATL and other headers. - Also I heard somewhere that debug info with MSVC was better than other compilers (but not sure if that's still the case). - We do have mingw build support in our source tree. It hasn't been used or maintained in a long time, and it's unlikely to still work. It might offer the ability to build from the *nix shell directly, without Cygwin, and thus build faster. However its use must have involved enormous work: many makefiles have special sections for it, many source files check for mingw, we have a custom UNO bridge for it, etc. Since it's so different from the MSVC build, both would need testing after changes are made. By comparison the Wine+MSVC approach is minimally invasive, and requires very few changes to the existing build. - Subtle differences in how different compilers work mean that just because one compiler works, doesn't mean another will. For example the old MSVC we use may error out on code that compiles in Clang and mingw. Such bugs will almost certainly reappear when running it on Wine, but will be hidden when using another compiler.

---------------------------------
MS Windows SDK 7.1
---------------------------------
In a separate test, I tried to build in Wine using a newer MS Windows SDK. We currently use "Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1", which is version 7.0 as per https://en.wikipedia.org/wiki/Microsoft_Windows_SDK. I tried 7.1, the "Microsoft Windows SDK for Windows 7 and .NET Framework 4". This was tried before my successful build with 7.0, and it also encountered the curl and libxml2 bugs (which I later fixed), as well as some new bugs. Python failed to build, probably because python uses vcbuild, and msbuild replaced vcbuild in that new SDK, so maybe the new SDK even requires Python 3. The icu and gtest modules have strange header file errors, maybe they need to be updated. And libtextcat failed because of missing msvcr100.dll, so it sounds like quite a lot of changes would be needed to get the 7.1 SDK working.

---------------------
Instructions
---------------------
To create the build environment:
1. Install the very latest version of Wine. You'll need to compile the latest Git from source, or wait for development version 10.2 to be released on Friday 21 February 2025 (and possibly a few more days for Linux distributions to package it). I've only used the 32 bit Wine. 2. Export a WINEPREFIX variable set to some directory where the environment will live:
export WINEPREFIX=/home/user/.wine-aoo-build
Make sure you do this in any new terminal/tab you open, where you plan to run Wine on that environment. 3. Create that WINEPREFIX by running any Wine tool, eg. "winecfg". When it asks to install Mono, click "No", Mono isn't good enough to replace .NET 2 for the Windows SDK. Configure any options in the winecfg window, then click "OK" to close it. 4. Get winetricks (Linux distribution packages usually have it), and install .NET 2 with:
winetricks dotnet20
It's needed for the Windows SDK.
5. Install the Windows SDK. Loop mount the ISO file onto a directory, and in that directory run:
wine setup.exe
6. Install Cygwin. On https://cygwin.org/install.html scroll down, and use the 32 bit Cygwin link, and these kind of options:
wine setup-x86.exe --no-verify --allow-unsupported-windows
and use one of the 32 bit URL links on that page. The setup screen looks distorted on Wine, with widgets overlapping and sizes wrong, and is just barely functional enough to select and install required packages. 7. Install the other Windows dependencies, preferably somewhere in that WINEPREFIX directory.

To build in Wine:
(This will start Cygwin in the current terminal tab:)
cd $WINEPREFIX/drive_c/cygwin/bin
wine bash.exe
export PATH="/cygdrive/c/cygwin/bin:$PATH"
(if your AOO source is in $WINEPREFIX/drive_c/AOO:)
cd /cygdrive/c/AOO/main
(apply the attached patch:)
patch -p1 < no-makecab.patch
(and build as usual:)
./configure ....
./bootstrap
source winenv.set.sh <http://winenv.set.sh>
cd instsetoo_native
build --all -P2 -- -P2

Regards
Damjan


---------------------------------------------------------------------
To unsubscribe, e-mail:dev-unsubscr...@openoffice.apache.org
For additional commands, e-mail:dev-h...@openoffice.apache.org

Attachment: smime.p7s
Description: Kryptografische S/MIME-Signatur

Reply via email to