Skip to content

Commit

Permalink
Port workerd to Windows using clang
Browse files Browse the repository at this point in the history
  • Loading branch information
mrbbot committed Apr 1, 2023
1 parent f609d1a commit 5e10e30
Show file tree
Hide file tree
Showing 133 changed files with 1,382 additions and 707 deletions.
73 changes: 53 additions & 20 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,22 +1,4 @@
build --cxxopt='-std=c++20' --host_cxxopt='-std=c++20' --force_pic --verbose_failures
build --cxxopt='-fcoroutines-ts' --host_cxxopt='-fcoroutines-ts'
build --cxxopt='-stdlib=libc++' --host_cxxopt='-stdlib=libc++'
build --linkopt='-stdlib=libc++' --host_linkopt='-stdlib=libc++'

build --action_env=BAZEL_COMPILER=clang
build --action_env=CC=clang
build --action_env=CXX=clang++

build --@capnp-cpp//src/kj:openssl=True --@capnp-cpp//src/kj:zlib=True --@capnp-cpp//src/kj:libdl=True

# Warning options.
build --cxxopt='-Wall' --host_cxxopt='-Wall'
build --cxxopt='-Wextra' --host_cxxopt='-Wextra'
build --cxxopt='-Wno-strict-aliasing' --host_cxxopt='-Wno-strict-aliasing'
build --cxxopt='-Wno-sign-compare' --host_cxxopt='-Wno-sign-compare'
build --cxxopt='-Wno-unused-parameter' --host_cxxopt='-Wno-unused-parameter'
build --cxxopt='-Wno-missing-field-initializers' --host_cxxopt='-Wno-missing-field-initializers'
build --cxxopt='-Wno-ignored-qualifiers' --host_cxxopt='-Wno-ignored-qualifiers'
common --enable_platform_specific_config

# Our dependencies (ICU, zlib, etc.) produce a lot of these warnings, so we disable them.
# TODO(cleanup): Can we disable warnings altogether from our dependencies, without disabling them
Expand All @@ -27,7 +9,6 @@ build --cxxopt='-Wno-ambiguous-reversed-operator' --host_cxxopt='-Wno-ambiguous-
# https://bazel.build/reference/command-line-reference#flag--reuse_sandbox_directories
build --reuse_sandbox_directories


# optimized LTO build. you'll need a fairly recent clang for this to work
build:thin-lto -c opt
build:thin-lto --cxxopt='-flto=thin'
Expand All @@ -54,3 +35,55 @@ build:fastdbg --@rules_rust//:extra_rustc_flags=-C,panic=unwind,-C,debug-asserti
# bazel and Rust use different LLVM versions. -C opt-level=s provides a comparatively small size
# improvement, ~35k or ~75k with LTO.
build:thin-lto --@rules_rust//:extra_rustc_flags=-C,panic=abort,-C,codegen-units=1

#
# Linux and macOS
#
build:unix --cxxopt='-std=c++20' --host_cxxopt='-std=c++20' --force_pic --verbose_failures
build:unix --cxxopt='-fcoroutines-ts' --host_cxxopt='-fcoroutines-ts'
build:unix --cxxopt='-stdlib=libc++' --host_cxxopt='-stdlib=libc++'
build:unix --linkopt='-stdlib=libc++' --host_linkopt='-stdlib=libc++'

build:unix --action_env=BAZEL_COMPILER=clang
build:unix --action_env=CC=clang
build:unix --action_env=CXX=clang++

# Warning options.
build:unix --cxxopt='-Wall' --host_cxxopt='-Wall'
build:unix --cxxopt='-Wextra' --host_cxxopt='-Wextra'
build:unix --cxxopt='-Wno-strict-aliasing' --host_cxxopt='-Wno-strict-aliasing'
build:unix --cxxopt='-Wno-sign-compare' --host_cxxopt='-Wno-sign-compare'
build:unix --cxxopt='-Wno-unused-parameter' --host_cxxopt='-Wno-unused-parameter'
build:unix --cxxopt='-Wno-missing-field-initializers' --host_cxxopt='-Wno-missing-field-initializers'
build:unix --cxxopt='-Wno-ignored-qualifiers' --host_cxxopt='-Wno-ignored-qualifiers'

build:unix --@capnp-cpp//src/kj:openssl=True --@capnp-cpp//src/kj:zlib=True --@capnp-cpp//src/kj:libdl=True

build:linux --config=unix
build:macos --config=unix

#
# Windows
#

# See https://bazel.build/configure/windows#symlink
startup --windows_enable_symlinks
build:windows --enable_runfiles
# We use LLVM's MSVC-compatible compiler driver to compile our code on Windows,
# as opposed to using MSVC directly. This enables us to use the "same" compiler
# frontend on Linux, macOS, and Windows, massively reducing the effort required
# to compile workerd on Windows. Notably, this provides proper support for
# `#pragma once` when using symlinked virtual includes, `__atomic_*` functions,
# a standards-compliant preprocessor, support for GNU statement expressions
# used by some KJ macros, and understands the `.c++` extension by default.
build:windows --compiler=clang-cl

build:windows --cxxopt='/std:c++20' --host_cxxopt='/std:c++20' --verbose_failures
build:windows --cxxopt='/await' --host_cxxopt='/await'
build:windows --cxxopt='/wo4503' --host_cxxopt='/wo4503'
build:windows --cxxopt='/DWINDOWS_LEAN_AND_MEAN' --host_cxxopt='/DWINDOWS_LEAN_AND_MEAN'
# The `/std:c++14` argument is unused during boringssl compilation and we don't
# want a warning when compiling each file.
build:windows --cxxopt='-Wno-unused-command-line-argument' --host_cxxopt='-Wno-unused-command-line-argument'

build:windows --@capnp-cpp//src/kj:openssl=True --@capnp-cpp//src/kj:zlib=True
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.0.0
6.1.1
15 changes: 9 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,34 @@ jobs:
test:
strategy:
matrix:
os: [ubuntu-22.04, macos-latest]
os: [ubuntu-22.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: bazelbuild/setup-bazelisk@v2
- name: Cache
id: cache
uses: actions/cache@v2
with:
path: ~/bazel-disk-cache
key: ${{ runner.os }}-${{ runner.arch }}-bazel-disk-cache
- run: mkdir -p ~/bazel-disk-cache
- name: Install dependencies
- name: Setup Linux
if: ${{ runner.os == 'Linux' }}
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get install -y build-essential git clang libc++-dev
- name: Setup Windows
if: ${{ runner.os == 'Windows' }}
run: |
[System.IO.File]::WriteAllLines((Join-Path -Path $env:USERPROFILE -ChildPath '.bazelrc'), 'startup --output_user_root=C:/tmp')
- name: Bazel build
run: |
bazel build --disk_cache=~/bazel-disk-cache --remote_cache=https://bazel:${{ secrets.BAZEL_CACHE_KEY }}@bazel-remote-cache.devprod.cloudflare.dev --verbose_failures //...
bazelisk build --disk_cache=~/bazel-disk-cache --remote_cache=https://bazel:${{ secrets.BAZEL_CACHE_KEY }}@bazel-remote-cache.devprod.cloudflare.dev --verbose_failures //...
- name: Bazel tests
run: |
bazel test --disk_cache=~/bazel-disk-cache --remote_cache=https://bazel:${{ secrets.BAZEL_CACHE_KEY }}@bazel-remote-cache.devprod.cloudflare.dev --verbose_failures --show_timestamps --keep_going --test_output=errors //...
bazelisk test --disk_cache=~/bazel-disk-cache --remote_cache=https://bazel:${{ secrets.BAZEL_CACHE_KEY }}@bazel-remote-cache.devprod.cloudflare.dev --verbose_failures --show_timestamps --keep_going --test_output=errors //...
- name: Report disk usage
if: success() || failure()
shell: bash
run: |
BAZEL_OUTPUT_BASE=$(bazel info --ui_event_filters=-WARNING output_base)
BAZEL_REPOSITORY_CACHE=$(bazel info --ui_event_filters=-WARNING repository_cache)
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ With that said, if you discover a bug that allows malicious code to break out of

### Supported Platforms

In theory, `workerd` should work on any POSIX system that is supported by V8.
In theory, `workerd` should work on any POSIX system that is supported by V8 and Windows.

In practice, `workerd` is tested on Linux and macOS under x86-64 and arm64 architectures.
On other platforms, you may have to do tinkering to make things work.
In practice, `workerd` is tested on:

- Linux and macOS (x86-64 and arm64 architectures)
- Windows (x86-64 architecture)

Windows users should run `workerd` under WSL (1 or 2).
On other platforms, you may have to do tinkering to make things work.

### Building `workerd`

Expand All @@ -76,6 +78,15 @@ To build `workerd`, you need:
* libc++ 11+ (e.g. packages `libc++-dev` and `libc++abi-dev` on Debian Bullseye)
* On macOS:
* full XCode 13+ installation
* On Windows:
* Visual Studio Community 2022, including "Desktop development with C++" features
* [LLVM 15](https://github.com/llvm/llvm-project/releases/)
* [MSYS2](https://www.msys2.org/) installed to `C:\tools\msys64` with the `BAZEL_SH` environment variable set to `C:\tools\msys64\usr\bin\bash.exe`
* [Python 3](https://www.python.org/downloads/) with a `python3` executable on the `PATH`
* GNU `patch` executable on the `PATH` (e.g. `pacman -S patch` in MSYS2 terminal, then copy `patch.exe` and `msys-2.0.dll` from `C:\tools\msys64\usr\bin` to a directory on the `PATH`)
* Add `startup --output_user_root=C:/tmp` to the `.bazelrc` file in your user directory
* Enable 8.3 filename support with `fsutil 8dot3name set 0` in an administrator command prompt
* Enable [developer mode](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) for symlink support

You may then build using:

Expand Down
20 changes: 16 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ rules_foreign_cc_dependencies()

http_archive(
name = "capnp-cpp",
sha256 = "62e337ef35061c774678be5d0b0abc8b69f78a0481b253bffe4992e74f649757",
strip_prefix = "capnproto-capnproto-6a3dd15/c++",
sha256 = "9dd4850a9cd8d2ff9a3cff2aedd0b1af956c3645d11c443adcdd9c8d312bb623",
strip_prefix = "capnproto-capnproto-4544af1/c++",
type = "tgz",
urls = ["https://github.com/capnproto/capnproto/tarball/6a3dd152d0d1245b1c44af8e76c78169cedadf03"],
urls = ["https://github.com/capnproto/capnproto/tarball/4544af13a83d6ed4127e6f91d48f8a1b57b44c91"],
)

http_archive(
Expand Down Expand Up @@ -152,6 +152,16 @@ http_file(
],
)

http_file(
name = "cargo_bazel_win_x64",
executable = True,
sha256 = "a57c496e8ff9d1b2dcd4f6a3a43c41ed0c54e9f3d48183ed411097c3590176d3",
urls = [
"https://github.com/bazelbuild/rules_rust/releases/download/0.10.0/cargo-bazel-x86_64-pc-windows-msvc.exe",
],
downloaded_file_path = "downloaded.exe" # .exe extension required for Windows to recognise as executable
)

http_archive(
name = "rules_rust",
sha256 = "0cc7e6b39e492710b819e00d48f2210ae626b717a3ab96e048c43ab57e61d204",
Expand Down Expand Up @@ -263,6 +273,7 @@ git_repository(
"//:patches/v8/0004-Add-ArrayBuffer-MaybeNew.patch",
"//:patches/v8/0005-Allow-compiling-on-macOS-catalina-and-ventura.patch",
"//:patches/v8/0006-Fix-v8-code_generator-imports.patch",
"//:patches/v8/0007-Allow-Windows-builds-under-Bazel.patch",
],
)

Expand All @@ -272,7 +283,8 @@ new_git_repository(
commit = "c6b68522318204f795a8f04caebf6c0beb679cc4",
shallow_since = "1676561136 +0000",
build_file = "@v8//:bazel/BUILD.icu",
patch_cmds = [ "find source -name BUILD.bazel | xargs rm" ]
patch_cmds = [ "find source -name BUILD.bazel | xargs rm" ],
patch_cmds_win = [ "Get-ChildItem -Path source -File -Include BUILD.bazel -Recurse | Remove-Item" ],
)

new_git_repository(
Expand Down
6 changes: 4 additions & 2 deletions build/kj_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def kj_test(
srcs = [src],
deps = [
"@capnp-cpp//src/kj:kj-test",
"@workerd//src/workerd/util:symbolizer",
] + deps,
] + select({
"@platforms//os:windows": [],
"//conditions:default": ["@workerd//src/workerd/util:symbolizer"],
}) + deps,
)
32 changes: 28 additions & 4 deletions build/rust_cxx_bridge.bzl
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
load("@rules_cc//cc:defs.bzl", "cc_library")

def rust_cxx_include(name, deps = [], visibility = [], include_prefix = None):
def rust_cxx_include(name, deps = [], visibility = [], include_prefix = None, target_compatible_with = None):
native.genrule(
name = "%s/generated" % name,
outs = ["cxx.h"],
cmd = "$(location @cxxbridge_vendor//:cxxbridge-cmd__cxxbridge) --header > \"$@\"",
tools = ["@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge"],
tools = select({
# "@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge" cannot be found on Windows
"@platforms//os:windows": [],
"//conditions:default": ["@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge"],
}),
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
cc_library(
name = name,
hdrs = ["cxx.h"],
include_prefix = include_prefix,
visibility = visibility,
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)

def rust_cxx_bridge(name, src, deps = [], visibility = [], strip_include_prefix = None, include_prefix = None):
def rust_cxx_bridge(name, src, deps = [], visibility = [], strip_include_prefix = None, include_prefix = None, target_compatible_with = None):
native.genrule(
name = "%s/generated" % name,
srcs = [src],
Expand All @@ -23,7 +35,15 @@ def rust_cxx_bridge(name, src, deps = [], visibility = [], strip_include_prefix
src + ".cc",
],
cmd = "$(location @cxxbridge_vendor//:cxxbridge-cmd__cxxbridge) $(location %s) -o $(location %s.h) -o $(location %s.cc)" % (src, src, src),
tools = ["@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge"],
tools = select({
# "@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge" cannot be found on Windows
"@platforms//os:windows": [],
"//conditions:default": ["@cxxbridge_vendor//:cxxbridge-cmd__cxxbridge"],
}),
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)

cc_library(
Expand All @@ -39,4 +59,8 @@ def rust_cxx_bridge(name, src, deps = [], visibility = [], strip_include_prefix
strip_include_prefix = strip_include_prefix,
include_prefix = include_prefix,
visibility = visibility,
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
28 changes: 21 additions & 7 deletions build/wd_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,31 @@ def wd_test(
)

def _wd_test_impl(ctx):
is_windows = ctx.target_platform_has_constraint(ctx.attr._platforms_os_windows[platform_common.ConstraintValueInfo])

# Bazel insists that the rule must actually create the executable that it intends to run; it
# can't just specify some other executable with some args. OK, fine, we'll use a script that
# just execs its args.
ctx.actions.write(
output = ctx.outputs.executable,
content = "#! /bin/sh\nexec \"$@\"\n",
is_executable = True,
)
if is_windows:
# Batch script executables must end with ".bat"
executable = ctx.actions.declare_file("%s_wd_test.bat" % ctx.label.name)
ctx.actions.write(
output = executable,
# PowerShell correctly handles forward slashes in executable paths generated by Bazel (e.g. "bazel-bin/src/workerd/server/workerd.exe")
content = "powershell -Command \"%*\"\r\n",
is_executable = True,
)
else:
executable = ctx.outputs.executable
ctx.actions.write(
output = executable,
content = "#! /bin/sh\nexec \"$@\"\n",
is_executable = True,
)

return [
DefaultInfo(
executable = ctx.outputs.executable,
executable = executable,
runfiles = ctx.runfiles(files = ctx.files.data)
),
]
Expand All @@ -64,5 +77,6 @@ _wd_test = rule(
),
"flags": attr.string_list(),
"data": attr.label_list(allow_files = True),
},
"_platforms_os_windows": attr.label(default = "@platforms//os:windows"),
}
)
2 changes: 1 addition & 1 deletion patches/capnp-ts@0.7.0.patch
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@@ -107,8 +107,6 @@ export class Struct extends Pointer {
static readonly setText = setText;
static readonly testWhich = testWhich;

- readonly _capnp!: _Struct;
-
/**
Expand Down
Loading

0 comments on commit 5e10e30

Please sign in to comment.