Commit Graph
164 Commits
Author SHA1 Message Date
Scott Taylor 8072fc0827 build: honor macOS SDK root for frameworks
Assisted-By: devx/6fc48df3-67c4-46f2-9e14-98e4ac4bc21d
2026-08-29 12:28:29 -04:00
Karl Seguin 6955751c10 Merge pull request #3285 from lightpanda-io/mem-vmhwm
mem: include v8 functions in binary layout optimization
2026-08-27 07:35:30 +08:00
Karl Seguin c8abf899ef mem: include v8 functions in binary layout optimization
https://github.com/lightpanda-io/browser/pull/3271 introduce an orderfile so
that hot sections of code were grouped together in the binary, resulting in more
efficient loading. But, it excluded v8 functions because v8 is compiled with
`-fno-unique-section-names` so each section gets the same name. Because of this
the orderfile can't target specific "hot" or "cold" functions.

As a follow up to 3271, I thought we'd be able to re-compile v8 without that
flag, but:

1 - The flag isn't directly exposed by v8, so we'd need to change v8's own build
    BUILD.gn in our build process
2 - It would make the .a file ~ 40MB larger (though the final lightpanda binary
    would stay the same size
3 - If we wanted to created two .a files (one with -fno-unique-section-names and
    one without), it would require a full rebuild (for both x86-64 and arm).

I didn't love those compromises, so I asked Claude if the sections names could
be generated in a separate file and then that could be used when generating out
lightpanda.ld. What claude came up with was a small Zig script
(mark_hot_sections.zig) which is now run as part of the build. It takes the
v8.a file (which still has `-fno-unique-section-names`), it takes a text list
of hot functions, and it re-generates v8.a with a special .text.hot and
.rodata.hot sections. lightpanda.ld can include these.

This PR depends on https://github.com/lightpanda-io/zig-v8-fork/pull/202 but
202 doesn't require a v8 rebuild. It merely allows prebuilt_v8_path to be
a lazypath, which we need because the prebuilt_v8_path that we pass is now
generated from this build script.
2026-08-26 12:53:45 +08:00
Karl Seguin fa36fb5a69 Merge pull request #3280 from lightpanda-io/dev-fast-host-glibc
build: pin dev_fast to the host's glibc version
2026-08-26 09:40:14 +08:00
Karl Seguin b8c9fa3d76 Build: Fix linux debug build
https://github.com/lightpanda-io/browser/pull/3271 broke linux debug builds
2026-08-26 09:10:49 +08:00
Karl Seguin a3ab6b0b7e glibc build version
So we're trying to limit glibc to 2.43.0 do to an issue in Zig's self-hosted
compiler. I'm on 2.44.0 and I hard-coded 2.43.0. But for anyone on a version
prior to 2.43.0, that causes issues. So this takes the host version but limits
it to 2.43.0
2026-08-26 06:47:17 +08:00
Karl Seguin 64cdead237 Merge pull request #3271 from lightpanda-io/mem-vmhwm
mem: On linux CI builds, use an orderfile
2026-08-26 06:35:25 +08:00
Adrià Arrufat 5dc2535aae build: pin dev_fast to the host's glibc version, not 2.43
The explicit version only exists to force Zig's bundled CRT (zig#31272),
but it also selects symbol versions. PR #3231 added tiny-skia, which
calls acosf, and glibc 2.43 re-versioned that symbol, so the binary now
fails to load on hosts with an older glibc:

  libm.so.6: version `GLIBC_2.43' not found

Use the detected host glibc instead: still an explicit version, so the
bundled CRT is still used, but never newer than what the binary runs on.
2026-08-25 17:02:18 +02:00
Karl Seguin ee1fd9207c mem: On linux CI builds, use an orderfile
CI build, for e2e-test and nightly now build with:
-Dorderfile/lightpanda.ld

This file informs the build on how to organize the code in the binary, grouping
hot code together so that we have to load less of the binary into memory.

lightpanda.ld will drift: we'll refactor our code, add new features, update
dependencies, update Zig, ... So it has to be re-generated. But we can do that
automatically in the CI (say, before the nightly build). That's for a follow up
PR.

This does not currently cover V8. V8 is being build with
`-no-unique-section-names`, so we don't get names that we can correctly
organize. The real win comes from doing this in V8, since a lot of V8 is cold.
This PR can land as-is, a zig-v8-fork PR will remove that flag, and then we can
have a follow up PR with an lightpanda.ld that includes the v8 symbols.

This is opt-in (via the -Dorderfile flag) because it adds ~20 seconds of
linking time.
2026-08-25 21:02:31 +08:00
Karl Seguin 289502e19a Merge pull request #3231 from lightpanda-io/screenshot
Screenshot
2026-08-25 18:12:00 +08:00
Karl Seguin 1c9971252a small tweak to the build
auto-discover .rs files in src/rust for the build (rather than maintaining the
list by hand).
2026-08-20 17:26:23 +08:00
Karl Seguin 52623fe7ef chore: don't let cargo's build progress show up as a "failed command"
Cargo prints its progress to stderr. Zig's build sees the stderr content and
prints it as a "failed command: ...". Capture cargo's stderr to silence this
fake-error. A status != 0 still causes the error to be printed.
2026-08-20 09:59:24 +08:00
Karl Seguin ff5b791b7e wip: screenshot 2026-08-19 21:49:02 +08:00
Adrià Arrufat 904e34b102 build: simplify build.zig
Deduplicate the three executable blocks and the vendored C library
module setup, drop vestigial error unions, and replace hand-rolled
formatting with b.fmt/b.pathJoin/std.mem.concat.

The snapshot-creator and skills executables now get the same
sanitize_c/sanitize_thread flags as the browser executable, which
they were silently missing.

Prebuilt V8 discovery now reports every cache miss with the probed
path. Previously a miss on the static archive path fell back to the
source build without a message, and the dev_fast message claimed a
source build was starting when the graph might not compile anything.
2026-08-15 15:08:41 +02:00
Karl Seguin 8caaf7ad96 dev: On linux -dev_fast is on by default
Assuming the conditions are met for -dev_fast to work (linux, debug, x86-64
without sanitizers), the -dev_fast now defaults to true.

download-v8 make target always downloads the .a (as before) and on linux x86-64
it also downloads the .so.
2026-08-14 10:43:34 +08:00
Karl Seguin af99e845df dev: support for pre-build shared library
Supports prebuild-v8 shared library and adds a `download-v8-shared` make target.
Depends on: https://github.com/lightpanda-io/zig-v8-fork/pull/198

The auto-discovery of the .so is done in the build.zig, which is different than
the auto-discovery of the .a which is done in the Makefile. This is intentional
and if we inverse -Ddev_fast so that it's on by default, the .a's auto discovery
will be moved to build.zig for consistency and explicitness. As-is, we have no
way to tell whether -Dprebuilt_v8_path=v8.a is being injected by Makefile or
is explicit (which isn't a problem so long as we're not doing dev_fast by
default).
2026-08-13 19:28:21 +08:00
Karl Seguin 77ef54f0ac dev: add -Ddev_fast flag
Only works in Debug mode. Only works on x86_64 Linux.

sets use_llvm = false and forces glibc 2.43 (1), causes v8 to be dynamically
linked (https://github.com/lightpanda-io/zig-v8-fork/pull/197).

For me, zig build -Ddev_fast is about 6x faster (~60 seconds -> ~10 seconds)

(1) https://codeberg.org/ziglang/zig/issues/31272
2026-08-11 09:39:45 +08:00
Adrià Arrufat cbce632401 Replace @cImport with build-system translateC
Zig 0.17 removes @cImport in favor of translate-c steps in the build
system. Each library's link function now creates an addTranslateC step
exposed as a module import: curl and isocline translate their headers
straight from the dependency tree, while sqlite3 uses the artifact's
emitted include tree since the amalgamation lives in a sub-dependency.

Terminal.zig and prompt_assist.zig previously instantiated two
independent @cImport namespaces for isocline; they now share one
translated module, so its types are identical across both files.
2026-07-27 12:07:28 +02:00
Karl Seguin 0871b6a8da disable Zig 0.16 signal_stack_size
Make sure jemallocator is disabled in Release builds (we only use it in Debug
builds to collect metrics. Supposedly something changed in our 0.16 build that
causes it to be initialized even though it isn't used. Not sure, for this, I'm
just doing what Claude tell me, but disabling something in Release that I know
we aren't using sounds ok).
2026-07-22 13:26:06 +08:00
Karl Seguin 8e42d63c1c zig: Zig 0.16
Built against https://github.com/lightpanda-io/zig-v8-fork/tree/zig-0.16 but
it doesn't require a new v8 build.

Built against https://github.com/lightpanda-io/boringssl-zig/tree/zig-0.16
since the current fork we point to isn't updated.

A global std.Io instance, lp.io. Way easier this way and requires 0 changes to
our libcurl integration / event loop.

Network code uses a new layer that does what Zig 0.15's posix package used to
do. Again, quicker migration that way. But, as long as we have the global IO,
and given the half-baked nature of networking in std.Io 0.16, this just makes
sense. Things can be migrated as needed.

The std.time.* -> std.Io.Timestamp/Clock/Duration resulted in _a lot_ of
changes. ArrayList = .{} -> ArrayList -> .empty also resulted in a lot of
changes, but that's obviously superficial. As is the trimLeft/trimRight ->
trimStart/trimEnd rename.

Locking adopt the `Uncancelable` variants, e.g. mutex.lockUncancelable() to
preserve the error-free signature (and, because cancellation would be something
we'd have to put more thought into).

std.json.ObjectMap is now unmanaged, so the allocator had to be passed along.
However, there's still a deprecated managed variant of MemoryPool, so I switched
to it (we can do a small follow up PR to move to the unmanaged after).

I tried use_llvm = false, but it locks my computer, consuming RAM until MacOS
gives me a popup I've never seen before, begging me to start killing processes.

Agent and the networking stuff saw the most significant changes.
2026-07-22 13:26:03 +08:00
Adrià Arrufat 3e801fb83b script: generate the PandaScript skill from the tool schemas
The /save script documentation lived as a hand-maintained string in
Agent.zig whose primitives table drifted whenever a tool changed. Move
it to src/script/skill.zig and render the reference (signatures, option
lists, enums, defaults, per-parameter descriptions) from Schema.all()
at first use, keeping the curated per-tool notes behind an exhaustive
switch on Tool so a new or renamed tool is a compile error until its
doc entry exists.

The rendered skill is shared by three consumers:
- the /save and revision system prompts (built lazily in Agent.zig)
- a new mcp://skill/pandascript resource
- `zig build skills`, which writes zig-out/skills/<name>/SKILL.md with
  Claude Code frontmatter via a registry-based generator exe, so
  future Lightpanda skills are one registry entry each

Schema.FieldEntry now retains per-parameter schema descriptions, which
previously existed only in the raw JSON.
2026-07-13 10:54:13 +02:00
Karl Seguin b054b26e56 dep: update libcurl and nghttp2
Nothing major, but the feature that caught my eye was the addition of a
threadpool for DNS resolution, rather than a thread-per-resolution (1). I've
enabled it.

(1) https://github.com/curl/curl/commit/39036c90216e059bbee64b86b198eae3135e0cda
2026-06-27 19:06:47 +08:00
Adrià Arrufat e048b4b293 Merge branch 'main' into agent 2026-06-01 12:36:08 +02:00
Karl Seguin 320ffa2819 Improve WPT /url/ tests
This is a bit all over the place.

1 - Replace libidn2 with rust-idna. It looks like there are different idna
    profiles, and rust-idna (from the servo project) implements the whatwg
    one. libidn2 would be too strict in some cases and not strict enough in
    others. (Gemini says I could use libidn2 for this, but what it suggested
    didn't work, and I couldn't figure it out myself, and claude insisted it
    _did not_ have the correct implementation for what we want).

2 - We previously only ran a URL through idna if it wasn't ascii. Turns out
    we also need to run it if there's a "xn--" (aka, an IDNA ACE prefix) in
    there. This helps us pass hundreds of WPT cases, and it's pretty cheap.

3 - Implement more of the Area WebAPI. Mostly copied from Anchor.

4 - Add username/password accessor to Anchor/Area

5 - window.open validates the URL (i.e. tries to resolve it and handles the
    error)

6 - Invalid idna conversion maps to a TypeError

7 - Cleanup closed popups on the next tick (like destroyed pages), rather than
    at an interval or on shutdown. This one seems unrelated, but some of these
    tests are opening hundreds (thousands?) of popups and then closing them.
2026-05-29 18:06:44 +08:00
Adrià Arrufat d0a48131da Merge branch 'main' into agent 2026-05-28 11:53:47 +02:00
Karl Seguin 479c29816a Remove legacy test
AFAIK, these aren't being used and I've personally not have reason to reference
/ look at them for months.

I have no issues though if we want to keep them in.
2026-05-27 08:55:04 +08:00
Adrià Arrufat 7f9953200d Merge branch 'main' into agent 2026-05-12 15:13:00 +02:00
Adrià Arrufat 842fbb78ef build: print version banner to stderr, not stdout
The build script wrote the version line to stdout, polluting any pipeline
that captures program output via 'zig build run' or similar. Banners
belong on stderr.
2026-05-12 15:12:50 +02:00
Adrià Arrufat 5d70174288 terminal: replace linenoise with isocline
Replaces the linenoise library with isocline for improved REPL
functionality. Updates build scripts and moves completion state from
global variables into the Terminal struct.
2026-05-11 17:52:49 +02:00
Adrià Arrufat f56b0426ca Merge branch 'main' into agent 2026-05-04 07:58:57 +02:00
Navid EMAD d76b76221f build: colocate libidn2 strchrnul shim with strverscmp block
config.h already has a hand-added _LIBIDN2_LP_DECLS guarded block at
the end declaring extern strverscmp for the same gnulib-overlay reason.
Move the strchrnul prototype into that block (still #ifdef __APPLE__
since glibc Linux already declares it) so all project-added externs
live in one place, the autoconf-generated section stays untouched, and
the precedent for "how this codebase handles missing glibc extensions"
is one consistent pattern instead of two.

Refresh the build.zig and strchrnul.c comments to point at the
relocated declaration.

No functional change — verified across -target x86_64-macos.{13.0,
14.0,15.4} (lookup.c pattern + the three TUs that include both
<config.h> and <string.h>) plus x86_64-linux-gnu, all under
-Wall -Wextra -Werror.
2026-05-02 10:11:41 +02:00
Navid EMAD 7b5e18e23d build: relocate libidn2 strchrnul prototype into config.h
Move the macOS strchrnul declaration from a side-channel header injected
via -include into vendor/libidn2/config.h itself, gated on __APPLE__.
config.h is the canonical place where libidn2 documents its
HAVE_STRCHRNUL detection — co-locating the platform fallback prototype
there mirrors gnulib's own approach (which declares missing symbols in
its substituted <string.h>) and removes the per-platform build-flag
asymmetry plus the dedicated include path.

The Darwin-only strchrnul.c implementation is unchanged; build.zig now
just adds it on Darwin without touching the lib/ flags array.

Verified that on both `-target x86_64-macos.14.0` (no libc strchrnul)
and `-target x86_64-macos.15.4` (libc has it) a TU mimicking lookup.c
(`#include "config.h"` then call strchrnul) compiles cleanly with no
implicit-declaration error and no redeclaration warning.
2026-05-02 10:00:42 +02:00
Navid EMAD 40900a358c build: provide strchrnul shim for libidn2 on macOS
libidn2's lib/lookup.c calls strchrnul() unconditionally — a glibc
extension that macOS libc neither defines nor declares. Upstream's
portable build relies on gnulib substituting <string.h> with a
declaration and linking gl/strchrnul.c, but that overlay is not wired
up here. The result was an "implicit function declaration" hard error
on every macOS nightly build.

Add a Darwin-only shim under vendor/libidn2/darwin/ and inject its
prototype into the libidn2 lib/ sources via -include. The shim mirrors
strchrnul's semantics without falling through to rawmemchr (also
glibc-only) since libidn2 only ever searches for '.'.
2026-05-02 09:52:05 +02:00
Adrià Arrufat 59dcb13cb4 Merge branch 'main' into agent 2026-04-30 07:36:48 +02:00
Karl Seguin 8181f0a1dd try to fix build 2026-04-28 22:48:33 +08:00
Karl Seguin 9fe628dd0f Initial idn support
Links to libidn2 and builds libcurl with it. This makes libcurl work, and by
extension browser, work on international domain names, e.g.

zig build run -- fetch "https://räksmörgås.se/"

With it available, we can use it in our WebAPIs which should also support these
domains, e.g:
  testing.expectEqual('xn--rksmrgs-5wao1o.se', new URL('https://räksmörgås.se').hostname);

There is more integration to be done here, but this is a first step.

claude wrote all of the build.zig code.

I don't have a strong opinion about this feature, I just dislike that our WPT
/url/* tests are at 1704 / 9095 and, this is the biggest chunk (although, this
specific commit just does the basic integration and probably won't fix too many
WPT cases directly).
2026-04-28 22:21:27 +08:00
Adrià Arrufat f99b0c8f25 Merge branch 'main' into agent 2026-04-27 17:39:06 +02:00
Karl Seguin 7819ee50fa Add and default to Blackhole storage
Tweak sqlite build to omit more features, hoping to shrink the size when sqlite
is used.
2026-04-26 09:04:33 +08:00
Adrià Arrufat c3e6d97fdf Merge branch 'main' into agent 2026-04-23 07:39:02 +02:00
Adrià Arrufat 68c1429fdd build: move snapshot_creator and legacy_test to an extras step
Profiling `zig build --release=fast` after a one-file edit showed the
cost was three parallel exe compiles of the same module — each re-runs
LLVM codegen when anything in `lightpanda_module` changes. All C/C++
deps (v8, sqlite, curl, brotli, nghttp2, boringssl) already cache across
builds and are not the bottleneck.

Default install now builds only the main `lightpanda` exe.
`lightpanda-snapshot-creator` and `legacy_test` move to a new named step
and can be built explicitly via `zig build extras`. CI is unaffected:
nightly.yml already invokes `snapshot_creator` as an explicit step, and
no job consumes the legacy_test artifact.

Measured (release=fast, one source file modified, 36/36 steps):
  before: real 3m32s, compile exe lightpanda ~3m, others ~2m each
  after:  real 2m43s, only compile exe lightpanda

Also tried and rejected:
  - self-hosted Zig backend for Debug: fatal linker error, unhandled
    relocation type R_X86_64_PC64 in V8 objects.
  - mold via `mold -run`: ~4s delta, within noise — Zig invokes LLD
    as a library, so no external `ld` process exists to intercept.
2026-04-22 11:16:28 +02:00
Adrià Arrufat 7e7cfee980 Merge branch 'main' into agent 2026-04-22 08:59:46 +02:00
Adrià Arrufat ca1f2c0854 build: port sqlite3 to zig build system 2026-04-22 07:52:10 +02:00
Adrià Arrufat 58308cfdca Merge branch 'main' into agent 2026-04-22 07:13:04 +02:00
Karl Seguin 6d0003ad2b Sqlite
This adds an app.storage which is a union around configurable storage engine
(currently, only sqlite).

It is _not_ being used anywhere right now. The goal is to get feedback on
the implementation and then move cache to it.

This doesn't expose a generic query API. The goal is that the storage will
expose high level methods, e.g. `cacheGet(req: CacheGetRequest)` and every
storage engine will translate the `storage.CacheGetRequest` as needed.

A thin wrapper around the Sqlite C api is included, e.g. exec(SQL, .{args}) a
`rows` and `row` fetcher. A connection pool is included. By default, an
in-memory DB is currently created. And a `migrations` table with an id of `1`
is created/inserted. I don't imagine needing fancy migratations.
2026-04-20 17:13:06 +08:00
Karl Seguin b08ae07598 build with sqlite3, just to see how it behaves in the CI 2026-04-20 15:43:49 +08:00
Adrià Arrufat 9004787398 Merge branch 'main' into agent 2026-04-19 19:33:45 +02:00
Karl Seguin 23e98a4ce0 Add WPT extensions
Some WPT tests need to interact with the browser in a way that isn't possible
with web apis. Browsers need to expose a way for tests to do this and then use
the testdriver-vendor.js to hook into these special WPT actions.

This commit sets up the infrastructure for supporting this and includes
the delete_all_cookies functionality needed by various cookie tests (e.g.
/cookies/attributes/attributes-ctl.sub.html).

A new compilation flag, `-Dwpt_extensions`, can be specified. When specified
a `window.webdriver` accessor is defined and a `WebDriver` type is exposed.

Note that, while I only implemented delete_all_cookies for now, I've seen other
tests fail because of missing vendor-specific implementation.
2026-04-17 15:59:06 +08:00
Adrià Arrufat b99fd47c9d Merge branch 'main' into agent 2026-04-10 17:16:29 +02:00
Adrià Arrufat d6cdafc480 build: track html5ever Rust sources as cargo step inputs 2026-04-10 16:42:42 +02:00
Adrià Arrufat f7a4f1345f Merge branch 'main' into agent 2026-04-07 06:49:56 +02:00