记一次失败的折腾。

起因,Windows下Racket的命令行编辑不好用,因为不能使用libedit。查看了以下racket的readline的源码,发现 (ffi-lib "libedit" '("3" "2" "0.0.43" "0.0.53" "0" "")))),这些数字大概意味着所支持的libedit的版本。于是乎下载了WinEditline,把其中的edit.dll改名成libedit-2.dll,然后放到racket的lib文件及。在racket中执行(require readline)倒是能够识别这个dll,但是由于WinEditline支持的特性有限,比如不支持history_base,所以无法使用。

WinEditline在MinGW环境中有相应的安装包。Windows下git发行版是MinGW编译的,所以git目录里面也能找到edit.dll。

editline

既然WinEditline不行,那就尝试下较新的editline吧。

先是打算在Ubuntu WSL上交叉编译。在Ubuntu上安装sudo apt install mingw-w64

由于editline依赖于ncurses,于是尝试在Ubuntu上编译ncurses。

参考How do I invoke the MinGW cross-compiler on Linux?,使用下面的命令进行编译:

./configure --host=x86_64-w64-mingw32 --without-zlib

结果出现错误:

/bin/sh -e ./tinfo/MKcaptab.sh mawk 1 ./tinfo/MKcaptab.awk ../include/Caps ../include/Caps-ncurses > comp_captab.c
./tinfo/MKcaptab.sh: 74: ./make_hash: not found
make[1]: *** [Makefile:264: comp_captab.c] Error 127

换用:

./configure CC=x86_64-w64-mingw32-gcc

错误依旧。

换用MSYS2

既然不能在Ubuntu WSL下交叉编译,那就试试MSYS2吧。

简单介绍以下MSYS2。MSYS2从Cygwin分支出来的,支持三种模式:msys2,mingw64, mingw32。msys2模式有点像Cygwin,posix兼容性好,但编出来的dll无法直接在win32下使用。mingw64和ming32对应的就是64位和32位的mingw环境。

使用scoop install msys2安装msys2,安装完以后使用msys2 -mingw进入mingw模式(64位系统下默认进入mingw64模式)。通过pacman把相关工具都装上。

  • pacman -S <pkg>安装<pkg>,对于mingw64,<pkg>都是mingw64-开头的。
  • pacman -Ss <keyword>按照<keyword>查找相应的软件包。

在msys-mingw64下

出现以下错误:

../ncurses/./tinfo/lib_setup.c: In function '_nc_get_screensize':
../ncurses/./tinfo/lib_setup.c:337:6: error: unknown type name 'STRUCT_WINSIZE'
  337 |      STRUCT_WINSIZE size;
      |      ^~~~~~~~~~~~~~
../ncurses/./tinfo/lib_setup.c:341:7: warning: implicit declaration of function 'ioctl'; did you mean 'isoctal'? [-Wimplicit-function-declaration]
  341 |   if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) >= 0) {
      |       ^~~~~
      |       isoctal
../ncurses/./tinfo/lib_setup.c:341:32: error: 'IOCTL_WINSIZE' undeclared (first use in this function)
  341 |   if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) >= 0) {
      |                                ^~~~~~~~~~~~~
../ncurses/./tinfo/lib_setup.c:341:32: note: each undeclared identifier is reported only once for each function it appears in
../ncurses/./tinfo/lib_setup.c:344:12: warning: implicit declaration of function 'WINSIZE_ROWS' [-Wimplicit-function-declaration]
  344 |          : WINSIZE_ROWS(size));
      |            ^~~~~~~~~~~~
../ncurses/./tinfo/lib_setup.c:345:15: warning: implicit declaration of function 'WINSIZE_COLS' [-Wimplicit-function-declaration]
  345 |       *colp = WINSIZE_COLS(size);
      |               ^~~~~~~~~~~~

采用Undefined reference building ncurses on cygwin提示的configure --enable-term-driver --enable-sp-funcs也没有解决问题。

换用MSYS2自带的ncurses

好吧,不编ncurses了行不行,采用msys-mingw64自带的mingw-w64-x86_64-ncurses直接编译editline呢?

试了以下,发现mingw没有termios.h这个头文件,从https://github.com/chjchoi/kai/tree/master/project/linux-cortexm-1.9.0/A2F/gdb-2011.03/cs-cygwin-wrapper抄了termios.h|c的源代码,继续编译,竟然出现下面的错误:

In file included from el.h:50,
                 from chared.c:51:
chartype.h:46:3:In file included from  el.h:50error: ,
                 from #error wchar_t must store ISO 10646 characters
   46 |  #common.c:50error wchar_t must store ISO 10646 characters
      |   :
^~~~~chartype.h:46:3:
error: #error wchar_t must store ISO 10646 characters
   46 |  #error wchar_t must store ISO 10646 characters
      |   ^~~~~
In file included from el.h:96,
                 from common.c:50:
tty.h:475:5: error: unknown type name 'speed_t'
  475 |     speed_t t_speed;
      |     ^~~~~~~
In file included from el.h:102,
                 from common.c:50:

算了放弃editline了。

其实ncurses自带有MinGW Port,不过所提供的版本是支持宽字符的版本,没有试出如何在editline中使用。

转向gnu的readline

readline-gpl可以使用gnu的readline替换editline。

下了readline 5.2的代码,在msys-mingw64上编译失败。

下了readline 6.2的代码,在msys-mingw64上依然编译失败。

clink使用的也是readline 6.2。尝试了以下clink中的readline,其默认是把readline当作静态库编译的。但是如果把readline当作动态库编译,依然会编译不过。

小结

本次折腾完全失败。看来cmd.exe还是半残的。要么在wsl中使用racket,要么在drracket中使用repl,要么在emacs中使用racket。

不过也不是完全没有收获,emacs的Geiser看似挺好用的,而且可以与Evil模式结合使用。

其他emacs相关的可以参考24.2 Emacs

其他

  • linenoise,A minimal, zero-config, BSD licensed, readline replacement used in Redis, MongoDB, and Android。

(本篇完)