在 Windows 上的 utop 中尝试`#require "ctypes.foreign";;` 时出错(Cygwin)
Error trying to `#require "ctypes.foreign";;` in utop on Windows (Cygwin)
我成功安装了 运行 OCaml + OPAM + utop在 Windows(在 Cygwin 中)感谢 awesome guide by Jonathan Protzenko。在utop中,我特别希望能够使用ctypes + ctypes.foreign 以快速试验和原型访问各种 WinAPI 调用。理论上,我设法成功安装了 ctypes 包(opam install ...
成功)。不幸的是,当我尝试在 utop 中实际加载它们 时,它们惨遭失败 并出现令人惊讶的错误消息:
utop # #require "ctypes.foreign";;
Error: Reference to undefined global `Ctypes_closure_properties'
尝试在 rlwrap ocaml
中执行相同的操作会给出更长的错误消息:
# #require "ctypes.foreign";;
C:\OCaml\lib\unix.cma: loaded
C:\OCaml\lib\bigarray.cma: loaded
C:\OCaml\lib\str.cma: loaded
C:\cygwin64\home\Mateusz\.opam\system\lib\bytes: added to search path
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes: added to search path
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes.cma: loaded
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes-foreign-base.cma: loaded
Cannot load required shared library dllctypes-foreign-base_stubs.
Reason: dllctypes-foreign-base_stubs.dll: Cannot resolve ffi_type_pointer.
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes-foreign-unthreaded.cma: loaded
Characters -1--1:
#require "ctypes.foreign";;
Error: Reference to undefined global `Ctypes_closure_properties'
注意:full transcript of the sessions is here — 它包含 cmd.exe 终端中 utop
会话的输出,以及 rlwrap ocaml
终端中的附加 rlwrap ocaml
会话的输出Cygwin 终端。
我完全不知道为什么会这样,或者我如何进一步尝试 debug/pinpoint/diagnose 这种情况,以便我可以尝试找到一些解决方法。 (顺便说一句——我是 OCaml 和 OPAM 的新手,虽然我在 C/C++ 和 Linux 方面相当有经验。)下面是我的一些问题,我imagine 可能有希望帮助解决问题,足以推动我克服障碍:
- 有没有办法在本地调整 git 存储库(即 ctypes)并将其传递给 OPAM 而不是原来的 github?
- 我已经成功 google 了 some comment, which seems to mention that "a static version of libffi" might work, as hinted also in ctypes issue #198;但我完全是 OCaml 的新手,不幸的是我不知道如何将这个建议应用到 utop?
- 我如何告诉 OPAM 将哪个 libffi 用于 ctypes? (具体来说,要使用 "static libffi"?)
- 如何检查我安装的 mingw64-x86_64-libffi Cygwin 包是静态链接还是动态链接?或者如果提供了两种变体,那么 ctypes 使用哪一种?我在 SO 上找到了一些关于如何检测 libffi.a 是否与 PIC (?) 重定位 [
-fpic
?] 链接的答案,但它们看起来都非常骇人听闻,而我的 none尝试过似乎真的有效,至少在我的情况下。
- 任何帮助都将不胜感激。我什至不知道该问谁这个问题,因为它是 OCaml、OPAM、utop 和 Cygwin 的交叉点,所有这些都是巨大的,有点 unrelated/orthogonal 系统。我试过 posting the issue on ctypes repo,但一个多月的时间只得到一个 "patches-welcome" 标签。
mingw64-x86_64-libffi 附带静态和动态库,但 gnu 链接器默认使用动态版本。
给 ctypes 的构建打补丁会很麻烦(ctypes 的构建系统相当复杂,是脚本和 makefile 的混合体)。所以只需尝试以下操作:删除动态库(/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libffi.dll.a
和 /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libffi-6.dll
),重建 ctypes,然后恢复删除的文件。
opam-repository-mingw
顺便说一下:https://fdopen.github.io/opam-repository-mingw/installation/ contains a patched version of flexdll (https://github.com/alainfrisch/flexdll/pull/3 已应用 - 问题并非特定于 libffi),它支持 libffi 的动态和静态版本。如果 /usr/x86_64-w64-mingw32/sys-root/mingw/bin
在您的 PATH 中,opam install ctypes-foreign ctypes utop
应该开箱即用。下面是完整的分步指南:
- 下载一个 64 位 graphical installer 和 运行 它。
- 安装完成后,启动"Cygwin64 Terminal"(gets installed into Cygwin group in the Start菜单).
- 键入
cygwin-install gui
启动 Cygwin Setup/Installer 并使用它安装一些文本编辑器 (joe或 nano 或 vim 或任何你喜欢的)。
使用您安装的文本编辑器编辑您的 ~/.bashrc
文件,添加以下行:
export PATH="/usr/x86_64-w64-mingw32/sys-root/mingw/bin:$PATH"
然后在您的 Cygwin 终端 中执行它(只需在终端中键入它,或者 运行 以下命令代替):
$ source ~/.bashrc
安装 depext 它将自动下载 OPAM 包所需的任何 OS 级别(本机)依赖项,使用它来安装 ctypes 和 utop:
$ opam install depext depext-cygwinports
$ opam depext -i ctypes-foreign ctypes utop
从Cygwin Terminal切换到cmd.exe, 例如,在 Cygwin 终端 中键入以下命令:
$ cmd /c start cmd
在cmd.exe终端启动utop,并用它调用MessageBox WinAPI function 作为一切正常的测试:
c:> utop
utop # #require "ctypes.foreign";;
utop # let dll = Dl.dlopen ~filename:"user32.dll" ~flags:[];;
val dll : Dl.library = <abstr>
utop # open Ctypes;;
utop # let mb =
Foreign.foreign ~from:dll "MessageBoxA"
(ptr void @-> string @-> string @-> uint @-> returning int) ;;
val mb : unit Ctypes_static.ptr -> bytes -> bytes -> Unsigned.uint -> int =
<fun>
utop # mb null "hello" "world" Unsigned.UInt.zero;;
- : int = 1
utop # #quit;;
c:>
[注意:并非所有上述 utop 命令都可能需要,但这对我有用。]
我成功安装了 运行 OCaml + OPAM + utop在 Windows(在 Cygwin 中)感谢 awesome guide by Jonathan Protzenko。在utop中,我特别希望能够使用ctypes + ctypes.foreign 以快速试验和原型访问各种 WinAPI 调用。理论上,我设法成功安装了 ctypes 包(opam install ...
成功)。不幸的是,当我尝试在 utop 中实际加载它们 时,它们惨遭失败 并出现令人惊讶的错误消息:
utop # #require "ctypes.foreign";;
Error: Reference to undefined global `Ctypes_closure_properties'
尝试在 rlwrap ocaml
中执行相同的操作会给出更长的错误消息:
# #require "ctypes.foreign";;
C:\OCaml\lib\unix.cma: loaded
C:\OCaml\lib\bigarray.cma: loaded
C:\OCaml\lib\str.cma: loaded
C:\cygwin64\home\Mateusz\.opam\system\lib\bytes: added to search path
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes: added to search path
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes.cma: loaded
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes-foreign-base.cma: loaded
Cannot load required shared library dllctypes-foreign-base_stubs.
Reason: dllctypes-foreign-base_stubs.dll: Cannot resolve ffi_type_pointer.
C:\cygwin64\home\Mateusz\.opam\system\lib\ctypes\ctypes-foreign-unthreaded.cma: loaded
Characters -1--1:
#require "ctypes.foreign";;
Error: Reference to undefined global `Ctypes_closure_properties'
注意:full transcript of the sessions is here — 它包含 cmd.exe 终端中 utop
会话的输出,以及 rlwrap ocaml
终端中的附加 rlwrap ocaml
会话的输出Cygwin 终端。
我完全不知道为什么会这样,或者我如何进一步尝试 debug/pinpoint/diagnose 这种情况,以便我可以尝试找到一些解决方法。 (顺便说一句——我是 OCaml 和 OPAM 的新手,虽然我在 C/C++ 和 Linux 方面相当有经验。)下面是我的一些问题,我imagine 可能有希望帮助解决问题,足以推动我克服障碍:
- 有没有办法在本地调整 git 存储库(即 ctypes)并将其传递给 OPAM 而不是原来的 github?
- 我已经成功 google 了 some comment, which seems to mention that "a static version of libffi" might work, as hinted also in ctypes issue #198;但我完全是 OCaml 的新手,不幸的是我不知道如何将这个建议应用到 utop?
- 我如何告诉 OPAM 将哪个 libffi 用于 ctypes? (具体来说,要使用 "static libffi"?)
- 如何检查我安装的 mingw64-x86_64-libffi Cygwin 包是静态链接还是动态链接?或者如果提供了两种变体,那么 ctypes 使用哪一种?我在 SO 上找到了一些关于如何检测 libffi.a 是否与 PIC (?) 重定位 [
-fpic
?] 链接的答案,但它们看起来都非常骇人听闻,而我的 none尝试过似乎真的有效,至少在我的情况下。 - 任何帮助都将不胜感激。我什至不知道该问谁这个问题,因为它是 OCaml、OPAM、utop 和 Cygwin 的交叉点,所有这些都是巨大的,有点 unrelated/orthogonal 系统。我试过 posting the issue on ctypes repo,但一个多月的时间只得到一个 "patches-welcome" 标签。
mingw64-x86_64-libffi 附带静态和动态库,但 gnu 链接器默认使用动态版本。
给 ctypes 的构建打补丁会很麻烦(ctypes 的构建系统相当复杂,是脚本和 makefile 的混合体)。所以只需尝试以下操作:删除动态库(/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libffi.dll.a
和 /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libffi-6.dll
),重建 ctypes,然后恢复删除的文件。
opam-repository-mingw
顺便说一下:https://fdopen.github.io/opam-repository-mingw/installation/ contains a patched version of flexdll (https://github.com/alainfrisch/flexdll/pull/3 已应用 - 问题并非特定于 libffi),它支持 libffi 的动态和静态版本。如果 /usr/x86_64-w64-mingw32/sys-root/mingw/bin
在您的 PATH 中,opam install ctypes-foreign ctypes utop
应该开箱即用。下面是完整的分步指南:
- 下载一个 64 位 graphical installer 和 运行 它。
- 安装完成后,启动"Cygwin64 Terminal"(gets installed into Cygwin group in the Start菜单).
- 键入
cygwin-install gui
启动 Cygwin Setup/Installer 并使用它安装一些文本编辑器 (joe或 nano 或 vim 或任何你喜欢的)。 使用您安装的文本编辑器编辑您的
~/.bashrc
文件,添加以下行:export PATH="/usr/x86_64-w64-mingw32/sys-root/mingw/bin:$PATH"
然后在您的 Cygwin 终端 中执行它(只需在终端中键入它,或者 运行 以下命令代替):
$ source ~/.bashrc
安装 depext 它将自动下载 OPAM 包所需的任何 OS 级别(本机)依赖项,使用它来安装 ctypes 和 utop:
$ opam install depext depext-cygwinports $ opam depext -i ctypes-foreign ctypes utop
从Cygwin Terminal切换到cmd.exe, 例如,在 Cygwin 终端 中键入以下命令:
$ cmd /c start cmd
在cmd.exe终端启动utop,并用它调用MessageBox WinAPI function 作为一切正常的测试:
c:> utop utop # #require "ctypes.foreign";; utop # let dll = Dl.dlopen ~filename:"user32.dll" ~flags:[];; val dll : Dl.library = <abstr> utop # open Ctypes;; utop # let mb = Foreign.foreign ~from:dll "MessageBoxA" (ptr void @-> string @-> string @-> uint @-> returning int) ;; val mb : unit Ctypes_static.ptr -> bytes -> bytes -> Unsigned.uint -> int = <fun> utop # mb null "hello" "world" Unsigned.UInt.zero;; - : int = 1 utop # #quit;; c:>
[注意:并非所有上述 utop 命令都可能需要,但这对我有用。]