# Verify And Build

> Use when compiling TS/C++, rebuilding iOS pods, troubleshooting JSI runtime errors, debugging native crashes, or sync'ing Android Gradle.

- Skill: `software-mansion/verify-and-build` (Agent Skill)
- Install (CLI): `npx skillmds@latest add software-mansion/verify-and-build`
- Raw SKILL.md: https://api.skillmd.com/api/skills/software-mansion/verify-and-build/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: software-mansion (https://skillmd.com/u/software-mansion)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/software-mansion/verify-and-build

---


# Skill: Verification, Compilation & Troubleshooting

Use this guide to compile, test, verify, and troubleshoot your modifications to the library (both JS/TS and native C++).

---

## 🛠️ Verification & Compilation Workflows

### 1. Build and Typecheck TypeScript

To check types and compile the TypeScript source code:

- **Verify Types (Fast)**:
  ```bash
  yarn typecheck
  ```
- **Run the TypeScript API Tests**:
  ```bash
  yarn workspace react-native-executorch test
  ```
  _Jest suites over the public `src/` surface — hooks, task pipelines, core
  primitives, the fetcher and the model registry — running against a fake
  native runtime, so they need no simulator, device or `.pte` file. See the
  [Add API Tests skill](../add-api-tests/SKILL.md)._
- **Build Bundles**:
  ```bash
  yarn prepare
  ```
  _This cleans target directories and builds modules into the `lib/` directory using `react-native-builder-bob`._
- **When**: After adding/updating TypeScript files under `src/`.
- **Verification**: Ensure no compiler or type-checking errors are raised.

### 2. Native Rebuilding

#### iOS Development

Whenever you modify native files under `cpp/` or update `.podspec`:

```bash
pushd apps/<domain-app>/ios && pod install && popd
```

- **Rebuilding**: Re-run the app from within the appropriate app folder:
  ```bash
  cd apps/<domain-app>
  yarn run ios
  ```
- **Clean Build**: If files aren't being picked up:
  - In Xcode: `Product` > `Clean Build Folder` (Cmd + Shift + K).

#### Android Development

Android compiles C++ source files on-demand during application builds:

```bash
cd apps/<domain-app>
yarn run android
```

- **Clean Build**: If caching issues occur:
  ```bash
  pushd apps/<domain-app>/android && ./gradlew clean && popd
  ```

---

## 🧹 C++ Static Analysis

Two complementary checks gate C++ quality. Always run both before committing.

### 1. `lint:cpp` — clang-tidy

Runs the project's `.clang-tidy` ruleset (bugprone / performance / clang-analyzer / llvm-include-order) over all `cpp/` sources.

```bash
# clang-tidy must be installed from Homebrew LLVM — the Xcode bundled version is too old:
CLANG_TIDY=$(brew --prefix llvm)/bin/clang-tidy yarn workspace react-native-executorch lint:cpp
```

- Requires ExecuTorch headers provisioned under `third-party/include` and `yarn install` (for JSI headers).
- Any finding fails the run (`--warnings-as-errors`). Suppress a deliberate, reviewed finding with `// NOLINTNEXTLINE(check-name)` rather than relaxing the shared config.
- **Homebrew LLVM is newer than CI's clang-tidy and reports checks CI does not have.** Before "fixing" a local finding, copy the unmodified base-branch version of the file in under a temp name and lint that too. A finding that also fires there is pre-existing and is not yours to fix in your PR.
- **A local macOS-only syntax check cannot see platform-conditional code.** Anything inside `#if defined(__ANDROID__)` / `#elif defined(__APPLE__)` compiles locally and can still fail CI on another target. Check by eye that new includes and `using` declarations sit at file scope, outside every preprocessor branch.

### 2. `check-cpp-warnings.sh` — clangd warning set

Compiles staged (or explicitly passed) `cpp/` sources with the same flags clangd uses in the editor (from `compile_flags.txt` + `-W` flags in `.clangd`), so the editor and CI stay in sync. Run from the package root (`packages/react-native-executorch/`):

```bash
# The script takes file paths as positional arguments and exits 0 immediately
# with none — it has no built-in file discovery. Pass files explicitly:
find cpp/ -path cpp/tests -prune -o \( -name '*.cpp' -o -name '*.h' \) -print | \
  xargs ./scripts/check-cpp-warnings.sh
```

The script skips gracefully (exit 0) when no compiler, `compile_flags.txt`, `.clangd`, or provisioned headers are found — it never blocks contributors who don't build the native code.

---

## 🔍 Debugging & Log Access

### 1. TypeScript & Worklet Logging

Logging inside worklets (functions annotated with `'worklet';`) behaves slightly differently as they run on a separate runtime thread.

- Use standard `console.log(...)` inside worklets.
- **Caution**: Worklet logs are piped back to the JS console, but passing complex circular objects to `console.log` from a worklet can fail or freeze. Stringify or log specific primitive properties instead.

### 2. Native C++ Debugging

Native JSI crashes, standard outputs, or ExecuTorch errors can be caught in the native log streams:

- **iOS**: Watch outputs directly inside the Xcode Console while running the app target.
- **Android**: Use Android Studio's logcat or run:
  ```bash
  adb logcat *:S ReactNative:V ReactNativeJS:V rnexecutorch:V
  ```

---

## 🚦 Common JSI Troubleshooting

### Symptom: `Error: JSI global object '__rnexecutorch_jsi__' is not registered.`

- **Cause 1**: The native code wasn't linked or JSI installation failed during loading.
  - _Fix_: Verify that you have registered your new extension/module in [cpp/RnExecutorch.cpp](../../../packages/react-native-executorch/cpp/RnExecutorch.cpp).
  - _Fix_: Re-run `pod install` (for iOS) or perform a Gradle sync/clean (for Android) to ensure your C++ changes compiled.
- **Cause 2**: The bridge did not invoke the native installation.
  - _Fix_: Ensure the JS entrypoint triggers the load (see [src/native/bridge.ts](../../../packages/react-native-executorch/src/native/bridge.ts)).

### Symptom: `TypeError: Cannot read property '<extension>' of undefined`

- **Cause**: You added an extension in C++ but forgot to register it in your TypeScript bridge bindings.
  - _Fix_: Check that `module.setProperty(rt, "<extension>", subModule)` is called in your native `install.cpp` and that your TS wrapper exports and references it under `rnexecutorchJsi.<extension>`.

---

## 📂 Model Hosting & Download Caching

This project does **not** bundle local `.pte` model files inside the React Native application package. Instead, the standard workflow is:

1. **Upload to Hugging Face**:
   - Upload compiled/exported `.pte` models directly to our Hugging Face repository bucket.
   - **Naming Convention**: All `.pte` files must follow the strict name contract:
     `modelname_optionalsize_backend_precision.pte`
     - _Example_: `efficientnet_v2_s_xnnpack_int8.pte`
     - _Example_: `style_transfer_candy_xnnpack_fp32.pte`

2. **Define in Models Manifest** ([src/models.ts](../../../packages/react-native-executorch/src/models.ts)):
   - **Single Export Registry Rule**: Define the new model configuration as an internal (private) `const` inside `models.ts`. **Do not** export individual model configuration constants. Instead, expose them solely by registering them under the appropriate category nested inside the main `models` registry object, which is the only exported symbol from `models.ts`.
   - _Example_:

     ```typescript
     // Defined internally (private)
     const MY_MODEL_XNNPACK_FP32: MyTaskModel = { ... };

     // Registered in the exported models object
     export const models = {
       ...
       myTask: {
         MY_MODEL: {
           XNNPACK_FP32: MY_MODEL_XNNPACK_FP32,
         }
       }
     };
     ```

3. **Runtime Downloading & Caching**:
   - The custom hook `useResourceDownload(config.modelPath)` handles checks automatically:
     - If the model file is not already in the device cache directory, it downloads it from the Hugging Face URL to `RNFS.CachesDirectoryPath`.
     - If the model file exists in the cache, it bypasses the download and returns the cached local path immediately to load the model.

---

## 🚫 Avoid / Anti-Patterns

- **Do NOT run code without verification:** Do not test TypeScript changes in the app without first running `yarn typecheck` (verify types), `yarn workspace react-native-executorch test` (API suites) and `yarn prepare` (build target bundles).
- **Do NOT skip native rebuilds after C++ edits:** If any C++ files or config bindings are added/modified, do not attempt to run the app without executing `pod install` (for iOS) or letting Gradle sync (for Android).
- **Do NOT run `lint:cpp` with the system `clang-tidy`**: Use the Homebrew LLVM binary: `CLANG_TIDY=$(brew --prefix llvm)/bin/clang-tidy yarn workspace react-native-executorch lint:cpp`.
- **Do NOT trust a green macOS-only syntax check for platform-conditional C++:** see the clang-tidy notes above.
- **Do NOT log complex objects inside worklets:** Avoid passing complex circular objects directly to `console.log()` inside functions annotated with `'worklet';` as it can hang or crash the worklet runtime thread.
- **Do NOT bundle local `.pte` files in the repository:** Do not commit heavy model binaries to the git repository. Always host them on Hugging Face and register their metadata in `src/models.ts`.

---

## 📋 Verification Checklist

When verifying or compiling your modifications, check that:

- [ ] TypeScript typechecking passes without errors (`yarn typecheck`).
- [ ] The TypeScript API tests pass (`yarn workspace react-native-executorch test`), and any new `src/` behavior is covered by them.
- [ ] Bundles compile successfully (`yarn prepare`).
- [ ] `pod install` has been run inside `apps/<domain-app>/ios/` after any native C++ edits.
- [ ] `lint:cpp` passes cleanly: `CLANG_TIDY=$(brew --prefix llvm)/bin/clang-tidy yarn workspace react-native-executorch lint:cpp`.
- [ ] `check-cpp-warnings.sh` passes cleanly (run via `find cpp/ -name '*.cpp' -o -name '*.h' | xargs ./scripts/check-cpp-warnings.sh` from the package root).
- [ ] No `.pte` files are staged or added to git history.
- [ ] Model configurations are registered inside the single `models` object registry in `src/models.ts`.
- [ ] Native runtime issues have been investigated using Xcode Console or `adb logcat`.

