From 997f2c21bf123559c1a4b31b62672f571a496269 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <jryans@gmail.com>
Date: Fri, 18 Jun 2021 17:38:22 +0100
Subject: [PATCH] Use targets in hak environment for cross-compiling

This arranges the hak environment target info around target IDs that come from
the builder, which simplifies cross-compiling. The `target.js` module is a
generated copy of the builder's `target.ts`.
---
 scripts/hak/hakEnv.js | 51 +++++++++++++++++++++----------------------
 scripts/hak/index.js  | 16 ++++++++++++--
 scripts/hak/target.js | 15 ++++++++++++-
 3 files changed, 53 insertions(+), 29 deletions(-)

diff --git a/scripts/hak/hakEnv.js b/scripts/hak/hakEnv.js
index 46fc68b..7ccd32f 100644
--- a/scripts/hak/hakEnv.js
+++ b/scripts/hak/hakEnv.js
@@ -1,5 +1,5 @@
 /*
-Copyright 2020 The Matrix.org Foundation C.I.C.
+Copyright 2020-2021 The Matrix.org Foundation C.I.C.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ const path = require('path');
 const os = require('os');
 
 const nodePreGypVersioning = require('node-pre-gyp/lib/util/versioning');
+const { TARGETS, getHost, isHostId } = require('./target');
 
 function getElectronVersion(packageJson) {
     // should we pick the version of an installed electron
@@ -42,30 +43,24 @@ function getRuntimeVersion(packageJson) {
     }
 }
 
-function detectArch() {
-    if (process.platform === 'win32') {
-        // vcvarsall.bat (the script that sets up the environment for
-        // visual studio build tools) sets an env var to tell us what
-        // architecture the active build tools target, so we auto-detect
-        // this.
-        const targetArch = process.env.VSCMD_ARG_TGT_ARCH;
-        if (targetArch === 'x86') {
-            return 'ia32';
-        } else if (targetArch === 'x64') {
-            return 'x64';
-        }
-    }
-    return process.arch;
-}
-
 module.exports = class HakEnv {
-    constructor(prefix, packageJson) {
+    constructor(prefix, packageJson, targetId) {
+        let target;
+        if (targetId) {
+            target = TARGETS[targetId];
+        } else {
+            target = getHost();
+        }
+
+        if (!target) {
+            throw new Error(`Unknown target ${targetId}!`);
+        }
+
         Object.assign(this, {
             // what we're targeting
             runtime: getRuntime(packageJson),
             runtimeVersion: getRuntimeVersion(packageJson),
-            platform: process.platform,
-            arch: detectArch(),
+            target,
 
             // paths
             projectRoot: prefix,
@@ -82,25 +77,29 @@ module.exports = class HakEnv {
 
     // {node_abi}-{platform}-{arch}
     getNodeTriple() {
-        return this.getRuntimeAbi() + '-' + this.platform + '-' + this.arch;
+        return this.getRuntimeAbi() + '-' + this.target.platform + '-' + this.target.arch;
     }
 
     isWin() {
-        return this.platform === 'win32';
+        return this.target.platform === 'win32';
     }
 
     isMac() {
-        return this.platform === 'darwin';
+        return this.target.platform === 'darwin';
     }
 
     isLinux() {
-        return this.platform === 'linux';
+        return this.target.platform === 'linux';
+    }
+
+    isHost() {
+        return isHostId(this.target.id);
     }
 
     makeGypEnv() {
         return Object.assign({}, process.env, {
-            npm_config_arch: this.arch,
-            npm_config_target_arch: this.arch,
+            npm_config_arch: this.target.arch,
+            npm_config_target_arch: this.target.arch,
             npm_config_disturl: 'https://atom.io/download/electron',
             npm_config_runtime: this.runtime,
             npm_config_target: this.runtimeVersion,
diff --git a/scripts/hak/index.js b/scripts/hak/index.js
index 56e3a30..df30d58 100644
--- a/scripts/hak/index.js
+++ b/scripts/hak/index.js
@@ -1,5 +1,5 @@
 /*
-Copyright 2020 The Matrix.org Foundation C.I.C.
+Copyright 2020-2021 The Matrix.org Foundation C.I.C.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -53,7 +53,19 @@ async function main() {
         process.exit(1);
     }
 
-    const hakEnv = new HakEnv(prefix, packageJson);
+    // Apply `--target <target>` option if specified
+    const targetIndex = process.argv.indexOf('--target');
+    let targetId;
+    if (targetIndex >= 0) {
+        if ((targetIndex + 1) >= process.argv.length) {
+            console.error("--target option specified without a target");
+            process.exit(1);
+        }
+        // Extract target ID and remove from args
+        targetId = process.argv.splice(targetIndex, 2)[1];
+    }
+
+    const hakEnv = new HakEnv(prefix, packageJson, targetId);
 
     const deps = {};
 
diff --git a/scripts/hak/target.js b/scripts/hak/target.js
index 5e58b4d..7460e7d 100644
--- a/scripts/hak/target.js
+++ b/scripts/hak/target.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.ENABLED_TARGETS = exports.TARGETS = void 0;
+exports.isHost = exports.isHostId = exports.getHost = exports.ENABLED_TARGETS = exports.TARGETS = void 0;
 const aarch64AppleDarwin = {
     id: 'aarch64-apple-darwin',
     platform: 'darwin',
@@ -58,3 +58,16 @@ exports.ENABLED_TARGETS = [
     exports.TARGETS['x86_64-unknown-linux-gnu'],
     exports.TARGETS['i686-pc-windows-msvc'],
 ];
+function getHost() {
+    return Object.values(exports.TARGETS).find(target => (target.platform === process.platform &&
+        target.arch === process.arch));
+}
+exports.getHost = getHost;
+function isHostId(id) {
+    return getHost()?.id === id;
+}
+exports.isHostId = isHostId;
+function isHost(target) {
+    return getHost()?.id === target.id;
+}
+exports.isHost = isHost;