Skip to content

Commit 140fb64

Browse files
committed
feat: wheel for mac is universal wheel now
1 parent 8297a9a commit 140fb64

File tree

4 files changed

+75
-75
lines changed

4 files changed

+75
-75
lines changed

.github/workflows/build-wheel.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ jobs:
109109
# Build wheel
110110
python setup.py bdist_wheel --plat-name win_amd64
111111
112-
- name: Build macOS wheel (Apple Silicon)
113-
if: runner.os == 'macOS' && runner.arch == 'arm64'
112+
- name: Build macOS wheel (Universal)
113+
if: runner == 'macos-latest'
114114
run: |
115115
# Create necessary directories
116116
mkdir -p artifacts
@@ -126,12 +126,12 @@ jobs:
126126
python scripts/download_artifacts.py $C2PA_VERSION
127127
128128
# Build wheel
129-
python setup.py bdist_wheel --plat-name macosx_11_0_arm64
129+
python setup.py bdist_wheel --plat-name macosx_10_9_universal2
130130
131131
# Rename wheel to ensure unique filename
132132
cd dist
133133
for wheel in *.whl; do
134-
mv "$wheel" "${wheel/macosx_11_0_arm64/macosx_11_0_arm64}"
134+
mv "$wheel" "${wheel/macosx_10_9_universal2/macosx_10_9_universal2}"
135135
done
136136
cd ..
137137

.github/workflows/build.yml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
strategy:
5252
fail-fast: false
5353
matrix:
54-
os: [ macos-latest, ubuntu-latest, ubuntu-24.04-arm ]
54+
os: [ macos-latest, ubuntu-latest, ubuntu-24.04-arm]
5555

5656
steps:
5757
- name: Checkout repository
@@ -105,7 +105,7 @@ jobs:
105105
github.event.pull_request.user.login == 'dependabot[bot]' ||
106106
contains(github.event.pull_request.labels.*.name, 'safe to test')
107107
108-
runs-on: windows-latest
108+
runs-on: [windows-latest, windows-2022]
109109

110110
steps:
111111
- name: Checkout repository
@@ -326,19 +326,22 @@ jobs:
326326
.\venv\Scripts\pytest .\tests\test_unit_tests.py -v
327327
328328
build-macos-wheel:
329-
name: Build macOS wheel
329+
name: Build macOS wheel (Universal)
330330
uses: ./.github/workflows/build-wheel.yml
331331
needs: [tests-unix, read-version]
332332
with:
333333
python-version: "3.10"
334334
artifact-name: wheels-macos-${{ matrix.target }}
335-
runs-on: macos-latest
335+
architecture: ${{ matrix.target }}
336336
c2pa-version: ${{ needs.read-version.outputs.c2pa-native-version }}
337337
secrets:
338338
github-token: ${{ secrets.GITHUB_TOKEN }}
339339
strategy:
340340
matrix:
341-
target: [aarch64]
341+
include:
342+
- target: universal2
343+
runs-on: macos-latest
344+
342345
if: |
343346
github.event_name != 'pull_request' ||
344347
github.event.pull_request.author_association == 'COLLABORATOR' ||
@@ -347,12 +350,15 @@ jobs:
347350
contains(github.event.pull_request.labels.*.name, 'safe to test')
348351
349352
test-built-macos-wheel:
350-
name: Test macOS built wheel
353+
name: Test macOS built wheel (Universal)
351354
needs: build-macos-wheel
352355
runs-on: macos-latest
353356
strategy:
354357
matrix:
355-
target: [aarch64]
358+
include:
359+
- target: universal2
360+
runs-on: macos-latest
361+
356362
if: |
357363
github.event_name != 'pull_request' ||
358364
github.event.pull_request.author_association == 'COLLABORATOR' ||
@@ -452,7 +458,7 @@ jobs:
452458
run: |
453459
echo "Downloaded Artifacts"
454460
ls -la dist/
455-
- name: Publish to PyPI
461+
- name: Publish to TestPyPI
456462
uses: pypa/gh-action-pypi-publish@release/v1
457463
with:
458464
packages-dir: dist

setup.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,25 @@ def get_version():
1717
PLATFORM_EXTENSIONS = {
1818
'win_amd64': 'dll',
1919
'win_arm64': 'dll',
20-
'macosx_x86_64': 'dylib',
21-
'apple-darwin': 'dylib', # we need to update the published keys
20+
'apple-darwin': 'dylib', # universal
2221
'linux_x86_64': 'so',
2322
'linux_aarch64': 'so',
2423
}
2524

2625
# Based on what c2pa-rs repo publishes
2726
PLATFORM_FOLDERS = {
2827
'universal-apple-darwin': 'dylib',
29-
'aarch64-apple-darwin': 'dylib',
30-
'x86_64-apple-darwin': 'dylib',
3128
'x86_64-pc-windows-msvc': 'dll',
3229
'x86_64-unknown-linux-gnu': 'so',
33-
'aarch64-unknown-linux-gnu': 'so', # Add ARM Linux support
30+
'aarch64-unknown-linux-gnu': 'so',
3431
}
3532

3633
# Directory structure
3734
ARTIFACTS_DIR = Path('artifacts') # Where downloaded libraries are stored
3835
PACKAGE_LIBS_DIR = Path('src/c2pa/libs') # Where libraries will be copied for the wheel
3936

4037

41-
def get_platform_identifier(cpu_arch = None) -> str:
38+
def get_platform_identifier() -> str:
4239
"""Get a platform identifier (arch-os) for the current system,
4340
matching downloaded identifiers used by the Github publisher.
4441
@@ -47,24 +44,15 @@ def get_platform_identifier(cpu_arch = None) -> str:
4744
cpu_arch: Optional CPU architecture for macOS. If not provided, returns universal build.
4845
4946
Returns one of:
50-
- universal-apple-darwin (for Mac, when cpu_arch is None, fallback)
51-
- aarch64-apple-darwin (for Mac ARM64)
52-
- x86_64-apple-darwin (for Mac x86_64)
47+
- universal-apple-darwin (for macOS)
5348
- x86_64-pc-windows-msvc (for Windows 64-bit)
5449
- x86_64-unknown-linux-gnu (for Linux 64-bit)
5550
- aarch64-unknown-linux-gnu (for Linux ARM64)
5651
"""
5752
system = platform.system().lower()
5853

5954
if system == "darwin":
60-
if cpu_arch is None:
61-
return "universal-apple-darwin"
62-
elif cpu_arch == "arm64":
63-
return "aarch64-apple-darwin"
64-
elif cpu_arch == "x86_64":
65-
return "x86_64-apple-darwin"
66-
else:
67-
raise ValueError(f"Unsupported CPU architecture for macOS: {cpu_arch}")
55+
return "universal-apple-darwin"
6856
elif system == "windows":
6957
return "x86_64-pc-windows-msvc"
7058
elif system == "linux":

src/c2pa/lib.py

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@
1010
import logging
1111
import platform
1212
from pathlib import Path
13-
from typing import Optional, Tuple
13+
from typing import Optional
1414
from enum import Enum
1515

1616
# Debug flag for library loading
1717
DEBUG_LIBRARY_LOADING = False
1818

19-
# Create a module-specific logger with NullHandler to avoid interfering with global configuration
20-
logger = logging.getLogger("c2pa")
21-
logger.addHandler(logging.NullHandler())
19+
# Configure logging
20+
logging.basicConfig(
21+
level=logging.INFO,
22+
format='%(asctime)s - %(levelname)s - %(message)s',
23+
force=True # Force configuration even if already configured
24+
)
25+
logger = logging.getLogger(__name__)
2226

2327

2428
class CPUArchitecture(Enum):
@@ -27,34 +31,20 @@ class CPUArchitecture(Enum):
2731
X86_64 = "x86_64"
2832

2933

30-
def get_platform_identifier(cpu_arch: Optional[CPUArchitecture] = None) -> str:
31-
"""Get the full platform identifier (arch-os) for the current system,
34+
def get_platform_identifier() -> str:
35+
"""Get the platform identifier (arch-os) for the current system,
3236
matching the downloaded identifiers used by the Github publisher.
3337
34-
Args:
35-
cpu_arch: Optional CPU architecture for macOS.
36-
If not provided, returns universal build.
37-
Only used on macOS systems.
38-
3938
Returns one of:
40-
- universal-apple-darwin (for Mac, when cpu_arch is None)
41-
- aarch64-apple-darwin (for Mac ARM64)
42-
- x86_64-apple-darwin (for Mac x86_64)
39+
- universal-apple-darwin (for Mac, ARM or Intel)
4340
- x86_64-pc-windows-msvc (for Windows 64-bit)
4441
- x86_64-unknown-linux-gnu (for Linux 64-bit)
42+
- aarch64-unknown-linux-gnu (for Linux ARM)
4543
"""
4644
system = platform.system().lower()
4745

4846
if system == "darwin":
49-
if cpu_arch is None:
50-
return "universal-apple-darwin"
51-
elif cpu_arch == CPUArchitecture.AARCH64:
52-
return "aarch64-apple-darwin"
53-
elif cpu_arch == CPUArchitecture.X86_64:
54-
return "x86_64-apple-darwin"
55-
else:
56-
raise ValueError(
57-
f"Unsupported CPU architecture for macOS: {cpu_arch}")
47+
return "universal-apple-darwin"
5848
elif system == "windows":
5949
return "x86_64-pc-windows-msvc"
6050
elif system == "linux":
@@ -81,7 +71,8 @@ def _get_architecture() -> str:
8171
elif sys.platform == "linux":
8272
return platform.machine()
8373
elif sys.platform == "win32":
84-
# win32 will cover all Windows versions (the 32 is a historical quirk)
74+
# win32 will cover all Windows versions
75+
# (the 32 is a historical quirk)
8576
return platform.machine()
8677
else:
8778
raise RuntimeError(f"Unsupported platform: {sys.platform}")
@@ -99,7 +90,8 @@ def _get_platform_dir() -> str:
9990
elif sys.platform == "linux":
10091
return "unknown-linux-gnu"
10192
elif sys.platform == "win32":
102-
# win32 will cover all Windows versions (the 32 is a historical quirk)
93+
# win32 will cover all Windows versions
94+
# (the 32 is a historical quirk)
10395
return "pc-windows-msvc"
10496
else:
10597
raise RuntimeError(f"Unsupported platform: {sys.platform}")
@@ -117,28 +109,31 @@ def _load_single_library(lib_name: str,
117109
Returns:
118110
The loaded library or None if loading failed
119111
"""
120-
if DEBUG_LIBRARY_LOADING:
121-
logger.info(f"Searching for library '{lib_name}' in paths: {[str(p) for p in search_paths]}")
112+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
113+
logger.info(
114+
f"Searching for library '{lib_name}' in paths: {[str(p) for p in search_paths]}")
122115
current_arch = _get_architecture()
123-
if DEBUG_LIBRARY_LOADING:
116+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
124117
logger.info(f"Current architecture: {current_arch}")
125118

126119
for path in search_paths:
127120
lib_path = path / lib_name
128-
if DEBUG_LIBRARY_LOADING:
121+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
129122
logger.info(f"Checking path: {lib_path}")
130123
if lib_path.exists():
131-
if DEBUG_LIBRARY_LOADING:
124+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
132125
logger.info(f"Found library at: {lib_path}")
133126
try:
134127
return ctypes.CDLL(str(lib_path))
135128
except Exception as e:
136129
error_msg = str(e)
137130
if "incompatible architecture" in error_msg:
138-
logger.error(f"Architecture mismatch: Library at {lib_path} is not compatible with current architecture {current_arch}")
131+
logger.error(
132+
f"Architecture mismatch: Library at {lib_path} is not compatible with current architecture {current_arch}")
139133
logger.error(f"Error details: {error_msg}")
140134
else:
141-
logger.error(f"Failed to load library from {lib_path}: {e}")
135+
logger.error(
136+
f"Failed to load library from {lib_path}: {e}")
142137
else:
143138
logger.debug(f"Library not found at: {lib_path}")
144139
return None
@@ -155,7 +150,7 @@ def _get_possible_search_paths() -> list[Path]:
155150
platform_dir = _get_platform_dir()
156151
platform_id = get_platform_identifier()
157152

158-
if DEBUG_LIBRARY_LOADING:
153+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
159154
logger.info(f"Using platform directory: {platform_dir}")
160155
logger.info(f"Using platform identifier: {platform_id}")
161156

@@ -196,9 +191,12 @@ def dynamically_load_library(
196191
Load the dynamic library containing the C-API based on the platform.
197192
198193
Args:
199-
lib_name: Optional specific library name to load. If provided, only this library will be loaded.
200-
This enables to potentially load wrapper libraries of the C-API that may have an other name
201-
(the presence of required symbols will nevertheless be verified once the library is loaded).
194+
lib_name: Optional specific library name to load.
195+
If provided, only this library will be loaded.
196+
This enables to potentially load wrapper libraries
197+
of the C-API that may have an other name
198+
(the presence of required symbols will nevertheless
199+
be verified once the library is loaded).
202200
203201
Returns:
204202
The loaded library or None if loading failed
@@ -212,15 +210,15 @@ def dynamically_load_library(
212210
else:
213211
raise RuntimeError(f"Unsupported platform: {sys.platform}")
214212

215-
if DEBUG_LIBRARY_LOADING:
213+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
216214
logger.info(f"Current working directory: {Path.cwd()}")
217215
logger.info(f"Package directory: {Path(__file__).parent}")
218216
logger.info(f"System architecture: {_get_architecture()}")
219217

220218
# Check for C2PA_LIBRARY_NAME environment variable
221219
env_lib_name = os.environ.get("C2PA_LIBRARY_NAME")
222220
if env_lib_name:
223-
if DEBUG_LIBRARY_LOADING:
221+
if DEBUG_LIBRARY_LOADING: # pragma: no cover
224222
logger.info(
225223
f"Using library name from env var C2PA_LIBRARY_NAME: {env_lib_name}")
226224
try:
@@ -229,13 +227,14 @@ def dynamically_load_library(
229227
if lib:
230228
return lib
231229
else:
232-
logger.error(f"Could not find library {env_lib_name} in any of the search paths")
230+
logger.error(
231+
f"Could not find library {env_lib_name} in any of the search paths")
233232
# Continue with normal loading if environment variable library
234233
# name fails
235234
except Exception as e:
236235
logger.error(f"Failed to load library from C2PA_LIBRARY_NAME: {e}")
237-
# Continue with normal loading if environment variable library name
238-
# fails
236+
# Continue with normal loading if
237+
# environment variable library name fails
239238

240239
possible_paths = _get_possible_search_paths()
241240

@@ -245,15 +244,22 @@ def dynamically_load_library(
245244
if not lib:
246245
platform_id = get_platform_identifier()
247246
current_arch = _get_architecture()
248-
logger.error(f"Could not find {lib_name} in any of the search paths: {[str(p) for p in possible_paths]}")
249-
logger.error(f"Platform: {platform_id}, Architecture: {current_arch}")
250-
raise RuntimeError(f"Could not find {lib_name} in any of the search paths (Platform: {platform_id}, Architecture: {current_arch})")
247+
logger.error(
248+
f"Could not find {lib_name} in any of the search paths: {[str(p) for p in possible_paths]}")
249+
logger.error(
250+
f"Platform: {platform_id}, Architecture: {current_arch}")
251+
raise RuntimeError(
252+
f"Could not find {lib_name} in any of the search paths (Platform: {platform_id}, Architecture: {current_arch})")
251253
return lib
252254

253255
# Default path (no library name provided in the environment)
254256
c2pa_lib = _load_single_library(c2pa_lib_name, possible_paths)
255257
if not c2pa_lib:
256-
logger.error(f"Could not find {c2pa_lib_name} in any of the search paths: {[str(p) for p in possible_paths]}")
257-
raise RuntimeError(f"Could not find {c2pa_lib_name} in any of the search paths")
258+
logger.error(
259+
f"Could not find {c2pa_lib_name} in any of the search paths: {
260+
[
261+
str(p) for p in possible_paths]}")
262+
raise RuntimeError(
263+
f"Could not find {c2pa_lib_name} in any of the search paths")
258264

259265
return c2pa_lib

0 commit comments

Comments
 (0)