使用GCC静态链接OpenMP

3

给定以下文件print.cpp:

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

我可以像这样静态链接:

我可以像这样静态链接:

g++ -static print.cpp

or like this

g++ -static-libgcc -Wl,-Bstatic -lc print.cpp -o print

现在让我们添加一些OpenMP,并将文件命名为print_omp.cpp。

#include <omp.h>
#include <stdio.h>
int main() { 
    printf("%d\n", omp_get_num_threads());
}

我可以像这样静态链接它(我用ldd检查过)。
g++ -fopenmp -static print_omp.cpp

然而,这并不起作用。

g++ -fopenmp -static-libgcc -Wl,-Bstatic -lc print_omp.cpp -o print

我已经尝试了各种组合,包括-Wl,--whole-archive -lpthread -Wl,--no-whole-archive 和 -lgomp -lpthread,但是都没有成功(我遇到了各种与pthreads链接的问题)。有人可以解释一下如何在不使用-static选项的情况下完成这个操作吗? GCC说:

在基于glibc的系统上,由于底层pthread实现的限制,OpenMP启用的应用程序无法进行静态链接。

然而,既然 g++ -fopenmp -static print_omp.cpp 可以正常工作,这对我来说就没有意义。
编辑: 我已经解决了这个问题。 库GOMP随GCC一起提供,而pthreads和libc来自GLIBC。所以我可以像这样静态链接GOMP。
ln -s `g++ -print-file-name=libgomp.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp

ldd展示

linux-vdso.so.1 =>  (0x00007fff71dbe000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc231923000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc23155c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc231b5c000)

然而,如果我尝试这样做

ln -s `g++ -print-file-name=libpthread.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp

它无法连接。Pthreads 和 libc 必须静态链接在一起。因此,一旦我添加

ln -s `g++ -print-file-name=libc.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp

ldd 返回

not a dynamic executable

1
libgcc 不是全部,libgomp 也不是其中的一部分。 - Vladimir F Героям слава
2个回答

4

我真的不明白为什么你想单独链接libgomp静态库,但是分开编译和链接命令可能会有所帮助。例如,假设main.cpp包含以下内容:

#include <omp.h>
#include <stdio.h>

int main() { 
#pragma omp parallel
  {
    printf("%d\n", omp_get_thread_num());
  }
}

然后:

~/tmp$ ls
main.cpp
~/tmp$ g++  -Wall -Werror -pedantic  -fopenmp main.cpp  -c
~/tmp$ ls
main.cpp  main.o
~/tmp$ locate libgomp.a
${SOME_PATH_TO_LIBGOMP}/libgomp.a
~/tmp$ g++  -Wall -Werror -pedantic main.o -o main.x ${SOME_PATH_TO_LIBGOMP}/libgomp.a -pthread
~/tmp$ ls
main.cpp  main.o  main.x
~/tmp$ ldd main.x
    linux-gate.so.1 =>  (0xb7747000)
    libstdc++.so.6 => /production/install/gnu/compiler/gcc/lib/libstdc++.so.6 (0xb765c000)
    libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb75fa000)
    libgcc_s.so.1 => /production/install/gnu/compiler/gcc/lib/libgcc_s.so.1 (0xb75de000)
    libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb75c2000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7413000)
    /lib/ld-linux.so.2 (0xb7748000)

1
看起来还不错。我明天会检查一下。基本上我正在Linux和Windows上制作一个共享库。其他开发人员希望尽可能少的依赖关系。最近我在一个旧版本的Linux NUMA系统上测试了我的库,由于缺少某个库的版本而中止。所以现在我正在尝试删除依赖项。令人惊讶的是,这在MSVC上很容易(除了OpenMP不能静态链接,除了Xbox)。但到目前为止,在Linux上比我预期的要麻烦得多。 - Z boson

2
我找到的最干净的解决方案是修改libgomp.spec文件。我的文件位于/usr/local/lib64/libgomp.spec。请按照以下内容进行更改:
*link_gomp: -l:libgomp.a %{static: -ldl }

请问您能否解释一下为什么这是最干净的解决方案? - Sascha Gottfried

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