一、 统一的预处理、编译、链接程序
一、1. 有些程序同时具有如下功能:
1. 预处理C/C++源代码
2. 编译C/C++源代码
3. 链接C/C++目标代码
例如:GCC的gcc、g++,MSVC的cl.exe。
一、2. 实际的情况也许更加复杂:
gcc、g++、cl.exe很有可能只是一个启动器。
用户只需要使用它们, 它们内部再根据特定条件, 执行其他程序,比如:
1. gcc、g++编译C/C++代码时, 最终会执行cc1/cc1plus程序。
该程序可能才是真正的C/C++编译器。
2. gcc、g++在链接C/C++目标代码时,最终会执行ld程序。
该程序可能才是真正的链接器。
3. cl.exe程序自己处理C/C++代码的预处理与编译工作。
4. cl.exe程序链接时,将执行link.exe。
该程序可能才是真正的链接器。
一、3. 我们的关注点
——上述复杂的情况我们大多数情况下无须操心:
1. 我们只需要使用gcc、g++
即使以后GCC将cc1、cc1plus、ld改为别的名字也不会受影响。
2. 我们只需要使用cl
即使以后cl不再担任编译工作或者link.exe被改为别的名字,同样不受影响。
——我们需要关心这些统一的程序,是根据何种条件, 决定它们的操作的?
本文只讨论编译:
1. 它们默认是通过何种条件, 决定按C语法或按C++语法编译一个翻译单元的。
2. 如何显式指定按C语法或者按C++语法去编译一个翻译单元。
二、 默认情况
如果不显式指定操作, gcc、g++、cl都是按文件后缀名来决定操作的。
二、1. 测试文件:
#ifndef __cplusplus
/* being treated as C translation unit */
#error !--- C ---!
#else
// being treated as C++ translation unit
#error !--- C++ ---!
#endif
我们建一个没有后缀的文件,叫nosuffix, 写入如上内容。
而且, 我们也不需要编译出目标代码。
只需要测试__cplusplus宏(见《预定义__cplusplus宏》)是否存在,并且用#error报告即可。
然后建立一些内容完全一样的文件:
#include "nosuffix"
这些文件共有10个:
c.c、 cpp.cpp、txt.txt、UC.C、UCPP.CPP、cc.cc、cxx.cxx、inl.inl、c++.c++、cp.cp。
(UC和UCPP是为了测试大写后缀名)
二、2. 测试方法
对GCC使用:
gcc(g++) filename >stdout.txt 2>stderr.txt
对MSVC使用:
cl filename >stdout.txt 2>stderr.txt
二、3. 测试结果
gcc、g++、cl对以下后缀名文件的默认操作如下表:
|
nosuffix
|
.c
|
.cpp
|
.txt
|
.C
|
.CPP
|
.cc
|
.cxx
|
.inl
|
.c++
|
.cp
|
gcc
|
obj
|
C
|
C++
|
obj
|
C++
|
C++
|
C++
|
C++
|
obj
|
C++
|
C++
|
g++
|
obj
|
C++
|
C++
|
obj
|
C++
|
C++
|
C++
|
C++
|
obj
|
C++
|
C++
|
cl
|
obj
|
C
|
C++
|
obj
|
C
|
C++
|
C++
|
C++
|
obj
|
obj
|
obj
|
对该表的几点说明:
1. 表中的obj表示该条件下, 统一程序将它们认作目标文件, 并打算执行链接工作。
这显然是错误的, 因为他们包含的是文本。
2. gcc、g++(编译代码)的区别
GCC认为带有.c、.cpp、.C、.CPP、.cc、.cxx、.c++、.cp(但不限于)后缀的文件是C/C++源文件。
gcc把带有.c后缀的文件, 当作C源文件, 把带有其他后缀名的文件当作C++源文件。
g++将带有上述所有后缀的文件,都当作C++源文件。
3. MSVC与GCC的区别
MSVC认为带有.c、.cpp、.C、.CPP、.cc、.cxx后缀的文件是C/C++源文件。
上述GCC相比, 排除了.c++和.cp
同时,windows下的文件名是不区分大小写的, 所以.c同.C,.cpp同.CPP是一样的。
与GCC相比, .C不再认为是C++源文件, 而是与.c一样作为C源文件处理。
二、4. 测试小结
由上表以及说明, 如果我们打算
编写跨平台的代码:
1. 不推荐使用的后缀名
.c++、.cp
——因为它们不被MSVC支持
.C
——因为MSVC并不区别对待.c与.C
2. 可以使用的后缀名
——对C源文件
可以使用.c。
——对C++源文件
可以使用.cpp、.cc、.cxx。
——.CPP不推荐
因为在xnix上 a.CPP与a.cpp是2个文件, 而复制到Windows上就将发生重名。
如果只使用.cpp就可以避免该情况。
3. 关于.inl
有些文件内容确实是C/C++代码, 但是却不直接作为翻译单元,而是被其他翻译单元包含。
理论上说,它们取任何名字都没关系。但是将它们取为.inl会得到一些好处:
—— 暗示该文件包含C/C++代码
—— 一些编辑器会对其按C/C++语法进行高亮。
三、 显式指定
有时候需要覆盖默认情况,显式指定我们需要的操作。
三、1. GCC “
-x”
GCC通过-x选项显式指定编译源代码的语言:
-x c(或-xc)
—— 将源代码作为C源文件。
-x c++、(或-xc++)
—— 将源代码作为C++源文件。
对于“二”中的测试, 只要将命令行改为:
gcc(g++) -x c (-xc) filename
所有文件都将被作为C源文件处理, 并输出 error !--- C ---!
而使用如下命令行:
gcc(g++) -x c++ (-xc++) filename
所有文件都将被作为C++源文件处理, 并输出 error !--- C++ ---!
三、2. MSVC “/TC” “/TP”
MSVC通过/TC(/TP)选项, 显式指定将输入作为C(C++)源代码。
对“二”中的测试, 命令行:
cl /TC filename
对所有文件都将输出 error !--- C --- !
命令行:
cl /TP filename
对所有文件都将输出 error !--- C++ ---!
四、总结
1. 使用“二、4”中推荐的方式,给源代码文件命名。
2. 覆盖默认情况,使用-x(GCC)或者/TC、/TP(MSVC)
3. 顺带提一点, gcc、g++用作链接时, 也有一些区别。
链接C++(或者C/C++混合)目标代码, 推荐使用g++。
因为GCC高版本中, gcc链接时默认不会导入C++需要的运行时库。
相关链接:
——源代码
http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/language
——《
预定义__cplusplus宏》
http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
转载请注明 :
文章作者 - OwnWaterloo
发表时间 - 2009年04月20日
原文链接 - http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html
posted on 2009-04-20 15:02
OwnWaterloo 阅读(2655)
评论(0) 编辑 收藏 引用