mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-23 14:01:15 +02:00
5 files changed
+301
-6
No files matched your search
Generated
+61
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785627969,
|
||||
"narHash": "sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "427bf4bd9435fdf21321c8cc628c24efc14c0f7a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1787135253,
|
||||
"narHash": "sha256-RD2kNWCG+Bjo6h+JVjWVNntZs2GtRoeY2xHjts/FNkA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ffb3c9b700e759be2ef13237c9d8f953b32a1e46",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1785031560,
|
||||
"narHash": "sha256-OmshNvn2vupOFpYinLUu+1Dnpu4n7Q5N3ggGVNHpkUI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "0e79af5e3d4dcfcd676ab5ba3f95d2e3352e078c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
description = "Description for the project";
|
||||
|
||||
inputs = {
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
|
||||
];
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
# "aarch64-linux"
|
||||
# "aarch64-darwin"
|
||||
# "x86_64-darwin"
|
||||
];
|
||||
perSystem =
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
packages.default = pkgs.callPackage ./packaging/nix/package.nix { };
|
||||
};
|
||||
flake = { };
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
|
||||
cmake,
|
||||
git,
|
||||
lld,
|
||||
ninja,
|
||||
pkg-config,
|
||||
vulkan-headers,
|
||||
makeWrapper,
|
||||
|
||||
capstone,
|
||||
curl,
|
||||
fontconfig,
|
||||
glib,
|
||||
gtk4,
|
||||
hicolor-icon-theme,
|
||||
libadwaita,
|
||||
elfutils,
|
||||
libglvnd,
|
||||
libplacebo,
|
||||
libsoup_3,
|
||||
libutf8proc,
|
||||
libyaml,
|
||||
minizip,
|
||||
nlohmann_json,
|
||||
openssl,
|
||||
sdl3,
|
||||
sdl3-ttf,
|
||||
vulkan-loader,
|
||||
webkitgtk_6_0,
|
||||
zlib,
|
||||
}:
|
||||
let
|
||||
# submodules are not part of the flake source tree
|
||||
# so these two vendored dependencies are fetched from their pinned upstream revisions
|
||||
libjnivmSrc = fetchFromGitHub {
|
||||
owner = "ChristopherHX";
|
||||
repo = "libjnivm";
|
||||
rev = "f24b98c198fcc5c59a68d1efadd3f5791eb01c2e";
|
||||
hash = "sha256-K4+1Zo7AJIouIqnHn2ZE4GyrNrYOczmWYblLAnGYA5w=";
|
||||
};
|
||||
vulkanHeadersSrc = fetchFromGitHub {
|
||||
owner = "KhronosGroup";
|
||||
repo = "Vulkan-Headers";
|
||||
rev = "8d6039a455a7ecc7d2a592ff97f62db4e59b70bf";
|
||||
hash = "sha256-+llJlEdzFcmqGBAdKHjYhkwBuH19ZngavmF1TQgejsI=";
|
||||
};
|
||||
|
||||
src = ../..;
|
||||
|
||||
lines = lib.splitString "\n" (builtins.readFile (lib.path.append src "CMakeLists.txt"));
|
||||
|
||||
matches = map (builtins.match "[[:space:]]*VERSION[[:space:]]+([0-9][0-9.]*).*") lines;
|
||||
|
||||
match = lib.findFirst (m: m != null) null matches;
|
||||
|
||||
version =
|
||||
if match == null then throw "could not find VERSION in CMakeLists.txt" else builtins.elemAt match 0;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "mocktail";
|
||||
inherit version;
|
||||
inherit src;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
git
|
||||
lld
|
||||
ninja
|
||||
pkg-config
|
||||
vulkan-headers
|
||||
makeWrapper
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
capstone
|
||||
curl
|
||||
fontconfig
|
||||
glib
|
||||
gtk4
|
||||
hicolor-icon-theme
|
||||
libadwaita
|
||||
elfutils
|
||||
libglvnd
|
||||
libplacebo
|
||||
libsoup_3
|
||||
libutf8proc
|
||||
libyaml
|
||||
minizip
|
||||
nlohmann_json
|
||||
openssl
|
||||
sdl3
|
||||
sdl3-ttf
|
||||
vulkan-loader
|
||||
webkitgtk_6_0
|
||||
zlib
|
||||
];
|
||||
|
||||
preConfigure = ''
|
||||
rm -rf third_party/libjnivm third_party/Vulkan-Headers
|
||||
cp -r --no-preserve=mode ${libjnivmSrc} third_party/libjnivm
|
||||
cp -r --no-preserve=mode ${vulkanHeadersSrc} third_party/Vulkan-Headers
|
||||
'';
|
||||
|
||||
# nixpkgs installs the header we need under include/libutf8proc
|
||||
NIX_CFLAGS_COMPILE = "-I${libutf8proc}/include/libutf8proc";
|
||||
|
||||
cmakeFlags = [
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_INSTALL_LIBDIR=lib"
|
||||
"-DMOCKTAIL_DEFAULT_COMPATIBILITY_MANIFEST=${placeholder "out"}/share/mocktail/metadata/roblox_compatibility.json"
|
||||
"-DMOCKTAIL_DEFAULT_SIGNING_TRUST_MANIFEST=${placeholder "out"}/share/mocktail/metadata/roblox_signing_certificates.json"
|
||||
"-DBUILD_TESTING=OFF"
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
for binary in $out/bin/*; do
|
||||
wrapProgram "$binary" --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath finalAttrs.buildInputs}
|
||||
done
|
||||
'';
|
||||
|
||||
fixupPhase = ''
|
||||
install -Dm644 ${finalAttrs.src}/LICENSE "$out/share/licenses/${finalAttrs.pname}/LICENSE"
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Android x86-64 Roblox compatibility runtime for Linux";
|
||||
homepage = "https://github.com/komaruworld/mocktail";
|
||||
license = licenses.asl20;
|
||||
platforms = platforms.unix;
|
||||
mainProgram = "mocktail";
|
||||
};
|
||||
})
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <csignal>
|
||||
@@ -2651,6 +2652,29 @@ struct SymbolResolveResult {
|
||||
SymbolResolveSource source = SymbolResolveSource::kMissing;
|
||||
};
|
||||
|
||||
// dlsym searches the object and its dependency chain, so a
|
||||
// stub that transitively links SDL or another host library would
|
||||
// satisfy EGL/GL/Vulkan lookups with unrelated host symbols
|
||||
//
|
||||
// So, we should only accept the symbol if its stub owns it.
|
||||
bool StubOwnsSymbolAddress(void* handle, void* address) {
|
||||
if (handle == nullptr || address == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Dl_info info = {};
|
||||
if (::dladdr(address, &info) == 0 || info.dli_fbase == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
link_map* map = nullptr;
|
||||
if (::dlinfo(handle, RTLD_DI_LINKMAP, &map) != 0 || map == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return reinterpret_cast<void*>(map->l_addr) == info.dli_fbase;
|
||||
}
|
||||
|
||||
SymbolResolveResult ResolveSymbolForBionic(const char* name, bool has_window,
|
||||
void* real_gles_handle,
|
||||
const std::vector<void*>& stub_handles) {
|
||||
@@ -2677,8 +2701,8 @@ SymbolResolveResult ResolveSymbolForBionic(const char* name, bool has_window,
|
||||
}
|
||||
|
||||
for (void* h : stub_handles) {
|
||||
result.address = ::dlsym(h, name);
|
||||
if (result.address != nullptr) {
|
||||
if (void *candidate = ::dlsym(h, name); candidate != nullptr && StubOwnsSymbolAddress(h, candidate)) {
|
||||
result.address = candidate;
|
||||
result.source = SymbolResolveSource::kStub;
|
||||
return result;
|
||||
}
|
||||
@@ -30398,6 +30422,32 @@ void* DelayedSendGameLoadedThread(void* arg) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Resolve the exact Android Vulkan loader adapter shipped next to this
|
||||
// runtime binary. Never resolve it by SONAME: an unversioned host
|
||||
// libvulkan.so on the search path (for example distribution or Nix wrappers)
|
||||
// would win, silently drop VK_KHR_android_surface support, and break
|
||||
// direct-Vulkan mode with "Unable to create Vulkan instance".
|
||||
static std::string RuntimeVulkanAdapterPath() {
|
||||
const char* override_dir = std::getenv("MOCKTAIL_RUNTIME_LIBRARY_DIR");
|
||||
std::string directory;
|
||||
if (override_dir != nullptr && override_dir[0] != '\0') {
|
||||
directory = override_dir;
|
||||
} else {
|
||||
char executable_path[4097] = {};
|
||||
const ssize_t length =
|
||||
::readlink("/proc/self/exe", executable_path,
|
||||
sizeof(executable_path) - 1U);
|
||||
if (length <= 0) return {};
|
||||
executable_path[length] = '\0';
|
||||
std::string path(executable_path);
|
||||
const std::string::size_type separator = path.find_last_of('/');
|
||||
if (separator == std::string::npos) return {};
|
||||
directory = separator == 0 ? "/" : path.substr(0, separator);
|
||||
}
|
||||
if (directory.empty()) return {};
|
||||
return directory + "/libvulkan.so";
|
||||
}
|
||||
|
||||
void* EngineStartupThread(void* arg) {
|
||||
auto* context = static_cast<EngineStartupContext*>(arg);
|
||||
if (context == nullptr) {
|
||||
@@ -32267,17 +32317,25 @@ int mocktail::legacy::Run(const runtime::CommandLineOptions& options,
|
||||
void* bionic_vulkan_adapter_handle = nullptr;
|
||||
for (const char* name : stub_names) {
|
||||
void* h = nullptr;
|
||||
bool exact_adapter = false;
|
||||
if (std::strcmp(name, "libEGL.so") == 0 &&
|
||||
bionic_egl_bridge.IsLoaded()) {
|
||||
h = bionic_egl_bridge.handle();
|
||||
} else {
|
||||
exact_adapter = true;
|
||||
} else if (std::strcmp(name, "libvulkan.so") == 0) {
|
||||
const std::string vulkan_adapter = RuntimeVulkanAdapterPath();
|
||||
if (!vulkan_adapter.empty()) {
|
||||
h = ::dlopen(vulkan_adapter.c_str(), RTLD_LAZY | RTLD_GLOBAL);
|
||||
exact_adapter = h != nullptr;
|
||||
}
|
||||
}
|
||||
if (h == nullptr) {
|
||||
h = ::dlopen(name, RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
|
||||
if (!h) h = ::dlopen(name, RTLD_LAZY | RTLD_GLOBAL);
|
||||
}
|
||||
if (h) {
|
||||
std::cout << " [stubs] Preloaded " << name;
|
||||
if (std::strcmp(name, "libEGL.so") == 0 &&
|
||||
bionic_egl_bridge.IsLoaded()) {
|
||||
if (exact_adapter) {
|
||||
std::cout << " via exact Mocktail adapter";
|
||||
}
|
||||
std::cout << '\n';
|
||||
@@ -32806,7 +32864,8 @@ int mocktail::legacy::Run(const runtime::CommandLineOptions& options,
|
||||
size_t vulkan_exports = 0;
|
||||
for (const char* name : kVulkanAdapterExports) {
|
||||
void* address = ::dlsym(bionic_vulkan_adapter_handle, name);
|
||||
if (address == nullptr) {
|
||||
if (address == nullptr ||
|
||||
!StubOwnsSymbolAddress(bionic_vulkan_adapter_handle, address)) {
|
||||
continue;
|
||||
}
|
||||
linker::RegisterSyntheticSymbol("libvulkan.so", name, address);
|
||||
|
||||
@@ -318,6 +318,14 @@ CanaryResult RunReadinessCanary(const CanaryOptions& options) {
|
||||
"__NV_PRIME_RENDER_OFFLOAD",
|
||||
"__VK_LAYER_NV_optimus",
|
||||
"__GLX_VENDOR_LIBRARY_NAME",
|
||||
// Dynamic-library search state and graphics library overrides
|
||||
// must reach the isolated runtime so that distributions which
|
||||
// resolve shared libraries through the launcher environment
|
||||
// (for example NixOS wrappers) still find libGLESv2/libEGL.
|
||||
"LD_LIBRARY_PATH",
|
||||
"MOCKTAIL_EGL_LIBRARY",
|
||||
"MOCKTAIL_GLES_LIBRARY",
|
||||
"MOCKTAIL_ANGLE_LIB_DIR",
|
||||
}) {
|
||||
AddInherited(name, &environment);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user