mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
## Summary - Make `bun:ffi`'s TinyCC compiler check standard C compiler environment variables - Add support for `C_INCLUDE_PATH` (include paths) and `LIBRARY_PATH` (library paths) - Fixes compilation on NixOS and other systems that don't use standard FHS paths ## Test plan - [x] Added regression test `test/regression/issue/26249.test.ts` that verifies: - Single path in `C_INCLUDE_PATH` works - Multiple colon-separated paths in `C_INCLUDE_PATH` work - [x] Verified test fails with system bun (without fix) - [x] Verified test passes with debug build (with fix) - [x] Verified existing `cc.test.ts` tests still pass Closes #26249 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
123 lines
2.9 KiB
TypeScript
123 lines
2.9 KiB
TypeScript
// https://github.com/oven-sh/bun/issues/26249
|
|
// Test that bun:ffi's cc() respects C_INCLUDE_PATH and LIBRARY_PATH environment variables.
|
|
// This is important for systems like NixOS where standard FHS paths don't exist.
|
|
|
|
import { expect, test } from "bun:test";
|
|
import { bunEnv, bunExe, isWindows, tempDir } from "harness";
|
|
import path from "path";
|
|
|
|
test.skipIf(isWindows)("cc() respects C_INCLUDE_PATH environment variable", async () => {
|
|
// Create a temp directory with a custom include dir and header file
|
|
using dir = tempDir("ffi-include-path-test", {
|
|
"custom_include": {
|
|
"myheader.h": `
|
|
#define MY_MAGIC_NUMBER 42
|
|
`,
|
|
},
|
|
"test.c": `
|
|
#include <myheader.h>
|
|
int get_magic() {
|
|
return MY_MAGIC_NUMBER;
|
|
}
|
|
`,
|
|
"test.js": `
|
|
import { cc } from "bun:ffi";
|
|
import path from "path";
|
|
|
|
const {
|
|
symbols: { get_magic },
|
|
} = cc({
|
|
source: path.join(import.meta.dir, "test.c"),
|
|
symbols: {
|
|
get_magic: {
|
|
returns: "int",
|
|
},
|
|
},
|
|
});
|
|
|
|
console.log(get_magic());
|
|
`,
|
|
});
|
|
|
|
// Run with C_INCLUDE_PATH set to our custom include directory
|
|
await using proc = Bun.spawn({
|
|
cmd: [bunExe(), "test.js"],
|
|
cwd: String(dir),
|
|
env: {
|
|
...bunEnv,
|
|
C_INCLUDE_PATH: path.join(String(dir), "custom_include"),
|
|
},
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
});
|
|
|
|
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
|
|
|
// Check that the header was found and the code compiled successfully
|
|
expect(stderr).not.toContain("myheader.h");
|
|
expect(stdout.trim()).toBe("42");
|
|
expect(exitCode).toBe(0);
|
|
});
|
|
|
|
test.skipIf(isWindows)("cc() respects multiple paths in C_INCLUDE_PATH", async () => {
|
|
// Create a temp directory with multiple custom include dirs
|
|
using dir = tempDir("ffi-multi-include-path-test", {
|
|
"include1": {
|
|
"header1.h": `
|
|
#define VALUE_A 10
|
|
`,
|
|
},
|
|
"include2": {
|
|
"header2.h": `
|
|
#define VALUE_B 20
|
|
`,
|
|
},
|
|
"test.c": `
|
|
#include <header1.h>
|
|
#include <header2.h>
|
|
int get_sum() {
|
|
return VALUE_A + VALUE_B;
|
|
}
|
|
`,
|
|
"test.js": `
|
|
import { cc } from "bun:ffi";
|
|
import path from "path";
|
|
|
|
const {
|
|
symbols: { get_sum },
|
|
} = cc({
|
|
source: path.join(import.meta.dir, "test.c"),
|
|
symbols: {
|
|
get_sum: {
|
|
returns: "int",
|
|
},
|
|
},
|
|
});
|
|
|
|
console.log(get_sum());
|
|
`,
|
|
});
|
|
|
|
// Run with C_INCLUDE_PATH set to multiple directories (colon-separated)
|
|
const include1 = path.join(String(dir), "include1");
|
|
const include2 = path.join(String(dir), "include2");
|
|
|
|
await using proc = Bun.spawn({
|
|
cmd: [bunExe(), "test.js"],
|
|
cwd: String(dir),
|
|
env: {
|
|
...bunEnv,
|
|
C_INCLUDE_PATH: `${include1}:${include2}`,
|
|
},
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
});
|
|
|
|
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
|
|
|
expect(stderr).not.toContain("header1.h");
|
|
expect(stderr).not.toContain("header2.h");
|
|
expect(stdout.trim()).toBe("30");
|
|
expect(exitCode).toBe(0);
|
|
});
|