Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS Support #6

Merged
merged 3 commits into from Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .bazelversion
@@ -0,0 +1 @@
5.3.0
3 changes: 1 addition & 2 deletions README.md
Expand Up @@ -36,7 +36,6 @@ The config format may change in backwards-incompatible ways before `workerd` lea

As of this writing, some major features are missing which we intend to fix shortly:

* **MacOS** is not supported yet, but should be imminently. We've never tried to build this code on Mac in the past, but we expect it should only require minor tweaks. Most of the work is figuring out how to wrangle the build system. (Windows users, meanwhile, should use WSL2. A native Windows port would be a challenge and is not currently being worked on.)
* **Binary Packages** for various distributions are not built yet. We intend to provide these once out of beta.
* **Wrangler/Miniflare integration** is in progress. The [Wrangler CLI tool](https://developers.cloudflare.com/workers/wrangler/) and [Miniflare](https://miniflare.dev/) will soon support local testing using `workerd` (replacing the previous simulated environment on top of Node). Wrangler should also support generating `workerd` configuration directly from a Wrangler project.
* **Multi-threading** is not implemented. `workerd` runs in a single-threaded event loop. For now, to utilize multiple cores, we suggest running multiple instances of `workerd` and balancing load across them. We will likely add some built-in functionality for this in the near future.
Expand All @@ -60,7 +59,7 @@ With that said, if you discover a bug that allows malicious code to break out of

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

In practice, `workerd` is tested on Linux (TODO: and MacOS) under x86-64 and arm64 architectures.
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.

Windows users should run `workerd` under WSL2.
Expand Down
20 changes: 19 additions & 1 deletion WORKSPACE
Expand Up @@ -89,14 +89,32 @@ protobuf_deps()
# workerd uses some Rust libraries, especially lolhtml for implementing HtmlRewriter.

http_file(
name = "cargo_bazel",
name = "cargo_bazel_linux_x64",
executable = True,
sha256 = "a9f81a6fd356fc01e3da2483bdd1f9dfb080b0bdf5a128fa036c048e5b301562",
urls = [
"https://github.com/bazelbuild/rules_rust/releases/download/0.10.0/cargo-bazel-x86_64-unknown-linux-gnu",
],
)

http_file(
name = "cargo_bazel_macos_x64",
executable = True,
sha256 = "fb80acb9fcfd83674f73e98bf956bc65b33f31a4380ba72fbc1a6a9bf22c2f8c",
urls = [
"https://github.com/bazelbuild/rules_rust/releases/download/0.10.0/cargo-bazel-x86_64-apple-darwin",
],
)

http_file(
name = "cargo_bazel_macos_arm64",
executable = True,
sha256 = "4104ea8edd3fccbcfc43265e4fa02dfc25b12b32250ff46456b829ab9cb78908",
urls = [
"https://github.com/bazelbuild/rules_rust/releases/download/0.10.0/cargo-bazel-aarch64-apple-darwin",
],
)

http_archive(
name = "rules_rust",
sha256 = "0cc7e6b39e492710b819e00d48f2210ae626b717a3ab96e048c43ab57e61d204",
Expand Down
34 changes: 32 additions & 2 deletions rust-deps/BUILD.bazel
@@ -1,6 +1,34 @@
load("//:build/rust_cxx_bridge.bzl", "rust_cxx_bridge", "rust_cxx_include")
load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor")
load("@rules_rust//rust:defs.bzl", "rust_static_library")
load("@bazel_skylib//lib:selects.bzl", "selects")

selects.config_setting_group(
name = "linux_x64",
match_all = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
)
selects.config_setting_group(
name = "macos_x64",
match_all = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
)
selects.config_setting_group(
name = "macos_arm64",
match_all = [
"@platforms//os:macos",
"@platforms//cpu:aarch64",
],
)
CARGO_BAZEL = select({
"//:linux_x64": "@cargo_bazel_linux_x64//file:downloaded",
"//:macos_x64": "@cargo_bazel_macos_x64//file:downloaded",
"//:macos_arm64": "@cargo_bazel_macos_arm64//file:downloaded",
})
mrbbot marked this conversation as resolved.
Show resolved Hide resolved

# TODO (before prod):
# - arm64 build
Expand All @@ -19,7 +47,7 @@ crates_vendor(
shallow_since = "1657163695 -0400",
)],
},
cargo_bazel = "@cargo_bazel//file:downloaded",
cargo_bazel = CARGO_BAZEL,
mode = "remote",
packages = {
"anyhow": crate.spec(
Expand Down Expand Up @@ -70,6 +98,7 @@ crates_vendor(
},
supported_platform_triples = [
"x86_64-unknown-linux-gnu",
"aarch64-apple-darwin",

# this is not used but its required to work around a bug in rules_rust where
# invalid select statements can get generated in vendored BUILD files
Expand All @@ -80,7 +109,7 @@ crates_vendor(
# To repin crates: bazel run //rust-deps:cxxbridge_vendor -- --repin
crates_vendor(
name = "cxxbridge_vendor",
cargo_bazel = "@cargo_bazel//file:downloaded",
cargo_bazel = CARGO_BAZEL,
mode = "remote",
packages = {
"cxxbridge-cmd": crate.spec(
Expand All @@ -90,6 +119,7 @@ crates_vendor(
# host toolchain only
supported_platform_triples = [
"x86_64-unknown-linux-gnu",
"aarch64-apple-darwin",
],
vendor_path = "cxxbridge_crates",
)
Expand Down
2 changes: 2 additions & 0 deletions rust-deps/crates/BUILD.ahash-0.7.6.bazel
Expand Up @@ -90,6 +90,7 @@ rust_library(
] + select_with_or({
# cfg(any(target_os = "linux", target_os = "android", target_os = "windows", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", target_os = "redox", target_os = "cloudabi", target_os = "haiku", target_os = "vxworks", target_os = "emscripten", target_os = "wasi"))
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
# Target Deps
Expand All @@ -100,6 +101,7 @@ rust_library(
],
# cfg(not(all(target_arch = "arm", target_os = "none")))
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:wasm32-unknown-unknown",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
Expand Down
1 change: 1 addition & 0 deletions rust-deps/crates/BUILD.getrandom-0.1.16.bazel
Expand Up @@ -96,6 +96,7 @@ rust_library(
#
# cfg(unix)
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
# Target Deps
Expand Down
1 change: 1 addition & 0 deletions rust-deps/crates/BUILD.getrandom-0.2.7.bazel
Expand Up @@ -91,6 +91,7 @@ rust_library(
#
# cfg(unix)
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
# Target Deps
Expand Down
2 changes: 2 additions & 0 deletions rust-deps/crates/BUILD.rand-0.7.3.bazel
Expand Up @@ -95,6 +95,7 @@ rust_library(
] + select_with_or({
# cfg(not(target_os = "emscripten"))
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:wasm32-unknown-unknown",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
Expand All @@ -113,6 +114,7 @@ rust_library(
#
# cfg(unix)
(
"@rules_rust//rust/platform:aarch64-apple-darwin",
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu",
): [
# Target Deps
Expand Down
8 changes: 4 additions & 4 deletions rust-deps/crates/defs.bzl
Expand Up @@ -363,12 +363,12 @@ _BUILD_PROC_MACRO_ALIASES = {

_CONDITIONS = {
"cfg(all(target_arch = \"wasm32\", not(target_os = \"emscripten\")))": ["wasm32-unknown-unknown"],
"cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))": ["x86_64-unknown-linux-gnu"],
"cfg(not(all(target_arch = \"arm\", target_os = \"none\")))": ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"],
"cfg(not(target_os = \"emscripten\"))": ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"],
"cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))": ["aarch64-apple-darwin", "x86_64-unknown-linux-gnu"],
"cfg(not(all(target_arch = \"arm\", target_os = \"none\")))": ["aarch64-apple-darwin", "wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"],
"cfg(not(target_os = \"emscripten\"))": ["aarch64-apple-darwin", "wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"],
"cfg(target_os = \"emscripten\")": [],
"cfg(target_os = \"wasi\")": [],
"cfg(unix)": ["x86_64-unknown-linux-gnu"],
"cfg(unix)": ["aarch64-apple-darwin", "x86_64-unknown-linux-gnu"],
}

###############################################################################
Expand Down
2 changes: 2 additions & 0 deletions src/workerd/api/analytics-engine-impl.h
Expand Up @@ -8,6 +8,8 @@

namespace workerd::api {

using kj::uint;

constexpr uint MAX_INDEXES_LENGTH = 1;
constexpr size_t MAX_INDEX_SIZE_IN_BYTES = 32;
constexpr uint MAX_ARRAY_MEMBERS = 20;
Expand Down
1 change: 1 addition & 0 deletions src/workerd/api/analytics-engine.h
Expand Up @@ -13,6 +13,7 @@
namespace workerd::api {

using kj::byte;
using kj::uint;

class AnalyticsEngine: public jsg::Object {
// Analytics Engine is a tool for customers to get telemetry about anything
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/r2-rpc.c++
Expand Up @@ -170,7 +170,7 @@ kj::Promise<R2Result> doR2HTTPPutRequest(jsg::Lock& js, kj::Own<kj::HttpClient>
}
}
} else {
expectedBodySize = 0ul;
expectedBodySize = uint64_t(0);
KJ_REQUIRE(streamSize == nullptr);
}

Expand Down
4 changes: 2 additions & 2 deletions src/workerd/api/streams/standard.h
Expand Up @@ -18,9 +18,9 @@ class WritableStreamDefaultController;
class TransformStreamDefaultController;

struct StreamQueuingStrategy {
using SizeAlgorithm = size_t(v8::Local<v8::Value>);
using SizeAlgorithm = uint64_t(v8::Local<v8::Value>);

jsg::Optional<size_t> highWaterMark;
jsg::Optional<uint64_t> highWaterMark;
jsg::Optional<jsg::Function<SizeAlgorithm>> size;

JSG_STRUCT(highWaterMark, size);
Expand Down
2 changes: 2 additions & 0 deletions src/workerd/api/url.h
Expand Up @@ -11,6 +11,8 @@

namespace workerd::api {

using kj::uint;

class URLSearchParams;

class URL: public jsg::Object {
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/io/cdp.capnp
Expand Up @@ -13,7 +13,7 @@ $Cxx.namespace("workerd::cdp");

enum LogType {
log @0;
debug @1;
debug @1 $Cxx.name("debug_"); # avoid collision with macro on Apple platforms
info @2;
error @3;
warning @4;
Expand Down
17 changes: 14 additions & 3 deletions src/workerd/io/worker.c++
Expand Up @@ -415,6 +415,17 @@ void reportStartupError(
}
}

uint64_t getCurrentThreadId() {
#if __linux__
return syscall(SYS_gettid);
#else
// Assume MacOS or BSD
uint64_t tid;
pthread_threadid_np(NULL, &tid);
return tid;
#endif
}

} // namespace

class Worker::InspectorClient: public v8_inspector::V8InspectorClient {
Expand All @@ -430,7 +441,7 @@ public:
auto& ioContext = IoContext::current();
timePoint = ioContext.now();
} else KJ_IF_MAYBE(info, inspectorTimerInfo) {
if (info->threadId == syscall(SYS_gettid)) {
if (info->threadId == getCurrentThreadId()) {
// We're on an inspector-serving thread.
timePoint = info->timer.now() + info->timerOffset
- kj::origin<kj::TimePoint>() + kj::UNIX_EPOCH;
Expand All @@ -448,14 +459,14 @@ public:

void setInspectorTimerInfo(kj::Timer& timer, kj::Duration timerOffset) {
// Helper for attachInspector().
inspectorTimerInfo = InspectorTimerInfo { timer, timerOffset, syscall(SYS_gettid) };
inspectorTimerInfo = InspectorTimerInfo { timer, timerOffset, getCurrentThreadId() };
}

private:
struct InspectorTimerInfo {
kj::Timer& timer;
kj::Duration timerOffset;
long threadId;
uint64_t threadId;
};

kj::Maybe<InspectorTimerInfo> inspectorTimerInfo;
Expand Down
21 changes: 19 additions & 2 deletions src/workerd/jsg/setup.c++
Expand Up @@ -2,6 +2,11 @@
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

#if __APPLE__
// We need to define `_XOPEN_SOURCE` to get `ucontext_t` on Mac.
#define _XOPEN_SOURCE
#endif

#include "setup.h"
#include <cxxabi.h>
#include "libplatform/libplatform.h"
Expand All @@ -12,6 +17,10 @@
#include <unicode/udata.h>
#endif

#if defined(__APPLE__) && defined(__aarch64__)
#include <mach/mach.h>
#endif

namespace workerd::jsg {

static bool v8Initialized = false;
Expand Down Expand Up @@ -542,11 +551,19 @@ kj::Maybe<kj::StringPtr> getJsStackTrace(void* ucontext, kj::ArrayPtr<char> scra

v8::RegisterState state;
auto& mcontext = reinterpret_cast<ucontext_t*>(ucontext)->uc_mcontext;
#if __x86_64__
#if defined(__APPLE__) && defined(__x86_64__)
state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
#elif defined(__APPLE__) && defined(__aarch64__)
state.pc = reinterpret_cast<void*>(arm_thread_state64_get_pc(mcontext->__ss));
state.sp = reinterpret_cast<void*>(arm_thread_state64_get_sp(mcontext->__ss));
state.fp = reinterpret_cast<void*>(arm_thread_state64_get_fp(mcontext->__ss));
#elif defined(__linux__) && defined(__x86_64__)
state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
#elif __aarch64__
#elif defined(__linux__) && defined(__aarch64__)
state.pc = reinterpret_cast<void*>(mcontext.pc);
state.sp = reinterpret_cast<void*>(mcontext.sp);
state.fp = reinterpret_cast<void*>(mcontext.regs[29]);
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/jsg/util.c++
Expand Up @@ -6,7 +6,7 @@
#include "setup.h"
#include <cxxabi.h>
#include <kj/debug.h>
#include <malloc.h>
#include <stdlib.h>

#include <workerd/util/sentry.h>

Expand Down
2 changes: 2 additions & 0 deletions src/workerd/jsg/wrappable.h
Expand Up @@ -17,6 +17,8 @@

namespace workerd::jsg {

using kj::uint;

class GcVisitor;
class HeapTracer;

Expand Down
2 changes: 2 additions & 0 deletions src/workerd/server/server.h
Expand Up @@ -21,6 +21,8 @@ namespace workerd::jsg {

namespace workerd::server {

using kj::uint;

class Server: private kj::TaskSet::ErrorHandler {
// Implements the single-tenant Workers Runtime server / CLI.
//
Expand Down
17 changes: 16 additions & 1 deletion src/workerd/server/workerd.c++
Expand Up @@ -32,6 +32,12 @@
#include <sys/auxv.h>
#endif

#ifdef __APPLE__
#include <libproc.h>
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#endif

namespace workerd::server {

static kj::StringPtr getVersionString() {
Expand Down Expand Up @@ -885,7 +891,16 @@ private:
}
#endif

// TODO(launch): Fall back to searching $PATH. Or on Mac, maybe use _NSGetExecutablePath()?
#if __APPLE__
// https://astojanov.github.io/blog/2011/09/26/pid-to-absolute-path.html
pid_t pid = getpid();
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) {
return tryOpenExe(pathbuf);
}
#endif

// TODO(launch): Fall back to searching $PATH.
return nullptr;
}

Expand Down