Skip to content

LLM model が呼び出す apply_patch を手にいれる #96

@satokaz

Description

@satokaz

vibe-local から呼び出せる apply_patch が Solaris 上になかったので探してみた:

Codex の apply-patch を build してみる。

Solaris 環境では、rust-tree-sitter がビルドできないので、調査してもらった結果、apply-patch はビルドできるようになった。
solaris_endian.h を作成し強制 include する必要があり、次のように実行:

cd /path/to/codex/codex-rs && \
CFLAGS='-include /path/to/solaris_endian.h' \
cargo build -p codex-apply-patch

-p codex-apply-patch--release に変えればリリースビルドに)

このコマンドが終了すれば codex-rs/target/debug/apply_patch が生成され、テストは同じディレクトリで cargo test -p codex-apply-patch で走らせることが可能。

テスト結果
$ cd /path/to/codex/codex-rs && CFLAGS='-include /path/to/codex/solaris_endian.h' cargo test -p codex-apply-patch
   Compiling regex-automata v0.4.13
   Compiling tree-sitter-bash v0.25.1
   Compiling tree-sitter v0.25.10
   Compiling difflib v0.4.0
   Compiling getrandom v0.3.4
   Compiling termtree v0.5.1
   Compiling assert_cmd v2.1.2
   Compiling predicates-tree v1.0.12
   Compiling predicates v3.1.3
   Compiling rustix v1.1.3
   Compiling errno v0.3.14
   Compiling wait-timeout v0.2.1
   Compiling runfiles v0.1.0 (https://github.com/dzbarsky/rules_rust?rev=b56cbaa8465e74127f1ea216f813cd377295ad81#b56cbaa8)
   Compiling yansi v1.0.1
   Compiling fastrand v2.3.0
   Compiling once_cell v1.21.3
   Compiling pretty_assertions v1.4.1
   Compiling tempfile v3.24.0
   Compiling regex v1.12.3
   Compiling bstr v1.12.1
   Compiling assert_matches v1.5.0
   Compiling codex-utils-cargo-bin v0.0.0 (/export/home/kazus/Gits/codex/codex-rs/utils/cargo-bin)
   Compiling codex-apply-patch v0.0.0 (/export/home/kazus/Gits/codex/codex-rs/apply-patch)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 21.47s
     Running unittests src/lib.rs (target/debug/deps/codex_apply_patch-54120e6d013d2d53)

running 49 tests
test invocation::tests::test_apply_patch_should_resolve_absolute_paths_in_cwd ... ok
test invocation::tests::test_apply_patch_with_arg_is_ignored ... ok
test invocation::tests::test_cd_or_apply_patch_is_ignored ... ok
test invocation::tests::test_cd_double_quoted_path_with_spaces ... ok
test invocation::tests::test_cd_pipe_apply_patch_is_ignored ... ok
test invocation::tests::test_apply_patch_resolves_move_path_with_effective_cwd ... ok
test invocation::tests::test_cd_single_quoted_path_with_spaces ... ok
test invocation::tests::test_cd_then_apply_patch_then_extra_is_ignored ... ok
test invocation::tests::test_cd_two_args_is_ignored ... ok
test invocation::tests::test_cd_with_semicolon_is_ignored ... ok
test invocation::tests::test_double_cd_then_apply_patch_is_ignored ... ok
test invocation::tests::test_echo_and_apply_patch_is_ignored ... ok
test invocation::tests::test_cmd_heredoc_with_cd ... ok
test invocation::tests::test_echo_then_cd_and_apply_patch_is_ignored ... ok
test invocation::tests::test_heredoc ... ok
test invocation::tests::test_heredoc_applypatch ... ok
test invocation::tests::test_heredoc_non_login_shell ... ok
test invocation::tests::test_heredoc_with_leading_cd ... ok
test invocation::tests::test_implicit_patch_single_arg_is_error ... ok
test invocation::tests::test_implicit_patch_bash_script_is_error ... ok
test invocation::tests::test_literal_applypatch ... ok
test invocation::tests::test_literal ... ok
test invocation::tests::test_powershell_heredoc ... ok
test invocation::tests::test_powershell_heredoc_no_profile ... ok
test invocation::tests::test_pwsh_heredoc ... ok
test parser::test_parse_one_hunk ... ok
test invocation::tests::test_unified_diff_insert_at_eof ... ok
test parser::test_parse_patch ... ok
test invocation::tests::test_unified_diff_last_line_replacement ... ok
test seek_sequence::tests::test_exact_match_finds_sequence ... ok
test parser::test_update_file_chunk ... ok
test parser::test_parse_patch_lenient ... ok
test seek_sequence::tests::test_pattern_longer_than_input_returns_none ... ok
test seek_sequence::tests::test_rstrip_match_ignores_trailing_whitespace ... ok
test seek_sequence::tests::test_trim_match_ignores_leading_and_trailing_whitespace ... ok
test tests::test_add_file_hunk_creates_file_with_contents ... ok
test tests::test_apply_patch_fails_on_write_error ... ok
test tests::test_delete_file_hunk_removes_file ... ok
test tests::test_multiple_update_chunks_apply_to_single_file ... ok
test tests::test_pure_addition_chunk_followed_by_removal ... ok
test tests::test_unified_diff_first_line_replacement ... ok
test tests::test_unified_diff_insert_at_eof ... ok
test tests::test_unified_diff ... ok
test tests::test_unified_diff_last_line_replacement ... ok
test tests::test_update_file_hunk_can_move_file ... ok
test tests::test_unified_diff_interleaved_changes ... ok
test tests::test_update_file_hunk_interleaved_changes ... ok
test tests::test_update_file_hunk_modifies_content ... ok
test tests::test_update_line_with_unicode_dash ... ok

test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s

     Running unittests src/main.rs (target/debug/deps/apply_patch-2c3ce22704bea51c)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/all.rs (target/debug/deps/all-feb1179d5e8f6f03)

running 17 tests
test suite::tool::test_apply_patch_cli_add_overwrites_existing_file ... ok
test suite::cli::test_apply_patch_cli_add_and_update ... ok
test suite::tool::test_apply_patch_cli_applies_multiple_chunks ... ok
test suite::cli::test_apply_patch_cli_stdin_add_and_update ... ok
test suite::tool::test_apply_patch_cli_delete_directory_fails ... ok
test suite::tool::test_apply_patch_cli_applies_multiple_operations ... ok
test suite::tool::test_apply_patch_cli_failure_after_partial_success_leaves_changes ... ok
test suite::tool::test_apply_patch_cli_move_overwrites_existing_destination ... ok
test suite::tool::test_apply_patch_cli_moves_file_to_new_directory ... ok
test suite::tool::test_apply_patch_cli_rejects_empty_patch ... ok
test suite::tool::test_apply_patch_cli_rejects_empty_update_hunk ... ok
test suite::tool::test_apply_patch_cli_rejects_invalid_hunk_header ... ok
test suite::tool::test_apply_patch_cli_rejects_missing_file_delete ... ok
test suite::tool::test_apply_patch_cli_requires_existing_file_for_update ... ok
test suite::tool::test_apply_patch_cli_reports_missing_context ... ok
test suite::tool::test_apply_patch_cli_updates_file_appends_trailing_newline ... ok
test suite::scenarios::test_apply_patch_scenarios ... ok

test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22s

   Doc-tests codex_apply_patch

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Building apply_patch`

apply_patch is a small Rust tool in this repository used to safely apply patches supplied by the Codex agent. It lives in the codex-rs/apply-patch crate and depends on tree-sitter/tree-sitter-bash for parsing shell heredocs.

This document explains how to build it on supported platforms, and includes a Solaris-specific workaround required on the current build host.

Requirements

  • Rust toolchain (stable, edition 2024). See docs/install.md for general workspace setup.
  • cargo (comes with Rust).
  • On Unix-like platforms: a C compiler (gcc/clang) capable of compiling the tree-sitter C code.

Basic build steps

From the repository root:

cd codex-rs
cargo build -p codex-apply-patch

That produces the apply_patch binary under codex-rs/target/debug/ (or target/release if you build with --release).

Tests are also available:

cargo test -p codex-apply-patch

The crate exports both a library and a standalone executable; the binary name is apply_patch.

Solaris / other unsupported platforms

The tree-sitter crate includes a C file that expects a POSIX-like <endian.h> header and contains compile-time checks for recognized platforms. On Solaris (and apparently other non-Linux/BSD/macOS targets) these checks fail with:

#error platform not supported

and the build aborts.

To work around this when building on Solaris, you can provide a minimal replacement header and force it to be included during the C build. The following steps were used successfully on this SunOS 5.11 host:

  1. Create solaris_endian.h alongside the repo (or somewhere in your workspace) with contents similar to:
#ifndef ENDIAN_H
#define ENDIAN_H

/*
 * Minimal endian header for Solaris when building tree-sitter.
 * We assume little-endian (x86_64) and provide the needed macros.
 */

#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN

#define htobe16(x) __builtin_bswap16(x)
#define htole16(x) (x)
#define be16toh(x) __builtin_bswap16(x)
#define le16toh(x) (x)

#define htobe32(x) __builtin_bswap32(x)
#define htole32(x) (x)
#define be32toh(x) __builtin_bswap32(x)
#define le32toh(x) (x)

#define htobe64(x) __builtin_bswap64(x)
#define htole64(x) (x)
#define be64toh(x) __builtin_bswap64(x)
#define le64toh(x) (x)

#endif /* ENDIAN_H */

(This file simply defines the macros that tree-sitter tries to detect; adjust if building on a big-endian architecture.)

  1. Export CFLAGS when running cargo so that the header is pulled in:
cd codex-rs
CFLAGS='-include /path/to/solaris_endian.h' \
    cargo build -p codex-apply-patch

or set the same value in your environment once. The -include flag forces the compiler to process our compatibility header before any other include, satisfying the #include <endian.h> in tree-sitter's C code.

  1. The build should then complete normally, producing a working apply_patch binary. (In our case the command finished in ~11s.)

The crate itself does not expose a feature flag to disable the tree-sitter dependency, so this workaround is necessary on platforms where tree-sitter's C code is not officially supported. The header can be committed to the repo or otherwise distributed to developers working on Solaris.

Notes for maintainers

  • The Solaris workaround is a local patch, not part of the upstream tree-sitter crate. If tree-sitter adds official Solaris support in the future, the header and special CFLAGS can be removed.
  • When editing apply-patch code, use cargo test -p codex-apply-patch to exercise its extensive unit tests and fixtures.
  • Logging and invocation details are documented in codex-rs/apply-patch/apply_patch_tool_instructions.md and in the source code comments.

With these instructions, anyone should be able to reproduce the build (even on non-Linux hosts) and understand the necessary environment changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions