mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-11 13:51:16 -03:00
Support linking against reentrant-configured curses
NCurses headers contain this conditional "#define cur_term": print "#elif @cf_cv_enable_reentrant@" print "NCURSES_WRAPPED_VAR(TERMINAL *, cur_term);" print "#define cur_term NCURSES_PUBLIC_VAR(cur_term())" print "#else" OpenSUSE Tumbleweed uses this configuration option; For reentrancy, cur_term is a function. If the NCurses autoconf variable @NCURSES_WRAP_PREFIX@ is not changed from its default, the function is called _nc_cur_term. I'm not sure if we have a need to support non-default @NCURSES_WRAP_PREFIX@ but if we do there are various ways; - search for the symbol with the cur_term suffix - figure out the prefix based on the local curses installation, for example by looking at the header files. Fixes #10243
This commit is contained in:
27
build.rs
27
build.rs
@@ -30,29 +30,42 @@ fn main() {
|
|||||||
|
|
||||||
// Handle case where CMake has found curses for us and where we have to find it ourselves.
|
// Handle case where CMake has found curses for us and where we have to find it ourselves.
|
||||||
rsconf::rebuild_if_env_changed("CURSES_LIBRARY_LIST");
|
rsconf::rebuild_if_env_changed("CURSES_LIBRARY_LIST");
|
||||||
if let Ok(lib_path_list) = env::var("CURSES_LIBRARY_LIST") {
|
let curses_libraries = if let Ok(lib_path_list) = env::var("CURSES_LIBRARY_LIST") {
|
||||||
let lib_paths = lib_path_list.split(',').filter(|s| !s.is_empty());
|
let lib_paths = lib_path_list.split(',').filter(|s| !s.is_empty());
|
||||||
let curses_libnames: Vec<_> = lib_paths
|
let curses_libnames: Vec<_> = lib_paths
|
||||||
.map(|libpath| {
|
.map(|libpath| {
|
||||||
let stem = Path::new(libpath).file_stem().unwrap().to_str().unwrap();
|
let stem = Path::new(libpath).file_stem().unwrap().to_str().unwrap();
|
||||||
// Ubuntu-32bit-fetched-pcre2's ncurses doesn't have the "lib" prefix.
|
// Ubuntu-32bit-fetched-pcre2's ncurses doesn't have the "lib" prefix.
|
||||||
stem.strip_prefix("lib").unwrap_or(stem)
|
stem.strip_prefix("lib").unwrap_or(stem).to_string()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
// We don't need to test the libs because presumably CMake already did
|
// We don't need to test the libs because presumably CMake already did
|
||||||
rsconf::link_libraries(&curses_libnames, LinkType::Default);
|
rsconf::link_libraries(&curses_libnames, LinkType::Default);
|
||||||
|
curses_libnames
|
||||||
} else {
|
} else {
|
||||||
let mut curses_found = false;
|
let mut curses_libraries = vec![];
|
||||||
for lib in ["ncurses", "curses"] {
|
let libs = ["ncurses", "curses"];
|
||||||
|
for lib in libs {
|
||||||
if target.has_library(lib) && target.has_symbol("setupterm", lib) {
|
if target.has_library(lib) && target.has_symbol("setupterm", lib) {
|
||||||
rsconf::link_library(lib, LinkType::Default);
|
rsconf::link_library(lib, LinkType::Default);
|
||||||
curses_found = true;
|
curses_libraries.push(lib.to_string());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !curses_found {
|
if curses_libraries.is_empty() {
|
||||||
rsconf::warn!("Could not locate a compatible curses library!");
|
panic!("Could not locate a compatible curses library (tried {libs:?})");
|
||||||
|
}
|
||||||
|
curses_libraries
|
||||||
|
};
|
||||||
|
|
||||||
|
for lib in curses_libraries {
|
||||||
|
if target.has_symbol("_nc_cur_term", &lib) {
|
||||||
|
rsconf::enable_cfg("_nc_cur_term");
|
||||||
|
if target.has_symbol("cur_term", &lib) {
|
||||||
|
rsconf::warn!("curses provides both cur_term and _nc_cur_term");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
docker/opensuse-tumbleweed.docker
Normal file
39
docker/opensuse-tumbleweed.docker
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
FROM opensuse/tumbleweed:latest
|
||||||
|
LABEL org.opencontainers.image.source=https://github.com/fish-shell/fish-shell
|
||||||
|
|
||||||
|
ENV LANG C.UTF-8
|
||||||
|
ENV LC_ALL C.UTF-8
|
||||||
|
|
||||||
|
RUN zypper --non-interactive install \
|
||||||
|
bash \
|
||||||
|
cmake \
|
||||||
|
diffutils \
|
||||||
|
gcc-c++ \
|
||||||
|
git-core \
|
||||||
|
ncurses-devel \
|
||||||
|
ninja \
|
||||||
|
pcre2-devel \
|
||||||
|
python311 \
|
||||||
|
python311-pip \
|
||||||
|
python311-pexpect \
|
||||||
|
openssl \
|
||||||
|
procps \
|
||||||
|
tmux \
|
||||||
|
sudo \
|
||||||
|
rust \
|
||||||
|
cargo
|
||||||
|
|
||||||
|
RUN usermod -p $(openssl passwd -1 fish) root
|
||||||
|
|
||||||
|
RUN groupadd -g 1000 fishuser \
|
||||||
|
&& useradd -p $(openssl passwd -1 fish) -d /home/fishuser -m -u 1000 -g 1000 fishuser \
|
||||||
|
&& mkdir -p /home/fishuser/fish-build \
|
||||||
|
&& mkdir /fish-source \
|
||||||
|
&& chown -R fishuser:fishuser /home/fishuser /fish-source
|
||||||
|
|
||||||
|
USER fishuser
|
||||||
|
WORKDIR /home/fishuser
|
||||||
|
|
||||||
|
COPY fish_run_tests.sh /
|
||||||
|
|
||||||
|
CMD /fish_run_tests.sh
|
||||||
@@ -62,8 +62,10 @@ mod sys {
|
|||||||
pub type putc_t = extern "C" fn(tputs_arg) -> libc::c_int;
|
pub type putc_t = extern "C" fn(tputs_arg) -> libc::c_int;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/// The ncurses `cur_term` TERMINAL pointer.
|
#[cfg(not(have_nc_cur_term))]
|
||||||
pub static mut cur_term: *const core::ffi::c_void;
|
pub static mut cur_term: *const core::ffi::c_void;
|
||||||
|
#[cfg(have_nc_cur_term)]
|
||||||
|
pub fn have_nc_cur_term() -> *const core::ffi::c_void;
|
||||||
|
|
||||||
/// setupterm(3) is a low-level call to begin doing any sort of `term.h`/`curses.h` work.
|
/// setupterm(3) is a low-level call to begin doing any sort of `term.h`/`curses.h` work.
|
||||||
/// It's called internally by ncurses's `initscr()` and `newterm()`, but the C++ code called
|
/// It's called internally by ncurses's `initscr()` and `newterm()`, but the C++ code called
|
||||||
@@ -77,6 +79,9 @@ pub fn setupterm(
|
|||||||
/// Frees the `cur_term` TERMINAL pointer.
|
/// Frees the `cur_term` TERMINAL pointer.
|
||||||
pub fn del_curterm(term: *const core::ffi::c_void) -> libc::c_int;
|
pub fn del_curterm(term: *const core::ffi::c_void) -> libc::c_int;
|
||||||
|
|
||||||
|
/// Sets the `cur_term` TERMINAL pointer.
|
||||||
|
pub fn set_curterm(term: *const core::ffi::c_void) -> *const core::ffi::c_void;
|
||||||
|
|
||||||
/// Checks for the presence of a termcap flag identified by the first two characters of
|
/// Checks for the presence of a termcap flag identified by the first two characters of
|
||||||
/// `id`.
|
/// `id`.
|
||||||
pub fn tgetflag(id: *const libc::c_char) -> libc::c_int;
|
pub fn tgetflag(id: *const libc::c_char) -> libc::c_int;
|
||||||
@@ -95,6 +100,19 @@ pub fn tgetstr(
|
|||||||
pub fn tputs(str: *const libc::c_char, affcnt: libc::c_int, putc: putc_t) -> libc::c_int;
|
pub fn tputs(str: *const libc::c_char, affcnt: libc::c_int, putc: putc_t) -> libc::c_int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ncurses `cur_term` TERMINAL pointer.
|
||||||
|
fn get_curterm() -> *const core::ffi::c_void {
|
||||||
|
#[cfg(have_nc_cur_term)]
|
||||||
|
unsafe {
|
||||||
|
sys::have_nc_cur_term()
|
||||||
|
}
|
||||||
|
#[cfg(not(have_nc_cur_term))]
|
||||||
|
unsafe {
|
||||||
|
sys::cur_term
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub use sys::tputs_arg as TputsArg;
|
pub use sys::tputs_arg as TputsArg;
|
||||||
|
|
||||||
/// The safe wrapper around curses functionality, initialized by a successful call to [`setup()`]
|
/// The safe wrapper around curses functionality, initialized by a successful call to [`setup()`]
|
||||||
@@ -434,7 +452,7 @@ pub fn setup<F>(term: Option<&CStr>, fd: i32, configure: F) -> Option<Arc<Term>>
|
|||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
// If cur_term is already initialized for a different $TERM value, calling setupterm() again
|
// If cur_term is already initialized for a different $TERM value, calling setupterm() again
|
||||||
// will leak memory. Call del_curterm() first to free previously allocated resources.
|
// will leak memory. Call del_curterm() first to free previously allocated resources.
|
||||||
let _ = sys::del_curterm(cur_term);
|
let _ = sys::del_curterm(get_curterm());
|
||||||
|
|
||||||
let mut err = 0;
|
let mut err = 0;
|
||||||
if let Some(term) = term {
|
if let Some(term) = term {
|
||||||
@@ -469,8 +487,8 @@ pub fn reset() {
|
|||||||
unsafe {
|
unsafe {
|
||||||
// Ignore the result of del_curterm() as the only documented error is that
|
// Ignore the result of del_curterm() as the only documented error is that
|
||||||
// `cur_term` was already null.
|
// `cur_term` was already null.
|
||||||
let _ = sys::del_curterm(cur_term);
|
let _ = sys::del_curterm(get_curterm());
|
||||||
sys::cur_term = core::ptr::null();
|
let _ = sys::set_curterm(core::ptr::null());
|
||||||
}
|
}
|
||||||
*term = None;
|
*term = None;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user