哪个 .cma 文件对应 OCaml 中的哪个模块?

7
如果我在OCaml toploop中编程,想要使用OCaml标准库其他库中的包,那么我该如何找到要加载的.cma文件呢?例如,在标准库中,Stringstr.cma中,Big_intnums.cma中,因此从模块名称或描述中无法区分文件名。

有没有一种简单的方法来查找模块的正确文件?

5个回答

6
通常情况下,对于一个 Ocaml 库 .cma,你可以使用 objinfo(也称为 ocamlobjinfo,特别是在 Debian、Ubuntu 等系统中)获取它定义的模块。因此,只要给出库路径(如 /usr/lib/ocaml 等),并有足够的时间,就可以构建模块与 Ocaml 库之间的映射关系。

1
谢谢提醒,我忘记了这个工具。在OCaml发行版中它被称为objinfo,但由Debian打包为ocamlobjinfo - gasche
是的,我忘记了,但他们应该称其为“objdump”以更不具体化一些^^ - Po' Lazarus
1
反向搜索更容易,而且不依赖于额外的工具 :) - ygrek
谢谢你的回答。我使用了 ocamlobjinfo 来构建一个像你建议的映射。 - Matthew Piziak

4

首先,您实际上并不想知道要加载哪个cma文件,而是想通过ocamlfind知道要加载哪个包。下一件事要注意的是,ocaml编译器需要执行相同的操作来编译项目 - 即根据源代码中引用的模块的名称查找该模块的已编译接口。因此让我们模拟这种行为。编译器从命令行获取包含路径,但我们必须搜索所有可能的包含路径。所以我们开始吧:

for i in $(ocamlfind list | cut -d ' ' -f 1) ; do
  if [ -r $(ocamlfind query $i)/XXX.cmi ] ; then
    echo $i; break;
  fi ;
done

或者

ocamlfind printconf path | xargs -n1 -I/ find / -name XXX.cmi

需要注意的是,从模块名称到文件名的映射并不是唯一的 - 例如,SomeModule 可以用 someModule.cmiSomeModule.cmi(较少见)来表示。


1
它假设你感兴趣的每个模块都是Findlib兼容的(即具有元文件),这在大多数情况下是成立的,并且元文件是完整和正确的,这有时是一厢情愿的想法... - Po' Lazarus
1
两种解决方案都不依赖于正确的META文件 :) 第二种解决方案仅使用ocamlfind来检测合理的包含路径。但无论哪种方式,它已经是XXI了,损坏的ocamlfind软件包应该被修复(并以最大程度的严重性惩罚有罪的人!),而不是采用变通方法。 - ygrek
没错!你两点都说对了…… cmi 文件应该与模块名称一起存在,但是对于打包的模块来说,获取完全限定名称还是相当复杂的(例如尝试在 ocamlgraph 上进行此操作)。 - Po' Lazarus

2

String(对于string数据类型的常规函数)不在str.cma中,而是在Str(用于操作正则表达式的函数)中。

nums.cma名称也有类似的原因:它主要封装了模块Num,该模块是不同“大数”库(NatBig_intRatio)之上的一层。请注意,现在您可能想使用Zarith代替。


有用的评论,但并不是真正的答案(解释-1)。 - ygrek

1
正如Po' Lazarus所建议的那样,我使用了ocamlobjinfo来构建一个映射表,将.cma文件和定义的模块进行了关联以便于参考。
  • bigarray.cma:
    • BigArray
  • dbm.cma:
    • Dbm
  • dynlink.cma:
    • Dynlinkaux
    • Dynlink
  • graphics.cma:
    • Graphics
    • GraphicsX11
  • nums.cma:
    • Int_misc
    • Nat
    • Big_int
    • Arith_flags
    • Ratio
    • Num
    • Arith_status
  • stdlib.cma
    • Pervasives
    • Array
    • List
    • Char
    • String
    • Sys
    • Hashtbl
    • Sort
    • Marshal
    • Obj
    • Int32
    • Int64
    • Nativeint
    • Lexing
    • Parsing
    • Set
    • Map
    • Stack
    • Queue
    • CamlinternalLazy
    • Lazy
    • Stream
    • Buffer
    • Printf
    • Format
    • Scanf
    • Arg
    • Printexc
    • Gc
    • Digest
    • Random
    • Callback
    • CamlinternalOO
    • Oo
    • CamlinternalMod
    • Genlex
    • Weak
    • Filename
    • Complex
    • ArrayLabels
    • ListLabels
    • StringLabels
    • MoreLabels
    • StdLabels
  • str.cma:
    • Str
  • toplevellib.cma:
    • Misc
    • Tbl
    • Config
    • Clflags
    • Terminfo
    • Ccomp
    • Warnings
    • Consistbl
    • Linenum
    • Location
    • Longident
    • Syntaxerr
    • Parser
    • Lexer
    • Parse
    • Printast
    • Unused_var
    • Ident
    • Path
    • Primitive
    • Types
    • Btype
    • Oprint
    • Subst
    • Predef
    • Datarepr
    • Env
    • Typedtree
    • Ctype
    • Printtyp
    • Includeclass
    • Mtype
    • Includecore
    • Includemod
    • Parmatch
    • Typetexp
    • Stypes
    • Typecore
    • Typedecl
    • Typeclass
    • Typemod
    • Lambda
    • Printlambda
    • Typeopt
    • Switch
    • Matching
    • Translobj
    • Translcore
    • Translclass
    • Translmod
    • Simplif
    • Runtimedef
    • Meta
    • Instruct
    • Bytegen
    • Printinstr
    • Opcodes
    • Emitcode
    • Bytesections
    • Dll
    • Symtable
    • Bytelink
    • Bytelibrarian
    • Bytepackager
    • Pparse
    • Errors
    • Compile
    • Main_args
    • Genprintval
    • Toploop
    • Trace
    • Topdirs
    • Topmain
  • unix.cma:
    • Unix
    • UnixLabels

我考虑过反转映射,按字母顺序排列模块,但这种安排提供了一个清晰的视图,显示哪些模块分隔到哪些文件中,同时仍允许读者使用CTRL-F查找他们需要的模块。 - Matthew Piziak

1

我从未注意到这个问题,但你说得对,从模块的名称中无法得出任何信息。由于我通常必须先阅读文档,因此我总是从文档(标准模块每个部分开头列出)中获取信息。

更加优雅的解决方案是使用GODI及其关联的findlib机制,它看起来解决了这个问题和许多其他问题。特别是,它可以扩展到不仅仅是OCaml发行版附带的模块。


我对GODI没有什么意见(好吧,几乎没有),但是Findlib也可以不使用GODI... - Po' Lazarus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接