Skip to content

Commit caae199

Browse files
committed
Add support for using pre-built Hermes via HERMES_BUILD_DIR
The build system now supports using an existing Hermes build instead of always cloning and building from git. This is useful for CI caching and sharing Hermes builds across multiple projects. Changes: - Add HERMES_BUILD_DIR option to specify pre-built Hermes location - Auto-detect source directory by reading CMAKE_HOME_DIRECTORY from CMakeCache.txt - Create dummy 'hermes' target when using external build (for compatibility with add_dependencies) - Remove unnecessary CACHE FORCE from HERMES_SRC/HERMES_BUILD variables - Update documentation with usage examples and CI workflow Usage: cmake -B build -DHERMES_BUILD_DIR=/path/to/hermes-build Backward compatible: existing builds continue to auto-build Hermes as before.
1 parent 5a82d13 commit caae199

File tree

2 files changed

+158
-56
lines changed

2 files changed

+158
-56
lines changed

CLAUDE.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,22 @@ void imgui_main(int argc, char *argv[],
265265
### Build System (CMake)
266266
267267
**Hermes Build Integration (cmake/HermesExternal.cmake):**
268+
The build system supports two modes for obtaining Hermes:
269+
270+
**Option 1: Using Pre-built Hermes (Recommended for CI/Shared Builds)**
271+
```bash
272+
# Point to an existing Hermes build directory
273+
cmake -B build -DHERMES_BUILD_DIR=/path/to/hermes-build
274+
```
275+
- **Fast Configuration**: Skips git clone and build, uses existing Hermes
276+
- **Auto-detect Source**: Reads source path from `CMakeCache.txt` in build directory
277+
- **Validation**: Checks that build directory and shermes binary exist
278+
- **Use Cases**:
279+
- CI caching: Build Hermes once, cache it, reuse across jobs
280+
- Local development: Share one Hermes build across multiple projects
281+
- Faster iteration: Skip 5-10 minute Hermes rebuild
282+
283+
**Option 2: Automatic Build (Default)**
268284
Hermes is automatically cloned and built as part of the CMake build using `ExternalProject_Add`:
269285
- **Automatic Git Clone**: Hermes is cloned from GitHub at configure time
270286
- **Configurable Version**: Set via `HERMES_GIT_TAG` (default: specific commit hash)
@@ -274,7 +290,9 @@ Hermes is automatically cloned and built as part of the CMake build using `Exter
274290
- **Per-Config Isolation**: Each build configuration gets its own Hermes clone
275291
- Debug: `cmake-build-debug/hermes-src/` (source) + `cmake-build-debug/hermes/` (build)
276292
- Release: `cmake-build-release/hermes-src/` (source) + `cmake-build-release/hermes/` (build)
277-
- **No Manual Setup**: Users don't need to manually build or specify HERMES_BUILD/HERMES_SRC paths
293+
- **No Manual Setup**: Users don't need to manually build or specify paths
294+
295+
**Build Configuration:**
278296
- **Static vs Shared Linking**:
279297
- Release builds: Link statically against `hermesvm_a`, `jsi`, and `boost_context` for optimal performance
280298
- Debug builds: Link dynamically against `hermesvm` shared library for faster build times
@@ -534,6 +552,36 @@ cmake -B cmake-build-debug -DHERMES_GIT_TAG=<commit-hash>
534552
cmake --build cmake-build-debug --target hermes-rebuild # Force rebuild
535553
```
536554

555+
**Using a pre-built Hermes:**
556+
```bash
557+
# Point to an existing Hermes build directory
558+
cmake -B cmake-build-debug -DCMAKE_BUILD_TYPE=Debug -DHERMES_BUILD_DIR=/path/to/hermes-build
559+
cmake --build cmake-build-debug
560+
```
561+
562+
**CI Workflow with Hermes Caching:**
563+
```yaml
564+
# Build Hermes once in a separate job, cache it, and reuse
565+
- name: Cache Hermes build
566+
id: hermes-cache
567+
uses: actions/cache@v4
568+
with:
569+
path: hermes-build
570+
key: ${{ runner.os }}-hermes-${{ hashFiles('.github/hermes-version.txt') }}
571+
572+
- name: Build Hermes (if not cached)
573+
if: steps.hermes-cache.outputs.cache-hit != 'true'
574+
run: |
575+
git clone https://github.com/facebook/hermes.git hermes-src
576+
cmake -S hermes-src -B hermes-build -DCMAKE_BUILD_TYPE=Release
577+
cmake --build hermes-build --config Release
578+
579+
- name: Build project with cached Hermes
580+
run: |
581+
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DHERMES_BUILD_DIR=${{ github.workspace }}/hermes-build
582+
cmake --build build
583+
```
584+
537585
**Important:**
538586
- Use `cmake --build` consistently to prevent spurious rebuilds
539587
- Do NOT alternate between `cmake --build` and running ninja directly (different ninja versions cause rebuild loops)

cmake/HermesExternal.cmake

Lines changed: 109 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,121 @@
44

55
# CMake configuration for building Hermes as an external project
66
#
7-
# This module clones Hermes from git and builds it in Release mode
8-
# regardless of the parent project's build type.
7+
# This module either uses a pre-built Hermes or clones and builds it from git.
98
#
109
# Configuration variables:
11-
# HERMES_GIT_URL - Git repository URL (default: https://github.com/facebook/hermes.git)
12-
# HERMES_GIT_TAG - Git tag/commit/branch to checkout (default: main)
10+
# HERMES_BUILD_DIR - Path to pre-built Hermes build directory (optional)
11+
# If set, skips auto-build and uses existing Hermes
12+
# HERMES_GIT_URL - Git repository URL (default: https://github.com/facebook/hermes.git)
13+
# HERMES_GIT_TAG - Git tag/commit/branch to checkout (default: specific commit)
1314
#
1415
# The module sets the following variables:
15-
# HERMES_SRC - Path to Hermes source directory (${CMAKE_BINARY_DIR}/hermes-src)
16-
# HERMES_BUILD - Path to Hermes build directory (${CMAKE_BINARY_DIR}/hermes)
16+
# HERMES_SRC - Path to Hermes source directory
17+
# HERMES_BUILD - Path to Hermes build directory
1718
# SHERMES - Path to shermes binary
1819
# HERMES - Path to hermes binary
1920

2021
include(ExternalProject)
2122

22-
# Configurable git parameters
23-
set(HERMES_GIT_URL "https://github.com/facebook/hermes.git"
24-
CACHE STRING "Hermes git repository URL")
25-
set(HERMES_GIT_TAG "80359d48dbf0a108031d69c8a22bad180cfb4df3"
26-
CACHE STRING "Hermes git tag/commit/branch to build")
27-
28-
# Set Hermes paths - everything in build directory
29-
set(HERMES_SRC "${CMAKE_BINARY_DIR}/hermes-src" CACHE STRING "Hermes source directory" FORCE)
30-
set(HERMES_BUILD "${CMAKE_BINARY_DIR}/hermes" CACHE STRING "Hermes build directory" FORCE)
31-
32-
# Configure Hermes build options
33-
set(HERMES_CMAKE_ARGS
34-
-DCMAKE_BUILD_TYPE=Release
35-
-DHERMES_ENABLE_TEST_SUITE=OFF
36-
-DHERMES_BUILD_APPLE_FRAMEWORK=OFF
37-
)
38-
39-
# Add Hermes as external project
40-
ExternalProject_Add(hermes
41-
GIT_REPOSITORY ${HERMES_GIT_URL}
42-
GIT_TAG ${HERMES_GIT_TAG}
43-
GIT_SHALLOW OFF
44-
GIT_PROGRESS ON
45-
SOURCE_DIR ${HERMES_SRC}
46-
BINARY_DIR ${HERMES_BUILD}
47-
CMAKE_ARGS ${HERMES_CMAKE_ARGS}
48-
BUILD_ALWAYS OFF
49-
INSTALL_COMMAND ""
50-
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config Release
51-
LOG_CONFIGURE ON
52-
LOG_BUILD ON
53-
LOG_OUTPUT_ON_FAILURE ON
54-
UPDATE_DISCONNECTED ON
55-
)
56-
57-
# Set tool paths (these will be valid after Hermes is built)
58-
set(SHERMES "${HERMES_BUILD}/bin/shermes" CACHE STRING "shermes tool path" FORCE)
59-
set(HERMES "${HERMES_BUILD}/bin/hermes" CACHE STRING "hermes compiler path" FORCE)
60-
61-
# Add a target for manual rebuilds
62-
add_custom_target(hermes-rebuild
63-
COMMAND ${CMAKE_COMMAND} --build ${HERMES_BUILD} --config Release --clean-first
64-
COMMENT "Rebuilding Hermes from scratch"
65-
)
66-
67-
message(STATUS "Hermes git URL: ${HERMES_GIT_URL}")
68-
message(STATUS "Hermes git tag: ${HERMES_GIT_TAG}")
69-
message(STATUS "Hermes will be cloned to: ${HERMES_SRC}")
70-
message(STATUS "Hermes will be built in Release mode at: ${HERMES_BUILD}")
23+
# Check if user provided a pre-built Hermes
24+
if(HERMES_BUILD_DIR)
25+
message(STATUS "Using external Hermes build: ${HERMES_BUILD_DIR}")
26+
27+
# Validate build directory exists
28+
if(NOT IS_DIRECTORY "${HERMES_BUILD_DIR}")
29+
message(FATAL_ERROR "HERMES_BUILD_DIR does not exist: ${HERMES_BUILD_DIR}")
30+
endif()
31+
32+
# Read CMakeCache.txt to find source directory
33+
set(CACHE_FILE "${HERMES_BUILD_DIR}/CMakeCache.txt")
34+
if(NOT EXISTS "${CACHE_FILE}")
35+
message(FATAL_ERROR "CMakeCache.txt not found in HERMES_BUILD_DIR: ${CACHE_FILE}")
36+
endif()
37+
38+
# Parse CMAKE_HOME_DIRECTORY from cache file
39+
file(STRINGS "${CACHE_FILE}" CACHE_LINES REGEX "^CMAKE_HOME_DIRECTORY:")
40+
if(NOT CACHE_LINES)
41+
message(FATAL_ERROR "CMAKE_HOME_DIRECTORY not found in ${CACHE_FILE}")
42+
endif()
43+
44+
# Extract path from "CMAKE_HOME_DIRECTORY:INTERNAL=/path/to/source"
45+
string(REGEX REPLACE "^CMAKE_HOME_DIRECTORY:INTERNAL=(.+)$" "\\1" HERMES_SRC_FROM_CACHE "${CACHE_LINES}")
46+
47+
# Validate source directory exists
48+
if(NOT IS_DIRECTORY "${HERMES_SRC_FROM_CACHE}")
49+
message(FATAL_ERROR "Hermes source directory from cache does not exist: ${HERMES_SRC_FROM_CACHE}")
50+
endif()
51+
52+
# Set paths
53+
set(HERMES_SRC "${HERMES_SRC_FROM_CACHE}")
54+
set(HERMES_BUILD "${HERMES_BUILD_DIR}")
55+
56+
# Validate shermes binary exists
57+
set(SHERMES "${HERMES_BUILD}/bin/shermes")
58+
if(NOT EXISTS "${SHERMES}")
59+
message(FATAL_ERROR "shermes binary not found: ${SHERMES}")
60+
endif()
61+
62+
# Set hermes binary path (optional tool, don't fail if missing)
63+
set(HERMES "${HERMES_BUILD}/bin/hermes")
64+
65+
message(STATUS "Hermes source: ${HERMES_SRC}")
66+
message(STATUS "Hermes build: ${HERMES_BUILD}")
67+
message(STATUS "shermes: ${SHERMES}")
68+
69+
# Create a dummy target so dependencies on 'hermes' still work
70+
add_custom_target(hermes)
71+
72+
else()
73+
# Auto-build Hermes from git
74+
75+
# Configurable git parameters
76+
set(HERMES_GIT_URL "https://github.com/facebook/hermes.git"
77+
CACHE STRING "Hermes git repository URL")
78+
set(HERMES_GIT_TAG "80359d48dbf0a108031d69c8a22bad180cfb4df3"
79+
CACHE STRING "Hermes git tag/commit/branch to build")
80+
81+
# Set Hermes paths - everything in build directory
82+
set(HERMES_SRC "${CMAKE_BINARY_DIR}/hermes-src")
83+
set(HERMES_BUILD "${CMAKE_BINARY_DIR}/hermes")
84+
85+
# Configure Hermes build options
86+
set(HERMES_CMAKE_ARGS
87+
-DCMAKE_BUILD_TYPE=Release
88+
-DHERMES_ENABLE_TEST_SUITE=OFF
89+
-DHERMES_BUILD_APPLE_FRAMEWORK=OFF
90+
)
91+
92+
# Add Hermes as external project
93+
ExternalProject_Add(hermes
94+
GIT_REPOSITORY ${HERMES_GIT_URL}
95+
GIT_TAG ${HERMES_GIT_TAG}
96+
GIT_SHALLOW OFF
97+
GIT_PROGRESS ON
98+
SOURCE_DIR ${HERMES_SRC}
99+
BINARY_DIR ${HERMES_BUILD}
100+
CMAKE_ARGS ${HERMES_CMAKE_ARGS}
101+
BUILD_ALWAYS OFF
102+
INSTALL_COMMAND ""
103+
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config Release
104+
LOG_CONFIGURE ON
105+
LOG_BUILD ON
106+
LOG_OUTPUT_ON_FAILURE ON
107+
UPDATE_DISCONNECTED ON
108+
)
109+
110+
# Set tool paths (these will be valid after Hermes is built)
111+
set(SHERMES "${HERMES_BUILD}/bin/shermes")
112+
set(HERMES "${HERMES_BUILD}/bin/hermes")
113+
114+
# Add a target for manual rebuilds
115+
add_custom_target(hermes-rebuild
116+
COMMAND ${CMAKE_COMMAND} --build ${HERMES_BUILD} --config Release --clean-first
117+
COMMENT "Rebuilding Hermes from scratch"
118+
)
119+
120+
message(STATUS "Hermes git URL: ${HERMES_GIT_URL}")
121+
message(STATUS "Hermes git tag: ${HERMES_GIT_TAG}")
122+
message(STATUS "Hermes will be cloned to: ${HERMES_SRC}")
123+
message(STATUS "Hermes will be built in Release mode at: ${HERMES_BUILD}")
124+
endif()

0 commit comments

Comments
 (0)