Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions scripts/build/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -863,10 +863,9 @@
// failure is loud ("cannot find -l:libatomic.a") and the fix is obvious.
const staticLibatomic = partial.staticLibatomic ?? true;

// TinyCC: off on Windows ARM64 (not supported), Android (no upstream
// bionic support; FFI cc() falls back to dlopen-only), and FreeBSD
// (oven-sh/tinycc has no FreeBSD target).
const tinycc = partial.tinycc ?? !((windows && arm64) || abi === "android" || freebsd);
// TinyCC: off on Android (no upstream bionic support; FFI cc() falls back
// to dlopen-only) and FreeBSD (oven-sh/tinycc has no FreeBSD target).
const tinycc = partial.tinycc ?? !(abi === "android" || freebsd);

Check failure on line 868 in scripts/build/config.ts

View check run for this annotation

Claude / Claude Code Review

Rust-side ENABLE_TINYCC gates not updated — bun:ffi still disabled on windows-arm64

Dropping the `(windows && arm64)` term from `cfg.tinycc` here builds libtcc.a on windows-aarch64, but two Rust-side mirrors of this predicate — both carrying explicit "keep in sync with cfg.tinycc in config.ts" comments — were not updated: `scripts/build/buildOptionsRs.ts:70-74` still emits `ENABLE_TINYCC = !cfg!(any(all(windows, target_arch = "aarch64"), ...))`, and `src/tcc_sys/tcc.rs:30,35` still swaps the `extern "C"` block for `unreachable!()` stubs on windows-aarch64. So `bun_core::Environ
Comment thread
claude[bot] marked this conversation as resolved.

const valgrind = partial.valgrind ?? false;
const fuzzilli = partial.fuzzilli ?? false;
Expand Down
6 changes: 1 addition & 5 deletions scripts/build/deps/tinycc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
* TinyCC — small embeddable C compiler. Powers bun:ffi's JIT-compile path,
* where user-provided C gets compiled and linked at runtime.
*
* Disabled on windows-arm64 (tinycc doesn't have an arm64-coff backend).
*
* Built via DirectBuild — no cmake sub-process. The old overlay
* CMakeLists.txt had two recurring ASAN workarounds for the c2str host
* tool (Linux ASLR/shadow-map, macOS 26.4 dyld deadlock); DirectBuild's
Expand All @@ -12,14 +10,12 @@

import type { Dependency, DirectBuild } from "../source.ts";

const TINYCC_COMMIT = "12882eee073cfe5c7621bcfadf679e1372d4537b";
const TINYCC_COMMIT = "c49c2204b07c526c9ad935fabfcaf3802cae1346";

export const tinycc: Dependency = {
name: "tinycc",
versionMacro: "TINYCC",

// The cfg.tinycc flag already encodes the windows-arm64 exclusion
// (see config.ts: `tinycc ?? !(windows && arm64)`).
enabled: cfg => cfg.tinycc,

source: () => ({
Expand Down
2 changes: 1 addition & 1 deletion scripts/build/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ export interface Dependency {

/**
* Whether this dep participates in the build at all. Defaults to always-on.
* E.g. libuv is windows-only, tinycc is disabled on windows-arm64.
* E.g. libuv is windows-only.
*/
enabled?: (cfg: Config) => boolean;

Expand Down
13 changes: 5 additions & 8 deletions test/js/bun/ffi/cc.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { cc, CString, JSCallback, ptr, type FFIFunction, type Library } from "bun:ffi";
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { promises as fs } from "fs";
import { bunEnv, bunExe, isArm64, isASAN, isWindows, normalizeBunSnapshot, tempDir, tempDirWithFiles } from "harness";
import { bunEnv, bunExe, isASAN, isWindows, normalizeBunSnapshot, tempDir, tempDirWithFiles } from "harness";
import path from "path";
Comment thread
claude[bot] marked this conversation as resolved.

// TinyCC (and all of bun:ffi) is disabled on Windows ARM64
const isFFIUnavailable = isWindows && isArm64;

// TODO: we need to install build-essential and Apple SDK in CI.
// It can't find includes. It can on machines with that enabled.
// TinyCC's setjmp/longjmp error handling conflicts with ASan.
it.todoIf(isWindows || isASAN || isFFIUnavailable)("can run a .c file", () => {
it.todoIf(isWindows || isASAN)("can run a .c file", () => {
const result = Bun.spawnSync({
cmd: [bunExe(), path.join(__dirname, "cc-fixture.js")],
cwd: __dirname,
Expand All @@ -23,7 +20,7 @@ it.todoIf(isWindows || isASAN || isFFIUnavailable)("can run a .c file", () => {

// TinyCC's setjmp/longjmp error handling conflicts with ASan.
// TinyCC is disabled on Windows ARM64.
describe.skipIf(isASAN || isFFIUnavailable)("given an add(a, b) function", () => {
describe.skipIf(isASAN)("given an add(a, b) function", () => {
const source = /* c */ `
Comment thread
claude[bot] marked this conversation as resolved.
int add(int a, int b) {
return a + b;
Expand Down Expand Up @@ -391,7 +388,7 @@ describe.skipIf(isWindows || isASAN)("threadsafe JSCallback invoked from a forei
// Pins GC liveness: compiled trampolines survive the library wrapper being
// collected, and a JSCallback's closure stays alive until close().
// TinyCC's setjmp/longjmp error handling conflicts with ASan.
describe.skipIf(isASAN || isFFIUnavailable)("GC liveness of compiled symbols and callbacks", () => {
describe.skipIf(isASAN)("GC liveness of compiled symbols and callbacks", () => {
it("keeps symbol functions and callback closures alive across forced GC", async () => {
using dir = tempDir("bun-ffi-cc-gc-liveness", {
"lib.c": /* c */ `
Expand Down Expand Up @@ -457,7 +454,7 @@ describe.skipIf(isASAN || isFFIUnavailable)("GC liveness of compiled symbols and
});
});

describe.skipIf(isFFIUnavailable)("double <-> JSValue conversions", () => {
describe("double <-> JSValue conversions", () => {
// JSC NaN-boxes doubles, so a NaN whose payload collides with the tag space
// ("impure NaN", see JSC's PureNaN.h) must never be encoded as-is: it would
// decode as a native-chosen JSValue (true, undefined, an Int32, or a cell
Expand Down
7 changes: 2 additions & 5 deletions test/js/bun/ffi/ffi-error-messages.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { dlopen, linkSymbols } from "bun:ffi";
import { describe, expect, test } from "bun:test";
import { isArm64, isMusl, isWindows } from "harness";
import { isMusl } from "harness";

// TinyCC (and all of bun:ffi) is disabled on Windows ARM64
const isFFIUnavailable = isWindows && isArm64;

describe.skipIf(isFFIUnavailable)("FFI error messages", () => {
describe("FFI error messages", () => {
test("dlopen shows library name when library cannot be opened", () => {
// Try to open a non-existent library
try {
Expand Down
5 changes: 1 addition & 4 deletions test/js/bun/ffi/ffi-viewSource-non-object.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { describe, expect, test } from "bun:test";
import { isArm64, isWindows } from "harness";

const isFFIUnavailable = isWindows && isArm64;

describe.skipIf(isFFIUnavailable)("FFI viewSource", () => {
describe("FFI viewSource", () => {
test("rejects non-object symbol descriptor values", () => {
// These should throw a TypeError because each symbol descriptor
// must be an object like { args: [...], returns: "void" }.
Expand Down
7 changes: 2 additions & 5 deletions test/js/node/fs/fs-writeSync-stdio-windows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@
// Now `fromJS`/`fromJSValidated` return `.fromUV(0|1|2)` directly, and
// `FD.uv()` checks the cached stdio handles before `GetStdHandle`.
import { describe, expect, test } from "bun:test";
import { bunEnv, bunExe, isArm64, isWindows, tempDir } from "harness";
import { bunEnv, bunExe, isWindows, tempDir } from "harness";
import { join } from "node:path";

describe.concurrent.skipIf(!isWindows)("fs.writeSync on Windows stdio/handles", () => {
// bun:ffi (TinyCC) is unavailable on Windows arm64, so this repro can only
// run on x64. The second test below covers the plain openSync→writeSync path
// on all Windows arches.
test.skipIf(isArm64)("fs.writeSync(1, ...) does not panic after SetStdHandle swaps stdout", async () => {
test("fs.writeSync(1, ...) does not panic after SetStdHandle swaps stdout", async () => {
const fixture = `
const fs = require("node:fs");
const { dlopen } = require("bun:ffi");
Expand Down
7 changes: 3 additions & 4 deletions test/napi/napi-value-ffi.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { spawnSync } from "bun";
import { cc, dlopen } from "bun:ffi";
import { beforeAll, describe, expect, it } from "bun:test";
import { bunEnv, bunExe, canBuildNodeAddons, isArm64, isASAN, isWindows } from "harness";
import { bunEnv, bunExe, canBuildNodeAddons, isASAN, isWindows } from "harness";
import { join } from "path";

import source from "./napi-app/ffi_addon_1.c" with { type: "file" };

// TinyCC (and all of bun:ffi) is disabled on Windows ARM64; the napi-app
// fixture needs a toolchain that can compile the reported Node headers.
const isFFIUnavailable = (isWindows && isArm64) || !canBuildNodeAddons();
// The napi-app fixture needs a toolchain that can compile the Node headers.
const isFFIUnavailable = !canBuildNodeAddons();

const symbols = {
set_instance_data: {
Expand Down
Loading