C++:所有升压路径操作segfault(OSX/GCC)

C++: All boost path operations segfault (OSX / GCC)

本文关键字:segfault OSX GCC 操作 路径 C++      更新时间:2023-10-16

我尝试使用boost路径执行的几乎所有操作都会出现一致的segfault。

编辑:似乎所有分段功能都与current_path()有关)

Sample program:
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <iostream>
using namespace std;
using namespace boost::filesystem;
using namespace boost::system;

int main(int argc, const char * argv[])
{
    error_code err;
    auto p = path("hello/../world");
    cout << p.string() << endl;
    path c = canonical(p, err);
    cout << c.string() << endl;
}

以上只是一个示例,以下也是segfault:
auto p = current_path(err);

以及:
auto p = initial_path(err);

编译者:
g++-4.9 -lboost_filesystem -lboost_system -std=c++11 main.cpp -o ./path-test

输出:

hello/../world
Segmentation fault: 11

GCC和Boost均通过Homebrew安装。

系统规格:

OSX:   10.9.4
GCC:   4.9.1
Boost: 1.0.55_2

编辑:

-g编译,并根据注释安装了信号处理程序,输出:

hello/../world
Segfault:
0   path-test                           0x000000010ea215b8 _Z7handleri + 28
1   libsystem_platform.dylib            0x00007fff8b9285aa _sigtramp + 26
2   ???                                 0x00007fff67bdf1a1 0x0 + 140734933889441
3   path-test                           0x000000010ea2196d _ZN5boost10filesystem9canonicalERKNS0_4pathERNS_6system10error_codeE + 69
4   path-test                           0x000000010ea21518 main + 138
5   libdyld.dylib                       0x00007fff832c35fd start + 1
6   ???                                 0x0000000000000001 0x0 + 1

Segfault信号处理程序(取自此问题):

void handler(int sig)
{
    void *array[10];
    size_t size;
    size = backtrace(array, 10);
    fprintf(stderr, "Segfault:n");
    backtrace_symbols_fd(array, size, STDERR_FILENO);
    exit(1);
}

您正在混合C++标准库的实现。

Boost,当通过brew安装时,将使用clang++进行编译。默认情况下,此工具链使用libc++

g++坚持使用自己的libstdc++实现。

这些实现不是二进制兼容的,这就是问题产生的地方。

我将boost的一个新副本提取到一个子目录中,做了一个:

$ ./bootstrap.sh --prefix=/usr/local/boost156 cxxflags="-arch i386 -arch x86_64" address-model=32_64 threading=multi macos-version=10.9 toolset=g++-4.8 stage

然后构建它(仅限静态;存在一个构建问题,在这种情况下,它无法在OSX下创建动态库-ld抱怨-h选项不受支持):

$ ./b2 --layout=tagged threading=multi link=static toolset=gcc-4.8

当我编译你的代码时(因为线程=multi,我不得不在链接选项中添加-mt):

$ g++-4.8 -g -std=c++11 -Iboost_1_56_0  -Lboost_1_56_0/stage/lib -lboost_filesystem-mt -lboost_system-mt main.cpp -o ./path-test
$ ./path-test
hello/../world
$

也就是说,在这种情况下它工作得很好。

这是什么意思?

  • 如果您尝试混合使用g++clang++,OSX上的C++库就是一个完整的PITA
  • 因为所有clang++代码默认使用libc++构建,所以如果您打算使用g++构建任何c++库,则必须拥有它们的私有副本
  • 自制程序在使用clang++编译时只是在遵循命令

这是一团糟,但如果你坚持<讽刺>一个真正的编译器<讽刺>,那你就没事了。TBH我更喜欢clang的错误消息,静态分析非常好;但是,如果必须使用g++,则必须保留要使用的任何c++库的私有副本,这些库也是用g++编译的。

除了Petersh的优秀答案外,对于任何通过自制程序使用gcc构建助推的人来说:

brew install boost --build-from-source --env=superenv --cc=gcc-<Your GCC version>

注意--env=superenv开关,这是Homebrew最近添加的开关,所以请确保您的酿造是最新的!

如果遇到问题,并且不确定boost是使用gcc还是clang编译的,请在任何boost动态库(.dylib文件)上使用otool -L,并查找libc++libstdc++条目。

例如,在我最终使其正常工作后运行以下命令:

otool -L /usr/local/lib/libboost_system.dylib

产生以下输出:

/usr/local/lib/libboost_system.dylib:
    /usr/local/lib/libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/local/lib/gcc/x86_64-apple-darwin13.3.0/4.9.1/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.20.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    /usr/local/Cellar/gcc/4.9.1/lib/gcc/x86_64-apple-darwin13.3.0/4.9.1/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)

第二个条目显示了这个boost-lib链接到GCC的libstd++。如果它说的是/usr/lib/libc++.dylib,那么它仍然与苹果的clang运行时相关联。

请注意,使用brew可以启用所有变体(单个/多个/静态/动态),因为公式的维护人员结合了补丁,以确保它在OSX上成功编译——这可能不是香草增强的基础。