Compare commits

..

1 Commits

Author SHA1 Message Date
Claude Bot
eb2113b17d fix(cmake): reduce noise in debug build linker flags on Linux
Move optimization-focused linker flags to release builds only:
- --icf=safe: identical code folding for size optimization
- -O2: enable string tail merging optimization
- -z,combreloc: combine relocations for faster loading

Keep debugging-related flags in all builds:
- --compress-debug-sections=zlib: compress debug sections for smaller files
- --gdb-index: faster debug symbol loading in GDB

This reduces verbose linker output and link times in debug builds
while preserving essential debugging functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-12 05:31:11 +00:00
4 changed files with 15 additions and 491 deletions

View File

@@ -993,24 +993,29 @@ if(LINUX)
--ld-path=${LLD_PROGRAM}
-fno-pic
-Wl,-no-pie
-Wl,-icf=safe
-Wl,--as-needed
-Wl,--gc-sections
-Wl,-z,stack-size=12800000
-Wl,--compress-debug-sections=zlib
-Wl,-z,lazy
-Wl,-z,norelro
# enable string tail merging
-Wl,-O2
# make debug info faster to load
-Wl,--gdb-index
-Wl,-z,combreloc
-Wl,--no-eh-frame-hdr
-Wl,--sort-section=name
-Wl,--hash-style=both
-Wl,--build-id=sha1 # Better for debugging than default
# make debug info faster to load
-Wl,--gdb-index
-Wl,-Map=${bun}.linker-map
)
if(RELEASE)
target_link_options(${bun} PUBLIC
-Wl,-icf=safe
# enable string tail merging
-Wl,-O2
-Wl,-z,combreloc
)
endif()
endif()
# --- Symbols list ---

View File

@@ -56,8 +56,6 @@ behavior: Behavior = .{},
/// 2. name ASC
/// "name" must be ASC so that later, when we rebuild the lockfile
/// we insert it back in reverse order without an extra sorting pass
/// Note: For workspace packages with both dev and peer dependencies,
/// dev dependencies are prioritized to prevent unnecessary network requests
pub fn isLessThan(string_buf: []const u8, lhs: Dependency, rhs: Dependency) bool {
const behavior = lhs.behavior.cmp(rhs.behavior);
if (behavior != .eq) {
@@ -1422,19 +1420,6 @@ pub const Behavior = packed struct(u8) {
.lt;
}
// Special handling for workspace packages with both dev and peer dependencies
// If both behaviors have workspace flag, prioritize dev over peer
if (lhs.workspace and rhs.workspace) {
if (lhs.dev and lhs.peer and rhs.peer and !rhs.dev) {
// lhs is workspace + dev + peer, rhs is workspace + peer only
return .gt;
}
if (rhs.dev and rhs.peer and lhs.peer and !lhs.dev) {
// rhs is workspace + dev + peer, lhs is workspace + peer only
return .lt;
}
}
if (lhs.isDev() != rhs.isDev()) {
return if (lhs.isDev())
.gt
@@ -1442,15 +1427,15 @@ pub const Behavior = packed struct(u8) {
.lt;
}
if (lhs.isPeer() != rhs.isPeer()) {
return if (lhs.isPeer())
if (lhs.isOptional() != rhs.isOptional()) {
return if (lhs.isOptional())
.gt
else
.lt;
}
if (lhs.isOptional() != rhs.isOptional()) {
return if (lhs.isOptional())
if (lhs.isPeer() != rhs.isPeer()) {
return if (lhs.isPeer())
.gt
else
.lt;

View File

@@ -1,185 +0,0 @@
import { test, expect } from "bun:test";
// Mock the Behavior struct for testing
class MockBehavior {
prod: boolean = false;
dev: boolean = false;
peer: boolean = false;
optional: boolean = false;
workspace: boolean = false;
bundled: boolean = false;
constructor(options: Partial<MockBehavior> = {}) {
Object.assign(this, options);
}
isProd() { return this.prod; }
isDev() { return this.dev; }
isPeer() { return this.peer; }
isOptional() { return this.optional && !this.peer; }
isWorkspace() { return this.workspace; }
isBundled() { return this.bundled; }
isWorkspaceOnly() { return this.workspace && !this.dev && !this.prod && !this.optional && !this.peer; }
eq(other: MockBehavior) {
return this.prod === other.prod &&
this.dev === other.dev &&
this.peer === other.peer &&
this.optional === other.optional &&
this.workspace === other.workspace &&
this.bundled === other.bundled;
}
// Mirror the comparison logic from Zig
cmp(other: MockBehavior): "lt" | "eq" | "gt" {
if (this.eq(other)) {
return "eq";
}
if (this.isWorkspaceOnly() !== other.isWorkspaceOnly()) {
return this.isWorkspaceOnly() ? "lt" : "gt";
}
if (this.isProd() !== other.isProd()) {
return this.isProd() ? "gt" : "lt";
}
// Special handling for workspace packages with both dev and peer dependencies
// If both behaviors have workspace flag, prioritize dev over peer
if (this.workspace && other.workspace) {
if (this.dev && this.peer && other.peer && !other.dev) {
// this is workspace + dev + peer, other is workspace + peer only
return "gt";
}
if (other.dev && other.peer && this.peer && !this.dev) {
// other is workspace + dev + peer, this is workspace + peer only
return "lt";
}
}
if (this.isDev() !== other.isDev()) {
return this.isDev() ? "gt" : "lt";
}
if (this.isPeer() !== other.isPeer()) {
return this.isPeer() ? "gt" : "lt";
}
if (this.isOptional() !== other.isOptional()) {
return this.isOptional() ? "gt" : "lt";
}
if (this.isWorkspace() !== other.isWorkspace()) {
return this.isWorkspace() ? "gt" : "lt";
}
return "eq";
}
}
test("dependency behavior comparison for workspace packages prioritizes dev+peer over peer-only", () => {
const workspaceDevPeer = new MockBehavior({ workspace: true, dev: true, peer: true });
const workspacePeerOnly = new MockBehavior({ workspace: true, peer: true });
// workspace + dev + peer should have higher priority than workspace + peer only
expect(workspaceDevPeer.cmp(workspacePeerOnly)).toBe("gt");
expect(workspacePeerOnly.cmp(workspaceDevPeer)).toBe("lt");
});
test("regular dev vs peer dependencies follow standard priority", () => {
const devBehavior = new MockBehavior({ dev: true });
const peerBehavior = new MockBehavior({ peer: true });
// Without workspace flag, dev and peer follow standard ordering
expect(devBehavior.cmp(peerBehavior)).toBe("gt");
expect(peerBehavior.cmp(devBehavior)).toBe("lt");
});
test("dependency behavior comparison handles production dependencies", () => {
const prodBehavior = new MockBehavior({ prod: true });
const devBehavior = new MockBehavior({ dev: true });
const peerBehavior = new MockBehavior({ peer: true });
// Production dependencies should have highest priority
expect(prodBehavior.cmp(devBehavior)).toBe("gt");
expect(prodBehavior.cmp(peerBehavior)).toBe("gt");
expect(devBehavior.cmp(prodBehavior)).toBe("lt");
expect(peerBehavior.cmp(prodBehavior)).toBe("lt");
});
test("dependency behavior comparison handles workspace dependencies", () => {
const workspaceOnlyBehavior = new MockBehavior({ workspace: true });
const devBehavior = new MockBehavior({ dev: true });
const peerBehavior = new MockBehavior({ peer: true });
// Workspace-only dependencies should have highest priority
expect(workspaceOnlyBehavior.cmp(devBehavior)).toBe("lt");
expect(workspaceOnlyBehavior.cmp(peerBehavior)).toBe("lt");
expect(devBehavior.cmp(workspaceOnlyBehavior)).toBe("gt");
expect(peerBehavior.cmp(workspaceOnlyBehavior)).toBe("gt");
});
test("dependency behavior comparison handles optional dependencies", () => {
const optionalBehavior = new MockBehavior({ optional: true });
const devBehavior = new MockBehavior({ dev: true });
const peerBehavior = new MockBehavior({ peer: true });
// Optional dependencies should have lower priority than dev/peer dependencies
expect(devBehavior.cmp(optionalBehavior)).toBe("gt");
expect(peerBehavior.cmp(optionalBehavior)).toBe("gt");
expect(optionalBehavior.cmp(devBehavior)).toBe("lt");
expect(optionalBehavior.cmp(peerBehavior)).toBe("lt");
});
test("workspace-specific behavior for dev+peer vs peer dependencies", () => {
// Test the specific Next.js monorepo scenario
const workspaceDevPeer = new MockBehavior({ workspace: true, dev: true, peer: true });
const workspacePeer = new MockBehavior({ workspace: true, peer: true });
const workspaceDev = new MockBehavior({ workspace: true, dev: true });
// Workspace dev+peer should be prioritized over workspace peer-only
expect(workspaceDevPeer.cmp(workspacePeer)).toBe("gt");
expect(workspacePeer.cmp(workspaceDevPeer)).toBe("lt");
// Workspace dev+peer vs workspace dev-only follows standard rules
expect(workspaceDevPeer.cmp(workspaceDev)).toBe("gt"); // peer flag adds to priority
});
test("non-workspace behavior remains unchanged", () => {
const devPeerBehavior = new MockBehavior({ dev: true, peer: true });
const peerOnlyBehavior = new MockBehavior({ peer: true });
const devOnlyBehavior = new MockBehavior({ dev: true });
// Without workspace flag, behavior follows standard priority rules
expect(devPeerBehavior.cmp(devPeerBehavior)).toBe("eq");
expect(devPeerBehavior.cmp(peerOnlyBehavior)).toBe("gt");
expect(devPeerBehavior.cmp(devOnlyBehavior)).toBe("gt"); // dev+peer has higher priority than dev-only
});
test("dependency sorting order matches intended priority", () => {
const behaviors = [
new MockBehavior({ workspace: true }), // workspace-only (highest priority)
new MockBehavior({ prod: true }), // production
new MockBehavior({ dev: true }), // dev
new MockBehavior({ peer: true }), // peer
new MockBehavior({ optional: true }), // optional (lowest priority)
];
// Test that each behavior has higher priority than the ones that come after it
for (let i = 0; i < behaviors.length - 1; i++) {
for (let j = i + 1; j < behaviors.length; j++) {
const result = behaviors[i].cmp(behaviors[j]);
const reverseResult = behaviors[j].cmp(behaviors[i]);
// Workspace-only should be "lt" (higher priority = lower in sort order)
// Others should be "gt" (higher priority = greater in comparison)
if (i === 0) {
expect(result).toBe("lt");
expect(reverseResult).toBe("gt");
} else {
expect(result).toBe("gt");
expect(reverseResult).toBe("lt");
}
}
}
});

View File

@@ -1,281 +0,0 @@
import { test, expect } from "bun:test";
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
import { join } from "path";
import { mkdirSync, rmSync } from "fs";
test("workspace devDependencies should take priority over peerDependencies for resolution", async () => {
const dir = tempDirWithFiles("dev-peer-priority", {
"package.json": JSON.stringify({
name: "test-monorepo",
version: "1.0.0",
workspaces: {
packages: ["packages/*"],
nodeLinker: "isolated"
},
}),
"packages/lib/package.json": JSON.stringify({
name: "lib",
version: "1.0.0",
dependencies: {},
devDependencies: {
"my-dep": "workspace:*" // Use workspace protocol for dev
},
peerDependencies: {
"my-dep": "^1.0.0" // Range that wants 1.x
},
}),
"packages/lib/test.js": `const dep = require("my-dep"); console.log(dep.version);`,
// Only provide workspace package with version 2.0.0
"packages/my-dep/package.json": JSON.stringify({
name: "my-dep",
version: "2.0.0",
main: "index.js",
}),
"packages/my-dep/index.js": `module.exports = { version: "2.0.0" };`,
});
// Run bun install with a dead registry to ensure no network requests
const { stdout, stderr, exitCode } = await new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "install", "--no-progress", "--no-summary"],
cwd: dir,
env: {
...bunEnv,
NPM_CONFIG_REGISTRY: "http://localhost:9999/", // Dead URL - will fail if used
},
stdout: "pipe",
stderr: "pipe",
});
proc.exited.then((exitCode) => {
Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]).then(([stdout, stderr]) => {
resolve({ stdout, stderr, exitCode });
});
});
});
if (exitCode !== 0) {
console.error("Install failed with exit code:", exitCode);
console.error("stdout:", stdout);
console.error("stderr:", stderr);
}
expect(exitCode).toBe(0);
// Check that no network requests were made for packages that should be resolved locally
expect(stderr).not.toContain("GET");
expect(stderr).not.toContain("http");
// Check that the lockfile was created correctly
const lockfilePath = join(dir, "bun.lock");
expect(await Bun.file(lockfilePath).exists()).toBe(true);
// Verify that version 2.0.0 (devDependency) was linked
// If peerDependency range ^1.0.0 was used, it would try to fetch from npm and fail
const testResult = await new Promise<string>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "packages/lib/test.js"],
cwd: dir,
env: bunEnv,
stdout: "pipe",
});
new Response(proc.stdout).text().then(resolve);
});
expect(testResult.trim()).toBe("2.0.0");
});
test("devDependencies and peerDependencies with different versions should coexist", async () => {
const dir = tempDirWithFiles("dev-peer-different-versions", {
"package.json": JSON.stringify({
name: "test-monorepo",
version: "1.0.0",
workspaces: {
packages: ["packages/*"],
nodeLinker: "isolated"
},
}),
"packages/lib/package.json": JSON.stringify({
name: "lib",
version: "1.0.0",
dependencies: {},
devDependencies: {
"utils": "1.0.0"
},
peerDependencies: {
"utils": "^1.0.0"
},
}),
"packages/lib/index.js": `console.log("lib");`,
"packages/utils/package.json": JSON.stringify({
name: "utils",
version: "1.0.0",
main: "index.js",
}),
"packages/utils/index.js": `console.log("utils");`,
});
// Run bun install in the monorepo
const { stdout, stderr, exitCode } = await new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "install", "--no-progress", "--no-summary"],
cwd: dir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
proc.exited.then((exitCode) => {
Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]).then(([stdout, stderr]) => {
resolve({ stdout, stderr, exitCode });
});
});
});
if (exitCode !== 0) {
console.error("Install failed with exit code:", exitCode);
console.error("stdout:", stdout);
console.error("stderr:", stderr);
}
expect(exitCode).toBe(0);
// Check that the lockfile was created correctly
const lockfilePath = join(dir, "bun.lock");
expect(await Bun.file(lockfilePath).exists()).toBe(true);
});
test("dependency behavior comparison prioritizes devDependencies", async () => {
const dir = tempDirWithFiles("behavior-comparison", {
"package.json": JSON.stringify({
name: "test-app",
version: "1.0.0",
dependencies: {},
devDependencies: {
"typescript": "^5.0.0"
},
peerDependencies: {
"typescript": "^4.0.0 || ^5.0.0"
},
}),
"index.js": `console.log("app");`,
});
// Run bun install
const { stdout, stderr, exitCode } = await new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "install", "--no-progress", "--no-summary"],
cwd: dir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
proc.exited.then((exitCode) => {
Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]).then(([stdout, stderr]) => {
resolve({ stdout, stderr, exitCode });
});
});
});
if (exitCode !== 0) {
console.error("Install failed with exit code:", exitCode);
console.error("stdout:", stdout);
console.error("stderr:", stderr);
}
expect(exitCode).toBe(0);
// Check that the lockfile was created correctly
const lockfilePath = join(dir, "bun.lock");
expect(await Bun.file(lockfilePath).exists()).toBe(true);
});
test("Next.js monorepo scenario should not make unnecessary network requests", async () => {
const dir = tempDirWithFiles("nextjs-monorepo", {
"package.json": JSON.stringify({
name: "nextjs-monorepo",
version: "1.0.0",
workspaces: {
packages: ["packages/*"],
nodeLinker: "isolated"
},
}),
"packages/web/package.json": JSON.stringify({
name: "web",
version: "1.0.0",
dependencies: {},
devDependencies: {
"next": "15.0.0-canary.119" // Specific canary version for dev
},
peerDependencies: {
"next": "^14.0.0 || ^15.0.0" // Range that would accept 14.x or 15.x stable
},
}),
"packages/web/test.js": `const next = require("next/package.json"); console.log(next.version);`,
// Only provide the canary version that matches devDependencies
"packages/next/package.json": JSON.stringify({
name: "next",
version: "15.0.0-canary.119",
main: "index.js",
}),
"packages/next/index.js": `console.log("next workspace");`,
});
// Run bun install with dead registry
const { stdout, stderr, exitCode } = await new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "install", "--no-progress", "--no-summary"],
cwd: dir,
env: {
...bunEnv,
NPM_CONFIG_REGISTRY: "http://localhost:9999/", // Dead URL
},
stdout: "pipe",
stderr: "pipe",
});
proc.exited.then((exitCode) => {
Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]).then(([stdout, stderr]) => {
resolve({ stdout, stderr, exitCode });
});
});
});
expect(exitCode).toBe(0);
// The key test: should not make network requests for packages that exist in workspace
// When devDependencies are prioritized over peerDependencies, the workspace version should be used
expect(stderr).not.toContain("GET");
expect(stderr).not.toContain("404");
expect(stderr).not.toContain("http");
// Check that the lockfile was created correctly
const lockfilePath = join(dir, "bun.lock");
expect(await Bun.file(lockfilePath).exists()).toBe(true);
// Verify that version 15.0.0-canary.119 (devDependency) was used
// If peer range was used, it would try to fetch a stable version from npm and fail
const testResult = await new Promise<string>((resolve) => {
const proc = Bun.spawn({
cmd: [bunExe(), "packages/web/test.js"],
cwd: dir,
env: bunEnv,
stdout: "pipe",
});
new Response(proc.stdout).text().then(resolve);
});
expect(testResult.trim()).toBe("15.0.0-canary.119");
});