blob: 52d0cb72881737730a4d4af248e8e16768d95a88 [file]
#!/bin/bash
# Run IREE executables with Bazel.
#
# Usage: iree-bazel-run [options] <target> [bazel-args...] [-- program-args...]
#
# Examples:
# iree-bazel-run //tools:iree-compile -- --help
# iree-bazel-run //runtime/src/iree/tokenizer:tokenizer_test
# iree-bazel-run --config=debug //tools:iree-opt -- input.mlir
set -e
# Source shared library.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/iree-bazel-lib"
iree_bazel_init "iree-bazel-run"
# Expand combined short flags (e.g., -nv -> -n -v).
eval "set -- $(iree_expand_combined_flags "$@")"
show_help() {
cat << 'EOF'
iree-bazel-run - Run IREE executables with Bazel
USAGE
iree-bazel-run [options] <target> [bazel-args...] [-- program-args...]
OPTIONS
-n, --dry_run Show the bazel command without executing
-v, --verbose Show the bazel command before executing
-w, --watch Watch mode: rebuild and restart on file changes
-h, --help Show this help
--trace Capture the run with Tracy; implies --config=perf --config=tracy
--trace_name NAME, --trace-name NAME
Override the sanitized trace artifact name
NOTE: Short flags can be combined: -nv is equivalent to -n -v
ARGUMENTS
target Bazel executable target (required)
bazel-args Arguments passed to bazel build (before --)
program-args Arguments passed to the executable (after --)
EXAMPLES
iree-bazel-run //tools:iree-compile -- --help
iree-bazel-run //tools:iree-opt -- input.mlir -o output.mlir
iree-bazel-run //runtime/src/iree/tokenizer:tokenizer_test
iree-bazel-run --config=debug //tools:iree-compile -- model.mlir
iree-bazel-run -w //tools:iree-opt -- input.mlir # Watch and restart on changes
iree-bazel-run -nv //tools:iree-compile -- --help # Show command only
iree-bazel-run --trace //tools:iree-run-module -- --module=model.vmfb --device=local-task
iree-bazel-run --trace --trace_name=run-module-sample //tools:iree-run-module -- --module=model.vmfb --device=local-task
WORKING DIRECTORY
Unlike raw "bazel run", this tool runs the binary from your current
working directory, so relative paths in arguments work as expected.
WATCH MODE
Watch mode (-w) uses ibazel and holds the Bazel server lock while the
binary runs. This is necessary for ibazel to control the process lifecycle
and restart on changes. Normal mode releases the lock after building.
COMMON TARGETS
//tools:iree-compile Main compiler
//tools:iree-opt MLIR optimization tool
//tools:iree-run-module Execute compiled modules
//tools:iree-benchmark-module Performance benchmarking
CONFIGURATIONS
--config=localdev Local dev optimizations (disk cache, skymeld)
--config=debug No optimizations, assertions enabled
--config=asserts Optimized with assertions
--config=asan Address Sanitizer
--config=msan Memory Sanitizer
--config=tsan Thread Sanitizer
--config=perf Opt/NDEBUG/O3/thin-LTO/native-codegen run
--config=tracy Runtime Tracy instrumentation
TRACY CAPTURE
--trace composes the normal build/run flow with a Tracy capture wrapper.
The Bazel build shape comes from --config=perf and --config=tracy; the
capture wrapper only starts tracy-capture and runs the already-built binary.
Trace artifacts are written to .tracy/<timestamp>-<name>.tracy. By default
the name is derived from the Bazel target; use --trace_name to override it.
SEE ALSO
iree-bazel-build, iree-bazel-test, iree-bazel-query, iree-bazel-cquery
EOF
}
# Parse arguments.
WATCH_MODE=0
TRACE_MODE=0
TRACE_NAME=""
TARGET=""
BAZEL_ARGS=()
PROGRAM_ARGS=()
PARSING_PROGRAM_ARGS=0
while [[ $# -gt 0 ]]; do
if [[ "${PARSING_PROGRAM_ARGS}" == "1" ]]; then
PROGRAM_ARGS+=("${1}")
shift
continue
fi
case "${1}" in
-h|--help)
show_help
exit 0
;;
--agent-md|--agent_md)
iree_show_agent_md
exit 0
;;
-n|--dry_run|--dry-run)
IREE_BAZEL_DRY_RUN=1
shift
;;
-v|--verbose)
IREE_BAZEL_VERBOSE=1
shift
;;
-w|--watch)
WATCH_MODE=1
shift
;;
--trace)
TRACE_MODE=1
shift
;;
--trace_name|--trace-name)
if [[ $# -lt 2 ]] || [[ -z "${2}" ]] || [[ "${2}" == -* ]]; then
iree_error "${1} requires a non-empty name"
exit 1
fi
TRACE_NAME="${2}"
shift 2
;;
--trace_name=*|--trace-name=*)
TRACE_NAME="${1#*=}"
if [[ -z "${TRACE_NAME}" ]]; then
iree_error "${1%%=*} requires a non-empty name"
exit 1
fi
shift
;;
--)
PARSING_PROGRAM_ARGS=1
shift
;;
-*)
BAZEL_ARGS+=("${1}")
shift
;;
*)
if [[ -z "${TARGET}" ]]; then
TARGET="${1}"
else
BAZEL_ARGS+=("${1}")
fi
shift
;;
esac
done
# Target is required for run.
if [[ -z "${TARGET}" ]]; then
iree_error "Target is required for bazel run"
echo ""
show_help
exit 1
fi
# Set up worktree (after arg parsing so --help works anywhere).
iree_setup_worktree
if [[ "${TRACE_MODE}" == "1" && "${WATCH_MODE}" == "1" ]]; then
iree_error "--trace is not supported with watch mode"
exit 1
fi
if [[ -n "${TRACE_NAME}" && "${TRACE_MODE}" != "1" ]]; then
iree_error "--trace_name requires --trace"
exit 1
fi
# Prepend default configs to bazel args.
iree_bazel_build_default_configs
if [[ "${TRACE_MODE}" == "1" ]]; then
BAZEL_ARGS=("${IREE_BAZEL_DEFAULT_CONFIGS[@]}" --config=perf --config=tracy "${BAZEL_ARGS[@]}")
else
BAZEL_ARGS=("${IREE_BAZEL_DEFAULT_CONFIGS[@]}" "${BAZEL_ARGS[@]}")
fi
# Dry run: show what would be run and exit.
if iree_is_verbose || iree_is_dry_run; then
if [[ "${WATCH_MODE}" == "1" ]]; then
BAZEL_BIN=$(iree_get_bazel_command "${WATCH_MODE}")
if [[ ${#PROGRAM_ARGS[@]} -gt 0 ]]; then
iree_info "Command: ${BAZEL_BIN} run --run_under=\"cd ${IREE_BAZEL_ORIG_CWD} && \" ${BAZEL_ARGS[*]} ${TARGET} -- ${PROGRAM_ARGS[*]}"
else
iree_info "Command: ${BAZEL_BIN} run --run_under=\"cd ${IREE_BAZEL_ORIG_CWD} && \" ${BAZEL_ARGS[*]} ${TARGET}"
fi
else
if [[ "${TRACE_MODE}" == "1" ]]; then
TRACE_CAPTURE_NAME="${TRACE_NAME:-${TARGET}}"
iree_info "Command: bazel build ${TARGET} ${BAZEL_ARGS[*]} && iree_tracy_capture.py --output-dir ${IREE_BAZEL_WORKTREE_DIR}/.tracy --name ${TRACE_CAPTURE_NAME} -- <binary> ${PROGRAM_ARGS[*]}"
elif [[ ${#PROGRAM_ARGS[@]} -gt 0 ]]; then
iree_info "Command: bazel build ${TARGET} ${BAZEL_ARGS[*]} && <binary> ${PROGRAM_ARGS[*]}"
else
iree_info "Command: bazel build ${TARGET} ${BAZEL_ARGS[*]} && <binary>"
fi
fi
iree_info "Run directory: ${IREE_BAZEL_ORIG_CWD}"
fi
if iree_is_dry_run; then
exit 0
fi
iree_debug "Running ${TARGET}"
if [[ "${WATCH_MODE}" == "1" ]]; then
# Watch mode: use ibazel run with --run_under to match our cwd behavior.
# NOTE: This holds the Bazel server lock while the binary runs, but that's
# acceptable for a dedicated watch shell. ibazel needs to control the process
# lifecycle to restart it on changes.
BAZEL_BIN=$(iree_get_bazel_command "${WATCH_MODE}")
CMD=("${BAZEL_BIN}" run --run_under="cd ${IREE_BAZEL_ORIG_CWD} && " "${BAZEL_ARGS[@]}" "${TARGET}")
if [[ ${#PROGRAM_ARGS[@]} -gt 0 ]]; then
CMD+=(-- "${PROGRAM_ARGS[@]}")
fi
iree_info "Watch mode: running from ${IREE_BAZEL_ORIG_CWD}"
exec "${CMD[@]}"
else
# Normal mode: build and execute from original working directory.
# This releases the Bazel server lock before execution, allowing parallel builds.
if [[ "${TRACE_MODE}" == "1" ]]; then
iree_bazel_build_quiet "${TARGET}" "${BAZEL_ARGS[@]}" || exit $?
BINARY_PATH=$(iree_bazel_get_binary_path "${TARGET}" "${BAZEL_ARGS[@]}")
if [[ -z "${BINARY_PATH}" ]] || [[ ! -x "${BINARY_PATH}" ]]; then
iree_error "Could not find built binary for ${TARGET}"
exit 1
fi
cd "${IREE_BAZEL_ORIG_CWD}"
TRACE_CAPTURE_NAME="${TRACE_NAME:-${TARGET}}"
exec "${IREE_BAZEL_WORKTREE_DIR}/build_tools/tracing/iree_tracy_capture.py" \
--output-dir "${IREE_BAZEL_WORKTREE_DIR}/.tracy" \
--name "${TRACE_CAPTURE_NAME}" \
-- "${BINARY_PATH}" "${PROGRAM_ARGS[@]}"
else
iree_bazel_build_and_exec "${TARGET}" "${IREE_BAZEL_ORIG_CWD}" "${BAZEL_ARGS[@]}" -- "${PROGRAM_ARGS[@]}"
fi
fi