oils-for-unix / oils

Oils is our upgrade path from bash to a better language and runtime. It's also for Python and JavaScript users who avoid shell!
http://www.oilshell.org/
Other
2.84k stars 157 forks source link

Readline on OpenBSD has a different API; oils-for-unix compiler error #1942

Open dontlaugh opened 6 months ago

dontlaugh commented 6 months ago

System Details

Error

The compiler starts erroring due to some missing symbols related to readline.

CXX cpp/frontend_pyreadline.cc
cpp/frontend_pyreadline.cc:123:9: error: use of undeclared identifier 'rl_callback_sigcleanup'
        rl_callback_sigcleanup();
        ^
cpp/frontend_pyreadline.cc:276:3: error: use of undeclared identifier 'rl_clear_history'; did you mean 'clear_history'?
  rl_clear_history();
  ^~~~~~~~~~~~~~~~
  clear_history
cpp/frontend_pyreadline.cc:274:16: note: 'clear_history' declared here
void Readline::clear_history() {
               ^
cpp/frontend_pyreadline.cc:288:21: error: use of undeclared identifier 'free_history_entry'
  histdata_t data = free_history_entry(entry);
                    ^
3 errors generated.

~The rl_clear_history function seems to be called clear_history in readline/readline.h.~ Oops that's Oils code

Ripgreppin' through /usr led me to this comment in OpenBSD's Bash NEWS file (a changelog)

2.  New Features in Readline

a.  Many changes to the signal handling:
        o Readline now catches SIGQUIT and cleans up the tty before returning;
        o A new variable, rl_catch_signals, is available to application writers 
          to indicate to readline whether or not it should install its own
          signal handlers for SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP,
          SIGTTIN, and SIGTTOU;
        o A new variable, rl_catch_sigwinch, is available to application
          writers to indicate to readline whether or not it should install its
          own signal handler for SIGWINCH, which will chain to the calling
          applications's SIGWINCH handler, if one is installed;
        o There is a new function, rl_free_line_state, for application signal
          handlers to call to free up the state associated with the current
          line after receiving a signal;
        o There is a new function, rl_cleanup_after_signal, to clean up the
          display and terminal state after receiving a signal;
        o There is a new function, rl_reset_after_signal, to reinitialize the
          terminal and display state after an application signal handler
          returns and readline continues

b.  There is a new function, rl_resize_terminal, to reset readline's idea of
    the screen size after a SIGWINCH.

c.  New public functions: rl_save_prompt and rl_restore_prompt.  These were
    previously private functions with a `_' prefix.

d.  New function hook: rl_pre_input_hook, called just before readline starts
    reading input, after initialization.

e.  New function hook: rl_display_matches_hook, called when readline would
    display the list of completion matches.  The new function
    rl_display_match_list is what readline uses internally, and is available
    for use by application functions called via this hook.

So there seem to be a lot of differences related to signal handling, so they ought to be approached with care.

dontlaugh commented 6 months ago

A workaround is to compile without readline and use rlwrap

./configure --without-readline
./_build/oils.sh
doas ./install

Needs hacks from #1943 to build/install. After that, invoke with rlwrap

% rlwrap osh         
osh-0.21.0$ echo $HOME
/home/coleman
osh-0.21.0$ 
andychu commented 6 months ago

Hm do you know what version of GNU readline is on OpenBSD?

I am not sure what versions we support, but we should document it

It looks like the current version is 8.2 - https://tiswww.case.edu/php/chet/readline/rltop.html

dontlaugh commented 6 months ago

Looks like 8.2 on my system:

% pkg_info readline
Information for https://ftp.openbsd.org/pub/OpenBSD/7.5/packages/aarch64/readline-8.2.tgz

Comment:
library to edit command lines as they are typed in

Description:
The GNU Readline library provides a set of functions for use by
applications that allow users to edit command lines as they are typed
in.  Both Emacs and vi editing modes are available. The Readline library
includes additional functions to maintain a list of previously-entered
command lines to recall and perhaps reedit those lines, and perform
csh-like history expansion on previous commands.

The history facilities are also placed into a separate library, the
History library, as part of the build process.  The History library may
be used without Readline in applications which desire its capabilities.

To avoid any confusion with the base readline/history library make sure
you link to ereadline and ehistory.  In the headers you can check for
RL_READLINE_VERSION, RL_VERSION_MAJOR and RL_VERSION_MINOR to see which
header you have picked up.

Maintainer: The OpenBSD ports mailing-list <ports@openbsd.org>

WWW: https://tiswww.case.edu/php/chet/readline/rltop.html
andychu commented 6 months ago

Hmm I'm surprised that a newer version is not working... I have readline 7.0 on my Ubuntu machine

I wonder if this is reproducible on Linux with readline 8.2

andychu commented 6 months ago

Oh I wonder if you can do

$ head _build/detected*
==> _build/detected-config.h <==
#define SIZEOF_INT 4
#define SIZEOF_LONG 8
#define SIZEOF_VOID_P 8
#define SIZEOF_SHORT 2
#define SIZEOF_FLOAT 4
#define SIZEOF_DOUBLE 8
#define SIZEOF_SIZE_T 8
#define SIZEOF_FPOS_T 16
#define SIZEOF_PID_T 4
#define SIZEOF_OFF_T 8

==> _build/detected-config.sh <==
HAVE_READLINE=1
READLINE_DIR=
PREFIX=/usr/local
DATAROOTDIR=/usr/local/share
STRIP_FLAGS=--gc-sections

==> _build/detected-cpp-config.h <==
#define HAVE_READLINE 1
#define HAVE_PWENT 1

That will show what your HAVE_READLINE setting is

Maybe that test is broken on OpenBSD somehow?

dontlaugh commented 6 months ago

~I think you might be onto something~ Doh! I forgot I had files from --without-readline on disk. Here is a new configure run.

0 % ./configure 
./configure: Wrote _build/detected-cpp-config.h
./configure: Wrote _build/detected-config.sh
./configure: Wrote _build/detected-config.h

0 % head _build/detected*
==> _build/detected-config.h <==
#define SIZEOF_INT 4
#define SIZEOF_LONG 8
#define SIZEOF_VOID_P 8
#define SIZEOF_SHORT 2
#define SIZEOF_FLOAT 4
#define SIZEOF_DOUBLE 8
#define SIZEOF_SIZE_T 8
#define SIZEOF_FPOS_T 8
#define SIZEOF_PID_T 4
#define SIZEOF_OFF_T 8

==> _build/detected-config.sh <==
HAVE_READLINE=1
READLINE_DIR=
PREFIX=/usr/local
DATAROOTDIR=/usr/local/share
STRIP_FLAGS=--gc-sections

==> _build/detected-cpp-config.h <==
#define HAVE_READLINE 1
#define HAVE_PWENT 1

There still might be something wrong with feature detection, but I'm not sure what it is. OpenBSD puts the headers here:

% ls /usr/include/readline        
chardefs.h  history.h  keymaps.h  readline.h  rlconf.h  rlstdc.h  rltypedefs.h  tilde.h

I wonder if this is reproducible on Linux with readline 8.2

Not on my Linux laptop. I have compiled Oils without any issues on my Void Linux machine, and it has readline 8.2

Perhaps OpenBSD patches readline.

dontlaugh commented 6 months ago

okay whoa I asked on libera #openbsd and got the lowdown.

pkg_info is not showing my current readline. the readline in BASE is much older

#define RL_READLINE_VERSION     0x0403          /* Readline 4.3 */
dontlaugh commented 6 months ago

So I found some more info. The readline in base is quite old, and a lot of gnu stuff in OpenBSD base is old.

However, readline 8.2 is available from the ports tree.

https://github.com/openbsd/ports/blob/master/devel/readline/Makefile#L31

I installed it with

doas pkg_add readline

Anything not in base gets installed under /usr/local. As you can see from the ports tree's makefile for readline, they also rename the library to ereadline. So some build script updates will need to happen.

Headers get installed here:

ls /usr/local/include/ereadline/readline 
chardefs.h  history.h  keymaps.h  readline.h  rlconf.h  rlstdc.h  rltypedefs.h  tilde.h

Example programs (?) here

ls /usr/local/share/readline 
excallback.c  fileman.c  histexamp.c  manexamp.c  rl-fgets.c  rl.c  rlbasic.c  rlcat.c  rlevent.c  rlptytest.c  rltest.c  rlversion.c

And libraries here

ls /usr/local/lib | grep readline
libereadline.a
libereadline.so.3.0

And it's got the symbols

output from nm ``` % nm /usr/local/lib/libereadline.so.3.0 | awk '/(_callback|_sigcleanup|clear_history)/' 0005a82c T _rl_arg_callback 0008ea08 B _rl_callback_data 00054ddc T _rl_callback_data_alloc 00054d1c T _rl_callback_data_dispose 0008ea00 B _rl_callback_func 00059a14 t _rl_char_search_callback 0003f748 t _rl_complete_sigcleanup 00032b1c T _rl_dispatch_callback 00058624 t _rl_insert_next_callback 00047818 T _rl_isearch_callback 0003aa5c T _rl_nsearch_callback 0008e748 B _rl_sigcleanup 00038dc8 t _rl_vi_callback_change_char 000386c8 t _rl_vi_callback_char_search 000398a0 t _rl_vi_callback_goto_mark 00039778 t _rl_vi_callback_set_mark 000370b0 T _rl_vi_domove_callback 0005cb90 T clear_history 0005476c T rl_callback_handler_install 00054d24 T rl_callback_handler_remove 00054850 T rl_callback_read_char 0008ea20 b rl_callback_read_char.olevel 00054e38 T rl_callback_sigcleanup 0005b058 T rl_clear_history 0003783c t rl_domove_motion_callback 00037120 t rl_domove_read_callback ```

So it seems like you need to include/link against ereadline on OpenBSD.

dontlaugh commented 6 months ago

Here is the ports entry https://github.com/openbsd/ports/blob/9c275c5eec69b00ca423afc88f72f39a640dfb1d/devel/readline/pkg/DESCR#L12

ereadline and perhaps also ehistory will be required.


On the other hand, pkg-config shows this.

% pkg-config --libs readline
-L/usr/local/lib -lreadline

% pkg-config --libs history               
-L/usr/local/lib -lhistory

% pkg-config --libs ereadline
Package ereadline was not found in the pkg-config search path

Update: currently manually hacking the readline paths in build/ninja-rules-cpp.sh to see if I can get oils to compile. That can help determine what changes the configure script needs, if any.

Update 2: adding -lreadline to $link_flags works, but -lhistory fails to link. -I/usr/local/include/ereadline seems to find the headers.

andychu commented 6 months ago

Oh thanks for trying it! Yes I'd be interested in the diff of what works

I don't have an OpenBSD machine to test on

Do you need -lhistory? is that separate on OpenBSD?

dontlaugh commented 6 months ago

Do you need -lhistory? is that separate on OpenBSD?

Yes, according to the DESC file in the ports entry for readline:

The history facilities are also placed into a separate library, the History library, as part of the build process. The History library may be used without Readline in applications which desire its capabilities.

To avoid any confusion with the base readline/history library make sure you link to ereadline and ehistory. In the headers you can check for RL_READLINE_VERSION, RL_VERSION_MAJOR and RL_VERSION_MINOR to see which header you have picked up.

I'm having some trouble getting it to link, though. Even though the compiled libraries are right next to the readline ones

% ls /usr/local/lib | grep history
libehistory.a
libehistory.so.3.0
andychu commented 6 months ago

Oh it has to be -lehistory not -lhistory ? confusingly the flag has to match whatever's after lib I think

dontlaugh commented 6 months ago

Not sure :( pkg-config seems to indicate it's -lhistory

pkg-config .pc files ``` % cat /usr/local/lib/pkgconfig/readline.pc prefix=/usr/local exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Readline Description: Gnu Readline library for command line editing URL: http://tiswww.cwru.edu/php/chet/readline/rltop.html Version: 8.2 Requires.private: termcap Libs: -L${libdir} -lreadline Cflags: -I${includedir} % cat /usr/local/lib/pkgconfig/history.pc prefix=/usr/local exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: History Description: Gnu History library for managing previously-entered lines URL: http://tiswww.cwru.edu/php/chet/readline/rltop.html Version: 8.2 Libs: -L${libdir} -lhistory Cflags: -I${includedir} ```

I might have to try a simplified C program to see precisely what's required to include these libraries.

andychu commented 5 months ago

Yeah I agree the best solution here is to produce a self-contained C program on OpenBSD that links GNU readline and calls a few functions

We have a similar problem on FreeBSD

I would like this to work, but I don't have access to either OpenBSD or FreeBSD machines

Description of how Oils works here:

https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/installing.20on.20FreeBSD

So if there's a simple C program example, then it can probably ported over to our build system pretty easily

andychu commented 5 months ago

Or I guess another solution is to use pkg-config ? Is that the standard on OpenBSD ?

I'm unclear about this

dontlaugh commented 5 months ago

I'm not sure if pkg-config is standard, but some libraries drop .pc files and stuff.

Regarding CI it seems like SourceHut has FreeBSD and OpenBSD images. I've been shopping around for a solution, myself, since I've become BSD-curious.

I haven't had time to work this issue in particular, but I haven't forgotten. Feel free to poke me again if I don't get back to you in ... a few weeks? :heart:

greggyb commented 5 months ago

I'm planning on getting a POC C program with readline on FreeBSD (from the Zulip thread Andy linked earlier), probably this weekend, in a Sourcehut build. I'll also give OpenBSD a try at the same time. And I'll update this issue with my results.

POC program and compilation: https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/installing.20on.20FreeBSD/near/437738525

POC program and compilation copied below:

#include <stdio.h>
#include <stdlib.h>

#include "readline/readline.h"

int main() {
    char *line;
    line = readline("Enter your name: ");
    printf("Hello, %s!\n", line);
    free(line);
    return 0;
}
# FreeBSD compilation
$ cc -I/usr/local/include -L/usr/local/lib -l readline r.c -o r
$ ./r
Enter your name: a
Hello, a!
dontlaugh commented 4 months ago

Thanks for the test program. Here's what happened when I built it on OpenBSD with the system readline and the one from ports.

-l readline links against the system readline.

% cc -I/usr/local/include -L/usr/local/lib -l readline r.c -o r

% ldd r
r:
    Start            End              Type  Open Ref GrpRef Name
    0000000829f40000 0000000829f71000 exe   1    0   0      r
    0000000d29e3b000 0000000d29eab000 rlib  0    1   0      /usr/lib/libreadline.so.5.0
    0000000d043b2000 0000000d044dd000 rlib  0    1   0      /usr/lib/libc.so.99.0
    0000000c6a7bd000 0000000c6a864000 rlib  0    1   0      /usr/lib/libcurses.so.15.0
    0000000d17be0000 0000000d17be0000 ld.so 0    1   0      /usr/libexec/ld.so

-l ereadline links against the readline from ports.

% cc -I/usr/local/include -L/usr/local/lib -l ereadline r.c -o r

% ldd r
r:
    Start            End              Type  Open Ref GrpRef Name
    0000001e0f690000 0000001e0f6c1000 exe   1    0   0      r
    00000022998df000 000000229996e000 rlib  0    1   0      /usr/local/lib/libereadline.so.3.0
    000000227a3b6000 000000227a4e1000 rlib  0    1   0      /usr/lib/libc.so.99.0
    0000002304d56000 0000002304dfd000 rlib  0    1   0      /usr/lib/libcurses.so.15.0
    00000022f81e0000 00000022f81e0000 ld.so 0    1   0      /usr/libexec/ld.so

Both versions executed fine.

andychu commented 4 months ago

OK thanks, this is helpful !

So I guess the first solution is for our build scripts to provide arbitrary control over -I -L -l or something

Right now we have this:

~/git/oilshell/oil$ ./configure --help
Usage: ./configure [OPTION...]

Detects system settings before a build of Oil.

Installation directories:
  --prefix=PREFIX               Prefix for the bin/ directory [/usr/local]
  --datarootdir=DATAROOTDIR     Prefix for data files, including man page [PREFIX/share]

Optional features:
  --with-readline               Fail unless readline is available.
  --without-readline            Don't compile with readline, even if it's available.
                                The shell won't have any interactive features.
  --readline=DIR                An alternative readline installation to link against
  --with-systemtap-sdt          Fail unless systemtap-sdt is available.
  --without-systemtap-sdt       Don't compile with systemtap-sdt, even if it's available.

which I guess is not enough ??

We are trying to follow GNU configure standards , but with a hand-written shell script, not autoconf

https://www.gnu.org/prep/standards/html_node/Configuration.html


Question -- does anyone have any shell snippets that show how bash is configured on FreeBSD and OpenBSD?

What flags are passed?

I think OSH should look the same way

(Unless bash is special somehow, because GNU readline and bash are maintained together ...)

dontlaugh commented 4 months ago

The bash shell is in ports, not base. Here it is in the ports tree: https://github.com/openbsd/ports/tree/master/shells/bash

None of the flags mention readline or ereadline :thinking:

Here's some inpection of the bash executable with nm, ldd, and grep.

The bash we're dealing with.

% which bash
/usr/local/bin/bash
Output `% ldd $(which bash)` ``` /usr/local/bin/bash: Start End Type Open Ref GrpRef Name 00000017679a0000 0000001767b30000 exe 1 0 0 /usr/local/bin/bash 0000001baa55e000 0000001baa605000 rlib 0 1 0 /usr/lib/libcurses.so.15.0 0000001b86771000 0000001b867c3000 rlib 0 1 0 /usr/local/lib/libintl.so.8.0 0000001bdbf17000 0000001bdc055000 rlib 0 2 0 /usr/local/lib/libiconv.so.7.1 0000001c370de000 0000001c37209000 rlib 0 1 0 /usr/lib/libc.so.99.0 0000001bae270000 0000001bae270000 ld.so 0 1 0 /usr/libexec/ld.so ```

Searching specifically for the missing symbols in my original compiler error

% nm $(which bash) | grep free_history
0014d2a0 T _rl_free_history_entry
0014e860 T free_history_entry
% nm $(which bash) | grep clear_history
000e5a64 T bash_clear_history
0014f220 T clear_history
0014d780 T rl_clear_history
% nm $(which bash) | grep sigcleanup   
00131fb8 t _rl_complete_sigcleanup
0018e8a8 B _rl_sigcleanup
00147650 T rl_callback_sigcleanup

The output T indicates an external symbol, but I actually don't know if that guarantees that the readline implementation is not embedded. I am going to go through fetching the sources from ports.

Some more wide-ranging searches for good measure.

Output `nm $(which bash) | grep readline` ``` 0018c4a8 B bash_readline_initialized 0018e600 b current_readline_init_file 0018e608 b current_readline_init_include_level 0018e610 b current_readline_init_lineno 001862b8 B current_readline_line 001862c0 B current_readline_line_index 001862b0 B current_readline_prompt 000e6c90 T initialize_readline 0018e5f8 b last_readline_init_file 000ee0a0 t maybe_make_readline_line 000f5b60 T pcomp_set_readline_variables 000e6980 T posix_readline_initialize 0017f19c d posix_readline_initialize.kseq 0018c4b8 b push_to_readline 00124db0 T readline 00125650 T readline_internal_char 0018e02c b readline_internal_char.lastc 00125214 T readline_internal_setup 001253ac T readline_internal_teardown 001808d4 D rl_gnu_readline_p 001859c0 D rl_readline_name 0018df40 B rl_readline_state 001808d0 D rl_readline_version 000846d0 t yy_readline_get 000848c0 t yy_readline_unget ```
Output `nm $(which bash) | grep history` ``` 0014eb38 T _hs_append_history_line 0014e318 T _hs_at_end_of_history 00152af0 T _hs_history_patsearch 0014ec20 T _hs_replace_history_data 0014d2a0 T _rl_free_history_entry 0014d1e4 T _rl_free_saved_history_line 0018efa8 B _rl_history_preserve_point 00185aac D _rl_history_saved_point 0018e38c b _rl_history_search_flags 0018e380 b _rl_history_search_len 0018e384 B _rl_history_search_pos 0018efb0 B _rl_saved_line_for_history 0014d118 T _rl_start_using_history 0014e654 T add_history 0014e8e8 T add_history_time 0014e510 T alloc_history_entry 0015272c T append_history 000e6314 T bash_add_history 000e5a64 T bash_clear_history 000e5b2c T bash_delete_history_range 000e5bc8 T bash_delete_last_history 000e58e8 T bash_history_disable 000e5928 T bash_history_enable 000e56a0 t bash_history_inhibit_expansion 000e5864 T bash_history_reinit 000e5658 T bash_initialize_history 00107560 t bash_set_history 000e65d4 T check_add_history 0014f220 T clear_history 0017f164 D command_oriented_history 0014e984 T copy_history_entry 0014e39c T current_history 00102938 t display_history 0018c470 B double_quotes_inhibit_history_expansion 000e9354 t dynamic_complete_history 0017f160 D enable_history_list 0018c488 B force_append_history 0014e860 T free_history_entry 0014f2f4 T get_history_event 000e86e8 t history_and_alias_expand_line 0015138c T history_arg_extract 00185ab4 D history_base 00102278 T history_builtin 0018efe0 B history_comment_char 0018c718 b history_completion_array 000ef160 t history_completion_generator 0018c704 b history_completion_generator.len 0018c700 b history_completion_generator.local_index 0018c708 b history_completion_generator.text 0018c49c B history_control 000872f8 T history_delimiting_chars 001863c0 b history_delimiting_chars.last_was_heredoc 00152744 t history_do_write 00169cc0 D history_doc 0014f838 T history_expand 000e775c t history_expand_line 0017ecac D history_expansion 00185ab8 D history_expansion_char 0018c47c B history_expansion_inhibited 00185ad0 D history_file_version 00152090 t history_filename 0014f73c t history_find_word 0014e4ac T history_get 0014e0a8 T history_get_history_state 0014e5b0 T history_get_time 0018f000 B history_inhibit_expansion_function 0014f1ec T history_is_stifled 0018efcc B history_length 0018c480 B history_lines_in_file 0018f02c B history_lines_read_from_file 0018c484 B history_lines_this_session 0018f030 B history_lines_written_to_file 0014e368 T history_list 0018efd8 B history_max_entries 0018f028 B history_multiline_entries 00185ac0 D history_no_expand_chars 000e681c T history_number 0018efc8 B history_offset 0018efe4 B history_quotes_inhibit_expansion 0018efe8 B history_quoting_state 0018c490 B history_reediting 00152ee8 T history_search 0018f038 B history_search_delimiter_chars 00152c30 t history_search_internal 00152f00 T history_search_pos 00152ef4 T history_search_prefix 0018e3a0 b history_search_string 0014e12c T history_set_history_state 0014e2b8 T history_set_pos 0018efd0 b history_size 0018efd4 b history_stifled 0018e398 b history_string_size 00185abc D history_subst_char 00152580 t history_tempfile 00151554 T history_tokenize 00151564 t history_tokenize_internal 00151920 t history_tokenize_word 0014e1dc T history_total_bytes 00152160 T history_truncate_file 00185ac8 D history_word_delimiters 0018f024 B history_write_timestamps 000e68ac T last_history_line 0018c498 B literal_history 000e5984 T load_history 0012e100 t make_history_line_current 0018efdc B max_input_history 000e618c T maybe_add_history 000e5c98 T maybe_append_history 000e5dbc T maybe_save_shell_history 0014e44c T next_history 0018e388 b noninc_history_pos 0014e3f8 T previous_history 00151c4c T read_history 00151c5c T read_history_range 0018c46c B remember_on_history 0014ecf0 T remove_history 0014ed90 T remove_history_range 0014ea4c T replace_history_entry 0014d874 T rl_beginning_of_history 0014d780 T rl_clear_history 0014db3c T rl_end_of_history 0014dd04 T rl_fetch_history 001392fc T rl_forward_search_history 0014db94 T rl_get_next_history 0014d8d4 T rl_get_previous_history 0012d9a8 T rl_history_search_backward 0012d8cc T rl_history_search_forward 0012db54 t rl_history_search_internal 0012da84 t rl_history_search_reinit 0012de6c T rl_history_substr_search_backward 0012dcf8 T rl_history_substr_search_forward 0014d524 T rl_replace_from_history 00139008 T rl_reverse_search_history 00139014 t rl_search_history 001274e4 T rl_vi_fetch_history 0018e8d0 b rl_yank_last_arg.history_skip 00185ab0 d saved_history_logical_offset 000ff2e8 t set_history_remembering 0014e00c t set_saved_history 000e689c T setup_history_ignore 0014ef78 T stifle_history 000a1124 T sv_history_control 0018efc0 b the_history 0014f194 T unstifle_history 0014e1a0 T using_history 0014e284 T where_history 00152ad8 T write_history ```

So that's bash. The libraries we want (I think) are both from ports and are located in /usr/local/lib/

% nm /usr/local/lib/libehistory.so.3.0 | grep free_history_entry
00014144 T free_history_entry

% nm /usr/local/lib/libereadline.so.3.0 | grep free_history_entry
0005ab70 T _rl_free_history_entry
0005c1a4 T free_history_entry

% nm /usr/local/lib/libereadline.so.3.0 | grep rl_callback_sigcleanup
00054e38 T rl_callback_sigcleanup

% nm /usr/local/lib/libereadline.so.3.0 | grep rl_clear_history      
0005b058 T rl_clear_history

pkg-config does point towards the history and readline implementations we want.

% pkg-config --libs readline 
-L/usr/local/lib -lreadline

% pkg-config --libs history 
-L/usr/local/lib -lhistory

Note that ehistory and ereadline can't be found by pkg-config

% pkg-config --libs ehistory
Package ehistory was not found in the pkg-config search path

% pkg-config --libs ereadline                                          
Package ereadline was not found in the pkg-config search path

However, as the compilation of the test program demonstrates, providing -L/usr/local/lib -lreadline will prefer the system readline, probably because it finds it first.

dontlaugh commented 4 months ago

Here is a new test program that includes some functions from history.h

#include <stdio.h>
#include <stdlib.h>

#include <readline/readline.h>
#include <readline/history.h>

void cb(char * line) {/* no-op */};

int main() {
    char *input;
    rl_initialize();
    // from readline.h
    rl_clear_history();
    // from history.h
    clear_history();
    while ((input = readline(">>> ")) != NULL) {
        if (*input) {
            add_history(input);
        }
        if (strlen(input) == 3) {
            HIST_ENTRY *e = remove_history(0);
            free_history_entry(e);
        }
        printf("You entered: %s\n", input);
        free(input);
    }
    rl_callback_sigcleanup();
    return 0;
}

This compiles with no warnings on OpenBSD (with ports readline installed)

% cc -I/usr/local/include/ereadline -L/usr/local/lib -l ereadline -l ehistory rltest.c -o rltest

Note the -I flag. This compiles with warnings.

% cc -I/usr/local/include -L/usr/local/lib -l ereadline -l ehistory rltest.c -o rltest
rltest.c:13:5: warning: call to undeclared function 'rl_clear_history'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    rl_clear_history();
    ^
rltest.c:22:13: warning: call to undeclared function 'free_history_entry'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
            free_history_entry(e);
            ^
rltest.c:27:5: warning: call to undeclared function 'rl_callback_sigcleanup'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    rl_callback_sigcleanup();
    ^
3 warnings generated.

And this test program requires -l ereadline and -ehistory. -lreadline and -lhistory don't work afaict. -lhistory is not found, and -lreadline is missing symbols.

% cc -I/usr/local/include/ereadline -L/usr/local/lib -l readline -l history rltest.c -o rltest 
ld: error: unable to find library -lhistory
cc: error: linker command failed with exit code 1 (use -v to see invocation)

% cc -I/usr/local/include/ereadline -L/usr/local/lib -l readline -l ehistory rltest.c -o rltest
ld: error: undefined symbol: rl_clear_history
>>> referenced by rltest.c
>>>               /tmp/rltest-7307dc.o:(main)

ld: error: undefined symbol: rl_callback_sigcleanup
>>> referenced by rltest.c
>>>               /tmp/rltest-7307dc.o:(main)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
dontlaugh commented 4 months ago

So, in summary, readline on OpenBSD needs

I'll try to play with the configure script a bit so see if I can make it work on 0.21.0; 0.22.0 needs #1991


Update: Success?!

I got it to compile with these hacks applied directly to the 0.21.0 source tarball. Note that I still needed to apply the fix from #1943 too

diff --git a/_build/oils.sh b/_build/oils.sh
index 7b66bdf..54a311c 100755
--- a/_build/oils.sh
+++ b/_build/oils.sh
@@ -220,7 +220,7 @@ main() {

   cd $out_dir
   for symlink in osh ysh; do
-    ln -s -f -v $out_name $symlink
+    ln -s -f $out_name $symlink
   done
 }

diff --git a/build/ninja-rules-cpp.sh b/build/ninja-rules-cpp.sh
index 029a27a..d427090 100755
--- a/build/ninja-rules-cpp.sh
+++ b/build/ninja-rules-cpp.sh
@@ -226,7 +226,7 @@ setglobal_link_flags() {

     *)
       if test "$HAVE_READLINE" = 1; then
-        link_flags="$link_flags -lreadline"
+        link_flags="$link_flags -L/usr/local/lib -lereadline -lehistory"
       fi
       if test -n "$READLINE_DIR"; then
         link_flags="$link_flags -L${READLINE_DIR}/lib"
@@ -357,7 +357,7 @@ symlink() {
   local out=$3

   cd $dir
-  ln -s -f -v $in $out
+  ln -s -f $in $out
 }

 # test/cpp-unit.sh sources this

I rely on CXXFLAGS for -I since it gets passed through

export CXXFLAGS='-I/usr/local/include/ereadline
./configure
_build/oils.sh
Compiler output, exit code 0 ``` _build/oils.sh: Building oils-for-unix: _bin/cxx-opt-sh/oils-for-unix CXX _gen/bin/oils_for_unix.mycpp.cc CXX _gen/bin/text_files.cc CXX _gen/core/runtime.asdl.cc _gen/bin/oils_for_unix.mycpp.cc:18294:26: warning: assigning field to itself [-Wself-assign-field] this->orig_local_modes = orig_local_modes; ^ _gen/bin/oils_for_unix.mycpp.cc:18295:20: warning: assigning field to itself [-Wself-assign-field] this->term_attrs = term_attrs; ^ CXX _gen/core/value.asdl.cc CXX _gen/cpp/build_stamp.cc CXX _gen/data_lang/nil8.asdl.cc CXX _gen/data_lang/pretty.asdl.cc CXX _gen/frontend/arg_types.cc CXX _gen/frontend/consts.cc CXX _gen/frontend/help_meta.cc CXX _gen/frontend/id_kind.asdl.cc CXX _gen/frontend/signal.cc CXX _gen/frontend/syntax.asdl.cc CXX _gen/osh/arith_parse.cc CXX _gen/ysh/grammar_tables.cc CXX cpp/core.cc CXX cpp/data_lang.cc 2 warnings generated. CXX cpp/fanos.cc CXX cpp/fanos_shared.c c++: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated] CXX cpp/frontend_flag_spec.cc CXX cpp/frontend_match.cc CXX cpp/frontend_pyreadline.cc CXX cpp/libc.cc CXX cpp/osh.cc CXX cpp/osh_tdop.cc CXX cpp/pgen2.cc CXX cpp/pylib.cc CXX cpp/stdlib.cc CXX mycpp/bump_leak_heap.cc CXX mycpp/gc_builtins.cc mycpp/gc_builtins.cc:176:53: warning: 'static_assert' with no message is a C++17 extension [-Wc++17-extensions] static_assert(sizeof(long long) == sizeof(int64_t)); ^ , "" 1 warning generated. CXX mycpp/gc_mops.cc mycpp/gc_mops.cc:21:58: warning: format specifies type 'long' but the argument has type 'BigInt' (aka 'long long') [-Wformat] int length = snprintf(s->data(), kInt64BufSize, "%ld", b); ~~~ ^ %lld 1 warning generated. CXX mycpp/gc_mylib.cc CXX mycpp/gc_str.cc CXX mycpp/hash.cc CXX mycpp/mark_sweep_heap.cc WAIT real 0.00 user 0.00 sys 0.00 LINK _bin/cxx-opt-sh/oils-for-unix gc_builtins.cc:108 (mycpp/gc_builtins.cc:108)(_build/obj/cxx-opt-sh/mycpp/gc_builtins.o:(repr(BigStr*))): warning: sprintf() is often misused, please use snprintf() ```

And a quick test of osh shows that readline history is working.

% _bin/cxx-opt-sh/oils-for-unix osh
osh-0.21.0$ echo do i have history
do i have history
osh-0.21.0$ echo yes i do         
yes i do
^Ch-0.21.0$ echo yes i do
osh-0.21.0$ exit