我正在使用YouCompleteMe Vim插件来进行文本补全(通过Vundle安装)。YouCompleteMe使用Clang对C语言系列(C、C ++、Objective-C、Objective-C ++)进行文本补全。然而,在YouCompleteMe更新后(通过Vim中的:VundleUpdate
),YouCompleteMe停止工作。
简而言之,问题是:如何针对自定义glibc版本编译Clang? Debian Wheezy附带glibc 2.13,而最新版本的Clang需要至少glibc 2.15(在下面有更详细的说明)。以防万一,我正在使用Debian Wheezy,x86-64和自定义Linux内核版本4.0.0-rc6。
因此,根据LLVM网站上的说明,我从git镜像下载了LLVM:
$ mkdir ~/code $ cd ~/code/llvm_source_tree $ git clone http://llvm.org/git/llvm.git $ cd ~/code/llvm_source_tree/llvm/tools $ git clone http://llvm.org/git/clang.git $ cd ~/code/llvm_source_tree/llvm/projects $ git clone http://llvm.org/git/compiler-rt.git $ git clone http://llvm.org/git/test-suite.git $ cd ~/code/llvm_source_tree/llvm $ git config branch.master.rebase true
然后,我按照LLVM网站上的指示编译了LLVM:
$ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make -j 5 $ su # make install
一切都很顺利,所以我继续使用YouCompleteMe安装说明编译YouCompleteMe支持库:
$ mkdir ~/ycm_build $ cd ~/ycm_build $ cmake -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp $ make ycm_support_libs
然后我运行了Vim,发现YouCompleteMe似乎仍然无法工作。当我在Vim中进入某个C++文件的编辑模式时(例如),YouCompleteMe会打印错误:The ycmd server SHUT DOWN (restart with :YcmRestartServer). Stderr (last 30 lines):
,之后:YcmRestartServer
会打印Restarting ycmd server...
,然后是('Connection aborted.', error(111, 'Connection refused'))
)。
:YcmDebugInfo
会打印以下内容:
Printing YouCompleteMe debug information... -- Server crashed, no debug info from server -- Server running at: http://127.0.0.1:37730 -- Server process ID: 22358 -- Server logfiles: -- /tmp/ycm_temp/server_37730_stdout.log -- /tmp/ycm_temp/server_37730_stderr.log
/tmp/ycm_temp/server_37730_stdout.log
为空,但 /tmp/ycm_temp/server_37730_stderr.log
包含以下行:
2015-05-20 17:06:46,126 - 调试信息 - 没有全局额外配置,不调用 YcmCorePreload 方法 最近的一次调用报错: 文件 "/usr/lib/python2.7/runpy.py",第 162 行:在主函数中运行模块时发生异常 "__main__", fname, loader, pkg_name) 文件 "/usr/lib/python2.7/runpy.py",第 72 行:执行代码 exec code in run_globals 文件 "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/ycmd/__main__.py",第 164 行:从主模块引入 Ycmd Main() 文件 "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/ycmd/__main__.py",第 150 行:从 ycmd 中引入处理程序 from ycmd import handlers 文件 "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/ycmd/../ycmd/handlers.py",第 30 行:导入出错 str( e ) ) ) RuntimeException: 导入 ycm_core 出错,请确保您已经将版本 3.2+ 的 libclang.[so|dll|dylib] 放置在 "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd" 文件夹中。请参阅文档中的安装指南。完整错误信息:/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found (required by /home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/ycmd/../libclang.so)
我运行了YouCompleteMe的测试,当运行./vim/bundle/YouCompleteMe/third_party/ycmd/run_tests.sh
时出现了以下错误:
RAN: '/usr/bin/make -j 8 ycm_core_tests'
STDOUT:
STDERR:
看起来Clang 3.6.0可能需要glibc 2.15或更新版本。Debian Wheezy使用的是glibc 2.13。因此,决定安装最新稳定版的glibc(目前是2.21)。之前已经编译过binutils并将其安装到了
/usr/local/bin/
,所以现在不需要再次进行。因此,下载http://ftp.gnu.org/gnu/glibc/glibc-2.21.tar.bz2,然后解压缩它,编译源代码并安装:
$ cd ~/code $ mkdir ~/code/glibc $ cd ~/code/glibc $ mv -iv ~/downloads/glibc-2.21.tar.bz2 . $ tar xjvf glibc-2.21.tar.bz2 $ cd glibc-2.21 $ mkdir build $ cd build $ ../configure --with-binutils=/usr/local/bin --prefix=/usr/local/glibc/glibc-2.21 $ make -j 5 $ su # make install
然后我重新编译了LLVM。 我向cmake
传递了CMAKE_CXX_FLAGS
环境变量,按照Employed Russian回答Stack Overflow的问题Multiple glibc libraries on a single host中的方法使用g++链接器标志:
$ export CMAKE_CXX_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/ld-linux.so.2' $ cmake -G'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make -j 5
然后我重新编译了YouCompleteMe支持库,再次将g ++链接器标志传递给cmake
的CMAKE_CXX_FLAGS
参数:
$ export CMAKE_CXX_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/ld-linux.so.2' $ cmake -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp
但是YouCompleteMe的问题仍然存在,测试仍然以相同的方式失败。也许使用CMAKE_CXX_FLAGS
不足以将g++链接器标志传递给cmake
?我还尝试在编译LLVM时使用LD_LIBRARY_PATH
与glibc 2.21:
$ cd ~/code/llvm_source_tree $ mkdir build2 $ cd build2 $ export LD_LIBRARY_PATH="/usr/local/glibc/glibc-2.21/lib:$LD_LIBRARY_PATH" $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/
结果出现以下错误:
cmake: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
然后我也尝试了LD_PRELOAD
:
$ export LD_PRELOAD='/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2 /usr/local/glibc/glibc-2.21/lib/libc.so.6' $ export LD_LIBRARY_PATH="/usr/local/glibc/glibc-2.21/lib:$LD_LIBRARY_PATH" $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/
但是出现了以下错误:
-- The C compiler identification is unknown -- The CXX compiler identification is unknown Inconsistency detected by ld.so: dl-minimal.c: 136: realloc: Assertion `ptr == alloc_last_block' failed!
然后我还尝试将/usr/local/glibc/glibc-2.21/lib/ld-2.21.so
添加到export LD_PRELOAD
中,但是错误信息没有任何改变。
posix_spawn@GLIBC_2.15
)最初来自于glibc 2.15。根据其文档,glibc试图保持向后兼容性,并且另一个缺失的符号(memcpy@GLIBC_2.14
)来自于glibc 2.14。因此,我没有尝试使用glibc 2.15进行所有操作。但现在我已经没有想法了,任何建议将不胜感激。
编辑1
我按照下面雇佣的俄国人的答案所说的做了,但我的问题没有任何改变。因此,我得出结论:export CMAKE_CXX_FLAGS
不是将g++链接器标志传递给cmake
的正确方法。CMAKE_CXX_FLAGS
是一个cmake
内部的变量名称,但cmake
根本不关心具有相同名称(CMAKE_CXX_FLAGS
)的环境变量。CMAKE_CXX_FLAGS
可以直接在CMakeLists.txt
中定义,但在LLVM编译说明中没有使用主CMakeLists.txt
,如果有更实用的选项,我不想从头开始重新创建LLVM编译脚本。但我仍然找到了3个其他可用的选项:
cmake
会从名为CXXFLAGS
的环境变量中初始化CMAKE_CXX_FLAGS
。请参见 sakra 在 SO 问题 Adding include directories to cmake when calling it from command line 中的答案。
$ export CXXFLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make
CMAKE_CXX_FLAGS
也可以使用命令行选项-DCMAKE_CXX_FLAGS
进行初始化:
$ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' -DCMAKE_CXX_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/ld-linux-x86-64.so.2' ~/code/llvm_source_tree/llvm/ $ make
CMAKE_CXX_FLAGS
也可以通过命令行使用-DCMAKE_CXX_FLAGS:STRING
进行初始化(请参见Building mpllibs):
$ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' -DCMAKE_CXX_FLAGS:STRING='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/ld-linux-x86-64.so.2' ~/code/llvm_source_tree/llvm/ $ make所有这三个选项都会产生完全相同的结果:编译LLVM最终都会出现与目标
llvm-tblgen
和intrinsics_gen
相关的错误(上面由cmake
命令生成的3个Makefile
之间唯一的区别在于目录名称,这是因为每个构建都是在不同的目录中完成的)。似乎目标llvm-tblgen
得到了适当的编译和链接,但之后目标llvm-tblgen
似乎成为了目标intrinsics_gen
的依赖项,而某种方式下llvm-tblgen
无法找到。这些是make
输出的最后几行(对于上述的3个构建,这些行是相同的)。
链接CXX可执行文件../../bin/llvm-tblgen [4%]已构建目标llvm-tblgen 扫描依赖项的目标intrinsic_gen [4%]正在构建Intrinsics.gen...... /bin/sh:1:../../../bin/llvm-tblgen:未找到 make [2]:*** [include / llvm / IR / Intrinsics.gen.tmp] 错误127 make [1]:*** [include / llvm / IR / CMakeFiles / intrinsics_gen.dir / all] 错误2 make:*** [全部] 错误2
我想知道这是否是LLVM中的错误,还是像我在上面的3个构建中所做的那样设置了cmake
变量CMAKE_CXX_FLAGS
是否足够,或者是由其他原因引起的。 如何继续进行的任何想法将不胜感激。
编辑2
根据Employed Russian在他的评论(下方的答案)中提供的建议:
$ export CXXFLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make
这也导致与目标llvm-tblgen
和intrinsics_gen
相关的编译错误,但与之前的错误不同。这是make
输出的最后几行:
链接CXX可执行文件../../bin/llvm-tblgen [ 4%] 已构建目标llvm-tblgen 扫描依赖项目标intrinsics_gen [ 4%] 正在构建Intrinsics.gen... ../../../bin/llvm-tblgen: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory make[2]: *** [include/llvm/IR/Intrinsics.gen.tmp] Error 127 make[1]: *** [include/llvm/IR/CMakeFiles/intrinsics_gen.dir/all] Error 2 make: *** [all] Error 2所以,看起来现在可以找到
llvm-tblgen
了,但是加载共享库 libtinfo.so.5
时出现错误。所以我将 --rpath=/usr/local/glibc/glibc-2.21
修改为 --rpath=/usr/local/glibc/glibc-2.21/lib
并再次尝试:
$ export CXXFLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make然而,这种
--rpath
的更改并没有改变 make
所产生的错误消息。我想知道这个共享库 libtinfo.so.5
应该放在哪里。然后我遇到了 Building the Clang + LLVM compilers website 并尝试将
-std=c++11
添加到 CXXFLAGS
中:
$ export CXXFLAGS='-std=c++11 -Wl,-rpath=/usr/local/glibc/glibc-2.21 -Wl,-dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make但是没有帮助,错误信息相同,即找不到共享库
libtinfo.so.5
。也许我的g++
版本太旧了,它是随Debian Wheezy一起提供的g++
4.7.2(g++ --version
打印出g++ (Debian 4.7.2-5) 4.7.2
)。Building the Clang + LLVM compilers website的作者写道,他尝试在Fedora 15上只使用g++
4.7.1构建LLVM失败了,而使用几次重启和不同的g++
版本(4.8、4.8.0、4.7.1)编译最终成功(在网站上描述)。有什么想法吗?
编辑3
如Employed Russian所建议的,我使用-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu
重新编译了glibc 2.21:
$ cd ~/code/glibc/glibc-2.21 $ mv -iv build old_build $ mkdir build $ cd build $ export LD_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu' $ ../configure --with-binutils=/usr/local/bin --prefix=/usr/local/glibc/glibc-2.21 $ make -j 5
make check
产生了一些错误:
测试结果总结: 112 失败 2073 通过 199 XFAIL 3 XPASS make[1]: *** [tests] 错误 1 make[1]: 离开目录 `/home/user/code/glibc/glibc-2.21' make: *** [check] 错误 2
无论如何,我安装了新编译的glibc 2.21:
$ su # make install
make install
产生了这个警告:
/home/user/code/glibc/glibc-2.21/build/elf/ldconfig: 警告:忽略无法打开的配置文件:/usr/local/glibc/glibc-2.21/etc/ld.so.conf:没有那个文件或目录 make[1]: 离开目录“/home/user/code/glibc/glibc-2.21”
然后,我再次使用-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu
重新编译了LLVM:
$ export CXXFLAGS='-std=c++11 -Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make
但是缺少libstdc++.so.6
:
因此,我得出结论,还必须使用 --rpath 指定其他某些库目录。 $ cd /usr $ sudo find . -name 'libstdc++.so.6' ./lib32/debug/libstdc++.so.6 ./lib32/libstdc++.so.6 ./lib/x86_64-linux-gnu/debug/libstdc++.so.6 ./lib/x86_64-linux-gnu/libstdc++.so.6 ./lib/git-annex.linux/usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./lib/i386-linux-gnu/libstdc++.so.6
其中,
./lib/x86_64-linux-gnu/libstdc++.so.6
对我来说似乎是最合适的。因此,我将/usr/lib/x86_64-linux-gnu
添加到 --rpath
中,然后再次重新编译了glibc 2.21:
$ cd ~/code/glibc/glibc-2.21 $ mv -iv build old_build2 $ mkdir build $ cd build $ export LD_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu' $ ../configure --with-binutils=/usr/local/bin --prefix=/usr/local/glibc/glibc-2.21 $ make -j 5
这一次我没有费心去make check
,而是直接进行安装:
$ su # make install
然后得到了同样看起来无害的警告:
/home/user/code/glibc/glibc-2.21/build/elf/ldconfig: 警告: 忽略无法打开的配置文件: /usr/local/glibc/glibc-2.21/etc/ld.so.conf: 没有那个文件或目录 make[1]: 离开目录 `/home/user/code/glibc/glibc-2.21'
因此,我将 /usr/lib/x86_64-linux-gnu
添加到 LLVM 的 --rpath
中,并重新编译了 LLVM:
$ export CXXFLAGS='-std=c++11 -Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/ $ make
编译成功后,我安装了 LLVM:
$ su # make install
然后,我使用与编译 LLVM 相同的 CXXFLAGS
重新编译了 YouCompleteMe 支持库:
$ export CXXFLAGS='-std=c++11 -Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp $ make ycm_support_libs
这个构建也成功了。然后我重新安装了YouCompleteMe:
$ cd $ .vim/bundle/YouCompleteMe/install.sh
完成功能似乎正常。然后我运行了YouCompleteMe的测试:
$ .vim/bundle/YouCompleteMe/run_tests.sh
好的,自动完成仍在工作。
$ .vim/bundle/YouCompleteMe/third_party/ycmd/run_tests.sh这导致了一个问题。似乎这个
.vim/bundle/YouCompleteMe/third_party/ycmd/run_tests.sh
重新编译支持库,而不使用我的 Makefile
,因此破坏了支持库。解决方案不是运行 .vim/bundle/YouCompleteMe/third_party/ycmd/run_tests.sh
。
[100%] 构建 CXX 对象 ycm/tests/CMakeFiles/ycm_core_tests.dir/TestUtils.cpp.o 链接 CXX 可执行文件 ycm_core_tests ../../clang+llvm-3.6.0-x86_64-linux-gnu/lib/libclang.so: undefined reference to `posix_spawn@GLIBC_2.15' ../../clang+llvm-3.6.0-x86_64-linux-gnu/lib/libclang.so: undefined reference to `memcpy@GLIBC_2.14' collect2: error: ld returned 1 exit status make[3]: *** [ycm/tests/ycm_core_tests] Error 1 make[2]: *** [ycm/tests/CMakeFiles/ycm_core_tests.dir/all] Error 2 make[1]: *** [ycm/tests/CMakeFiles/ycm_core_tests.dir/rule] Error 2 make: *** [ycm_core_tests] Error 2
所以我按照最近的方式重新编译了支持库,然后再次安装YouCompleteMe:
$ export CXXFLAGS='-std=c++11 -Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2' $ cmake -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp $ make ycm_support_libs
$ cd $ .vim/bundle/YouCompleteMe/install.sh
最后,YouCompleteMe又可以正常工作了!
/usr/lib
,/lib
, 或者/lib/x86_64-linux-gnu
等Wheezy上的系统库。你的glibc-2.21
构建也可能没有在那里查找。尝试将系统库路径添加到你的RPATH
中,像这样:-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu
。 - Employed Russian/usr/lib/x86_64-linux-gnu
实际上也是必需的,像这样:-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib:/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu
。 - nrz