macOS (Apple silicon and Intel): Fry3DX.app with its content in Resources and MoltenVK in Frameworks, OpenGL 4.1 when there's no Vulkan; the program's own path, memory, OS and CPU names on a Mac; files dropped on the window (and opened from the Finder) open; presets macos-arm64/macos-x64, a CI job, tools/package.py macos makes one universal app

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-20 17:36:24 +02:00
commit e22cd2e3e6
15 changed files with 273 additions and 40 deletions

View file

@ -2,6 +2,7 @@
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <thread>
@ -15,6 +16,11 @@
#include <sys/utsname.h>
#include <unistd.h>
#endif
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#include <mach/mach.h>
#include <sys/sysctl.h>
#endif
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__x86_64__) || defined(__i386__)
@ -30,6 +36,14 @@ std::string trim(std::string s) {
return s.substr(i);
}
#if defined(__APPLE__)
std::string sysctlText(const char* name) {
char buf[256] = {};
size_t size = sizeof buf - 1;
return sysctlbyname(name, buf, &size, nullptr, 0) == 0 ? trim(buf) : std::string();
}
#endif
// The CPU's own name for itself (x86: cpuid's brand string; elsewhere /proc/cpuinfo).
std::string cpuName() {
#if defined(_MSC_VER) || defined(__x86_64__) || defined(__i386__)
@ -46,6 +60,9 @@ std::string cpuName() {
char brand[49] = {};
std::memcpy(brand, regs, 48);
if (brand[0]) return trim(brand);
#endif
#if defined(__APPLE__)
if (std::string s = sysctlText("machdep.cpu.brand_string"); !s.empty()) return s; // ("Apple M2 Pro" too)
#endif
std::ifstream in("/proc/cpuinfo");
for (std::string line; std::getline(in, line);)
@ -64,6 +81,11 @@ std::string osName() {
fn(&v);
const char* name = v.dwMajorVersion == 10 ? (v.dwBuildNumber >= 22000 ? "Windows 11" : "Windows 10") : "Windows";
return std::string(name) + " (build " + std::to_string(v.dwBuildNumber) + ")";
#elif defined(__APPLE__)
utsname u{};
uname(&u);
const std::string v = sysctlText("kern.osproductversion");
return "macOS " + (v.empty() ? std::string("?") : v) + " (" + u.machine + ")";
#else
utsname u{};
uname(&u);
@ -95,6 +117,19 @@ Memory memory() {
if (GlobalMemoryStatusEx(&s)) m.total = s.ullTotalPhys, m.used = s.ullTotalPhys - s.ullAvailPhys;
PROCESS_MEMORY_COUNTERS pmc{sizeof pmc};
if (K32GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof pmc)) m.ours = pmc.WorkingSetSize;
#elif defined(__APPLE__)
uint64_t total = 0;
size_t size = sizeof total;
if (sysctlbyname("hw.memsize", &total, &size, nullptr, 0) == 0) m.total = total;
vm_statistics64_data_t vm{};
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, reinterpret_cast<host_info64_t>(&vm), &count) == KERN_SUCCESS) {
const uint64_t page = uint64_t(sysconf(_SC_PAGESIZE)); // (used as Activity Monitor counts it: in use by apps, wired, compressed)
m.used = (uint64_t(vm.internal_page_count) - vm.purgeable_count + vm.wire_count + vm.compressor_page_count) * page;
}
mach_task_basic_info_data_t task{};
mach_msg_type_number_t taskCount = MACH_TASK_BASIC_INFO_COUNT;
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, reinterpret_cast<task_info_t>(&task), &taskCount) == KERN_SUCCESS) m.ours = task.resident_size;
#else
uint64_t available = 0;
std::ifstream in("/proc/meminfo");
@ -114,4 +149,39 @@ Memory memory() {
return m;
}
std::string executablePath() {
#if defined(_WIN32)
char exe[1024] = {};
GetModuleFileNameA(nullptr, exe, sizeof exe);
return exe;
#elif defined(__APPLE__)
char exe[4096] = {};
uint32_t size = sizeof exe;
if (_NSGetExecutablePath(exe, &size) != 0) return {};
std::error_code ec;
const auto real = std::filesystem::canonical(exe, ec);
return ec ? std::string(exe) : real.string();
#else
std::error_code ec;
const auto p = std::filesystem::read_symlink("/proc/self/exe", ec);
return ec ? std::string() : p.string();
#endif
}
bool debuggerAttached() {
#if defined(_WIN32)
return IsDebuggerPresent();
#elif defined(__APPLE__)
kinfo_proc info{};
size_t size = sizeof info;
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
return sysctl(mib, 4, &info, &size, nullptr, 0) == 0 && (info.kp_proc.p_flag & P_TRACED) != 0;
#else
std::ifstream f("/proc/self/status");
for (std::string line; std::getline(f, line);)
if (line.rfind("TracerPid:", 0) == 0) return std::atoi(line.c_str() + 10) != 0;
return false;
#endif
}
} // namespace keel::sys