ungoogled-chromium-windows
ungoogled-chromium-windows copied to clipboard
Cross-compiling (ungoogled) Chromium for Windows from Linux
...without touching a Windows PC.
This should make possible a u-c build that is...
-
More easily reproducible and CI-friendly, since no manual "install Visual Studio on your PC" step is involved;
-
More hermetic, in that we don't have to worry about said PC having been surreptitiously compromised;
-
Faster, in line with the experience of others;
-
Less costly to run, given how GitHub double-counts each minute of GitHub Actions that runs on Windows as compared to Linux.
Google has posted official instructions on how to cross-compile Chromium for Windows, but that documentation makes some CI-averse assumptions (packaging up a manual Visual Studio installation) and glosses over several important details (e.g. SetEnv files and the rc
executable).
Even more unfortunately, I could not find that anyone has distilled those instructions into a working setup that others can use as a starting point. So, given that I've already built this beast (for Linux) more times than I care to count, I figured I'd take a stab at it.
To begin with, I'd like to draw your attention to a nifty little project called msvc-wine. They have put together a Python script (vsdownload.py
) that can download any of Microsoft's current SDK offerings, without needing to run some setup/installer/wizard thing. This eliminates the requirement of a Windows PC altogether.
For compiling Windows resource files, Google has a re-implementation of rc
that they use in the cross build. The source is available here. (That may seem like a random location, but it is directly referenced in the Chromium tree. Nico appears to be a Googler.)
Many guides for performing cross builds have some variation of a "put the Windows SDK on a VFAT-formatted filesystem" step, to recreate the case-insensitive lossage of the target OS. (You have winsock2.h
vs. WinSock2.h
, advapi32.lib
vs. AdvAPI32.Lib
etc., and files are often referenced via both forms.) This was more hassle than I wanted to deal with, so I wrote up a script (case-fold.sh
) that creates a bunch of symlinks to get the same effect.
And with all that, I've put together tooling to build a Docker image that provides a suitable Linux environment (based on Debian unstable or Ubuntu mantic) for performing the cross build. I've already run through building 119.0.6045.159 with it several times.
Edited 2024-04-09: Please see current information and usage instructions here. This work has come a long way since the initial post.
Original, now-obsolete verbiage
Unfortunately, the build is not fully working yet---with `-k 0`, it gets a bit past the halfway mark before stopping. While all the tooling issues I've come across have been addressed, there are a number of funky C++ errors that I can't make heads or tails of... things like implicit `StringPiece` conversions not working correctly. I'm using Clang 17, so I don't think it's an issue of the compiler not being new enough. I'm hoping that folks who have more experience with this codebase, and with the Windows side of things in general, will be able to make sense of what's going on.Here is a log file produced by a second invocation of ninja ... -k 0 chrome
that shows all the error messages, strung together. If you are successful in reproducing my build, then this is what you should see.
Steps to get this working:
-
git clone
the relevant source location onto a system with a Docker host; -
Edit the top of the
Dockerfile
to choose Debian or Ubuntu as your base (it should not take much work to adapt the image build to some other distro, like Arch, but this is what I can provide), and editAPT_MIRROR
to point to a faster/local APT host if you have one; -
Edit the
setup.sh
script to uncomment theaccept_license
variable, by which you accept the Microsoft EULA mumblemumble; -
Build the Docker image with
make build-image
; -
If that is successful, then you can start a container with
make run
; -
Unpack a Chromium source tarball inside the container;
-
In the top-level directory of the Chromium source tree, run the
~/prepare-source.sh
script. This will fix a few minor source issues, put some necessary files into place, and rungn gen
with a configuration that is known to work; -
Run e.g.
ninja -C out/Release -k 0 chrome
, and see how far it gets; -
To delete the image, exit the container and run
make clean
.
Of course, you will have to customize the container workflow to suit your needs (add mounts, change the user ID, etc.). Some points to keep in mind:
-
All the Microsoft SDK stuff is installed under
/opt/microsoft/
, and the Chromium-relevant environment variables are set accordingly; -
Google's
rc
is available in source form under/usr/local/src/
, and binary under/usr/local/bin/
; -
All the necessary compiler and library (distro) packages that I'm aware of are installed. More may be needed by later stages of the build;
-
Additional case-variation symlinks under
/opt/microsoft/
may be needed by later stages of the build. These will have to be added to thecase-fold.sh
script; -
If you build the image more than once, then I suggest tarring up the files under
~/cache/
, copying that out, and then uncommenting theADD ... cache.tar ...
directive in theDockerfile
. This will allow you to run through the MSVC "install" process again without re-downloading the ~2.5 GB lot from Microsoft; -
The scripts are reasonably commented to explain what's going on, so please feel free to read through them beforehand;
-
I am more than happy to reproduce and sort out tooling issues as you encounter them. What I need help with is the Chromium codebase itself, as the C++-fu in use is beyond my ken;
-
As you can see, I haven't even bothered to bring in the u-c patches or tooling yet. Gotta walk (i.e. build plain Chromium) before you can run, I say! But that is naturally the end goal.
Some additional notes:
Google has a CI instance covering this cross build, but it has been broken for months. The most recent successful build that I could find (without spending too much time looking for it, given the poor UI) dates from the end of May.
Here is the GN config they use, though this doesn't work for our purposes (e.g. we need use_sysroot=false
since we're not using a Linux sysroot):
dcheck_always_on = true
is_clang = true
is_component_build = true
is_debug = false
llvm_force_head_revision = true
symbol_level = 1
target_os = "win"