Always search for host in ~/.local/share/yabridge

This commit is contained in:
Robbert van der Helm
2020-11-20 02:20:41 +01:00
parent abb2206970
commit c69037b649
9 changed files with 122 additions and 45 deletions
+6
View File
@@ -8,6 +8,12 @@ Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Changed
- Yabridge will now always search for `yabridge-host.exe` in
`~/.local/share/yabridge`, even if that directory is not in the search path.
This should make setup easier.
### Fixed
- Fixed an issue where _Renoise_ would show an error message when trying to load
+20 -24
View File
@@ -83,12 +83,12 @@ or by running `yabridgectl --help`.
First, yabridgectl needs to know where it can find yabridge's files. If you have
downloaded the prebuilt binaries, then you can simply extract the archive to
`~/.local/share` and yabridgectl will pick up the files in
`~/.local/share/yabridge` automatically[\*](#why-local-share-yabridge). You also
won't have to do any additional work if you're using one of the AUR packages. If
you have compiled yabridge from source or if you installed the files to some
other location, then you can use `yabridgectl set --path=<path>` to tell
yabridgectl where it can find the files.
`~/.local/share` and both yabridge and yabridgectl will pick up the files in
`~/.local/share/yabridge` automatically. You also won't have to do any
additional work if you're using one of the AUR packages. If you have compiled
yabridge from source or if you installed the files to some other location, then
you can use `yabridgectl set --path=<path>` to tell yabridgectl where it can
find the files.
Secondly, yabridgectl will default to the copy-based installation method. If you
are using a VST host with individually sandboxed plugins such as Bitwig Studio
@@ -107,16 +107,6 @@ tell your VST host to search for plugins in the directories you just added and
you'll be good to go. _Don't forget to rerun `yabridgectl sync` whenever you
update yabridge if you are using the copy-based installation method._
<sup id="why-local-share-yabridge">
*Instead of copying yabridge's files to <code>~/.local/share</code>, it would
also be possible to install yabridge to <code>/usr/local/bin</code> and
<code>/usr/local/lib</code>. While this does avoid the need to modify your
<code>PATH</code> environment variable when using the copy-based installation
method, it could also cause other issues if you're not careful. This is why
it's recommended to install yabridge to your home directory if you're not
using one of the AUR packages.
</sup>
### Manual setup
To set up yabridge without using yabridgectl, first download and extract
@@ -143,15 +133,21 @@ update yabridge.
### Search path setup
If you're using the _copy-based_ installation method and you're not using any of
the AUR packages, then you may have to modify your _login shell_'s `PATH`
environment variable so that yabridge is able to find the files in the directory
you've extracted yabridge's files to. Yabridgectl will automatically check
whether this is set up correctly when you run `yabridgectl sync`, and it will
show a warning if it detects any issues. _If you do not see such a warning after
running `yabridgectl sync`, then you can skip this section._
This section is only relevant if you're using the _copy-based_ installation
method and your yabridge files are located somewhere other than in
`~/.local/share/yabridge`. If you're using one of the AUR packages then you can
also skip this section.
To do this, you'll want to add yabridge's installation directory to your login
Yabridge needs to know where it can find `yabridge-host.exe`. By default
yabridge will search your through search path as well as in
`~/.local/share/yabridge` if that exists. When loading yabridge from a
non-standard location, such as when building from source, you may have to modify
your _login shell_'s `PATH` environment variable so that yabridge is able to
find its files. Yabridgectl will automatically check whether this is set up
correctly when you run `yabridgectl sync`, and it will show a warning if it
detects any issues. _If you do not see such a warning after running `yabridgectl sync`, then you can skip this section._
To set this, you'll want to add yabridge's installation directory to your login
shell's `PATH` environment variable. If you're unsure what your login shell is,
then you can open a terminal and run `echo $SHELL` to find out. For the below
examples I'll assume you're using the default installation location at
+16 -1
View File
@@ -118,7 +118,8 @@ fs::path find_vst_host(PluginArchitecture plugin_arch, bool use_plugin_groups) {
// Boost will return an empty path if the file could not be found in the
// search path
const fs::path vst_host_path = bp::search_path(host_name);
const fs::path vst_host_path =
bp::search_path(host_name, get_modified_search_path());
if (vst_host_path == "") {
throw std::runtime_error("Could not locate '" + std::string(host_name) +
"'");
@@ -176,6 +177,20 @@ boost::filesystem::path generate_group_endpoint(
return get_temporary_directory() / socket_name.str();
}
std::vector<boost::filesystem::path> get_modified_search_path() {
std::vector<boost::filesystem::path> search_path =
boost::this_process::path();
const bp::environment environment = boost::this_process::environment();
if (auto home_directory = environment.find("HOME");
home_directory != environment.end()) {
search_path.push_back(fs::path(home_directory->to_string()) / ".local" /
"share" / "yabridge");
}
return search_path;
}
fs::path get_this_file_location() {
// HACK: Not sure why, but `boost::dll::this_line_location()` returns a path
// starting with a double slash on some systems. I've seen this happen
+12 -1
View File
@@ -80,7 +80,8 @@ PluginArchitecture find_vst_architecture(boost::filesystem::path);
* when developing, as you can simply symlink the the libyabridge.so
* file in the build directory without having to install anything to
* /usr.
* 2. In the regular search path.
* 2. In the regular search path, augmented with `~/.local/share/yabridge` to
* ease the setup process.
*
* @param plugin_arch The architecture of the plugin, either 64-bit or 32-bit.
* Used to determine which host application to use, if available.
@@ -143,6 +144,16 @@ boost::filesystem::path generate_group_endpoint(
const boost::filesystem::path& wine_prefix,
const PluginArchitecture architecture);
/**
* Return the search path as defined in `$PATH`, with `~/.local/share/yabridge`
* appended to the end. I'd rather not do this since more magic makes things
* harder to comprehend, but I can understand that modifying your login shell's
* `PATH` environment variable can be a big hurdle if you've never done anything
* like that before. And since this is the recommended installation location, it
* makes sense to also search there by default.
*/
std::vector<boost::filesystem::path> get_modified_search_path();
/**
* Return a path to this `.so` file. This can be used to find out from where
* this link to or copy of `libyabridge.so` was loaded.
+10
View File
@@ -242,6 +242,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "is_executable"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@@ -704,6 +713,7 @@ dependencies = [
"anyhow",
"clap",
"colored",
"is_executable",
"lazy_static",
"promptly",
"rayon",
+3 -2
View File
@@ -10,10 +10,11 @@ repository = "https://github.com/robbert-vdh/yabridge"
license = "GPL-3.0-or-later"
[dependencies]
anyhow = "1.0.31"
aho-corasick = "0.7.13"
colored = "2.0.0"
anyhow = "1.0.31"
clap = { version = "3.0.0-beta.1", features = ["wrap_help"] }
colored = "2.0.0"
is_executable = "0.1.2"
lazy_static = "1.4.0"
promptly = "0.3.0"
rayon = "1.3.1"
+7 -7
View File
@@ -29,15 +29,15 @@ use xdg::BaseDirectories;
use crate::files::{self, SearchResults};
/// The name of the config file, relative to `$XDG_CONFIG_HOME/CONFIG_PREFIX`.
const CONFIG_FILE_NAME: &str = "config.toml";
pub const CONFIG_FILE_NAME: &str = "config.toml";
/// The name of the XDG base directory prefix for yabridgectl, relative to `$XDG_CONFIG_HOME` and
/// `$XDG_DATA_HOME`.
const YABRIDGECTL_PREFIX: &str = "yabridgectl";
/// The name of the library file we're searching for.
const LIBYABRIDGE_NAME: &str = "libyabridge.so";
pub const LIBYABRIDGE_NAME: &str = "libyabridge.so";
/// The name of the script we're going to run to verify that everything's working correctly.
const YABRIDGE_HOST_EXE_NAME: &str = "yabridge-host.exe";
pub const YABRIDGE_HOST_EXE_NAME: &str = "yabridge-host.exe";
/// The name of the XDG base directory prefix for yabridge's own files, relative to
/// `$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`.
const YABRIDGE_PREFIX: &str = "yabridge";
@@ -191,8 +191,8 @@ impl Config {
}
Err(anyhow!(
"Could not find '{}' in either '{}' or '{}'. You can tell yabridgectl where \
to search for it using 'yabridgectl set --path=<path>'.",
"Could not find '{}' in either '{}' or '{}'. You can override the default \
search path using 'yabridgectl set --path=<path>'.",
LIBYABRIDGE_NAME,
system_path.display(),
user_path.display()
@@ -229,12 +229,12 @@ impl Config {
/// Fetch the XDG base directories for yabridge's own files, converting any error messages if this
/// somehow fails into a printable string to reduce boiler plate. This is only used when searching
/// for `libyabridge.so` when no explicit search path has been set.
fn yabridge_directories() -> Result<BaseDirectories> {
pub fn yabridge_directories() -> Result<BaseDirectories> {
BaseDirectories::with_prefix(YABRIDGE_PREFIX).context("Error while parsing base directories")
}
/// Fetch the XDG base directories used for yabridgectl, converting any error messages if this
/// somehow fails into a printable string to reduce boiler plate.
fn yabridgectl_directories() -> Result<BaseDirectories> {
pub fn yabridgectl_directories() -> Result<BaseDirectories> {
BaseDirectories::with_prefix(YABRIDGECTL_PREFIX).context("Error while parsing base directories")
}
+12
View File
@@ -17,6 +17,7 @@
use anyhow::Result;
use clap::{app_from_crate, App, AppSettings, Arg};
use colored::Colorize;
use std::env;
use std::path::{Path, PathBuf};
use crate::config::Config;
@@ -27,6 +28,17 @@ mod files;
mod utils;
fn main() -> Result<()> {
// We'll modify our `PATH` environment variable so it matches up with
// `get_modified_search_path()` from `src/plugin/utils.h` for easier setup
let yabridge_home = config::yabridge_directories()?.get_data_home();
env::set_var(
"PATH",
match env::var("PATH") {
Ok(path) => format!("{}:{}", path, yabridge_home.display()),
_ => format!("{}", yabridge_home.display()),
},
);
let mut config = Config::read()?;
// Used for validation in `yabridgectl rm <path>`
+36 -10
View File
@@ -18,6 +18,7 @@
use anyhow::{Context, Result};
use colored::Colorize;
use is_executable::IsExecutable;
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs;
@@ -28,7 +29,7 @@ use std::path::Path;
use std::process::{Command, Stdio};
use textwrap::Wrapper;
use crate::config::{Config, KnownConfig};
use crate::config::{self, Config, KnownConfig, YABRIDGE_HOST_EXE_NAME};
/// (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
@@ -82,15 +83,33 @@ pub fn hash_file(file: &Path) -> Result<i64> {
Ok(hasher.finish() as i64)
}
/// Verify that `yabridge-host.exe` is accessible in a login shell. Returns unit if it is, or if we
/// the login shell is set to an unknown shell. In the last case we'll just print a warning since we
/// don't know how to invoke the shell as a login shell. This is needed when using copies to ensure
/// that yabridge can find the host binaries when the VST host is launched from the desktop
/// enviornment.
/// Verify that `yabridge-host.exe` can be found when yabridge is run in a host launched from the
/// GUI. We do this by launching a login shell, appending `~/.local/share/yabridge` to the login
/// shell's search path since that's what yabridge also does, and then making the the file can be
/// found. Returns unit if it can be found, or if we the login shell is set to an unknown shell. In
/// the last case we'll just print a warning since we don't know how to invoke the shell as a login
/// shell. This is needed when using copies to ensure that yabridge can find the host binaries when
/// the VST host is launched from the desktop enviornment.
///
/// When we could not find `yabridge-host.exe`, we'll return `Err(shell_name)` so we can print a
/// descriptive warning message.
pub fn verify_path_setup() -> Result<(), String> {
// First we'll check `~/.local/share/yabridge`, since that's a special location where yabridge
// will always search
if config::yabridge_directories()
.ok()
.and_then(|dirs| {
dirs.get_data_home()
.push(YABRIDGE_HOST_EXE_NAME)
.is_executable()
})
.unwrap_or(false)
{
return Ok(());
}
// Then we'll check the login shell, since DAWs launched from the GUI will have the same
// environment
match env::var("SHELL") {
Ok(shell_path) => {
// `$SHELL` will often contain a full path, but it doesn't have to
@@ -113,13 +132,20 @@ pub fn verify_path_setup() -> Result<(), String> {
| "zsh" => command
.arg("-l")
.arg("-c")
.arg("command -v yabridge-host.exe"),
.arg(format!("command -v {}", YABRIDGE_HOST_EXE_NAME)),
// These shells either have their own implementation of `which` and don't support
// `command`, or they don't have a seperate login shell flag
"elvish" | "oil" => command.arg("-c").arg("command -v yabridge-host.exe"),
"elvish" | "oil" => command
.arg("-c")
.arg(format!("command -v {}", YABRIDGE_HOST_EXE_NAME)),
// xonsh's which implementation is broken as of writing this, so I left it out
"pwsh" => command.arg("-l").arg("-c").arg("which yabridge-host.exe"),
"nu" => command.arg("-c").arg("which yabridge-host.exe"),
"pwsh" => command
.arg("-l")
.arg("-c")
.arg(format!("which {}", YABRIDGE_HOST_EXE_NAME)),
"nu" => command
.arg("-c")
.arg(format!("which {}", YABRIDGE_HOST_EXE_NAME)),
shell => {
eprintln!(
"\n{}",