mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Yeah so this adds libogg, libvorbis, and libopus to the Rust library on the client. This is intended for use by the client soon-ish to replace .NET ogg vorbis implementations and add opus support. This turns out to be a huge pain thanks to https://github.com/rust-lang/rfcs/issues/2771 . To solve this I ended up compiling the projects as staticlib and creating a build.py script to invoke the linker. This sucks a *lot* and I have yet to write the linker invocations for Linux/Windows, but it's probably the best option we have.
120 lines
3.6 KiB
Python
Executable File
120 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
#
|
|
# This helper exists SOLELY to work around https://github.com/rust-lang/rfcs/issues/2771
|
|
# Instead of compiling our libs directly to a cdylib, we compile them to a staticlib
|
|
# and link manually. This is cool and all, except that's a lot of work.
|
|
# And involves three platform-specific linkers. *sigh*
|
|
#
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import platform
|
|
import shlex
|
|
import tempfile
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
@dataclass
|
|
class LinkerData:
|
|
out_file: str
|
|
inputs: list[str] = field(default_factory=list)
|
|
libs: list[str] = field(default_factory=list)
|
|
lib_search_paths: list[str] = field(default_factory=list)
|
|
pkg_config_libs: list[str] = field(default_factory=list)
|
|
export_symbols: list[str] = field(default_factory=list)
|
|
|
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--release", action="store_true")
|
|
|
|
args = parser.parse_args()
|
|
cmd = ["cargo", "build", "-p", "robust-native-server", "-p", "robust-native-client"]
|
|
if args.release:
|
|
cmd.append("--release")
|
|
|
|
subprocess.run(cmd, check=True)
|
|
|
|
target_dir = os.path.join("target", "debug")
|
|
if args.release:
|
|
target_dir = os.path.join("target", "release")
|
|
|
|
link(LinkerData(
|
|
out_file=os.path.join(target_dir, platform_dylib_name("robust_native_client")),
|
|
inputs=[os.path.join(target_dir, platform_staticlib_name("robust_native_client"))],
|
|
pkg_config_libs=["ogg", "opus", "vorbis"],
|
|
export_symbols=read_symbols_def("ogg")
|
|
+ read_symbols_def("vorbis")
|
|
+ read_symbols_def("opus")
|
|
+ read_symbols_def("client")))
|
|
|
|
link(LinkerData(
|
|
out_file=os.path.join(target_dir, platform_dylib_name("robust_native_server")),
|
|
inputs=[os.path.join(target_dir, platform_staticlib_name("robust_native_server"))]))
|
|
|
|
def link(data: LinkerData):
|
|
system = platform.system()
|
|
if system == "Darwin":
|
|
link_macos(data)
|
|
else:
|
|
raise NotImplementedError()
|
|
|
|
#
|
|
# Per-platform linker invocations are mostly inspired by what rustc does
|
|
#
|
|
|
|
def link_macos(data: LinkerData):
|
|
symbol_list_file = tempfile.NamedTemporaryFile("w+")
|
|
symbol_list_file.writelines((f"_{n.strip()}\n" for n in data.export_symbols))
|
|
symbol_list_file.flush()
|
|
|
|
# Todo: crosscompile
|
|
args = [
|
|
"cc",
|
|
"-Wl,-exported_symbols_list",
|
|
f"-Wl,{symbol_list_file.name}",
|
|
"-arch", "arm64",
|
|
"-nodefaultlibs",
|
|
"-Wl,-dead_strip",
|
|
"-mmacosx-version-min=11.0.0",
|
|
"-dynamiclib",
|
|
"-o", data.out_file,
|
|
"-liconv", "-lSystem", "-lc", "-lm"
|
|
] + get_pkg_config_linker_flags(data.pkg_config_libs) + data.inputs
|
|
|
|
args.extend(("-L" + p for p in data.lib_search_paths))
|
|
args.extend(("-l" + l for l in data.libs))
|
|
|
|
subprocess.run(args, check=True)
|
|
|
|
def get_pkg_config_linker_flags(names: list[str]) -> list[str]:
|
|
if not names:
|
|
return []
|
|
|
|
result = subprocess.run(["pkg-config", "--libs"] + names, check=True, stdout=subprocess.PIPE)
|
|
return shlex.split(result.stdout.decode("utf-8"))
|
|
|
|
def read_symbols_def(name: str) -> list[str]:
|
|
with open(os.path.join("symbols", name + ".txt"), "r") as f:
|
|
return [line.strip() for line in f.readlines() if not line.startswith("#")]
|
|
|
|
def platform_staticlib_name(name: str) -> str:
|
|
if platform.system() == "Windows":
|
|
return name + ".lib"
|
|
|
|
return f"lib{name}.a"
|
|
|
|
def platform_dylib_name(name: str) -> str:
|
|
if platform.system() == "Windows":
|
|
return name + ".dll"
|
|
|
|
if platform.system() == "Darwin":
|
|
return f"lib{name}.dylib"
|
|
|
|
return f"lib{name}.so"
|
|
|
|
main()
|