Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# ITK-Wasm AI Agent Instructions

## Project Overview

ITK-Wasm compiles [ITK](https://itk.org/) C++ image processing to WebAssembly for browser, Node.js, and Python execution. The architecture spans:

- **C++ Core** (`include/`, `src/`): ITK pipeline interface with `itkPipeline.h` CLI parsing
- **Docker Build Images** (`src/docker/`): Emscripten and WASI toolchain containers
- **CLI** (`packages/core/typescript/itk-wasm/src/cli/`): `itk-wasm` build/bindgen commands
- **Language Bindings**: TypeScript (`packages/*/typescript/`) and Python (`packages/*/python/`)
- **Example Packages** (`packages/`): image-io, mesh-io, dicom, downsample, etc.

## Development Workflow

```bash
# Full build
pnpm install
pnpm build
pnpm test

# Individual package development
cd packages/<package-name>
pnpm build:emscripten # or build:wasi
pnpm build:gen:typescript
pnpm build:gen:python
pnpm test
```

### Debug WebAssembly Builds

```bash
pixi shell
pnpm build:emscripten:debug && pnpm build:wasi:debug
pnpm build && pnpm test
```

### Docker Image Development

```bash
# Build with local ITK source for bug fixes
./src/docker/build.sh --local-itk /path/to/ITK
# Or via environment variable
export ITK_WASM_LOCAL_ITK_SOURCE=/path/to/ITK
./src/docker/build.sh
```

## Package Structure Convention

Each `packages/<name>/` contains:
- C++ pipelines (`.cxx` files) with `CMakeLists.txt`
- `package.json` with `itk-wasm` config section for test data, Docker images, package names
- `typescript/` and `python/` directories for generated bindings
- `test/data/` with input/baseline files (downloaded via `test:data:download`)

## Key Patterns

### C++ Pipeline Structure

Use `ITK_WASM_PARSE` macro and typed inputs/outputs from `include/`:
```cpp
#include "itkPipeline.h"
#include "itkInputImage.h"
#include "itkOutputImage.h"

int main(int argc, char * argv[]) {
itk::wasm::Pipeline pipeline("operation-name", "Description", argc, argv);
// Add options, parse with ITK_WASM_PARSE(pipeline), process, return
}
```

### Test Data Management

Test data uses content-addressed storage. To add/modify:
```bash
# In package directory
pnpm test:data:pack # Creates test/data.tar.gz, outputs CID
# Ask user to upload to IPFS host, update package.json itk-wasm.test-data-hash and test-data-urls
```

### Binding Generation

The CLI generates TypeScript/Python bindings from WASI builds:
```bash
itk-wasm bindgen --interface typescript # or python
```

## Environment Variables

Key variables in `itk_wasm_env.bash`:
- `ITK_WASM_ITK_REPOSITORY`, `ITK_WASM_ITK_BRANCH`: ITK source for Docker builds
- `ITK_WASM_LOCAL_ITK_SOURCE`: Use local ITK directory in Docker builds
- `ITK_WASM_*_TEST_DATA_HASH/URLS`: Per-package test data configuration

## Commit Convention

Uses [conventional commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, etc.
36 changes: 36 additions & 0 deletions src/docker/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,39 @@ pnpm clean && pnpm install && pnpm build && pnpm test
git add -- packages/core/typescript/itk-wasm/src/cli/default-image-tag.js
git commit -m "feat(itk-wasm-cli): update default Docker image for $(date '+%Y%m%d')-$(git rev-parse --short HEAD)"
```

## Building with a Local ITK Repository

To test ITK bug fixes or develop new features for the wasm toolchains, you can build Docker images using a local ITK source directory instead of cloning from the remote repository.

### Using the `--local-itk` Argument

```bash
# Clone ITK locally (if not already present)
git clone https://github.com/InsightSoftwareConsortium/ITK.git /path/to/local/ITK
cd /path/to/local/ITK
git checkout <your-branch-or-commit>

# Build Docker images with local ITK source
./src/docker/build.sh --local-itk /path/to/local/ITK
# Or for individual image builds:
./src/docker/itk-wasm-base/build.sh --local-itk /path/to/local/ITK --with-wasi
```

### Using the `ITK_WASM_LOCAL_ITK_SOURCE` Environment Variable

Alternatively, set the environment variable for scripting or CI workflows:

```bash
export ITK_WASM_LOCAL_ITK_SOURCE=/path/to/local/ITK
./src/docker/build.sh
```

### Notes

- The local ITK source is copied into the Docker build context, so changes to the local directory after starting the build will not be reflected.
- DCMTK patches are automatically applied to the local ITK source during the Docker build.
- This is useful for:
- Testing ITK bug fixes before they are merged upstream
- Developing new ITK features for wasm toolchains
- Debugging ITK issues specific to Emscripten or WASI builds
15 changes: 14 additions & 1 deletion src/docker/itk-wasm-base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,20 @@ RUN curl -L https://api.github.com/repos/facebook/zstd/tarball/${zstd_GIT_TAG} |
cd .. && \
rm -rf zstd-build zstd

RUN . /itk_wasm_env_vars.sh && git clone --branch $ITK_WASM_ITK_BRANCH --single-branch --depth 1 $ITK_WASM_ITK_REPOSITORY && \
# Support using a local ITK source directory instead of cloning from git
ARG USE_LOCAL_ITK=0
COPY ITKLocalCopy /ITKLocalCopy

# Either use local ITK source or clone from git repository
RUN . /itk_wasm_env_vars.sh && \
if [ "$USE_LOCAL_ITK" = "1" ] && [ -d /ITKLocalCopy ] && [ "$(ls -A /ITKLocalCopy 2>/dev/null | grep -v .gitkeep)" ]; then \
echo "Using local ITK source" && \
mv /ITKLocalCopy /ITK; \
else \
echo "Cloning ITK from $ITK_WASM_ITK_REPOSITORY branch $ITK_WASM_ITK_BRANCH" && \
rm -rf /ITKLocalCopy && \
git clone --branch $ITK_WASM_ITK_BRANCH --single-branch --depth 1 $ITK_WASM_ITK_REPOSITORY; \
fi && \
sed -i -e '/^option(OPJ_USE_THREAD/c\option(OPJ_USE_THREAD "use threads" OFF)' \
/ITK/Modules/ThirdParty/GDCM/src/gdcm/Utilities/gdcmopenjpeg/src/lib/openjp2/CMakeLists.txt

Expand Down
Empty file.
75 changes: 65 additions & 10 deletions src/docker/itk-wasm-base/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,41 @@ BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
debug=false
wasi=false
version_tag=false
local_itk=""
build_cmd="build"
tag_flag="--tag"
host_arch=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')
for param; do
if [[ $param == '--with-debug' ]]; then
debug=true
elif [[ $param == '--with-wasi' ]]; then
wasi=true
elif [[ $param == '--version-tag' ]]; then
version_tag=true
else
newparams+=("$param")
fi
while [[ $# -gt 0 ]]; do
case $1 in
--with-debug)
debug=true
shift
;;
--with-wasi)
wasi=true
shift
;;
--version-tag)
version_tag=true
shift
;;
--local-itk)
local_itk="$2"
shift 2
;;
*)
newparams+=("$1")
shift
;;
esac
done
set -- "${newparams[@]}" # overwrites the original positional params

# Support ITK_WASM_LOCAL_ITK_SOURCE environment variable as fallback
if [[ -z "$local_itk" && -n "${ITK_WASM_LOCAL_ITK_SOURCE:-}" ]]; then
local_itk="$ITK_WASM_LOCAL_ITK_SOURCE"
fi

# Note: also need to set in wasi-sdk-pthread-itkwasm.cmake
wasi_ld_flags="-flto -lwasi-emulated-process-clocks -lwasi-emulated-signal -lc-printscan-long-double"
wasi_c_flags="-flto -msimd128 -D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_SIGNAL"
Expand All @@ -46,13 +65,38 @@ emscripten_threads_c_flags="-pthread -msimd128 -flto -Wno-warn-absolute-paths -D
emscripten_threads_debug_ld_flags="-pthread -s MALLOC=mimalloc -s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency -fno-lto -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB"
emscripten_threads_debug_c_flags="-pthread -msimd128 -fno-lto -Wno-warn-absolute-paths"

# Handle local ITK source
local_itk_build_arg=""
if [[ -n "$local_itk" ]]; then
if [[ ! -d "$local_itk" ]]; then
echo "Error: Local ITK directory does not exist: $local_itk"
exit 1
fi
echo "Using local ITK source from: $local_itk"
# Clear placeholder and copy local ITK source
rm -rf "$script_dir/ITKLocalCopy"/*
cp_exe=$(which rsync 2>/dev/null || which cp)
$cp_exe -a "$local_itk"/* "$script_dir/ITKLocalCopy/"
local_itk_build_arg="--build-arg USE_LOCAL_ITK=1"
fi

# Cleanup function to restore ITKLocalCopy to placeholder state
cleanup_local_itk() {
if [[ -n "$local_itk" ]]; then
rm -rf "$script_dir/ITKLocalCopy"/*
touch "$script_dir/ITKLocalCopy/.gitkeep"
fi
}
trap cleanup_local_itk EXIT

$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:latest-$host_arch \
--build-arg IMAGE=quay.io/itkwasm/emscripten-base \
--build-arg HOST_ARCH=$host_arch \
--build-arg CMAKE_BUILD_TYPE=Release \
--build-arg VCS_REF=${VCS_REF} \
--build-arg VCS_URL=${VCS_URL} \
--build-arg BUILD_DATE=${BUILD_DATE} \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:${TAG}-$host_arch \
Expand All @@ -63,6 +107,7 @@ if $version_tag; then
--build-arg VCS_REF=${VCS_REF} \
--build-arg VCS_URL=${VCS_URL} \
--build-arg BUILD_DATE=${BUILD_DATE} \
$local_itk_build_arg \
$script_dir $@
fi

Expand All @@ -76,6 +121,7 @@ $exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:latest-threads-$host_a
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_threads_ld_flags}" \
--build-arg CFLAGS="${emscripten_threads_c_flags}" \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:${TAG}-threads-$host_arch \
Expand All @@ -88,6 +134,7 @@ if $version_tag; then
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_threads_ld_flags}" \
--build-arg CFLAGS="${emscripten_threads_c_flags}" \
$local_itk_build_arg \
$script_dir $@
fi

Expand All @@ -102,6 +149,7 @@ if $wasi; then
--build-arg BASE_IMAGE=docker.io/dockcross/web-wasi-emulated-threads \
--build-arg LDFLAGS="${wasi_ld_flags}" \
--build-arg CFLAGS="${wasi_c_flags}" \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/wasi-base:${TAG}-$host_arch \
Expand All @@ -115,6 +163,7 @@ if $wasi; then
--build-arg BASE_IMAGE=docker.io/dockcross/web-wasi-emulated-threads \
--build-arg LDFLAGS="${wasi_ld_flags}" \
--build-arg CFLAGS="${wasi_c_flags}" \
$local_itk_build_arg \
$script_dir $@
fi
fi
Expand All @@ -132,6 +181,7 @@ if $debug; then
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_debug_ld_flags}" \
--build-arg CFLAGS="${emscripten_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:${TAG}-debug-$host_arch \
Expand All @@ -145,6 +195,7 @@ if $debug; then
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_debug_ld_flags}" \
--build-arg CFLAGS="${emscripten_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
fi
$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:latest-threads-debug-$host_arch \
Expand All @@ -158,6 +209,7 @@ if $debug; then
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_threads_debug_ld_flags}" \
--build-arg CFLAGS="${emscripten_threads_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/emscripten-base:${TAG}-threads-debug-$host_arch \
Expand All @@ -171,6 +223,7 @@ if $debug; then
--build-arg BUILD_DATE=${BUILD_DATE} \
--build-arg LDFLAGS="${emscripten_threads_debug_ld_flags}" \
--build-arg CFLAGS="${emscripten_threads_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
fi
if $wasi; then
Expand All @@ -184,6 +237,7 @@ if $debug; then
--build-arg BASE_IMAGE=docker.io/dockcross/web-wasi-emulated-threads \
--build-arg LDFLAGS="${wasi_debug_ld_flags}" \
--build-arg CFLAGS="${wasi_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
if $version_tag; then
$exe $build_cmd $tag_flag quay.io/itkwasm/wasi-base:${TAG}-debug-$host_arch \
Expand All @@ -197,6 +251,7 @@ if $debug; then
--build-arg BASE_IMAGE=docker.io/dockcross/web-wasi-emulated-threads \
--build-arg LDFLAGS="${wasi_debug_ld_flags}" \
--build-arg CFLAGS="${wasi_debug_c_flags}" \
$local_itk_build_arg \
$script_dir $@
fi
fi
Expand Down
Loading