macOS Mojave(10.14.2) 编译KhronosGroup/SPIR项目的spir_12分支(llvm-3.2编译)

官方提供了一个名为 KhronosGroup/SPIR 的开源项目,支持OpenCL编译成SPIR代码的功能

注意: Vulkan使用SPIR-V也就是 spirv-1.0 分支,不使用此分支。本文实际上可以作为 llvm-3.2 在最新的 macOS Mojave(10.14.2) 上的编译指南。

这个工具使用的LLVM的版本非常古老,编译的时候问题多多。

这个工具在 macOS Mojave(10.14.2) 系统上使用 gcc 8.2.0 的编译流程如下:

$ cd ~

$ git clone http://llvm.org/git/llvm.git llvm

$ cd llvm

$ git checkout --track -b release_32 remotes/origin/release_32

$ cd llvm/tools

$ git clone https://github.com/KhronosGroup/SPIR clang

$ cd clang

# 官方要求检出 spir_12 分支,但是貌似执行完成 clone 之后,就已经在这个分支上了
# git checkout --track -b spir_12 remotes/origin/spir_12

$ cd ../..

$ mkdir build

$ cd build

# 只能使用GCC编译,不能使用自带的LLVM编译
$ brew install gcc

$ brew unlink gcc

$ brew cleanup

$ brew link gcc

# 指定路径
$ export PATH=$(brew --prefix)/bin:$PATH

# 重定向编译工具到我们安装的GCC版本,版本号从brew的命令行中查询得到,如果安装了多个版本,请手工指定这个参数
$ export GCC_VER=$(brew list --versions | grep gcc | sed 's/\([0-9]\).*/\1/g' | tr -cd "[0-9]")

$ export CC="$(brew --prefix)/bin/gcc-$GCC_VER"

$ export CXX="$(brew --prefix)/bin/g++-$GCC_VER"

# 链接库目录
$ export CMAKE_LIBRARY_PATH=$(brew --prefix)/lib

$ export CMAKE_INCLUDE_PATH=$(brew --prefix)/include

# 不能使用 GCC 引入的 ar,ranlib 这两个程序,这两个程序处理的库不能被ld正常链接,我们需要使用macOS官方提供的 ar,ranlib
# 出现这个问题的原因在于macOS上的GCC并没有提供ld,其实即使提供ld也不能正常执行,原因在于macOS与GNU格式不兼容,无法正常链接
# 因此只能使用系统自带的链接工具,链接工具只认识系统自带的 ar,ranlib 转换后文件的格式
$ mv /usr/local/bin/ranlib /usr/local/bin/ranlib2

$ ln -s /usr/bin/ranlib /usr/local/bin/ranlib

$ mv /usr/local/bin/ar /usr/local/bin/ar2

$ ln -s /usr/bin/ar /usr/local/bin/ar

# 不能编译成动态库,原因在于这个版本的代码存在循环依赖的问题,动态库无法成功编译,只能编译成静态库
$ cmake .. -DBUILD_SHARED_LIBS=OFF

# 多线程同时编译,提高编译速度
$ make -j8

如果使用 Xcode Version 10.1 (10B61) 编译会报告如下错误:

[ 14%] Building CXX object lib/Analysis/CMakeFiles/LLVMAnalysis.dir/LazyValueInfo.cpp.o
llvm/lib/Analysis/LazyValueInfo.cpp:998:14: error: no matching member function for call to
      'insert'
    worklist.insert(worklist.end(), succ_begin(ToUpdate), succ_end(ToUpdate));
    ~~~~~~~~~^~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/vector:713:14: note: 
      candidate function not viable: no known conversion from 'llvm::succ_iterator' (aka
      'SuccIterator<llvm::TerminatorInst *, llvm::BasicBlock>') to 'std::__1::vector<llvm::BasicBlock *,
      std::__1::allocator<llvm::BasicBlock *> >::size_type' (aka 'unsigned long') for 2nd argument
    iterator insert(const_iterator __position, size_type __n, const_reference __x);
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/vector:724:9: note: 
      candidate template ignored: requirement '!__is_forward_iterator<SuccIterator<TerminatorInst *, BasicBlock>
      >::value' was not satisfied [with _InputIterator = llvm::SuccIterator<llvm::TerminatorInst *,
      llvm::BasicBlock>]
        insert(const_iterator __position, _InputIterator __first, _InputIterator __last);
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/vector:734:9: note: 
      candidate template ignored: requirement 'is_constructible<value_type, typename
      iterator_traits<SuccIterator<TerminatorInst *, BasicBlock> >::reference>::value' was not satisfied [with
      _ForwardIterator = llvm::SuccIterator<llvm::TerminatorInst *, llvm::BasicBlock>]
        insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last);
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/vector:705:14: note: 
      candidate function not viable: requires 2 arguments, but 3 were provided
    iterator insert(const_iterator __position, const_reference __x);
             ^
1 error generated.
make[2]: *** [lib/Analysis/CMakeFiles/LLVMAnalysis.dir/LazyValueInfo.cpp.o] Error 1
make[1]: *** [lib/Analysis/CMakeFiles/LLVMAnalysis.dir/all] Error 2
make: *** [all] Error 2

上述错误产生的原因在于 macOS 官方提供的 C++ 标准库中增加了校验 is_constructible (要求模版中的类必须明确构造函数和析构函数)这个逻辑,这个功能貌似在 C++ 14 中才加入的,显然这个校验有些操之过急了。

如果编译的时候出现如下错误信息:

ld: warning: ignoring file ../../lib/libLLVMTableGen.a, file was built for archive which is not the architecture being linked (x86_64): ../../lib/libLLVMTableGen.a
ld: warning: ignoring file ../../lib/libLLVMSupport.a, file was built for archive which is not the architecture being linked (x86_64): ../../lib/libLLVMSupport.a

...................................

ld: symbol(s) not found for architecture x86_64

...................................

则说明编译的时候,没有指定使用 macOS 官方提供的 ar , ranlib ,链接这两个程序到Xcode提供的即可。

如果编译的时候出现如下错误信息:

[ 78%] Building CXX object tools/clang/lib/Sema/CMakeFiles/clangSema.dir/AnalysisBasedWarnings.cpp.o
In file included from llvm/tools/clang/include/clang/Sema/DeclSpec.h:26,
                 from llvm/tools/clang/include/clang/Sema/Sema.h:22,
                 from llvm/tools/clang/include/clang/Sema/SemaInternal.h:18,
                 from llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp:17:
llvm/tools/clang/include/clang/Sema/AttributeList.h: In constructor 'clang::VecTypeHintAttributeList::VecTypeHintAttributeList(clang::IdentifierInfo*, clang::SourceRange, clang::IdentifierInfo*, clang::SourceLocation, clang::IdentifierInfo*, clang::SourceLocation, clang::ParsedType, clang::AttributeList::Syntax)':
llvm/tools/clang/include/clang/Sema/AttributeList.h:360:75: error: use of deleted function 'clang::AttributeList::~AttributeList()'
                     argumentKindLoc, NULL, 0, syntaxUsed), VecType(vecType) {}
                                                                           ^
In file included from llvm/tools/clang/include/clang/Sema/DeclSpec.h:26,
                 from llvm/tools/clang/include/clang/Sema/Sema.h:22,
                 from llvm/tools/clang/include/clang/Sema/SemaInternal.h:18,
                 from llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp:17:
llvm/tools/clang/include/clang/Sema/AttributeList.h:209:3 note: declared here
   ~AttributeList() LLVM_DELETED_FUNCTION;
   ^
make[2]: *** [tools/clang/lib/Sema/CMakeFiles/clangSema.dir/AnalysisBasedWarnings.cpp.o] Error 1
make[1]: *** [tools/clang/lib/Sema/CMakeFiles/clangSema.dir/all] Error 2
make: *** [all] Error 2

这是由于llvm/tools/clang/include/clang/Sema/AttributeList.h这个文件中的 ~AttributeList() LLVM_DELETED_FUNCTION; 这句话造成的,按理说这个析构函数不应该被调用到才对,但是代码中仍然有地方隐式调用了,我们需要做的就是去掉这行代码的 LLVM_DELETED_FUNCTION 属性即可。

# macOS 下面的sed相当的蛋痛
$ sed -i "" "s/^[ \t]*~AttributeList()[ \t]*LLVM_DELETED_FUNCTION;/~AttributeList() ;/g" llvm/tools/clang/include/clang/Sema/AttributeList.h

 

编译完成后的使用方式如下:

$ cd ~

# for opencl_spir.h
$ git clone https://github.com/KhronosGroup/SPIR-Tools.git

$ ~/llvm/build/bin/clang -cc1 -emit-llvm-bc -triple <triple> <OpenCL compile options> -cl-spir-compile-options "<OpenCL compile options>" -include ~/SPIR-Tools/headers/opencl_spir.h -o <output> <input>
  • <triple>: for 32 bit SPIR use spir-unknown-unknown, for 64 bit SPIR use spir64-unknown-unknown.
  • Note<OpenCL compile options> appears twice. The command line option -cl-spir-compile-options "<OpenCL compile options>" specifies the compile options that occur in the SPIR metadata.
  • <opencl_spir.h>: download opencl_spir.h from https://github.com/KhronosGroup/SPIR-Tools/blob/master/headers/opencl_spir.h
  • -O: -O0 (default) is the only tested option value at the moment. It's assumed by design that all optimizations are executed by SPIR consumer.

参考链接


macOS Mojave(10.14.2)使用"sed -i"命令时报错'sed: 1: "xxx": extra characters at the end of l command"'

最近在 macOS Mojave(10.14.2)使用"sed -i"命令时报错,类似如下:

$ sed -i "s/^[ \t]*~AttributeList()[ \t]*LLVM_DELETED_FUNCTION;/~AttributeList() ;/g" llvm/tools/clang/include/clang/Sema/AttributeList.h
sed: 1: "llvm/tools/clang/includ ...": extra characters at the end of l command

刚刚遇到这个问题,百思不得其解。后来搜索了一下,才找到解释。

如下:

$ man sed

..................................................

     -i extension
             Edit files in-place, saving backups with the specified extension.  If a zero-length extension is given,
             no backup will be saved.  It is not recommended to give a zero-length extension when in-place editing
             files, as you risk corruption or partial content in situations where disk space is exhausted, etc.

...................................................

sed  -i 需要带一个字符串,用来备份源文件,这个字符串会加在源文件名后面组成备份的文件名。
如果这个字符串长度为 0,就是说是个空串,那么不备份。

$ sed -i "_nima" 's/xx/python/g' example.txt

这样 sed 不仅会修改文件,并且会生成一个 example.txt_nima 的备份文件。

如果不想备份修改前的内容,可以直接给个空参数,如下:

$ sed -i "" 's/xx/python/g' example.txt

所以,上面的命令,我们需要修改成如下方式:

$ sed -i "" "s/^[ \t]*~AttributeList()[ \t]*LLVM_DELETED_FUNCTION;/~AttributeList() ;/g" llvm/tools/clang/include/clang/Sema/AttributeList.h

蛮扯淡的。

参考链接