【问题标题】:clang linker problemclang 链接器问题
【发布时间】:2011-05-08 19:09:04
【问题描述】:

我刚刚试用了最新的 llvm 和 clang trunk 版本。他们编译时没有一个开箱即用的警告,但我在链接一个 hello world 示例时遇到了麻烦。我的代码是

#include <stdio.h>
int main(){
  printf("hello\n");
}

如果我使用

编译
clang test.c

我收到以下错误

/usr/bin/ld: crt1.o: No such file: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)

使用 -v 表明 gnu ld 被调用为

"/usr/bin/ld" --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o a.out crt1.o crti.o crtbegin.o -L -L/../../.. /tmp/cc-0XJTsG.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed crtend.o crtn.o

但我有 crt1.o 目标文件!

$ locate crt1.o
/usr/lib/Mcrt1.o
/usr/lib/Scrt1.o
/usr/lib/crt1.o
/usr/lib/gcrt1.o

同样有效的是

clang -c test.c
gcc test.o

当然

gcc test.c

我进一步尝试了什么:

$ clang -Xlinker "-L /usr/lib" test.c 
/usr/bin/ld: crt1.o: No such file: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ clang -Xlinker "-L /usr/lib" test.c -v 
"/usr/bin/ld" --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o a.out crt1.o crti.o crtbegin.o -L -L/../../.. -L /usr/lib /tmp/cc-YsI9ES.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed crtend.o

我还尝试将 crt1.o 文件复制到当前目录中。这似乎奏效了。好吧,它没有编译,因为在那之后 crti.o 丢失了。

我的发行版是 Ubuntu。

好吧,我真的不知道下一步该尝试什么。我不知道如何修复 clang,也不知道如何在 ld 调用中注入必要的路径。有什么想法吗?

【问题讨论】:

  • 我的clang页面中只有-Xlinker的简短描述,但是-Xlinker不应该为带有参数的选项传递两次吗?这就是 gcc 的手册页对 -Xlinker 的说明。

标签: c linker clang


【解决方案1】:

似乎是clang版本,无法检测主机的linux版本和gcc版本..

clang 中的这段代码必须添加到 crt* 的路径: llvm›tools›clang›lib›Driver›Tools.cpp

  CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o")));
  CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
  CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));

GetFilePath 将尝试在当前 ToolChain 的 getFilePaths() 列表中搜索请求的文件(文件 clang/lib/Driver/ToolChains.cpp)。如果找不到文件,它将返回名称不变。

请给我你的 ubuntu 版本(uname -acat /etc/lsb-release)、clang 和 llvm 的确切版本(svn 修订号)以及gcc -v 输出

【讨论】:

  • 奇怪的是,我拥有的那个函数的实现与你引用的不同......但是添加 Paths.push_back("/usr/lib");Paths.push_back("/usr/lib/gcc /i486-linux-gnu/4.4/");成功了。如果我正确解释了我拥有的代码,那么它只会在 /usr/lib64 不存在时在 /usr/lib 中查找。但是该目录存在于我的系统中
  • 有一句很古老的名言。现在我得到llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver 并且可以检查您的clang rev、ubuntu 和gcc 版本组合的代码
  • GetFilePath() 的代码尝试在getFilePaths() 列表中的每个目录中打开一个询问的文件 (crt1.o)。如果某处有文件,它将停止,否则它将返回没有路径的文件名
  • 我已经成功地设置了环境变量 COMPILER_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.4.4 与最新的 SVN(版本 3.1SVN)。
  • sam,具体的 svn 版本和分支是什么?
【解决方案2】:

这个可怕的 HACK “修复”了在 Ubuntu 11.10 (x86) 上使用 clang 3.0(r142716) 编译/链接

在 /usr/include/stdio.h:28 中包含的文件中:
/usr/include/features.h:323:10:致命错误:找不到“bits/predefs.h”文件

/usr/bin/ld: 找不到 crt1.o: 没有那个文件或目录
/usr/bin/ld: 找不到 crti.o: 没有这样的文件或目录

diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 75300b5..3e2be30 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -241,6 +241,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
   // FIXME: Handle environment options which affect driver behavior, somewhere
   // (client?). GCC_EXEC_PREFIX, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS.

+  PrefixDirs.push_back("/usr/lib/i386-linux-gnu");
   if (char *env = ::getenv("COMPILER_PATH")) {
     StringRef CompilerPath = env;
     while (!CompilerPath.empty()) {
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index b066e71..c6ffee8 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -562,10 +562,12 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
       AddPath("/usr/include/x86_64-linux-gnu", System, false, false, false);
       AddPath("/usr/include/i686-linux-gnu/64", System, false, false, false);
       AddPath("/usr/include/i486-linux-gnu/64", System, false, false, false);
+      AddPath("/usr/include/i386-linux-gnu/64", System, false, false, false);
     } else if (triple.getArch() == llvm::Triple::x86) {
       AddPath("/usr/include/x86_64-linux-gnu/32", System, false, false, false);
       AddPath("/usr/include/i686-linux-gnu", System, false, false, false);
       AddPath("/usr/include/i486-linux-gnu", System, false, false, false);
+      AddPath("/usr/include/i386-linux-gnu", System, false, false, false);
     } else if (triple.getArch() == llvm::Triple::arm) {
       AddPath("/usr/include/arm-linux-gnueabi", System, false, false, false);
     }

【讨论】:

【解决方案3】:

在最近的 (3.5) 版本中,对于在安装了 pre-gcc 4.7 libstdc++ 库的系统上使用 --with-gcc-toolchain 配置选项进行构建的任何人来说,此类问题再次出现。

你会看到它有两种风格:

echo '#include <string>' | clang++ -xc++ -
<stdin>:1:10: fatal error: 'string' file not found
#include <string>
          ^
1 error generated.

...以及不打算找到各种crt文件。

在这两种情况下,您都可以通过以下方式解决问题,直到问题得到解决:

printf '#include <string>\nint main( int argc, char *argv[] ) { return 0; }' > /tmp/blah.cc
# Fixes issue not finding C++ headers; note that it must be gcc >= 4.7
clang++ --gcc-toolchain=/path/to/gcc/install -c -o /tmp/blah.o /tmp/blah.cc
# Fixes the link error
clang++ --gcc-toolchain=/path/to/gcc/install /tmp/blah.o /tmp/blah

【讨论】:

    【解决方案4】:

    运行:

    clang -v
    

    在我的示例输出中是:

    clang version 3.0 (tags/RELEASE_30/final)
    Target: armv7l-unknown-linux-gnueabi
    Thread model: posix
    

    以 root 身份运行以下命令以使用目标创建缺少的目录作为链接:

    ln -s /lib/arm-linux-gnueabi /lib/armv7l-unknown-linux-gnueabi
    ln -s /usr/lib/arm-linux-gnueabi /usr/lib/armv7l-unknown-linux-gnueabi
    ldconfig
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 2012-10-22
      • 2016-03-31
      • 1970-01-01
      相关资源
      最近更新 更多