Skip to content

Commit

Permalink
Add support to build AppImages on ARM
Browse files Browse the repository at this point in the history
  • Loading branch information
rmartin16 committed Dec 7, 2023
1 parent 13551e5 commit 3938e7c
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 23 deletions.
1 change: 1 addition & 0 deletions changes/1564.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AppImages can now be built for the ARM architecture.
2 changes: 1 addition & 1 deletion docs/reference/platforms/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Platform support
+---------+-----------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+
| iOS | |iOS|_ | |f| | |y| | | | | | | | |
+---------+-----------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+
| Linux | |AppImage|_ | |v| | | | | | |v| | |v| | | |
| Linux | |AppImage|_ | |v| | |v| | | | | |v| | |v| | |v| | |v| |
+ +-----------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+
| | |Flatpak|_ | | | | | | |v| | |f| | |v| | |v| |
+ +-----------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/platforms/linux/appimage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ AppImage
+--------+-------+-----+--------+-------+-----+--------+-----+-------+
| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 |
+========+=======+=====+========+=======+=====+========+=====+=======+
| |v| | | | | | |v| | |v| | | |
| |v| | |v| | | | | |v| | |v| | |v| | |v| |
+--------+-------+-----+--------+-------+-----+--------+-----+-------+

.. admonition:: Best effort support
Expand Down
2 changes: 1 addition & 1 deletion src/briefcase/bootstraps/pursuedpybear.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def pyproject_table_linux_system_arch(self):

def pyproject_table_linux_appimage(self):
return """
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
# ?? FIXME
Expand Down
2 changes: 1 addition & 1 deletion src/briefcase/bootstraps/pygame.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def pyproject_table_linux_system_arch(self):

def pyproject_table_linux_appimage(self):
return """
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
]
Expand Down
2 changes: 1 addition & 1 deletion src/briefcase/bootstraps/toga.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def pyproject_table_linux_system_arch(self):

def pyproject_table_linux_appimage(self):
return """
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
# Needed to compile pycairo wheel
Expand Down
22 changes: 17 additions & 5 deletions src/briefcase/integrations/linuxdeploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,28 @@ def file_path(self) -> Path:
"""The folder on the local filesystem that contains the file_name."""

@classmethod
def arch(cls, host_arch: str) -> str:
def arch(cls, tools: ToolCache) -> str:
"""The architecture defined (and supported) by linuxdeploy for AppImages."""
system_arch = tools.host_arch

# use 32bit linuxdeploy if using 32bit Python on 64bit hardware
if tools.is_32bit_python:
system_arch = {
"aarch64": "armv8l",
"x86_64": "i686",
}.get(tools.host_arch, tools.host_arch)

try:
return {
"x86_64": "x86_64",
"i686": "i386",
}[host_arch]
"armv7l": "armhf",
"armv8l": "armhf",
"aarch64": "aarch64",
}[system_arch]
except KeyError as e:
raise UnsupportedHostError(
f"Linux AppImages cannot be built on {host_arch}."
f"Linux AppImages cannot be built on {tools.host_arch}."
) from e

def exists(self) -> bool:
Expand Down Expand Up @@ -222,7 +234,7 @@ class LinuxDeployQtPlugin(LinuxDeployPluginBase, ManagedTool):

@property
def file_name(self) -> str:
return f"linuxdeploy-plugin-qt-{self.arch(self.tools.host_arch)}.AppImage"
return f"linuxdeploy-plugin-qt-{self.arch(self.tools)}.AppImage"

@property
def download_url(self) -> str:
Expand Down Expand Up @@ -333,7 +345,7 @@ def file_path(self) -> Path:

@property
def file_name(self) -> str:
return f"linuxdeploy-{self.arch(self.tools.host_arch)}.AppImage"
return f"linuxdeploy-{self.arch(self.tools)}.AppImage"

@property
def download_url(self) -> str:
Expand Down
16 changes: 12 additions & 4 deletions src/briefcase/platforms/linux/appimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def project_path(self, app):

def binary_name(self, app):
safe_name = app.formal_name.replace(" ", "_")
arch = LinuxDeploy.arch(self.tools.host_arch)
arch = LinuxDeploy.arch(self.tools)
return f"{safe_name}-{app.version}-{arch}.AppImage"

def binary_path(self, app):
Expand Down Expand Up @@ -175,13 +175,21 @@ class LinuxAppImageCreateCommand(
def output_format_template_context(self, app: AppConfig):
context = super().output_format_template_context(app)

# Add the manylinux tag to the template context.
try:
tag = getattr(app, "manylinux_image_tag", "latest")
manylinux_arch = {
"x86_64": "x86_64",
"i386": "i686",
}[LinuxDeploy.arch(self.tools.host_arch)]
"aarch64": "aarch64",
}[LinuxDeploy.arch(self.tools)]
except KeyError:
manylinux_arch = "unknown"
self.logger.warning(
f"There is not a manylinux base image for {self.tools.host_arch}"
)

# Add the manylinux tag to the template context.
try:
tag = getattr(app, "manylinux_image_tag", "latest")
context["manylinux_image"] = f"{app.manylinux}_{manylinux_arch}:{tag}"
if app.manylinux in {"manylinux1", "manylinux2010", "manylinux2014"}:
context["vendor_base"] = "centos"
Expand Down
8 changes: 4 additions & 4 deletions tests/commands/new/test_build_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def main():
]
""",
pyproject_table_linux_appimage="""
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
# Needed to compile pycairo wheel
Expand Down Expand Up @@ -578,7 +578,7 @@ def main():
]
""",
pyproject_table_linux_appimage="""
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
# ?? FIXME
Expand Down Expand Up @@ -748,7 +748,7 @@ def main():
]
""",
pyproject_table_linux_appimage="""
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
]
Expand Down Expand Up @@ -1178,7 +1178,7 @@ def main():
]
""",
pyproject_table_linux_appimage="""
manylinux = "manylinux2014"
manylinux = "manylinux_2_28"
system_requires = [
# Needed to compile pycairo wheel
Expand Down
16 changes: 11 additions & 5 deletions tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,23 @@ def test_file_path(linuxdeploy, mock_tools):


@pytest.mark.parametrize(
"host_os, host_arch, linuxdeploy_arch",
"host_os, host_arch, is_32bit_python, linuxdeploy_arch",
[
("Linux", "x86_64", "x86_64"),
("Linux", "i686", "i386"),
("Darwin", "x86_64", "x86_64"),
("Linux", "x86_64", False, "x86_64"),
("Linux", "x86_64", True, "i386"),
("Linux", "i686", True, "i386"),
("Linux", "aarch64", True, "armhf"),
("Linux", "aarch64", False, "aarch64"),
("Linux", "armv7l", True, "armhf"),
("Linux", "armv8l", True, "armhf"),
("Darwin", "x86_64", False, "x86_64"),
],
)
def test_file_name(mock_tools, host_os, host_arch, linuxdeploy_arch):
def test_file_name(mock_tools, host_os, host_arch, is_32bit_python, linuxdeploy_arch):
"""Linuxdeploy filename is architecture dependent."""
mock_tools.host_os = host_os
mock_tools.host_arch = host_arch
mock_tools.is_32bit_python = is_32bit_python

linuxdeploy = LinuxDeploy(mock_tools)

Expand Down
26 changes: 26 additions & 0 deletions tests/platforms/linux/appimage/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,32 @@ def test_finalize_nodocker(create_command, first_app_config, capsys):
"use_non_root_user": True,
},
),
# Linux on aarch64 hardware
(
"manylinux_2_28",
None,
"Linux",
"aarch64",
False,
{
"manylinux_image": "manylinux_2_28_aarch64:latest",
"vendor_base": "almalinux",
"use_non_root_user": True,
},
),
# Linux on arm hardware
(
"manylinux_2_28",
None,
"Linux",
"armv7l",
False,
{
"manylinux_image": "manylinux_2_28_unknown:latest",
"vendor_base": "almalinux",
"use_non_root_user": True,
},
),
# macOS on x86_64
(
"manylinux2014",
Expand Down

0 comments on commit 3938e7c

Please sign in to comment.