Disable relocatable tree logic when DATADIR or SYSCONFDIR are non-default

If all of

	$PREFIX/bin/fish
	$PREFIX/share/fish
	$PREFIX/etc/fish

exist, then fish assumes it's in a relocatable directory tree.
This is used by homebrew (PREFIX=/usr/local) and maybe also nix(?).

Other Linux distros prefer to use /etc/fish instead of $PREFIX/etc/fish
[1].  To do so, they need to pass -DCMAKE_INSTALL_SYSCONFDIR=/etc.
The relocatable tree logic assumes default data and sysconf dirs
(relative to a potentially relocatable prefix). If the user changes
any of those, and the relocatable tree logic happens to kick in,
that'd overrule user preference, which is surprising.

So a non-default data or sysconf path is a strong enough signal that
we want to disable the relocatable tree logic. Do that.

Closes #10748

[1]: ff2f69cd56/PKGBUILD (L43)
This commit is contained in:
Johannes Altmanninger
2026-04-04 00:47:10 +08:00
parent e25b4b6f05
commit 0367aaea7d
2 changed files with 7 additions and 3 deletions

View File

@@ -16,7 +16,9 @@ pub struct ConfigPaths {
pub doc: Option<PathBuf>, // e.g., /usr/local/share/doc/fish
}
pub const PREFIX: &str = env!("PREFIX");
const SYSCONF_DIR: &str = env!("SYSCONFDIR");
const DATADIR: Option<&str> = option_env!("DATADIR");
impl ConfigPaths {
pub fn new() -> Self {
@@ -58,7 +60,7 @@ macro_rules! log_optional_path {
fn from_exec_path(unresolved_exec_path: &'static FishPath) -> Self {
let default_layout = |exec_path_parent: Option<&Path>| {
let data = option_env!("DATADIR").map(|p| PathBuf::from(p).join("fish"));
let data = DATADIR.map(|p| PathBuf::from(p).join("fish"));
Self {
sysconf: PathBuf::from(SYSCONF_DIR).join("fish"),
bin: option_env!("BINDIR")
@@ -111,6 +113,8 @@ fn from_exec_path(unresolved_exec_path: &'static FishPath) -> Self {
let prefix = exec_path_parent.parent().unwrap();
let data = prefix.join("share/fish");
let sysconf = prefix.join("etc/fish");
DATADIR.expect("cmake sets datadir").strip_prefix(PREFIX) == Some("/share") &&
SYSCONF_DIR.strip_prefix(PREFIX) == Some("/etc") &&
data.exists() && sysconf.exists()
// Installations with prefix set to exactly the workspace root are not supported;
// those will behave like non-installed builds inside the workspace.

View File

@@ -8,7 +8,7 @@
use crate::common::{
UnescapeStringStyle, cstr2wcstring, osstr2wcstring, str2wcstring, unescape_string,
};
use crate::env::config_paths::ConfigPaths;
use crate::env::config_paths::{ConfigPaths, PREFIX};
use crate::env::{EnvMode, EnvSetMode, EnvVar, Statuses};
use crate::env_dispatch::{VarChangeMilieu, env_dispatch_init, env_dispatch_var_change};
use crate::event::Event;
@@ -536,7 +536,7 @@ fn setup_user(global_exported_mode: EnvSetMode, vars: &EnvStack) {
colon_split(&[cstr2wcstring(cstr)])
} else {
vec![
str2wcstring(env!("PREFIX")) + L!("/bin"),
str2wcstring(PREFIX) + L!("/bin"),
L!("/usr/bin").to_owned(),
L!("/bin").to_owned(),
]