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: