From 44a615affb11fd5757e5a34838eb10daa4e0e1a2 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 4 Mar 2026 20:18:16 +0000 Subject: [PATCH] Require opt-in via `force-arch` to run x86 on macOS arm (#352) * require opt-in via `force-arch` to run x86 on macOS arm * Update src/setup-julia.ts * Run `make everything-from-scratch`, and check-in * Fix CI in #352 (#373) * Fix CI in #352 * Clarify a statement about the support for 32-bit builds --------- Co-authored-by: Dilum Aluthge --- .github/workflows/example-builds-nightly.yml | 29 +++++++--- .github/workflows/example-builds.yml | 56 ++++++++++++++------ README.md | 12 +++++ action.yml | 4 ++ dist/index.js | 8 ++- lib/setup-julia.js | 8 ++- src/setup-julia.ts | 7 ++- 7 files changed, 100 insertions(+), 24 deletions(-) diff --git a/.github/workflows/example-builds-nightly.yml b/.github/workflows/example-builds-nightly.yml index 28a850b..227a51b 100644 --- a/.github/workflows/example-builds-nightly.yml +++ b/.github/workflows/example-builds-nightly.yml @@ -20,13 +20,23 @@ jobs: strategy: fail-fast: false matrix: - julia-version: [nightly, 1.13-nightly] - julia-arch: [x64, x86] - os: [ubuntu-latest, macOS-latest, windows-latest] + julia-version: + - nightly + - 1.13-nightly + julia-wordsize: + - 64 + - 32 + os: + - ubuntu-latest + - windows-latest + - macos-15-intel # Intel + - macos-latest # Apple Silicon # 32-bit Julia binaries are not available on macOS exclude: - - os: macOS-latest - julia-arch: x86 + - os: macos-15-intel # Intel + julia-wordsize: 32 + - os: macos-latest # Apple Silicon + julia-wordsize: 32 steps: - uses: actions/checkout@v6.0.2 @@ -47,7 +57,14 @@ jobs: uses: ./ with: version: ${{ matrix.julia-version }} - arch: ${{ matrix.julia-arch }} + # If `julia-wordsize` is 32, then we set `arch` to `x86`, because we know that + # 32-bit builds of Julia are only available for x86. + # + # If `julia-wordsize` is 64, then we set `arch` to `${{ runner.arch }}`, which + # GitHub will automatically expand to the correct value (`x86_64` or `aarch64`) + # based on the architecture of the underlying GitHub Runner (virtual machine). + arch: ${{ matrix.julia-wordsize == '32' && 'x86' || runner.arch }} + - run: julia --version - run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()' - name: "Check that the correct julia is used and that archive mtimes are maintained" diff --git a/.github/workflows/example-builds.yml b/.github/workflows/example-builds.yml index 0d54e42..46dd30f 100644 --- a/.github/workflows/example-builds.yml +++ b/.github/workflows/example-builds.yml @@ -12,6 +12,9 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + jobs: test: runs-on: ${{ matrix.os }} @@ -19,24 +22,40 @@ jobs: strategy: fail-fast: false matrix: - # include '1.6' here to test info message about lts tag existing - julia-version: ['1.0.5', '1.2', '^1.5.0-beta1', '1', '1.6', 'lts', 'pre'] - julia-arch: [x64, x86] - os: [ubuntu-latest, macOS-latest, windows-latest] + julia-version: + - '1.0.5' + - '1.2' + - '^1.5.0-beta1' + - '1' + - '1.6' + - '1.10' # include '1.10' here to test info message about lts tag existing + - 'lts' + - 'pre' + julia-wordsize: + - 64 + - 32 + os: + - ubuntu-latest + - windows-latest + - macos-15-intel # Intel + - macos-latest # Apple Silicon # 32-bit Julia binaries are not available on macOS exclude: - - os: macOS-latest - julia-arch: x86 - include: - - os: macOS-latest - julia-arch: aarch64 - julia-version: 'lts' - - os: macOS-latest - julia-arch: aarch64 - julia-version: '1' - + - os: macos-15-intel # Intel + julia-wordsize: 32 + - os: macos-latest # Apple Silicon + julia-wordsize: 32 + # Julia versions prior to 1.8 do not have native builds for Apple Silicon + - os: macos-latest # Apple Silicon + julia-version: '1.0.5' + - os: macos-latest # Apple Silicon + julia-version: '1.2' + - os: macos-latest # Apple Silicon + julia-version: '1.6' steps: - uses: actions/checkout@v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@v6 if: ${{ ! startsWith(github.ref, 'refs/heads/releases') }} @@ -55,7 +74,14 @@ jobs: uses: ./ with: version: ${{ matrix.julia-version }} - arch: ${{ matrix.julia-arch }} + # If `julia-wordsize` is 32, then we set `arch` to `x86`, because we know that + # Tier 1 32-bit builds of Julia are only available for x86. + # + # If `julia-wordsize` is 64, then we set `arch` to `${{ runner.arch }}`, which + # GitHub will automatically expand to the correct value (`x86_64` or `aarch64`) + # based on the architecture of the underlying GitHub Runner (virtual machine). + arch: ${{ matrix.julia-wordsize == '32' && 'x86' || runner.arch }} + - run: julia --version - run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()' - name: "Check that the correct julia is used and that archive mtimes are maintained" diff --git a/README.md b/README.md index 1c5f382..17f8c92 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,18 @@ This action sets up a Julia environment for use in actions by downloading a spec # Specifying 'default' uses the architecture of the runner executing the job. arch: 'default' + # Force the use of the specified architecture even when it may be suboptimal on the runner. + # + # By default, requesting x86 or x64 on an aarch64 macOS runner (Apple Silicon) will fail with an error, + # as this is usually a misconfiguration. Set this to 'true' to override the error and allow the installation. + # + # Note: x64 Julia can run on Apple Silicon via Rosetta 2, but native aarch64 is typically preferred. + # + # Supported values: true | false + # + # Default: false + force-arch: 'false' + # Set the display setting for printing InteractiveUtils.versioninfo() after installing. # # Starting Julia and running InteractiveUtils.versioninfo() takes a significant amount of time (1s or ~10% of the total build time in testing), diff --git a/action.yml b/action.yml index 091b7ae..8d2ae5e 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,10 @@ inputs: description: 'Architecture of the Julia binaries. Defaults to the architecture of the runner executing the job.' required: false default: 'default' + force-arch: + description: 'Force the use of the specified architecture even when it may be suboptimal on the runner (e.g., x86 on Apple Silicon macOS runners). By default, requesting x86/x64 on aarch64 macOS runners will fail with an error.' + required: false + default: 'false' show-versioninfo: description: 'Display InteractiveUtils.versioninfo() after installing' required: false diff --git a/dist/index.js b/dist/index.js index 437b892..1eca0dd 100644 --- a/dist/index.js +++ b/dist/index.js @@ -585,6 +585,7 @@ function run() { const versionInput = core.getInput('version').trim(); const includePrereleases = core.getInput('include-all-prereleases').trim() == 'true'; const originalArchInput = core.getInput('arch').trim(); + const forceArch = core.getInput('force-arch').trim() == 'true'; const projectInput = core.getInput('project').trim(); // Julia project file // It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}` // while the strategy matrix only contains a key `${{ matrix.version }}`. @@ -601,7 +602,12 @@ function run() { throw new Error(`Arch input must not be null`); } if (originalArchInput == 'x64' && os.platform() == 'darwin' && os.arch() == 'arm64') { - core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or left it unspecified for the correct default).'); + if (forceArch) { + core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. The "force-arch" input is set to "true", so proceeding with x64 installation. Note that this will mean Julia will be run under Rosetta emulation.'); + } + else { + throw new Error('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or "default" or left it unspecified for the correct default). To force the use of x64 on this runner, set the "force-arch" input to "true".'); + } } let processedArchInput; if (originalArchInput == "default") { diff --git a/lib/setup-julia.js b/lib/setup-julia.js index da6d49c..e44f994 100644 --- a/lib/setup-julia.js +++ b/lib/setup-julia.js @@ -83,6 +83,7 @@ function run() { const versionInput = core.getInput('version').trim(); const includePrereleases = core.getInput('include-all-prereleases').trim() == 'true'; const originalArchInput = core.getInput('arch').trim(); + const forceArch = core.getInput('force-arch').trim() == 'true'; const projectInput = core.getInput('project').trim(); // Julia project file // It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}` // while the strategy matrix only contains a key `${{ matrix.version }}`. @@ -99,7 +100,12 @@ function run() { throw new Error(`Arch input must not be null`); } if (originalArchInput == 'x64' && os.platform() == 'darwin' && os.arch() == 'arm64') { - core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or left it unspecified for the correct default).'); + if (forceArch) { + core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. The "force-arch" input is set to "true", so proceeding with x64 installation. Note that this will mean Julia will be run under Rosetta emulation.'); + } + else { + throw new Error('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or "default" or left it unspecified for the correct default). To force the use of x64 on this runner, set the "force-arch" input to "true".'); + } } let processedArchInput; if (originalArchInput == "default") { diff --git a/src/setup-julia.ts b/src/setup-julia.ts index 587dc67..f5c47e4 100644 --- a/src/setup-julia.ts +++ b/src/setup-julia.ts @@ -45,6 +45,7 @@ async function run() { const versionInput = core.getInput('version').trim() const includePrereleases = core.getInput('include-all-prereleases').trim() == 'true' const originalArchInput = core.getInput('arch').trim() + const forceArch = core.getInput('force-arch').trim() == 'true' const projectInput = core.getInput('project').trim() // Julia project file // It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}` @@ -63,7 +64,11 @@ async function run() { } if (originalArchInput == 'x64' && os.platform() == 'darwin' && os.arch() == 'arm64') { - core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or left it unspecified for the correct default).') + if (forceArch) { + core.warning('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. The "force-arch" input is set to "true", so proceeding with x64 installation. Note that this will mean Julia will be run under Rosetta emulation.') + } else { + throw new Error('[setup-julia] x64 arch has been requested on a macOS runner that has an arm64 (Apple Silicon) architecture. You may have meant to use the "aarch64" arch instead (or "default" or left it unspecified for the correct default). To force the use of x64 on this runner, set the "force-arch" input to "true".') + } } let processedArchInput: string;