文章
服务器与存储开发
作者:Steve Clamage
2014 年 9 月发布
|
在 Oracle Solaris Studio 12.4 中,默认模板编译模型已经由 Oracle Solaris Studio 12.3 及早期版本中使用的 definitions-separate 模型更改为 definitions-included 模型。大多数应用将受益于这种变化。有些应用要恢复到早期版本的行为,则需要在 Oracle Solaris Studio C++ 编译器 (CC) 命令行中添加显式选项 -template=extdef。本文介绍此变化及其可能对构建 C++ 应用产生的影响。
Oracle Solaris Studio 12.4:C++ 用户指南 第 5 章讨论了组织模板源代码的两种方式:
.cc 文件中。在需要的地方包含该 .cc 文件。对应的 C++ 编译器选项是 -template=extdef。-template=no%extdef。过去,Oracle Solaris Studio C++ 编译器沿袭了第一个 C++ 编译器 Cfront 中引入的模板编译模型。因此,默认情况下,编译器使用 definitions-separate 模型。如果头文件 foo.h 包含模板声明,对于任何需要模板定义的编译,编译器自动包括 foo.cc。
注:本文使用 .cc 作为 C++ 源文件扩展名。本讨论同样适用于 Oracle Solaris Studio C++ 编译器识别的其他扩展名:.c、.cpp、.C、.c++ 和 .cxx。
definitions-separate 模型对源代码组织有以下要求。
foo.h 中缺失的任何模板定义均在 foo.cc 中。foo.cc 文件只包含 foo.h 中缺失的模板定义。foo.cc 文件不得包含 foo.h。foo.cc 文件不得单独编译。如果您想想只要包含 foo.h 的地方通常都会自动包含 foo.cc,就会立即明白以上限制的原因。
清单 1 显示函数模板 times2 的 definitions-separate 组织。
File times2.h
template<class T> T times2(T val);
File times2.cc
template<class T> T times2(T val) { return val*2; }
清单 1. 模板 times2,definitions-separate。
在清单 1 中,根据需要自动包括 times2.cc 文件。
清单 2 显示模板 times2 的 definitions-included 组织。
File times2.h
template<class T> T times2(T val) { return val*2; }
清单 2. 模板 times2,definitions-included。
在清单 2 中,模板定义包含在头文件中。没有单独的 .cc 文件。
清单 3 显示 definitions-included 模型的替代组织。
File times2.h
template<class T> T times2(T val);
#include "times2.cc"
File times2.cc
template<class T> T times2(T val) { return val * 2; }
清单 3. 模板 times2,替代 definitions-included。
在清单 3 中,模板定义在单独的文件中,但该文件通过 #include 指令显式包括。
在采用 definitions-separate 模板模型的编译器方面,早期版本的 Oracle Solaris Studio 可谓别具一格。原来使用其他编译器开发的代码经常与该模型发生冲突,经常在启用 -template=extdef 选项时不能编译。有些流行的开源代码(尤其是最近版本的 Boost)不能编译。开发人员经常需要在 CC 命令行添加 -template=no%extdef,才能让代码成功编译。
由于这些原因,Oracle Solaris Studio 团队更改了 Oracle Solaris Studio 12.4 中的默认行为,这样 definitions-separate 不再是默认模型。-template 选项的默认值由 -template=extdef 更改为 -template=no%extdef。
如果实际的源代码模型(包含定义或单独定义)与编译器期待的模型不匹配,会出现什么状况?有两种可能:
-template=extdef 选项(Oracle Solaris Studio 12.4 之前编译器版本的默认模型)生效,但未 遵循 definitions-separate 模型,可能多次编译 foo.cc 文件,从而导致编译和链接时出现多重定义错误。-template=no%extdef 选项(Oracle Solaris Studio 12.4 编译器的默认模型)生效,但已 遵循 definitions-separate 模型,可能从不编译 foo.cc 文件,从而可能在编译和链接时出现定义缺失错误。stdcxx 库的问题截至本文撰写时,通过 -library=stdcxx4 选项选择的 Oracle Solaris 版本的 Apache stdcxx 库与新的默认选项 -template=no%extdef 不兼容。您在编译时可能也会看到以 Warning: Could not find source for __rw:: 开头的警告,涉及库的内部。您在链接时可能会看到缺少名称中包括 __rw:: 的符号的错误。
在推出该库的更新版本之前,您可能需要向具有 -library=stdcxx4 的 CC 命令行添加 -template=extdef。
如果显式使用任一 -template=[no%]extdef 选项,则无需任何更改。Oracle Solaris Studio 12.4 中的唯一不同在于未指定这两个选项中任一者时的默认编译器行为。
如果您完全使用 Oracle Solaris Studio C++ 开发代码,或者该代码依赖于 definitions-separate 模板模型,可能需要在 CC 命令行添加选项 -template=extdef,以便恢复到 Oracle Solaris 12.3 及更低版本编译器的行为。
您还可以考虑修改源代码的组织方式,使其适用于任一模板编译模型。上面的清单 2 是适用任一模型的代码示例,其模板定义在头文件中且没有对应的 .cc 文件。
最后,这些选项只影响 C++ 程序的编译。它们不影响成功编译后 C++ 程序的含义。
Oracle Solaris Studio 12.4:C++ 用户指南
Steve Clamage 是 Oracle Solaris Studio 团队的高级工程师,并且是 Oracle C++ 编译器的项目主管。他从 1996 年开始一直担任美国 C++ 标准委员会的主席。
| 修订版 1.0,2014 年 9 月 12 日 |