此示例包含多个文件:
(JavascriptExecutor)driver.executeScript("window.scrollBy(0,250)", "");
// baz.cxx
int wat = 0;
int counter = ++wat;
// foo.cxx (empty)
// bar.cxx (empty)
// main.cxx
#include <iostream>
extern int wat;
int main() {
std::cout << wat << '\n';
}
按原样,如果您只运行// makefile
run : main.cxx foo.so bar.so
g++ -std=c++11 $^ -o $@
baz.a : baz.cxx
g++ -std=c++11 -c $^ -o baz.o -fPIC
ar rcs $@ baz.o
%.so : %.cxx baz.a
g++ -std=c++11 $< -Wl,--whole-archive baz.a -Wl,--no-whole-archive -o $@ -shared -fPIC
,那么所有内容都包含编译,构建,链接,运行和输出make && LD_LIBRARY_PATH=. ./run
。这是因为2
和foo.so
都提供了bar.so
,wat
的初始化运行了两次。
在这种情况下,有没有办法以某种方式强制counter
无法与多重定义错误相关联,同时仍然确保run
和foo.so
都有{bar.so
的定义1}}?
答案 0 :(得分:2)
您可以将链接描述文件rule x
when
Policy( available, $reqs: requestedCovers, $covs: covers )
accumulate( Cover( $type: type ) from $covs;
$covered: collectSet( $type ) )
$s: String( this not memberOf $covered ) from $reqs
then
...$s is not covered...
end
和libfoo.so
与静态部分一起使用,这会产生符号冲突(并在一些非显而易见的地方安装实际的DSO,以便libbar.so
和{ {1}}不要接他们。)
这样的事情:
-lfoo
-lbar
libfoo.so
INPUT(conflict.o)
INPUT(./foo.so)
libbar.so
INPUT(conflict.o)
INPUT(./bar.so)
这导致:
conflict.cxx
这只会在链接编辑器的同一次运行中检测冲突。您仍然可以使用int conflict;
和g++ -std=c++11 main.cxx -o run -L. -lfoo -lbar
conflict.o:(.bss+0x0): multiple definition of `conflict'
conflict.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
链接两个不同的DSO,并将这两个DSO链接到应用程序中,而不会出现链接编辑器中的错误。
ABI注释解决了类似的问题,但我认为这些问题需要进行特定的-lfoo
更改。
如果运行时检查是可接受的,则可以使用每个DSO定义的弱符号列表,这些符号需要冲突,并实现ELF构造函数,如果定义了多个DSO,则会中止该过程。我不知道在静态链接时使用GNU工具链可以获得同样可靠的东西。也许这值得针对binutils的RFE错误。
答案 1 :(得分:1)
我认为解决问题的唯一正确方法是将bar.a
解决方案的内容移动到某个共享库,从而解决钻石继承问题......但我认为这超出了这个问题的范围。 / p>
我唯一能想到的就是在链接最终可执行文件之前创建“自定义”验证程序。像这样:
nm *.so | \ # get all symbols
grep " [B|T] " | \ # only exported ones
egrep -v "__bss_start|_end|_fini|_init" | \ # filter out some commons, probably to be extended
awk '{print $3}' | \ # get only symbol name
sort | uniq -c | \ # sort and count
egrep -v "^[ ]+1 " # get only those that have multiple definitions
这将打印多次定义的库中的所有强(导出)符号。您可以轻松地将其包装在脚本中,如果输出不为空且有意义的消息,则返回错误状态代码。
修补后的makefile的实验版本如下所示:
run: main.cxx foo.so bar.so
! nm foo.so bar.so | grep " [B|T] " | egrep -v "__bss_start|_end|_fini|_init" | awk '{print $3}' | sort | uniq -c | egrep -v "^[ ]+1 "
g++ -std=c++11 $^ -o $@
(注意!
反转最终grep的退出代码,该代码搜索任何不以裸1开头的uniq -c
输出
我知道这真的是一种黑客,丑陋和不便携的解决方案,但我认为它可能在像你这样的角落里有一些价值。