在Mac上编译构建Moses

Moses是统计机器翻译领域最常见的工具(可能没有“之一”),使用C++编写。由于工作需要,我需要训练一个翻译模型,而平行语料比较小,使用NMT不现实,因此自然需要考虑借助moses的帮助。但是moses官网上的指导稍微有点乱,而且代码库里也存在一些错误,我自己也把C++忘光了(本来也就学了个皮毛),所以编译不是很顺利,好在靠组内两位C++大拿的指导最后搞定了。这里我简要记一下踩过的坑

我的系统是Mac OS High Sierra 10.13.6,编译器信息如下

1
2
3
4
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

一、手工构建boost库

官网上说如果手工构建boost,需要在编译moses时指定位置。我开始的方案是直接用brew install boost,然后编译的时候指定好boost装在了哪儿。后来我发现效果好像不太好,总之有错误发生。比较稳妥的方法是直接从官网下载boost源码然后编译

(当然,构建失败可能是后面所叙几个原因造成的,我之前没有仔细检查过。不过手工编译boost至少在我这儿行得通)

二、修改phrase-extract/syntax-common/tree-inl.h

该文件有一些地方写得不太符合C++关于模板类的语法,所以会导致error。具体修改如下(这里只贴改后的版本,下同)

76行

1
typename Tree<T>::template PreOrderIter<V> &Tree<T>::PreOrderIter<V>::operator++() {

103行

1
typename Tree<T>::template PreOrderIter<V> Tree<T>::PreOrderIter<V>::operator++(int) {

165行

1
typename Tree<T>::template LeafIter<V> &Tree<T>::LeafIter<V>::operator++() {

190行

1
typename Tree<T>::template LeafIter<V> Tree<T>::LeafIter<V>::operator++(int) {

简单说,把所有返回Tree<T>::PreOderIter<V>的函数定义的返回类型改为typename Tree<T>::template PreOderIter<V>LeafIter的同理

三、修改symal/{Jamfile,cmd.c}

由于在构建的时候指定了-std=c++0x,因此不会编译C文件且会报错

1
2
3
error: invalid argument '-std=c++0x' not allowed with 'C'

"clang++" -x c -O3 -std=c++0x -O3 -finline-functions -Wno-inline -Wall -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_THREAD_DYN_DLL -DKENLM_MAX_ORDER=6 -DMOSES_VERSION_ID=\"mmt-mvp-v0.12.1-2808-g3545225c0-dirty\" -DNDEBUG -DTRACE_ENABLE=1 -DWITH_THREADS -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -I"." -c -o "symal/bin/clang-darwin-4.2.1/release/link-static/threading-multi/cmd.o" "symal/cmd.c"

这里的解决方法分三步

  1. 修改Jamfile文件,改为

    1
    exe symal : symal.cpp cmd.cpp ;
  2. 将cmd.c重命名为cmd.cpp

  3. 由于此时变为C++文件,因此callocmalloc的返回值不能是void*,需要加六处类型转换 147行

    1
    int *subrange = (int *)calloc(2, sizeof(int));

    155行

    1
    int *value = (int *)calloc(1, sizeof(int));

    323行

    1
    a = (char **)calloc(n+1, sizeof(char *));

    328行

    1
    a[n] = (char *)malloc(l+1);

    482行

    1
    indent = (char *)malloc(l+2);

    581行

    1
    if(!(Line=(char *)malloc(LINSIZ))) {

之后应该就可以编译成功了


A short summary of this blog: How to build Moses on Mac

This article records the issues and solutions I caught when I built moses, the de facto SMT toolkit on Mac. The details of my system can be referred to the Chinese part. Generally there are three issues:

  1. Boost library. I failed to build the system if I install the boost via brew install boost (It kept prompting that a library cannot be linked). When I built the boost library manually errors have gone.
  2. phrase-extract/syntax-common/tree-inl.hdoesn't follow the C++ syntax on templates. Follow the detailed above to solve it
  3. symal/cmd.cis a C file whilst make file indicates that C++ 0x standard should be followed. So just rename cmd.c to a c++ file extension e.g. cmd.cpp, then modify Jamfile. Since the code should follow C++ syntax instead of C syntax now, the return type of calloc/malloc is void* and cannot be directly used, thus a type cast should be applied. Details could also be checked in the Chinese part.
坚持原创技术分享,您的支持将鼓励我继续创作!