diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d1c236..17196ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,17 +26,22 @@ jobs: with: python-version: '3.10' - - name: Use ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: 20241030-${{ matrix.os }} - - name: Bootstrap run: npx zx bootstrap.mjs --verbose - name: Build run: npx zx build.mjs --target-arch ${{ matrix.arch }} + - name: Export + run: npx zx export.mjs + + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: executorch-${{ matrix.os }}-${{ matrix.arch }} + path: executorch-${{ matrix.os }}-${{ matrix.arch }}-*.zip + retention-days: 1 + release: if: startsWith(github.ref, 'refs/tags/') needs: [build] @@ -60,4 +65,4 @@ jobs: draft: true name: ExecuTorch ${{ github.ref_name }} body: '## Changelog' - files: '*.gz' + files: '*.zip' diff --git a/.gitignore b/.gitignore index 27c4aef..6aaf11b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *.swp +*.zip + +/dist /out diff --git a/bootstrap.mjs b/bootstrap.mjs index f14f2ae..aa4e54c 100755 --- a/bootstrap.mjs +++ b/bootstrap.mjs @@ -5,4 +5,4 @@ import {python} from './common.mjs'; await $`git submodule sync --recursive` await $`git submodule update --init --recursive` -await $({cwd: 'executorch'})`${await python()} install_requirements.py` +await $({cwd: 'executorch'})`${python} install_requirements.py` diff --git a/build.mjs b/build.mjs index b3ae6a2..24205de 100755 --- a/build.mjs +++ b/build.mjs @@ -4,7 +4,7 @@ import {python, torchPath} from './common.mjs'; const flags = [ `CMAKE_PREFIX_PATH=${await torchPath()}`, - `PYTHON_EXECUTABLE=${await python()}`, + `PYTHON_EXECUTABLE=${python}`, `FLATC_EXECUTABLE=${await which('flatc')}`, 'EXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON', 'EXECUTORCH_BUILD_EXTENSION_MODULE=ON', @@ -14,46 +14,44 @@ const flags = [ 'EXECUTORCH_BUILD_XNNPACK=ON', ] +const targetArch = argv['target-arch'] || process.arch +const targetOs = argv['target-os'] || { + darwin: 'mac', + linux: 'linux', + win32: 'win', +}[process.platform] + if (process.platform == 'darwin') { flags.push('CMAKE_TOOLCHAIN_FILE=third-party/ios-cmake/ios.toolchain.cmake', 'DEPLOYMENT_TARGET=10.15', 'EXECUTORCH_BUILD_COREML=ON', 'EXECUTORCH_BUILD_MPS=ON') - const targetArch = argv['target-arch'] || process.arch if (targetArch == 'arm64') flags.push('PLATFORM=MAC_ARM64') else if (targetArch == 'x64') flags.push('PLATFORM=MAC') else throw new Error(`Unsupport target arch ${targetArch} on macOS`) +} else { + if (targetArch != process.arch) + throw new Error('Cross-compilation is not supported except for macOS') } -// Use ccache when available. -try { - flags.push(`CMAKE_CXX_COMPILER_LAUNCHER=${await which('ccache')}`) -} catch {} - // Use clang when possible. try { process.env.CC = await which('clang') process.env.CXX = await which('clang++') } catch {} -const outDir = 'out' // Regenerate project if repo or build args args updated. -const stamp = `${outDir}/.initalized` -const buildArgs = await captureBuildArgs() -if (!fs.existsSync(stamp) || fs.readFileSync(stamp).toString() != buildArgs) { +const outDir = 'out' +const stamp = [ targetArch, targetOs, await $`git submodule`, ...flags ].join('\n') +const stampFile = `${outDir}/.stamp` +if (!fs.existsSync(stampFile) || fs.readFileSync(stampFile).toString() != stamp) { fs.emptyDirSync(outDir) await $`cmake executorch -B ${outDir} ${flags.map(f => '-D' + f)}` - fs.writeFileSync(stamp, buildArgs) + fs.writeFileSync(stampFile, stamp) } // Run building. await $`cmake --build ${outDir} --config Release -j` - -// Return a text used for identifying whether we should clean out dir. -async function captureBuildArgs() { - const text = await $`git submodule` - return text + flags.join('\n') -} diff --git a/common.mjs b/common.mjs index efca324..49ac8c7 100644 --- a/common.mjs +++ b/common.mjs @@ -1,14 +1,13 @@ $.verbose = true -export async function python() { - try { - return await which('python3') - } catch { - return await which('python') - } +export let python +try { + python = await which('python3') +} catch { + python = await which('python') } export async function torchPath() { - const r = await $`${await python()} -c 'import torch as _; print(_.__path__[0])'` + const r = await $`${python} -c 'import torch as _; print(_.__path__[0])'` return r.stdout.trim() } diff --git a/export.mjs b/export.mjs new file mode 100755 index 0000000..d5d75d9 --- /dev/null +++ b/export.mjs @@ -0,0 +1,25 @@ +#!/usr/bin/env zx + +import {python} from './common.mjs'; + +await fs.emptyDir('dist') + +// Copy headers. +const headers = await glob([ + 'executorch/extension/data_loader/**/*.h', + 'executorch/extension/module/**/*.h', + 'executorch/extension/tensor/**/*.h', + 'executorch/runtime/**/*.h', + 'executorch/schema/**/*.h', +]) +await Promise.all(headers.map(h => fs.copy(h, `dist/include/${h}`))) + +// Copy static libs. +const libs = await glob('out/**/*.a') +await Promise.all(libs.map(l => fs.copy(l, `dist/libs/${path.basename(l)}`))) + +// Zip files. +const [ targetArch, targetOs ] = String(await fs.readFile('out/.stamp')).split('\n') +const name = `executorch-${targetOs}-${targetArch}-full` +await $`${python} -c "import shutil; shutil.make_archive('${name}', 'zip', 'dist')"` +await fs.remove('dist')