Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[V3 Linux] aarch64 compilation #3854

Open
wants to merge 2 commits into
base: v3-alpha
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions v3/internal/commands/appimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"sync"

Expand Down Expand Up @@ -72,7 +73,18 @@ func generateAppImage(options *GenerateAppImageOptions) error {
// Get the last path of the binary and normalise the name
name := normaliseName(filepath.Base(options.Binary))

appDir := filepath.Join(options.BuildDir, name+"-x86_64.AppDir")
// Architecture-specific variables using a map
archDetails := map[string]string{
"arm64": "aarch64",
"x86_64": "x86_64",
}

arch, exists := archDetails[runtime.GOARCH]
if !exists {
return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH)
}

kodflow marked this conversation as resolved.
Show resolved Hide resolved
appDir := filepath.Join(options.BuildDir, fmt.Sprintf("%s-%s.AppDir", name, arch))
s.RMDIR(appDir)

log(p, "Preparing AppImage Directory: "+appDir)
Expand All @@ -92,27 +104,38 @@ func generateAppImage(options *GenerateAppImageOptions) error {
// Download linuxdeploy and make it executable
s.CD(options.BuildDir)

// Download necessary files
// Download URLs using a map based on architecture
urls := map[string]string{
"linuxdeploy": fmt.Sprintf("https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-%s.AppImage", arch),
"AppRun": fmt.Sprintf("https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-%s", arch),
}

// Download necessary files concurrently
log(p, "Downloading AppImage tooling")
var wg sync.WaitGroup
wg.Add(2)

go func() {
if !s.EXISTS(filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage")) {
s.DOWNLOAD("https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage", filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage"))
linuxdeployPath := filepath.Join(options.BuildDir, filepath.Base(urls["linuxdeploy"]))
if !s.EXISTS(linuxdeployPath) {
s.DOWNLOAD(urls["linuxdeploy"], linuxdeployPath)
}
s.CHMOD(filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage"), 0755)
s.CHMOD(linuxdeployPath, 0755)
wg.Done()
}()

go func() {
target := filepath.Join(appDir, "AppRun")
if !s.EXISTS(target) {
s.DOWNLOAD("https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64", target)
s.DOWNLOAD(urls["AppRun"], target)
}
s.CHMOD(target, 0755)
wg.Done()
}()

Comment on lines +113 to +135
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling in the concurrent download goroutines.

Currently, errors from s.DOWNLOAD and s.CHMOD within the goroutines are not being captured. If a download fails or permission changes fail, the program may proceed without the necessary tools, leading to runtime errors. Consider handling these errors to ensure robustness.

One way to handle this is to collect errors via a channel:

     var wg sync.WaitGroup
+    errCh := make(chan error, 2)
     wg.Add(2)

     go func() {
         linuxdeployPath := filepath.Join(options.BuildDir, filepath.Base(urls["linuxdeploy"]))
         if !s.EXISTS(linuxdeployPath) {
-            s.DOWNLOAD(urls["linuxdeploy"], linuxdeployPath)
+            if err := s.DOWNLOAD(urls["linuxdeploy"], linuxdeployPath); err != nil {
+                errCh <- err
+                return
+            }
         }
-        s.CHMOD(linuxdeployPath, 0755)
+        if err := s.CHMOD(linuxdeployPath, 0755); err != nil {
+            errCh <- err
+            return
+        }
         wg.Done()
     }()

     go func() {
         target := filepath.Join(appDir, "AppRun")
         if !s.EXISTS(target) {
-            s.DOWNLOAD(urls["AppRun"], target)
+            if err := s.DOWNLOAD(urls["AppRun"], target); err != nil {
+                errCh <- err
+                return
+            }
         }
-        s.CHMOD(target, 0755)
+        if err := s.CHMOD(target, 0755); err != nil {
+            errCh <- err
+            return
+        }
         wg.Done()
     }()

     wg.Wait()
+    close(errCh)
+    for err := range errCh {
+        return err
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Download necessary files concurrently
log(p, "Downloading AppImage tooling")
var wg sync.WaitGroup
wg.Add(2)
go func() {
if !s.EXISTS(filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage")) {
s.DOWNLOAD("https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage", filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage"))
linuxdeployPath := filepath.Join(options.BuildDir, filepath.Base(urls["linuxdeploy"]))
if !s.EXISTS(linuxdeployPath) {
s.DOWNLOAD(urls["linuxdeploy"], linuxdeployPath)
}
s.CHMOD(filepath.Join(options.BuildDir, "linuxdeploy-x86_64.AppImage"), 0755)
s.CHMOD(linuxdeployPath, 0755)
wg.Done()
}()
go func() {
target := filepath.Join(appDir, "AppRun")
if !s.EXISTS(target) {
s.DOWNLOAD("https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64", target)
s.DOWNLOAD(urls["AppRun"], target)
}
s.CHMOD(target, 0755)
wg.Done()
}()
// Download necessary files concurrently
log(p, "Downloading AppImage tooling")
var wg sync.WaitGroup
errCh := make(chan error, 2)
wg.Add(2)
go func() {
linuxdeployPath := filepath.Join(options.BuildDir, filepath.Base(urls["linuxdeploy"]))
if !s.EXISTS(linuxdeployPath) {
if err := s.DOWNLOAD(urls["linuxdeploy"], linuxdeployPath); err != nil {
errCh <- err
return
}
}
if err := s.CHMOD(linuxdeployPath, 0755); err != nil {
errCh <- err
return
}
wg.Done()
}()
go func() {
target := filepath.Join(appDir, "AppRun")
if !s.EXISTS(target) {
if err := s.DOWNLOAD(urls["AppRun"], target); err != nil {
errCh <- err
return
}
}
if err := s.CHMOD(target, 0755); err != nil {
errCh <- err
return
}
wg.Done()
}()
wg.Wait()
close(errCh)
for err := range errCh {
return err
}

wg.Wait()

// Processing GTK files
log(p, "Processing GTK files.")
filesNeeded := []string{"WebKitWebProcess", "WebKitNetworkProcess", "libwebkit2gtkinjectedbundle.so"}
files, err := findGTKFiles(filesNeeded)
Expand All @@ -122,48 +145,48 @@ func generateAppImage(options *GenerateAppImageOptions) error {
s.CD(appDir)
for _, file := range files {
targetDir := filepath.Dir(file)
// Strip leading forward slash
if targetDir[0] == '/' {
targetDir = targetDir[1:]
}
var err error
targetDir, err = filepath.Abs(targetDir)
if err != nil {
return err
}
s.MKDIR(targetDir)
s.COPY(file, targetDir)
}

// Copy GTK Plugin
err = os.WriteFile(filepath.Join(options.BuildDir, "linuxdeploy-plugin-gtk.sh"), gtkPlugin, 0755)
if err != nil {
return err
}

// Determine GTK Version
// Run ldd on the binary and capture the output
targetBinary := filepath.Join(appDir, "usr", "bin", options.Binary)
lddOutput, err := s.EXEC(fmt.Sprintf("ldd %s", targetBinary))
if err != nil {
println(string(lddOutput))
return err
}
lddString := string(lddOutput)
// Check if GTK3 is present
var DeployGtkVersion string
if s.CONTAINS(lddString, "libgtk-x11-2.0.so") {
switch {
case s.CONTAINS(lddString, "libgtk-x11-2.0.so"):
DeployGtkVersion = "2"
} else if s.CONTAINS(lddString, "libgtk-3.so") {
case s.CONTAINS(lddString, "libgtk-3.so"):
DeployGtkVersion = "3"
} else if s.CONTAINS(lddString, "libgtk-4.so") {
case s.CONTAINS(lddString, "libgtk-4.so"):
DeployGtkVersion = "4"
} else {
default:
return fmt.Errorf("unable to determine GTK version")
}

// Run linuxdeploy to bundle the application
s.CD(options.BuildDir)
//log(p, "Generating AppImage (This may take a while...)")
cmd := fmt.Sprintf("./linuxdeploy-x86_64.AppImage --appimage-extract-and-run --appdir %s --output appimage --plugin gtk", appDir)
linuxdeployAppImage := filepath.Join(options.BuildDir, fmt.Sprintf("linuxdeploy-%s.AppImage", arch))

cmd := fmt.Sprintf("%s --appimage-extract-and-run --appdir %s --output appimage --plugin gtk", linuxdeployAppImage, appDir)
s.SETENV("DEPLOY_GTK_VERSION", DeployGtkVersion)
output, err := s.EXEC(cmd)
if err != nil {
Expand All @@ -172,7 +195,7 @@ func generateAppImage(options *GenerateAppImageOptions) error {
}

// Move file to output directory
targetFile := filepath.Join(options.BuildDir, name+"-x86_64.AppImage")
targetFile := filepath.Join(options.BuildDir, fmt.Sprintf("%s-%s.AppImage", name, arch))
s.MOVE(targetFile, options.OutputDir)

log(p, "AppImage created: "+targetFile)
Expand Down