From 67035fb475391d0a6dfdfffa9833536d91b04196 Mon Sep 17 00:00:00 2001
From: trashbyte <github@trashbyte.io>
Date: Mon, 15 Nov 2021 17:11:18 -0800
Subject: [PATCH] Added support for target-specific config metadata with
 [package.metadata.<target>.bootloader]

---
 Readme.md                 |  4 ++++
 src/builder/disk_image.rs | 16 +++++++++++++--
 src/builder/error.rs      |  7 +++++++
 src/config.rs             | 43 ++++++++++++++++++++++++++++++---------
 4 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/Readme.md b/Readme.md
index a569690..9c782ab 100644
--- a/Readme.md
+++ b/Readme.md
@@ -87,6 +87,10 @@ test-timeout = 300
 test-no-reboot = true
 ```
 
+## Target-specific configuration
+
+Target-specific configuration can be done through `[package.metadata.<target-triple>.bootimage]`. The default architecture if none is specified is `x86_64`.
+
 ## License
 
 Licensed under either of
diff --git a/src/builder/disk_image.rs b/src/builder/disk_image.rs
index 2f3cfab..031ba6b 100644
--- a/src/builder/disk_image.rs
+++ b/src/builder/disk_image.rs
@@ -10,11 +10,23 @@ pub fn create_disk_image(
         .tool(&llvm_tools::exe("llvm-objcopy"))
         .ok_or(DiskImageError::LlvmObjcopyNotFound)?;
 
+    let format = match std::env::var("TARGET") {
+        Ok(target) => {
+            match target.split("-").next() {
+                Some("x86_64") => "elf64-x86-64",
+                Some("aarch64") => "elf64-aarch64",
+                _ => return Err(DiskImageError::TargetNotSupported { target })
+            }
+        },
+        Err(_) => "elf64-x86-64"
+    };
+
     // convert bootloader to binary
     let mut cmd = Command::new(objcopy);
-    cmd.arg("-I").arg("elf64-x86-64");
+    cmd.arg("-I").arg(format);
     cmd.arg("-O").arg("binary");
-    cmd.arg("--binary-architecture=i386:x86-64");
+    // --binary-architecture is deprecated
+    //cmd.arg("--binary-architecture=i386:x86-64");
     cmd.arg(bootloader_elf_path);
     cmd.arg(output_bin_path);
     let output = cmd.output().map_err(|err| DiskImageError::Io {
diff --git a/src/builder/error.rs b/src/builder/error.rs
index 5c0cab1..fb092e3 100644
--- a/src/builder/error.rs
+++ b/src/builder/error.rs
@@ -133,6 +133,13 @@ pub enum DiskImageError {
     #[error("Could not find `llvm-objcopy` in the `llvm-tools-preview` rustup component.")]
     LlvmObjcopyNotFound,
 
+    /// The build target is not supported
+    #[error("The specified build target '{target}' is not supported. Supported architectures are: x86_64, aarch64")]
+    TargetNotSupported {
+        /// The specified build target (from env:TARGET)
+        target: String
+    },
+
     /// The `llvm-objcopy` command failed
     #[error("Failed to run `llvm-objcopy`: {}", String::from_utf8_lossy(.stderr))]
     ObjcopyFailed {
diff --git a/src/config.rs b/src/config.rs
index 3bed52a..ed9f776 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -57,18 +57,41 @@ fn read_config_inner(manifest_path: &Path) -> Result<Config> {
             .context("Failed to parse Cargo.toml")?
     };
 
-    let metadata = cargo_toml
-        .get("package")
-        .and_then(|table| table.get("metadata"))
-        .and_then(|table| table.get("bootimage"));
-    let metadata = match metadata {
+    let target = std::env::var("TARGET");
+    let target_metadata = match target {
+        Ok(target) => {
+            let metadata = cargo_toml
+                .get("package")
+                .and_then(|table| table.get("metadata"))
+                .and_then(|table| table.get(target))
+                .and_then(|table| table.get("bootimage"));
+                match metadata {
+                    Some(metadata) => metadata.as_table(),
+                    None => None
+                }
+        },
+        Err(_) => None
+    };
+    let metadata = match target_metadata {
+        // have target-specific config
+        Some(meta) => meta,
+        // no target-specific config, fallback to default
         None => {
-            return Ok(ConfigBuilder::default().into());
-        }
-        Some(metadata) => metadata
-            .as_table()
-            .ok_or_else(|| anyhow!("Bootimage configuration invalid: {:?}", metadata))?,
+            let metadata = cargo_toml
+                .get("package")
+                .and_then(|table| table.get("metadata"))
+                .and_then(|table| table.get("bootimage"));
+            match metadata {
+                None => {
+                    return Ok(ConfigBuilder::default().into());
+                }
+                Some(metadata) => metadata
+                    .as_table()
+                    .ok_or_else(|| anyhow!("Bootimage configuration invalid: {:?}", metadata))?,
+            }
+        }   
     };
+    
 
     let mut config = ConfigBuilder::default();