1 module arch;
2 
3 
4 // Supported OS + arch combination
5 
6 import std.process;
7 import std.string;
8 
9 public:
10 
11 enum Arch
12 {
13     windows_x86,
14     windows_x86_64,
15     mac_x86_64,
16     mac_arm64,
17     mac_UB,
18     linux_x86_64
19 }
20 
21 
22 Arch detectArch(const(char)[] pluginPath)
23 {
24     static bool detectPEBitness(const(char)[] pluginPath) // true if 64-bit, false else
25     {
26         import std.stdio;
27         File f = File(pluginPath, "rb");
28         f.seek(0x3c);
29 
30         short[1] bufOffset;
31         short[] offset = f.rawRead(bufOffset[]);
32 
33         f.seek(offset[0]);
34 
35         ubyte[6] buf;
36         ubyte[] flag = f.rawRead(buf[]);
37 
38         if (flag[] == "PE\x00\x00\x4C\x01")
39             return false;
40         else if (flag[] == "PE\x00\x00\x64\x86")
41             return true;
42         else
43             throw new Exception("Couldn't parse file as PE");
44     }
45 
46     version(Windows)
47     {
48         // check if PE file and if so which arch
49         try
50         {
51             if (detectPEBitness(pluginPath))
52                 return Arch.windows_x86_64;
53             else
54                 return Arch.windows_x86;
55         }
56         catch(Exception e)
57         {
58         	throw new Exception("Unsupported OS/arch combination in bench, please modify the bench tool");
59         }
60     }
61     else version(OSX)
62     {
63         // run a `file` command
64         auto fileResult = executeShell(escapeShellCommand("file", pluginPath));
65         if (fileResult.status != 0) throw new Exception("file command failed");
66 
67         bool has_x86_64 = indexOf(fileResult.output, "Mach-O 64-bit dynamically linked shared library x86_64") != -1;
68         bool has_arm64  = indexOf(fileResult.output, "Mach-O 64-bit dynamically linked shared library arm64") != -1;
69 
70         if ( has_x86_64 && !has_arm64) return Arch.mac_x86_64;
71         if (!has_x86_64 &&  has_arm64) return Arch.mac_arm64;
72         if ( has_x86_64 &&  has_arm64) return Arch.mac_UB;
73         throw new Exception("Unsupported arch combination in bench, please modify the bench tool");
74     }
75     else version(linux)
76     {
77         auto fileResult = executeShell(escapeShellCommand("file", pluginPath));
78         if (fileResult.status != 0) throw new Exception("file command failed");
79         bool has_x86_64 = indexOf(fileResult.output, "x86_64") != -1;
80         if (has_x86_64) return Arch.linux_x86_64;
81         throw new Exception("Unsupported arch combination in bench, please modify the bench tool");
82     }
83     else
84         throw new Exception("Unsupported OS/arch combination in bench, please modify the bench tool");
85 }
86 
87 
88 string archName(Arch arch)
89 {
90     final switch(arch) with(Arch)
91     {
92         case windows_x86:    return "x86";
93         case windows_x86_64: return "x86_64";
94         case mac_x86_64:     return "x86_64";
95         case mac_arm64:      return "arm64";
96         case mac_UB:         return "Universal Binary";
97         case linux_x86_64:   return "x86_64";
98     }
99 }
100 
101 
102 // bench tool assume naming conventions for the `process` executable:
103 //
104 // On Windows, process.exe    exists for x86    VST 2.4
105 //             process64.exe  exists for x86_64 VST 2.4
106 //
107 // On macOS,   process-x86_64 exists for x86_64 VST 2.4
108 //             process-arm64  exists for x86_64 VST 2.4
109 //
110 // This is necessary in order to compare plugins between different architectures.
111 string processExecutablePathForThisArch(Arch arch)
112 {
113     final switch(arch) with(Arch)
114     {
115         case windows_x86:    return "process.exe";
116         case windows_x86_64: return "process64.exe";
117         case mac_x86_64:     return "process-x86_64";
118         case mac_arm64:      return "process-arm64";
119         case mac_UB:         return "process-arm64"; // Can use any, so might as well take the fastest option
120         case linux_x86_64:   return "process";
121     }
122 }
123 
124 private: