Modernise '--arch' option handling to use StringChoiceOption, and add
arm64 to the choices.

Globally replace 'is_64bit' with 'installArch' indicating the
architecture we will be doing an install of.

'Start Menu' suffix logic is generalized: If we're installing for a
non-native arch, the arch name used as the suffix (except we continue to
use the historic '32-bit' for x86).

The default root for a native-arch installation remains as 'C:\cygwin64'
for x86_64 installs, 'C:\cygwin' otherwise. ('C:\cygwin_aarch64' seems
like too much typing to make it the default on arm64). Add appropriate
suffixes to avoid collisions for the new non-native possibilites.

(Not sure if we really need this, as there are probably vanishingly few
existing x86-on-arm64 installs where this could cause a collision (and
these are detected, see below))

The title used for the mintty terminal shortcut is similarly adjusted.

directory_contains_wrong_version() is generalized to read the arch of
any existing cygwin1.dll in the install directory, and stop with an
error if it is different.

Just like at the moment, where nothing precludes running an x86
installer with '--arch x86_64', you can now also run with '--arch
aarch64' on x86 or x86_64, but you still won't be able to do anything
useful to run the resulting install.

Or in table form:

install arch | native arch | startmenu suffix | terminal icon title       | 
root directory

x86          | x86         |                  | "Cygwin Terminal"         | 
C:\cygwin
x86_64       | x86         | " (x86_64)"      | "Cygwin64 Terminal"       | 
C:\cygwin64

x86          | x86_64      | " (32-bit)"      | "Cygwin Terminal"         | 
C:\cygwin
x86_64       | x86_64      |                  | "Cygwin64 Terminal"       | 
C:\cygwin64

x86          | arm64       | " (32-bit)"      | "Cygwin Terminal"         | 
C:\cygwin
x86_64       | arm64       | " (x86_64)"      | "Cygwin64 Terminal"       | 
C:\cygwin64

Changes to:

install arch | native arch | startmenu suffix | terminal icon title       | 
root directory

x86          | x86         |                  | "Cygwin Terminal"         | 
C:\cygwin
x86_64       | x86         | " (x86_64)"      | "Cygwin64 Terminal"       | 
C:\cygwin64
arm64        | x86         | " (arm64)"       | "Cygwin Terminal (arm64)" | 
C:\cygwin_arm64

x86          | x86_64      | " (32-bit)"      | "Cygwin Terminal"         | 
C:\cygwin
x86_64       | x86_64      |                  | "Cygwin64 Terminal"       | 
C:\cygwin64
arm64        | x86_64      | " (arm64)"       | "Cygwin Terminal (arm64)" | 
C:\cygwin_arm64

x86          | arm64       | " (32-bit)"      | "Cygwin32 Terminal"       | 
C:\cygwin32
x86_64       | arm64       | " (x86_64)"      | "Cygwin64 Terminal"       | 
C:\cygwin64
arm64        | arm64       |                  | "Cygwin Terminal"         | 
C:\cygwin
---
 desktop.cc    | 41 ++++++++++++++++++------
 desktop.h     |  2 +-
 ini.cc        |  2 +-
 main.cc       | 34 ++++++++++----------
 mount.cc      | 23 +++++++++++++-
 mount.h       |  2 +-
 res.pot       |  8 ++---
 res/en/res.rc |  8 ++---
 root.cc       | 86 +++++++++++++++++++++++++--------------------------
 script.cc     |  2 +-
 state.cc      |  6 +---
 state.h       |  2 +-
 win32.cc      |  5 +--
 13 files changed, 129 insertions(+), 92 deletions(-)

diff --git a/desktop.cc b/desktop.cc
index be7cc6e..7795aad 100644
--- a/desktop.cc
+++ b/desktop.cc
@@ -95,14 +95,13 @@ make_link (const std::string& linkpath,
               icon.c_str(), fname.c_str());
 }
 
-const char *startmenusuffix()
+const std::string
+startmenusuffix()
 {
-  if (!is_64bit && (WowNativeMachine() != IMAGE_FILE_MACHINE_I386))
+  if ((installArch == IMAGE_FILE_MACHINE_I386) && (WowNativeMachine() != 
IMAGE_FILE_MACHINE_I386))
     return " (32-bit)";
-#ifdef __x86_64__
-  if (WowNativeMachine() != IMAGE_FILE_MACHINE_AMD64)
-    return " (x86_64)";
-#endif
+  if (WowNativeMachine() != installArch)
+    return " (" + machine_name(installArch) + ")";
   else
     return "";
 }
@@ -125,7 +124,7 @@ start_menu (const std::string& title, const std::string& 
target,
                              CSIDL_PROGRAMS, &id);
   SHGetPathFromIDList (id, path);
   strncat (path, startmenudir(), MAX_PATH - strlen(path) - 1);
-  strncat (path, startmenusuffix(), MAX_PATH - strlen(path) - 1);
+  strncat (path, startmenusuffix().c_str(), MAX_PATH - strlen(path) - 1);
   LogBabblePrintf ("Program directory for program link: %s", path);
   make_link (path, title, target, arg, iconpath);
 }
@@ -212,8 +211,30 @@ save_icon (std::string &iconpath, const char 
*resource_name)
 #define TARGET         "/bin/mintty"
 #define DEFAULTICON    "/Cygwin.ico"
 #define TERMINALICON   "/Cygwin-Terminal.ico"
-#define TERMINALTITLE  (is_64bit ? "Cygwin64 Terminal" \
-                                 : "Cygwin Terminal")
+#define TERMINALTITLE   terminaltitle()
+
+static const std::string
+terminaltitle()
+{
+  /* The x86_64 terminal is always called "Cygwin64 Terminal" */
+  if (installArch == IMAGE_FILE_MACHINE_AMD64)
+    return "Cygwin64 Terminal";
+
+  /* Otherwise, just use the plain name when arches match  */
+  if (WowNativeMachine() == installArch)
+    return "Cygwin Terminal";
+
+  /* Likewise, the x86 terminal is called just "Cygwin Terminal" on x86_64 */
+  if (installArch == IMAGE_FILE_MACHINE_I386)
+    {
+      if (WowNativeMachine() == IMAGE_FILE_MACHINE_AMD64)
+        return "Cygwin Terminal";
+      else
+        return "Cygwin32 Terminal";
+    }
+
+  return "Cygwin Terminal (" + machine_name(installArch) + ")";
+}
 
 static void
 do_desktop_setup ()
@@ -312,7 +333,7 @@ check_startmenu (const std::string title, const std::string 
target)
   SHGetPathFromIDList (id, path);
   LogBabblePrintf ("Program directory for program link: %s", path);
   strcat (path, startmenudir());
-  strcat (path, startmenusuffix());
+  strcat (path, startmenusuffix().c_str());
   std::string fname = std::string(path) + "/" + title + ".lnk";
 
   if (_access (fname.c_str(), 0) == 0)
diff --git a/desktop.h b/desktop.h
index d4ce72d..4e6f5ca 100644
--- a/desktop.h
+++ b/desktop.h
@@ -43,7 +43,7 @@ public:
   virtual bool OnMessageApp (UINT uMsg, WPARAM wParam, LPARAM lParam);
 };
 
-const char *startmenusuffix();
+const std::string startmenusuffix();
 
 extern BoolOption NoShortcutsOption;
 extern BoolOption NoStartMenuOption;
diff --git a/ini.cc b/ini.cc
index 6eefcac..d919d45 100644
--- a/ini.cc
+++ b/ini.cc
@@ -150,7 +150,7 @@ private:
 
 std::string SetupArch()
 {
-  return is_64bit ? "x86_64" : "x86";
+  return machine_name(installArch);
 }
 
 std::string SetupBaseName()
diff --git a/main.cc b/main.cc
index 6ae3256..91d0eca 100644
--- a/main.cc
+++ b/main.cc
@@ -100,7 +100,17 @@ static StringChoiceOption::StringChoices quiet_types({
     {"hidden", QuietHidden},
   });
 
-static StringOption Arch ("", 'a', "arch", IDS_HELPTEXT_ARCH, false);
+static StringChoiceOption::StringChoices arch_choices({
+    {"64", IMAGE_FILE_MACHINE_AMD64},
+    {"x86_64", IMAGE_FILE_MACHINE_AMD64},
+    {"amd64", IMAGE_FILE_MACHINE_AMD64},
+    {"32", IMAGE_FILE_MACHINE_I386},
+    {"x86", IMAGE_FILE_MACHINE_I386},
+    {"aarch64", IMAGE_FILE_MACHINE_ARM64},
+    {"arm64", IMAGE_FILE_MACHINE_ARM64},
+  });
+
+static StringChoiceOption Arch (arch_choices, 'a', "arch", IDS_HELPTEXT_ARCH, 
false);
 StringChoiceOption UnattendedOption (quiet_types, 'q', "quiet-mode", 
IDS_HELPTEXT_QUIET_MODE, true, -1, QuietUnattended);
 static BoolOption PackageManagerOption (false, 'M', "package-manager", 
IDS_HELPTEXT_PACKAGE_MANAGER);
 static BoolOption NoAdminOption (false, 'B', "no-admin", 
IDS_HELPTEXT_NO_ADMIN);
@@ -257,22 +267,10 @@ WinMain (HINSTANCE h,
     else if (HelpOption)
       help_option = true;
 
-    if (((std::string) Arch).size ())
-      {
-        if (((std::string) Arch).find ("64") != std::string::npos)
-          is_64bit = true;
-        else if (((std::string) Arch).find ("32") != std::string::npos
-                 || ((std::string) Arch).find ("x86") != std::string::npos)
-          is_64bit = false;
-        else
-          {
-            char buff[80 + ((std::string) Arch).size ()];
-            sprintf (buff, "Invalid option for --arch:  \"%s\"",
-                     ((std::string) Arch).c_str ());
-            fprintf (stderr, "*** %s\n", buff);
-            exit (1);
-          }
-      }
+    if (Arch.isPresent())
+      installArch = Arch;
+    else
+      installArch = WindowsProcessMachine();
 
     if (GuiLangOption.isPresent())
       {
@@ -350,7 +348,7 @@ WinMain (HINSTANCE h,
 #ifdef _X86_
           (TRUE)
 #else
-          (!is_64bit)
+          (installArch == IMAGE_FILE_MACHINE_I386)
 #endif
         {
           mbox (NULL, IDS_UNSUPPORTED_WINDOWS_ARCH,
diff --git a/mount.cc b/mount.cc
index a38f52c..0d15c71 100644
--- a/mount.cc
+++ b/mount.cc
@@ -356,13 +356,34 @@ read_mounts (const std::string val)
        }
     }
 
+  /*
+    The default root directory: for historical reasons (you could already have 
a
+    x86 install in cygwin), it's always cygwin64 for an x86_64 install.
+
+    It isn't critical that these are unique by arch, as we'll later check and
+    warn if it already contains a cygwin install for a different arch.
+  */
   if (!root_here)
     {
       /* Affected path always < MAX_PATH. */
       char windir[MAX_PATH];
       GetSystemWindowsDirectory (windir, sizeof (windir));
       windir[2] = 0;
-      m->native = std::string (windir) + (is_64bit ? "\\cygwin64" : 
"\\cygwin");
+
+      std::string rootdir;
+      if (installArch == IMAGE_FILE_MACHINE_AMD64)
+        rootdir = "\\cygwin64";
+      else if (WowNativeMachine() == installArch)
+        rootdir = "\\cygwin";
+      else if (installArch == IMAGE_FILE_MACHINE_I386)
+          if (WowNativeMachine() == IMAGE_FILE_MACHINE_AMD64)
+            rootdir = "\\cygwin";
+          else
+            rootdir = "\\cygwin32";
+      else
+        rootdir = "\\cygwin_" + machine_name(installArch);
+
+      m->native = std::string (windir) + rootdir;
       m->posix = "/";
       root_here = m;
       add_usr_mnts (++m);
diff --git a/mount.h b/mount.h
index c451a02..b0ff251 100644
--- a/mount.h
+++ b/mount.h
@@ -18,7 +18,7 @@
 #include <string>
 #include "String++.h"
 
-#define SETUP_KEY_WOW64 (is_64bit ? KEY_WOW64_64KEY : KEY_WOW64_32KEY)
+#define SETUP_KEY_WOW64 ((installArch != IMAGE_FILE_MACHINE_I386) ? 
KEY_WOW64_64KEY : KEY_WOW64_32KEY)
 
 void create_install_root ();
 void read_mounts (const std::string);
diff --git a/res.pot b/res.pot
index a4994e4..040923a 100644
--- a/res.pot
+++ b/res.pot
@@ -1061,12 +1061,12 @@ msgstr ""
 msgid ""
 "Target CPU mismatch\n"
 "\n"
-"You're trying to install a %s bit version of Cygwin into a directory "
-"containing a %s bit version of Cygwin.  Continuing to do so would break the "
+"You're trying to install the %s version of Cygwin into a directory "
+"containing the %s version of Cygwin.  Continuing to do so would break the "
 "existing installation.\n"
 "\n"
-"Either run setup-%s.exe to update your existing %s bit installation of "
-"Cygwin, or choose another directory for your %s bit installation."
+"Either run setup-%s.exe to update your existing %s installation of Cygwin, "
+"or choose another directory for your %s installation."
 msgstr ""
 
 #: STRINGTABLE.IDS_GET_SITELIST_ERROR
diff --git a/res/en/res.rc b/res/en/res.rc
index e526b99..0bdd4c7 100644
--- a/res/en/res.rc
+++ b/res/en/res.rc
@@ -613,12 +613,12 @@ BEGIN
     IDS_MIXED_BITNESS_ERROR
         "Target CPU mismatch"
         "\n\n"
-        "You're trying to install a %s bit version of Cygwin into a directory "
-        "containing a %s bit version of Cygwin.  Continuing to do so would "
+        "You're trying to install the %s version of Cygwin into a directory "
+        "containing the %s version of Cygwin.  Continuing to do so would "
         "break the existing installation."
         "\n\n"
-        "Either run setup-%s.exe to update your existing %s bit installation 
of Cygwin, "
-        "or choose another directory for your %s bit installation."
+        "Either run setup-%s.exe to update your existing %s installation of 
Cygwin, "
+        "or choose another directory for your %s installation."
     IDS_GET_SITELIST_ERROR
           "Can't get list of download sites.\n"
           "Make sure your network settings are correct and try again."
diff --git a/root.cc b/root.cc
index ccbd6ae..83af9ea 100644
--- a/root.cc
+++ b/root.cc
@@ -152,70 +152,70 @@ directory_has_spaces ()
   return 0;
 }
 
-static int
-directory_contains_wrong_version (HWND h)
+static USHORT
+read_fileheader_machine_type(std::string fn)
 {
   HANDLE fh;
-  std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
-
-  /* Check if we have a cygwin1.dll.  If not, this is a new install.
-     If yes, check if the target machine type of this setup version is the
-     same as the machine type of the install Cygwin DLL.  If yes, just go
-     ahead.  If not, show a message and indicate this to the caller.
-
-     If anything goes wrong reading the header of cygwin1.dll, we check
-     cygcheck.exe's binary type.  This also covers the situation that the
-     installed cygwin1.dll is broken for some reason. */
-  fh = CreateFileA (cygwin_dll.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
-                   NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  fh = CreateFileA (fn.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
+                    NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
   if (fh != INVALID_HANDLE_VALUE)
     {
       DWORD read = 0;
       struct {
-       LONG dos_header[32];
-       IMAGE_NT_HEADERS32 nt_header;
+        LONG dos_header[32];
+        IMAGE_NT_HEADERS32 nt_header;
       } hdr;
 
       ReadFile (fh, &hdr, sizeof hdr, &read, NULL);
       CloseHandle (fh);
-      if (read != sizeof hdr)
-       fh = INVALID_HANDLE_VALUE;
-      else
-       {
-         /* 32 bit setup and 32 bit inst? */
-         if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386
-             && !is_64bit)
-           return 0;
-         /* 64 bit setup and 64 bit inst? */
-         if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
-             && is_64bit)
-           return 0;
-       }
+      if (read == sizeof hdr)
+        {
+          return hdr.nt_header.FileHeader.Machine;
+        }
     }
-  if (fh == INVALID_HANDLE_VALUE)
+  return IMAGE_FILE_MACHINE_UNKNOWN;
+}
+
+static int
+directory_contains_wrong_version (HWND h)
+{
+  /*
+    Check if we have a cygwin1.dll.  If not, this is a new install.
+
+    If yes, check if the target machine type for setup is the same as the
+    machine type of the installed Cygwin DLL.  If yes, just go ahead.  If not,
+    show a message and indicate this to the caller.
+
+    If anything goes wrong reading the header of cygwin1.dll, we check
+    cygcheck.exe's binary type.  This also covers the situation that the
+    installed cygwin1.dll is broken for some reason.
+  */
+
+  std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
+  USHORT headerArch = read_fileheader_machine_type(cygwin_dll);
+
+  if (headerArch == IMAGE_FILE_MACHINE_UNKNOWN)
     {
-      DWORD type;
       std::string cygcheck_exe = get_root_dir() + "\\bin\\cygcheck.exe";
+      headerArch = read_fileheader_machine_type(cygcheck_exe);
 
-      /* Probably new installation */
-      if (!GetBinaryType (cygcheck_exe.c_str (), &type))
+      if (headerArch == IMAGE_FILE_MACHINE_UNKNOWN)
         {
+          /* No cygcheck either, probably a new installation */
           is_new_install = true;
           return 0;
         }
-      /* 64 bit setup and 64 bit inst? */
-      if (type == SCS_32BIT_BINARY && !is_64bit)
-       return 0;
-      /* 32 bit setup and 32 bit inst? */
-      if (type == SCS_64BIT_BINARY && is_64bit)
-       return 0;
     }
 
+  /* machine type matches */
+  if (headerArch == installArch)
+    return 0;
+
   /* Forestall mixing. */
-  const char *setup_ver = is_64bit ? "64" : "32";
-  const char *inst_ver = is_64bit ? "32" : "64";
-  mbox (h, IDS_MIXED_BITNESS_ERROR, MB_OK,
-        setup_ver, inst_ver, is_64bit ? "x86" : "x86_64", inst_ver, setup_ver);
+  const char *setup_ver = machine_name(installArch).c_str();
+  const char *inst_ver = machine_name(headerArch).c_str();
+  mbox (h, IDS_MIXED_BITNESS_ERROR, MB_OK, setup_ver, inst_ver, inst_ver,
+        inst_ver, setup_ver);
   return 1;
 }
 
diff --git a/script.cc b/script.cc
index f578ea6..fbc7e27 100644
--- a/script.cc
+++ b/script.cc
@@ -142,7 +142,7 @@ init_run_script ()
   SetEnvironmentVariable ("CYGWINFORALL",
                           (root_scope == IDC_ROOT_SYSTEM) ? "-A" : NULL);
 
-  const char *sms = startmenusuffix();
+  const char *sms = startmenusuffix().c_str();
   if (strlen(sms) > 0)
     SetEnvironmentVariable ("CYGWIN_START_MENU_SUFFIX", sms);
 
diff --git a/state.cc b/state.cc
index ef14116..7e07a59 100644
--- a/state.cc
+++ b/state.cc
@@ -30,8 +30,4 @@ int root_desktop;
 
 LANGID langid;
 
-#ifdef __x86_64__
-bool is_64bit = true;
-#else
-bool is_64bit = false;
-#endif
+USHORT installArch;
diff --git a/state.h b/state.h
index c4b88a4..9c0e706 100644
--- a/state.h
+++ b/state.h
@@ -48,6 +48,6 @@ extern int root_desktop;
 
 extern LANGID langid;
 
-extern bool is_64bit;
+extern USHORT installArch;
 
 #endif /* SETUP_STATE_H */
diff --git a/win32.cc b/win32.cc
index cd7fec5..eb709b1 100644
--- a/win32.cc
+++ b/win32.cc
@@ -21,6 +21,7 @@
 #include "ini.h"
 #include <sys/stat.h>
 #include "String++.h"
+#include <iomanip>
 
 NTSecurity nt_sec;
 
@@ -483,11 +484,11 @@ machine_name(USHORT machine)
       return "x86_64";
       break;
     case IMAGE_FILE_MACHINE_ARM64:
-      return "ARM64";
+      return "arm64";
       break;
     default:
       std::stringstream machine_desc;
-      machine_desc << std::hex << machine;
+      machine_desc << std::hex << std::setw(4) << std::setfill('0') << machine;
       return machine_desc.str();
     }
 }
-- 
2.45.1

Reply via email to