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
66 changes: 66 additions & 0 deletions .github/workflows/testing-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,69 @@ jobs:
script: |
apps/support/android_smoke_test.sh apps/HelloAndroid/app/build/outputs/apk/debug/app-debug.apk com.example.hellohalide .CameraActivity android.permission.CAMERA "requires a buffer of exactly"
apps/support/android_smoke_test.sh apps/HelloAndroidCamera2/app/build/outputs/apk/debug/app-debug.apk com.example.helloandroidcamera2 .CameraActivity android.permission.CAMERA

baremetal-apps:
# Deliberately its own job: needs an arm-none-eabi cross toolchain and
# QEMU's Arm system emulator, neither of which any other job installs.
# Actually cross-compiles and runs all three documented build methods
# (see apps/HelloBaremetal/README.md) under QEMU with semihosting, rather
# than only checking that they build for host.
if: "!contains(github.event.pull_request.labels.*.name, 'skip_buildbots')"
name: HelloBaremetal apps
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v7

- uses: astral-sh/setup-uv@v7

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libpng-dev libjpeg-dev gcc-arm-none-eabi qemu-system-arm

- name: Sync CI environment
run: |
uv sync --group ci-llvm-main --no-install-project
echo "${GITHUB_WORKSPACE}/.venv/bin" >> "$GITHUB_PATH"
echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/.venv" >> "$GITHUB_ENV"

- name: Configure LLVM
run: echo "Halide_LLVM_ROOT=$(halide-llvm --prefix)" >> "$GITHUB_ENV"

- name: Configure CMake
run: >-
cmake --preset ci-linux-x86-64
-DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install"

- name: Build and install Halide
run: cmake --build build --target install

- name: Build HelloBaremetal (host target)
working-directory: apps/HelloBaremetal
env:
CMAKE_PREFIX_PATH: ${{ github.workspace }}/install
run: |
for method in cmake-twice cmake-super_build cmake-external_project; do
cmake -S "$method" -B "$method/build"
cmake --build "$method/build"
done

# The actual point of this job: build.sh cross-compiles each method for
# the bare-metal Arm target, then ctest runs the result under QEMU with
# semihosting, actually exercising the cross-compiled binary rather than
# only checking that it builds for host.
- name: Build and run HelloBaremetal (bare-metal cross-compile under QEMU)
working-directory: apps/HelloBaremetal
env:
CMAKE_PREFIX_PATH: ${{ github.workspace }}/install
run: |
declare -A test_dir=(
[cmake-twice]=build-target
[cmake-super_build]=build/app
[cmake-external_project]=build
)
for method in cmake-twice cmake-super_build cmake-external_project; do
( cd "$method" && ./build.sh )
ctest --test-dir "$method/${test_dir[$method]}" --output-on-failure
done
2 changes: 1 addition & 1 deletion apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ add_app(hannk)
add_app(harris)
# add_app(HelloAndroid) # don't build HelloAndroid here because it is driven by gradle
# add_app(HelloAndroidCamera2) # don't build HelloAndroidCamera2 here because it is driven by gradle
add_app(HelloBaremetal)
# add_app(HelloBaremetal) # cross-compiles for a bare-metal ARM target; see apps/HelloBaremetal/README.md
# add_app(HelloiOS) # don't build HelloiOS here because it isn't universal.
add_app(HelloPyTorch)
# add_app(HelloWasm) # driven by its own super-build; see apps/HelloWasm/README.md
Expand Down
23 changes: 0 additions & 23 deletions apps/HelloBaremetal/CMakeLists.txt

This file was deleted.

32 changes: 23 additions & 9 deletions apps/HelloBaremetal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,34 @@ modify some parts if you target for different setup.

## How to build

Unlike most other apps in this repo, there is no top-level `CMakeLists.txt` here
-- each of the three `cmake-<xxx>` subdirectories below is an independent CMake
project you build directly.

### Cross compilation

Halide cross-compiling in CMake is tricky and there are a couple of ways to
realize it. This application demonstrates 3 different ways with concrete code,
located in `CMakeLists.txt` in the following sub directories.
located in `CMakeLists.txt` in the following subdirectories.

1. cmake-twice
2. cmake-super_build
3. cmake-external_project

If you want to understand the detail of build steps, please read "Cross
compiling" section of [README_cmake](../../README_cmake.md#cross-compiling), and
then `build.sh` and `CMakeLists.txt` in each sub directories.
compiling" section of
[HalideCMakePackage](../../doc/HalideCMakePackage.md#cross-compiling), and then
`build.sh` and `CMakeLists.txt` in each subdirectory.

### Build procedure

#### Baremetal target

As a prerequisite, toolchain described above needs to be installed in your host
machine. The detail of the toolchanin configuration is set in
[toolchain.arm-32-sample.cmake](cmake/toolchain.arm-32-sample.cmake), which you
might need to modify depending on the target baremetal system. Then, just run
the build script in one of the aforementioned sub directories.
machine. The detail of the toolchain configuration is set in
[toolchain.noos-arm32-sample.cmake](cmake/toolchain.noos-arm32-sample.cmake),
which you might need to modify depending on the target baremetal system. Then,
just run the build script in one of the aforementioned subdirectories.

```
cd cmake-<xxx>/
Expand All @@ -68,5 +73,14 @@ cmake --build build/

## How to run

`run.sh` in each sub directories is a sample script that shows how to run the
executable on QEMU Arm System emulator with semihosting mode.
After building for the bare-metal target, `ctest` runs the executable on QEMU
Arm System emulator with semihosting mode:

```
ctest --test-dir build-target --output-on-failure # cmake-twice
ctest --test-dir build/app --output-on-failure # cmake-super_build
ctest --test-dir build --output-on-failure # cmake-external_project
```

`run_baremetal.sh` (the script `ctest` invokes under the hood) can also be run
directly against any executable built for this target.
37 changes: 21 additions & 16 deletions apps/HelloBaremetal/cmake-external_project/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.28)

# Enable assembly language (.s) support additionally
project(HelloBaremetal LANGUAGES C CXX ASM)
project(HelloBaremetal)

# Set up C++ language settings
set(CMAKE_CXX_STANDARD 17)
Expand All @@ -10,7 +8,6 @@ set(CMAKE_CXX_EXTENSIONS NO)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)

set(GEN_EXE "add.generator")
set(GEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/generator)

# Step 1
Expand All @@ -22,10 +19,10 @@ ExternalProject_Add(
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/generator
BINARY_DIR ${GEN_BINARY_DIR}
INSTALL_COMMAND ""
CMAKE_ARGS -DGEN_EXE=${GEN_EXE}
CMAKE_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
CONFIGURE_HANDLED_BY_BUILD TRUE
)


# Step 2
# Build application with cross compiler,
# where the generator executable built in Step 1 is imported and called
Expand All @@ -36,16 +33,15 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)

# NOTE : find_package(HelloBaremetal-add_generator REQUIRED) is not ready at configuration time.
# Instead, declare the generator executable as imported, which is built in external project
add_executable(${GEN_EXE} IMPORTED)
# Specify the location of exe file to import
set_property(TARGET ${GEN_EXE} PROPERTY IMPORTED_LOCATION ${GEN_BINARY_DIR}/${GEN_EXE})
add_executable(add.generator IMPORTED)
set_property(TARGET add.generator PROPERTY IMPORTED_LOCATION ${GEN_BINARY_DIR}/add.generator)
# Associate with external project so that it invokes build process
add_dependencies(${GEN_EXE} gen_project)
add_dependencies(add.generator gen_project)

# Generate filter function
add_halide_library(
add
FROM ${GEN_EXE}
FROM add.generator
GENERATOR add
# You may set Target feature in addition to what is set in the toolchain file
FEATURES debug
Expand All @@ -58,8 +54,17 @@ add_halide_library(
add_executable(add_filter ${SRC_DIR}/filter.cpp)
target_link_libraries(add_filter PRIVATE Halide::ImageIO add)

# Depending on the target CPU, we need to enable Arm NEON manually
# if the executable contains any SIMD instructions.
target_sources(add_filter PRIVATE "$<$<BOOL:${BAREMETAL}>:${SRC_DIR}/enable_neon.s>")
# It is safe to do it in boot up process before main function (or C runtime) starts.
target_link_options(add_filter PRIVATE "$<$<BOOL:${BAREMETAL}>:--entry=_enable_neon>")
# Test that the app actually works, under QEMU with semihosting. Only
# meaningful for the actual bare-metal cross-compile; in the host-target
# build mode there's no toolchain to run it through.
if (CMAKE_CROSSCOMPILING)
enable_testing()
set(IMAGE ${SRC_DIR}/../images/gray_small.pgm)
if (EXISTS ${IMAGE})
add_test(
NAME add_filter
COMMAND ${SRC_DIR}/run_baremetal.sh $<TARGET_FILE:add_filter> ${IMAGE} 16 out.pgm
)
set_tests_properties(add_filter PROPERTIES PASS_REGULAR_EXPRESSION "Success!")
endif ()
endif ()
8 changes: 2 additions & 6 deletions apps/HelloBaremetal/cmake-external_project/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@ set -eo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
readonly TOOLCHAIN_FILE="${PWD}/../cmake/toolchain.noos-arm32-sample.cmake"

rm -rf build

cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}"

cmake --build build/
cmake -S . -B build --toolchain "${TOOLCHAIN_FILE}" --fresh
cmake --build build
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
cmake_minimum_required(VERSION 3.28)

project(HelloBaremetal-gen)

if (NOT DEFINED GEN_EXE)
message(FATAL_ERROR "CMakeVariable GEN_EXE is not set")
endif ()

# Set up C++ language settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
Expand All @@ -16,4 +11,4 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
find_package(Halide REQUIRED)

# Build generator
add_halide_generator(${GEN_EXE} SOURCES ${SRC_DIR}/add_generator.cpp)
add_halide_generator(add.generator SOURCES ${SRC_DIR}/add_generator.cpp)
4 changes: 0 additions & 4 deletions apps/HelloBaremetal/cmake-external_project/run.sh

This file was deleted.

19 changes: 12 additions & 7 deletions apps/HelloBaremetal/cmake-super_build/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ ExternalProject_Add(
BINARY_DIR ${GEN_BINARY_DIR}
INSTALL_COMMAND ""
CMAKE_ARGS
-DGEN_PACKAGE=${GEN_PACKAGE}
-DGEN_NAMESPACE=${GEN_NAMESPACE}
-DGEN_EXE=${GEN_EXE}
-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
-DGEN_PACKAGE=${GEN_PACKAGE}
-DGEN_NAMESPACE=${GEN_NAMESPACE}
-DGEN_EXE=${GEN_EXE}
CONFIGURE_HANDLED_BY_BUILD TRUE
)

# Step 2
Expand All @@ -32,11 +34,14 @@ ExternalProject_Add(
ExternalProject_Add(
app_project
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/app
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/app
INSTALL_COMMAND ""
DEPENDS gen_project # To make sure generator is ready
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${APP_TOOLCHAIN_FILE}
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/bin
-D${GEN_PACKAGE}_ROOT:FILEPATH=${GEN_BINARY_DIR}
-DGEN_TARGET=${GEN_NAMESPACE}${GEN_EXE}
-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
-DCMAKE_TOOLCHAIN_FILE=${APP_TOOLCHAIN_FILE}
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/bin
-D${GEN_PACKAGE}_ROOT:FILEPATH=${GEN_BINARY_DIR}
-DGEN_TARGET=${GEN_NAMESPACE}${GEN_EXE}
CONFIGURE_HANDLED_BY_BUILD TRUE
)
23 changes: 15 additions & 8 deletions apps/HelloBaremetal/cmake-super_build/app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.28)

# Enable assembly language (.s) support additionally
project(HelloBaremetal-app LANGUAGES C CXX ASM)
project(HelloBaremetal-app)

if (NOT DEFINED GEN_TARGET)
message(FATAL_ERROR "CMakeVariable GEN_TARGET is not set")
Expand Down Expand Up @@ -35,8 +33,17 @@ add_halide_library(
add_executable(add_filter ${SRC_DIR}/filter.cpp)
target_link_libraries(add_filter PRIVATE Halide::ImageIO add)

# Depending on the target CPU, we need to enable Arm NEON manually
# if the executable contains any SIMD instructions.
target_sources(add_filter PRIVATE "$<$<BOOL:${BAREMETAL}>:${SRC_DIR}/enable_neon.s>")
# It is safe to do it in boot up process before main function (or C runtime) starts.
target_link_options(add_filter PRIVATE "$<$<BOOL:${BAREMETAL}>:--entry=_enable_neon>")
# Test that the app actually works, under QEMU with semihosting. Only
# meaningful for the actual bare-metal cross-compile; in the host-target
# build mode there's no toolchain to run it through.
if (CMAKE_CROSSCOMPILING)
enable_testing()
set(IMAGE ${SRC_DIR}/../images/gray_small.pgm)
if (EXISTS ${IMAGE})
add_test(
NAME add_filter
COMMAND ${SRC_DIR}/run_baremetal.sh $<TARGET_FILE:add_filter> ${IMAGE} 16 out.pgm
)
set_tests_properties(add_filter PROPERTIES PASS_REGULAR_EXPRESSION "Success!")
endif ()
endif ()
8 changes: 2 additions & 6 deletions apps/HelloBaremetal/cmake-super_build/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@ set -eo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
readonly TOOLCHAIN_FILE="${PWD}/../cmake/toolchain.noos-arm32-sample.cmake"

rm -rf build

cmake -S . -B build \
-DAPP_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}"

cmake --build build/
cmake -S . -B build -DAPP_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" --fresh
cmake --build build
4 changes: 0 additions & 4 deletions apps/HelloBaremetal/cmake-super_build/run.sh

This file was deleted.

Loading
Loading