MetaCore/Apps/MetaCoreEditor/main.cpp
2026-06-02 09:19:17 +08:00

193 lines
6.0 KiB
C++

#include "MetaCoreEditor/MetaCoreEditorApp.h"
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <new>
#include <vector>
#if defined(_WIN32)
#include <crtdbg.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#else
#include <limits.h>
#include <unistd.h>
#endif
namespace {
std::filesystem::path MetaCoreGetExecutableDirectory() {
#if defined(_WIN32)
std::vector<wchar_t> buffer(MAX_PATH, L'\0');
while (true) {
const DWORD copied = GetModuleFileNameW(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()));
if (copied == 0) {
return {};
}
if (copied < buffer.size() - 1) {
return std::filesystem::path(std::wstring(buffer.data(), copied)).parent_path();
}
buffer.resize(buffer.size() * 2, L'\0');
}
#else
std::vector<char> buffer(PATH_MAX, '\0');
while (true) {
const ssize_t copied = readlink("/proc/self/exe", buffer.data(), buffer.size());
if (copied < 0) {
return {};
}
if (static_cast<std::size_t>(copied) < buffer.size()) {
return std::filesystem::path(std::string(buffer.data(), static_cast<std::size_t>(copied))).parent_path();
}
buffer.resize(buffer.size() * 2, '\0');
}
#endif
}
std::filesystem::path MetaCoreGetCrashLogPath() {
const std::filesystem::path executableDirectory = MetaCoreGetExecutableDirectory();
if (!executableDirectory.empty()) {
return executableDirectory / "editor.crash.log";
}
return "editor.crash.log";
}
void MetaCoreResetCrashLog() {
std::ofstream stream(MetaCoreGetCrashLogPath(), std::ios::trunc);
}
void MetaCoreWriteCrashLog(const std::string& message) {
std::ofstream stream(MetaCoreGetCrashLogPath(), std::ios::app);
if (!stream.is_open()) {
return;
}
stream << message << '\n';
}
void MetaCoreWriteCrashLogRaw(const char* message) {
if (message == nullptr) {
return;
}
FILE* file = nullptr;
const std::filesystem::path crashLogPath = MetaCoreGetCrashLogPath();
#if defined(_WIN32)
if (fopen_s(&file, crashLogPath.string().c_str(), "a") == 0 && file != nullptr) {
#else
file = std::fopen(crashLogPath.string().c_str(), "a");
if (file != nullptr) {
#endif
std::fputs(message, file);
std::fputs("\n", file);
std::fclose(file);
}
}
#if defined(_WIN32)
void MetaCoreInvalidParameterHandler(
const wchar_t* expression,
const wchar_t* functionName,
const wchar_t* fileName,
unsigned int line,
uintptr_t reserved
) {
(void)reserved;
MetaCoreWriteCrashLog("metacore.app: invalid parameter triggered");
if (expression != nullptr) {
MetaCoreWriteCrashLog("metacore.app: invalid parameter expression=<non-null>");
}
if (functionName != nullptr) {
MetaCoreWriteCrashLog("metacore.app: invalid parameter function=<non-null>");
}
if (fileName != nullptr) {
MetaCoreWriteCrashLog("metacore.app: invalid parameter file=<non-null>");
}
MetaCoreWriteCrashLog("metacore.app: invalid parameter line=" + std::to_string(line));
}
void MetaCorePureCallHandler() {
MetaCoreWriteCrashLog("metacore.app: purecall handler triggered");
}
#endif
void MetaCoreSignalHandler(int signalValue) {
MetaCoreWriteCrashLog("metacore.app: signal=" + std::to_string(signalValue));
}
void MetaCoreTerminateHandler() {
MetaCoreWriteCrashLog("metacore.app: std::terminate triggered");
if (std::exception_ptr exceptionPtr = std::current_exception(); exceptionPtr != nullptr) {
try {
std::rethrow_exception(exceptionPtr);
} catch (const std::exception& exceptionObject) {
MetaCoreWriteCrashLog(std::string("metacore.app: exception=") + exceptionObject.what());
} catch (...) {
MetaCoreWriteCrashLog("metacore.app: exception=<non-std exception>");
}
} else {
MetaCoreWriteCrashLog("metacore.app: exception=<none>");
}
std::_Exit(3);
}
void MetaCoreInstallDebugCrashHooks() {
#if defined(_WIN32) && defined(_DEBUG)
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_set_invalid_parameter_handler(&MetaCoreInvalidParameterHandler);
_set_purecall_handler(&MetaCorePureCallHandler);
std::set_terminate(&MetaCoreTerminateHandler);
std::signal(SIGABRT, &MetaCoreSignalHandler);
MetaCoreWriteCrashLog("metacore.app: debug crash hooks installed");
#endif
}
} // namespace
int main(int argc, char* argv[]) {
if (argc > 0) {
const std::filesystem::path executableDirectory = MetaCoreGetExecutableDirectory();
if (!executableDirectory.empty()) {
std::filesystem::current_path(executableDirectory);
}
}
MetaCoreResetCrashLog();
MetaCoreInstallDebugCrashHooks();
MetaCoreWriteCrashLogRaw("metacore.app: hooks installed");
MetaCoreWriteCrashLogRaw("metacore.app: set current_path done");
MetaCoreWriteCrashLogRaw("metacore.app: construct app begin");
MetaCore::MetaCoreEditorApp editorApp;
MetaCoreWriteCrashLogRaw("metacore.app: construct app done");
MetaCoreWriteCrashLogRaw("metacore.app: initialize begin");
if (!editorApp.Initialize(argc, argv)) {
MetaCoreWriteCrashLogRaw("metacore.app: initialize failed");
std::cerr << "MetaCoreEditorApp initialize failed\n";
return 1;
}
MetaCoreWriteCrashLogRaw("metacore.app: initialize done");
MetaCoreWriteCrashLogRaw("metacore.app: run begin");
const int exitCode = editorApp.Run();
MetaCoreWriteCrashLogRaw("metacore.app: run done");
editorApp.Shutdown();
MetaCoreWriteCrashLogRaw("metacore.app: shutdown done");
return exitCode;
}