c++ - 从 OSX 平台转换并使用 gcc 和 llvm 时构建失败

标签 c++ c macos gcc

我继承了一个用 C 和 C++ 编写的相当大和复杂的软件包,它使用 gcc 在 Mac OSX Lion 上成功构建:

$> gcc --version
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)

我的任务是使用命令行工具附带的默认 Mac 编译器在 OSX Mavericks 上构建相同的包。

$> gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix

OSX Lion 构建完成,但 OSX Mavericks 构建失败并出现以下错误:

Undefined symbols for architecture x86_64:
"_MRIsetVoxVal", referenced from ...

我已经通过以下代码块将错误源追踪到一个头文件:

#ifdef __cplusplus
float  MRIgetVoxVal( const MRI *mri, int c, int r, int s, int f);
int    MRIsetVoxVal(MRI *mri, int c, int r, int s, int f, float voxval);
void   MRIdbl2ptr(double v, void *pmric, int mritype);
double MRIptr2dbl(void *pmric, int mritype);
#else
inline float  MRIgetVoxVal(const MRI *mri, int c, int r, int s, int f);
inline int    MRIsetVoxVal(MRI *mri, int c, int r, int s, int f, float voxval);
inline void   MRIdbl2ptr(double v, void *pmric, int mritype);
inline double MRIptr2dbl(void *pmric, int mritype);
#endif

如果我通过简单地删除 if elseinline 语句来修改上面的代码块,使其看起来如下所示,那么构建将在两个平台上完成:

float  MRIgetVoxVal( const MRI *mri, int c, int r, int s, int f);
int    MRIsetVoxVal(MRI *mri, int c, int r, int s, int f, float voxval);
void   MRIdbl2ptr(double v, void *pmric, int mritype);
double MRIptr2dbl(void *pmric, int mritype);

所以看起来在 OSX Lion 上,触发了 ifdef __cplusplus 语句,它产生了所需的行为。在 Mavericks 上,else 语句被触发,最终导致错误。

如果这是一个非常基本的问题,请原谅我,但 C 和 C++ 不在我的专业领域之内。这里发生了什么? #ifdef __cplusplus 到底是什么意思,为什么一个版本的 gcc 会被它触发而另一个版本不会?

最佳答案

在编译器正确介入之前,preprocessor 执行许多任务。以散列 ('#') 开头的行是预处理器指令,包括诸如文件包含 (#include <stdio.h>)、宏变量定义 (#define DEBUG 1)、宏函数定义 (#define LENGTH(array) (sizeof(array) / sizeof(0[array]))) 和条件编译 (#if ... #endif) 等任务,如您所见代码片段。

宏允许在编译时通过用其值替换宏名称来重写源代码。它们是实现许多任务的早期方法,但大体上不尊重 C/C++ 语法,因此在许多方面被(例如)inline 说明符、模板、trait 类和 nullptr 取代,哪个更好地尊重语法和语义。

一些宏在 header 中定义(参见“limits.h”,在 C++ 中替换为 numeric_limits 以获取某些示例)。其他由预处理器定义; __cplusplus 是其中之一,它应该在编译器处理 C++ 文件时定义(由文件扩展名或可能的命令行参数确定,例如 GCC 的“-x”)。您可以使用“-dD”或“-dM”选项(如 gcc man 页面和 online docs 中所述)以及在预处理后停止的“-E”选项来指示 gcc 列出宏。 Nadeau Software Consulting 发布了有关如何为各种编译器列出 predefined macros 的提示。根据它,clang 应该接受与 gcc 相同的参数,因此请在 Mavericks 上尝试以下操作:

gcc -dM -E -x c++ /dev/null | less

__cplusplus 是 C++ 标准(C++11 中的第 16.8 1 节)所要求的。 Lion 和 Mavericks 构建的 gcc 之间的一大区别是后者使用 clang 前端,而前者使用 GCC。网络搜索“clang __cplusplus”表明 clang 应该支持它,因此如果未定义 __cplusplus,则 clang 可能会将文件编译为 C。您可以尝试“-x c++”选项来强制使用 C++。您也可以尝试“-std=gnu++11”选项,但我怀疑它在这里不会有什么不同,因为它旨在支持非标准 Gnu C++ extensions 而不是提供完整的 GCC 兼容性。

关于c++ - 从 OSX 平台转换并使用 gcc 和 llvm 时构建失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28508465/

相关文章:

c - AND、OR 、XOR 字符串与 127

mysql - 在 El Capitan 上退出 MySQL 而不重新启动

objective-c - 如何在 OSX 上防止消息对话框 "myapp wants to sign using privateKey ..."?

c++ - 在 Windows 中将 rinside 与 qt 一起使用

c++ - 可移植检测 __VA_OPT__ 支持?

c++ - 如何删除xsi :type information from gSoap message?

c - 将 char 指针传递给函数的替代方法

macos - cabal install ...失败 - osx - 许多不满意的包

c++ - 如何配置 teamcity 构建代理以使用系统上的包含文件?

c++ - 无符号变量的默认值是多少?