Skip to content

Commit 372af5f

Browse files
linesightclaude
andcommitted
Add macOS ARM (Apple Silicon) CI workflow and build support
- Add .github/workflows/ci-macos.yml: compile/test/wheel jobs on macos-14 (M1 runner); CI copies the correct cef_version.h from the downloaded CEF package before configuring CMake so API hashes are always right - Add src/version/cef_version_macarm64.h: CEF 146 version header for macosarm64; hashes are overwritten at CI time from the downloaded package - Update tools/common.py: detect platform.machine()=='arm64' on macOS and set OS_POSTFIX2='macarm64' / CEF_POSTFIX2='macosarm64' accordingly; also point get_cefpython_version() at cef_version_macarm64.h on ARM - Update CMakeLists.txt: on Apple with arm64 processor use cef*_macarm64 glob and cef_version_macarm64.h; Intel macOS unchanged Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ebc151a commit 372af5f

4 files changed

Lines changed: 240 additions & 6 deletions

File tree

.github/workflows/ci-macos.yml

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
name: CI macOS ARM
2+
3+
on:
4+
push:
5+
branches: ["github-actions-ci", "master", "146-macos"]
6+
pull_request:
7+
branches: ["master"]
8+
workflow_dispatch:
9+
inputs:
10+
bypass_cache:
11+
description: "Bypass all caches for a clean run"
12+
type: boolean
13+
default: false
14+
15+
jobs:
16+
compile:
17+
runs-on: macos-14
18+
timeout-minutes: 90
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
23+
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Python
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
33+
- name: Read CEF version
34+
id: cef-version
35+
run: |
36+
ver=$(python3 -c "
37+
import re, sys
38+
h = open('src/version/cef_version_macarm64.h').read()
39+
m = re.search(r'#define CEF_VERSION \"([^\"]+)\"', h)
40+
print(m.group(1))
41+
")
42+
echo "value=$ver" >> $GITHUB_OUTPUT
43+
44+
- name: Cache CEF binaries
45+
uses: actions/cache@v4
46+
if: ${{ inputs.bypass_cache != true }}
47+
with:
48+
path: |
49+
build/cef_binary_*
50+
build/cef*_macarm64
51+
key: cef-macosarm64-${{ steps.cef-version.outputs.value }}
52+
53+
- name: Install build tools
54+
run: python tools/requirements.py
55+
56+
- name: Download CEF binaries
57+
run: python tools/download_cef.py
58+
59+
- name: Update version header from downloaded CEF
60+
run: |
61+
cef_dir=$(ls -d build/cef_binary_*_macosarm64 2>/dev/null | head -1)
62+
cp "$cef_dir/include/cef_version.h" src/version/cef_version_macarm64.h
63+
64+
- name: Prepare prebuilt CEF
65+
run: python tools/automate.py --prebuilt-cef
66+
67+
- name: Configure CMake
68+
run: cmake -S . -B build/_cmake_build -G Ninja -DCMAKE_BUILD_TYPE=Release
69+
70+
- name: Build
71+
run: cmake --build build/_cmake_build --parallel
72+
73+
- name: Stage build outputs
74+
run: |
75+
mkdir -p build/artifacts
76+
cp build/_cmake_build/cefpython_py*.so build/artifacts/
77+
cp build/_cmake_build/subprocess_build/subprocess build/artifacts/
78+
cef_dir=$(ls -d build/cef*_macarm64 2>/dev/null | head -1)
79+
find "$cef_dir/bin" -maxdepth 1 -mindepth 1 \
80+
! -name 'cefclient*' ! -name 'cefsimple*' ! -name 'ceftests*' \
81+
-exec cp -r {} build/artifacts/ \;
82+
83+
- name: Upload build artifacts
84+
uses: actions/upload-artifact@v4
85+
with:
86+
name: build-py${{ matrix.python-version }}-macosarm64
87+
path: build/artifacts/
88+
retention-days: 1
89+
90+
test:
91+
needs: compile
92+
runs-on: macos-14
93+
timeout-minutes: 30
94+
strategy:
95+
fail-fast: false
96+
matrix:
97+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
98+
99+
steps:
100+
- name: Checkout
101+
uses: actions/checkout@v4
102+
103+
- name: Set up Python
104+
uses: actions/setup-python@v5
105+
with:
106+
python-version: ${{ matrix.python-version }}
107+
108+
- name: Download build artifacts
109+
uses: actions/download-artifact@v4
110+
with:
111+
name: build-py${{ matrix.python-version }}-macosarm64
112+
path: build/artifacts/
113+
114+
- name: Set up cefpython3 package for testing
115+
run: |
116+
cp -r build/artifacts/. cefpython3/
117+
chmod +x cefpython3/subprocess
118+
119+
- name: Run unit tests
120+
run: python unittests/_test_runner.py
121+
env:
122+
PYTHONPATH: ${{ github.workspace }}
123+
124+
wheel:
125+
needs: test
126+
runs-on: macos-14
127+
timeout-minutes: 15
128+
strategy:
129+
fail-fast: false
130+
matrix:
131+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
132+
133+
steps:
134+
- name: Checkout
135+
uses: actions/checkout@v4
136+
137+
- name: Set up Python
138+
uses: actions/setup-python@v5
139+
with:
140+
python-version: ${{ matrix.python-version }}
141+
142+
- name: Download build artifacts
143+
uses: actions/download-artifact@v4
144+
with:
145+
name: build-py${{ matrix.python-version }}-macosarm64
146+
path: build/artifacts/
147+
148+
- name: Set up cefpython3 package
149+
run: cp -r build/artifacts/. cefpython3/
150+
151+
- name: Build wheel
152+
run: python tools/build_distrib.py
153+
154+
- name: Upload wheel artifact
155+
uses: actions/upload-artifact@v4
156+
with:
157+
name: cefpython3-py${{ matrix.python-version }}-macosarm64
158+
path: build/dist/*.whl

CMakeLists.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ if(NOT CEF_ROOT)
4141
if(WIN32)
4242
set(_cef_glob_pat "${CMAKE_SOURCE_DIR}/build/cef*_win64")
4343
elseif(APPLE)
44-
set(_cef_glob_pat "${CMAKE_SOURCE_DIR}/build/cef*_mac64")
44+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
45+
set(_cef_glob_pat "${CMAKE_SOURCE_DIR}/build/cef*_macarm64")
46+
else()
47+
set(_cef_glob_pat "${CMAKE_SOURCE_DIR}/build/cef*_mac64")
48+
endif()
4549
else()
4650
set(_cef_glob_pat "${CMAKE_SOURCE_DIR}/build/cef*_linux64")
4751
endif()
@@ -71,7 +75,11 @@ set(PYX_STAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/pyx_stage")
7175
if(WIN32)
7276
set(_cef_ver_header "${SRC_DIR}/version/cef_version_win.h")
7377
elseif(APPLE)
74-
set(_cef_ver_header "${SRC_DIR}/version/cef_version_mac.h")
78+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
79+
set(_cef_ver_header "${SRC_DIR}/version/cef_version_macarm64.h")
80+
else()
81+
set(_cef_ver_header "${SRC_DIR}/version/cef_version_mac.h")
82+
endif()
7583
else()
7684
set(_cef_ver_header "${SRC_DIR}/version/cef_version_linux.h")
7785
endif()

src/version/cef_version_macarm64.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2018 Marshall A. Greenblatt. All rights reserved.
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions are
5+
// met:
6+
//
7+
// * Redistributions of source code must retain the above copyright
8+
// notice, this list of conditions and the following disclaimer.
9+
// * Redistributions in binary form must reproduce the above
10+
// copyright notice, this list of conditions and the following disclaimer
11+
// in the documentation and/or other materials provided with the
12+
// distribution.
13+
// * Neither the name of Google Inc. nor the name Chromium Embedded
14+
// Framework nor the names of its contributors may be used to endorse
15+
// or promote products derived from this software without specific prior
16+
// written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
//
30+
// ---------------------------------------------------------------------------
31+
//
32+
// This file is generated by the make_version_header.py tool.
33+
//
34+
35+
#ifndef CEF_INCLUDE_CEF_VERSION_H_
36+
#define CEF_INCLUDE_CEF_VERSION_H_
37+
38+
#define CEF_VERSION "146.0.11+g3a0fcf1+chromium-146.0.7680.179"
39+
#define CEF_VERSION_MAJOR 146
40+
#define CEF_VERSION_MINOR 0
41+
#define CEF_VERSION_PATCH 11
42+
#define CEF_COMMIT_NUMBER 3505
43+
#define CEF_COMMIT_HASH "3a0fcf1e1b6249b50c96ac77c429bfefade09d96"
44+
#define COPYRIGHT_YEAR 2026
45+
46+
#define CHROME_VERSION_MAJOR 146
47+
#define CHROME_VERSION_MINOR 0
48+
#define CHROME_VERSION_BUILD 7680
49+
#define CHROME_VERSION_PATCH 179
50+
51+
#define CEF_SANDBOX_COMPAT_HASH "06ced0d54abb1a72"
52+
53+
// API hashes for macOS ARM64 (CEF_API_VERSION 999999).
54+
// These are overwritten by the CI from the downloaded CEF package headers.
55+
#define CEF_API_HASH_PLATFORM "95e5118d3fc65ae6c2645b6f381947d38586e669"
56+
#define CEF_API_HASH_UNIVERSAL "95e5118d3fc65ae6c2645b6f381947d38586e669"
57+
58+
#define DO_MAKE_STRING(p) #p
59+
#define MAKE_STRING(p) DO_MAKE_STRING(p)
60+
61+
#endif // CEF_INCLUDE_CEF_VERSION_H_

tools/common.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@
5151
OS_POSTFIX2 = "win32" if ARCH32 else "win64"
5252
CEF_POSTFIX2 = "windows32" if ARCH32 else "windows64"
5353
elif OS_POSTFIX == "mac":
54-
OS_POSTFIX2 = "mac32" if ARCH32 else "mac64"
55-
CEF_POSTFIX2 = "macosx32" if ARCH32 else "macosx64"
54+
if platform.machine() == "arm64":
55+
OS_POSTFIX2 = "macarm64"
56+
CEF_POSTFIX2 = "macosarm64"
57+
else:
58+
OS_POSTFIX2 = "mac32" if ARCH32 else "mac64"
59+
CEF_POSTFIX2 = "macosx32" if ARCH32 else "macosx64"
5660
elif OS_POSTFIX == "linux":
5761
OS_POSTFIX2 = "linux32" if ARCH32 else "linux64"
5862
CEF_POSTFIX2 = "linux32" if ARCH32 else "linux64"
@@ -470,8 +474,11 @@ def get_version_from_command_line_args(caller_script, ignore_error=False):
470474

471475
def get_cefpython_version():
472476
"""Get CEF version from the 'src/version/' directory."""
473-
header_file = os.path.join(SRC_DIR, "version",
474-
"cef_version_"+OS_POSTFIX+".h")
477+
if OS_POSTFIX == "mac" and platform.machine() == "arm64":
478+
header_name = "cef_version_macarm64.h"
479+
else:
480+
header_name = "cef_version_" + OS_POSTFIX + ".h"
481+
header_file = os.path.join(SRC_DIR, "version", header_name)
475482
return get_version_from_file(header_file)
476483

477484

0 commit comments

Comments
 (0)