[yabridgectl] Determine libyabridge-vst3.so arch

We're going to need this for supporting merged VST3 bundles with a
32-bit libyabridge-vst3.so.
This commit is contained in:
Robbert van der Helm
2021-06-24 15:23:41 +02:00
parent 3e0a2dc913
commit b521debbb7
3 changed files with 59 additions and 10 deletions
+4 -4
View File
@@ -108,7 +108,7 @@ pub fn show_status(config: &Config) -> Result<()> {
"libyabridge-vst3.so: {}\n",
files
.libyabridge_vst3
.map(|path| format!("'{}'", path.display()))
.map(|(path, arch)| format!("'{}' ({})", path.display(), arch))
.unwrap_or_else(|| "<not found>".red().to_string())
);
}
@@ -204,11 +204,11 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
let files: YabridgeFiles = config.files()?;
let libyabridge_vst2_hash = utils::hash_file(&files.libyabridge_vst2)?;
let libyabridge_vst3_hash = match &files.libyabridge_vst3 {
Some(path) => Some(utils::hash_file(path)?),
Some((path, _)) => Some(utils::hash_file(path)?),
None => None,
};
if let Some(libyabridge_vst3_path) = &files.libyabridge_vst3 {
if let Some((libyabridge_vst3_path, _)) = &files.libyabridge_vst3 {
println!("Setting up VST2 and VST3 plugins using:");
println!("- {}", files.libyabridge_vst2.display());
println!("- {}\n", libyabridge_vst3_path.display());
@@ -308,7 +308,7 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
if install_file(
options.force,
config.method,
files.libyabridge_vst3.as_ref().unwrap(),
&files.libyabridge_vst3.as_ref().unwrap().0,
libyabridge_vst3_hash,
&native_module_path,
)? || *updated_libyabridge
+17 -4
View File
@@ -27,7 +27,8 @@ use std::path::{Path, PathBuf};
use which::which;
use xdg::BaseDirectories;
use crate::files::{self, SearchResults};
use crate::files::{self, LibArchitecture, SearchResults};
use crate::utils;
/// The name of the config file, relative to `$XDG_CONFIG_HOME/YABRIDGECTL_PREFIX`.
pub const CONFIG_FILE_NAME: &str = "config.toml";
@@ -143,8 +144,9 @@ pub struct YabridgeFiles {
/// The path to `libyabridge-vst2.so` we should use.
pub libyabridge_vst2: PathBuf,
/// The path to `libyabridge-vst3.so` we should use, if yabridge has been compiled with VST3
/// support.
pub libyabridge_vst3: Option<PathBuf>,
/// support. We need to know if it's a 32-bit or a 64-bit library so we can properly set up the
/// merged VST3 bundles.
pub libyabridge_vst3: Option<(PathBuf, LibArchitecture)>,
/// The path to `yabridge-host.exe`. This is the path yabridge will actually use, and it does
/// not have to be relative to `yabridge_home`.
pub yabridge_host_exe: PathBuf,
@@ -260,7 +262,18 @@ impl Config {
// Based on that we can check if `libyabridge-vst3.so` exists, since yabridge can be
// compiled without VST3 support
let libyabridge_vst3 = match libyabridge_vst2.with_file_name(LIBYABRIDGE_VST3_NAME) {
path if path.exists() => Some(path),
path if path.exists() => {
// We need to know `libyabridge-vst3.so`'s architecture to be able to set up the
// bundle properly
let arch = utils::get_elf_architecture(&path).with_context(|| {
format!(
"Could not determine ELF architecture for '{}'",
path.display()
)
})?;
Some((path, arch))
}
_ => None,
};
+38 -2
View File
@@ -16,13 +16,14 @@
//! Small helper utilities.
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use colored::Colorize;
use is_executable::IsExecutable;
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs;
use std::hash::Hasher;
use std::io::{Read, Seek, SeekFrom};
use std::os::unix::fs as unix_fs;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
@@ -30,7 +31,7 @@ use std::process::{Command, Stdio};
use textwrap::Wrapper;
use crate::config::{self, Config, KnownConfig, YABRIDGE_HOST_EXE_NAME};
use crate::files::NativeFile;
use crate::files::{LibArchitecture, NativeFile};
/// (Part of) the expected output when running `yabridge-host.exe`. Used to verify that everything's
/// working correctly. We'll only match this prefix so we can modify the exact output at a later
@@ -86,6 +87,41 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
})
}
/// Get the architecture of the ELF file at `path`. This detection is a bit naive, but we'd rather
/// not depend on `libmagic` or `libreadelf` just for this, since encountering a 32-bit yabridge
/// library is going to be incredibly rare.
///
/// This is based on this file header specification:
/// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
pub fn get_elf_architecture(path: &Path) -> Result<LibArchitecture> {
// We'll assume `path` points to an ELF file and immediately skip to the good stuff
let mut file = fs::File::open(path)?;
// I doubt yabridge will ever run on a Big-Endian machine until audio production on Windows on
// ARM also becomes big, but we still need to account for this
let little_endian = {
let mut endianness_bytes = [0u8; 1];
file.seek(SeekFrom::Start(0x05))?; // e_ident[EI_DATA], 1 byte
file.read_exact(&mut endianness_bytes)?;
endianness_bytes[0] == 1
};
let mut machine_arch_bytes = [0u8; 2];
file.seek(SeekFrom::Start(0x12))?; // e_machine, 2 bytes
file.read_exact(&mut machine_arch_bytes)?;
let machine_arch = if little_endian {
u16::from_le_bytes(machine_arch_bytes)
} else {
u16::from_be_bytes(machine_arch_bytes)
};
match machine_arch {
0x03 => Ok(LibArchitecture::Lib32), // x86
0x3E => Ok(LibArchitecture::Lib64), // AMD x86-64
_ => Err(anyhow!("'{}' is not a recognized ELF machine ISA")),
}
}
/// Get the type of a file, if it exists.
pub fn get_file_type(path: PathBuf) -> Option<NativeFile> {
match path.symlink_metadata() {