单个源⽂件⽣成可执⾏程序
下⾯是⼀个保存在⽂件 helloworld.cpp 中⼀个简单的 C++ 程序的代码: 单个源⽂件⽣成可执⾏程序
/* helloworld.cpp */#include int main(int argc,char *argv[]){ std::cout << \"hello, world\" << std::endl; return(0);} 程序使⽤定义在头⽂件 iostream 中的 cout,向标准输出写⼊⼀个简单的字符串。该代码可⽤以下命令编译为可执⾏⽂件: $ g++ helloworld.cpp 编译器 g++ 通过检查命令⾏中指定的⽂件的后缀名可识别其为 C++ 源代码⽂件。 ** 编译器默认的动作:** 编译源代码⽂件⽣成对象⽂件(object file),链接对象⽂件和 libstd c++ 库中的函数得到可执⾏程序。然后删除对象⽂件。由于命令⾏中未指定可执⾏程序的⽂件名,编译器采⽤默认的 a.out。程序可以这样来运⾏:$ ./a.outhello, world 更普遍的做法是通过 -o 选项指定可执⾏程序的⽂件名。下⾯的命令将产⽣名为 helloworld 的可执⾏⽂件: $ g++ helloworld.cpp -o helloworld 在命令⾏中输⼊程序名可使之运⾏: $ ./helloworldhello, world 程序 g++ 是将 gcc 默认语⾔设为 C++ 的⼀个特殊的版本,链接时它⾃动使⽤ C++ 标准库⽽不⽤ C 标准库。通过遵循源码的命名规范并指定对应库的名字,⽤ gcc 来编译链接 C++ 程序是可⾏的,如下例所⽰: $ gcc helloworld.cpp -lstdc++ -o helloworld 选项 -l (ell)通过添加前缀 lib 和后缀 .a 将跟随它的名字变换为库的名字libstdc++.a。⽽后它在标准库路径中查找该库。gcc 的编译过程和输出⽂件与 g++ 是完全相同的。 在⼤多数系统中,GCC 安装时会安装⼀名为 c++ 的程序。如果被安装,它和 g++ 是等同,如下例所⽰,⽤法也⼀致: $ c++ helloworld.cpp -o helloworld 多个源⽂件⽣成可执⾏程序 如果多于⼀个的源码⽂件在 g++ 命令中指定,它们都将被编译并被链接成⼀个单⼀的可执⾏⽂件。下⾯是⼀个名为 speak.h的头⽂件;它包含⼀个仅含有⼀个函数的类的定义: /* speak.h */ #include public: void sayHello(const char *);}; 下⾯列出的是⽂件 speak.cpp的内容:包含 sayHello()函数的函数体: /* speak.cpp */#include \"speak.h\" void Speak::sayHello(const char *str){ std::cout << \"Hello \" << str << \"\\n\";} ⽂件hellospeak.cpp内是⼀个使⽤ Speak 类的程序: /* hellospeak.cpp */#include \"speak.h\" int main(int argc,char *argv[]){ Speak speak; speak.sayHello(\"world\"); return(0);} 下⾯这条命令将上述两个源码⽂件编译链接成⼀个单⼀的可执⾏程序: $ g++ hellospeak.cpp speak.cpp -o hellospeak PS:这⾥说⼀下为什么在命令中没有提到“speak.h“该⽂件(原因是:在“speak.cpp“中包含有”#include\"speak.h\"“这句代码,它的意思是搜索系统头⽂件⽬录之前将先在当前⽬录中搜索⽂件“speak.h“。⽽”speak.h“正在该⽬录中,不⽤再在命令中指定了)。 源⽂件⽣成对象⽂件 选项 -c ⽤来告诉编译器编译源代码但不要执⾏链接,输出结果为对象⽂件。⽂件默认名与源码⽂件名相同,只是将其后缀变为.o。例如,下⾯的命令将编译源码⽂件 hellospeak.cpp并⽣成对象⽂件 hellospeak.o: $ g++ -c hellospeak.cpp 命令 g++ 也能识别 .o ⽂件并将其作为输⼊⽂件传递给链接器。下列命令将编译源码⽂件为对象⽂件并将其链接成单⼀的可执⾏程序: $ g++ -c hellospeak.cpp $ g++ -c speak.cpp $ g++ hellospeak.o speak.o -o hellospeak 选项 -o 不仅仅能⽤来命名可执⾏⽂件。它也⽤来命名编译器输出的其他⽂件。例如:除了中间的对象⽂件有不同的名字外,下列命令⽣将⽣成和上⾯完全相同的可执⾏⽂件: $ g++ -c hellospeak.cpp -o hspk1.o $ g++ -c speak.cpp -o hspk2.o $ g++ hspk1.o hspk2.o -o hellospeak 编译预处理 选项 -E使 g++ 将源代码⽤编译预处理器处理后不再执⾏其他动作。下⾯的命令预处理源码⽂件 helloworld.cpp 并将结果显⽰在标准输出中: $ g++ -E helloworld.cpp 本⽂前⾯所列出的 helloworld.cpp 的源代码,仅仅有六⾏,⽽且该程序除了显⽰⼀⾏⽂字外什么都不做,但是,预处理后的版本将超过 1200⾏。这主要是因为头⽂件 iostream 被包含进来,⽽且它⼜包含了其他的头⽂件,除此之外,还有若⼲个处理输⼊和输出的类的定义。预处理过的⽂件的 GCC 后缀为.ii,它可以通过 -o 选项来⽣成,例如: $ gcc -E helloworld.cpp -o helloworld.ii ⽣成汇编代码 选项 -S指⽰编译器将程序编译成汇编语⾔,输出汇编语⾔代码⽽后结束。下⾯的命令将由 C++ 源码⽂件⽣成汇编语⾔⽂件 helloworld.s: $ g++ -S helloworld.cpp ⽣成的汇编语⾔依赖于编译器的⽬标平台。 创建静态库 静态库是编译器⽣成的⼀系列对象⽂件的集合。链接⼀个程序时⽤库中的对象⽂件还是⽬录中的对象⽂件都是⼀样的。库中的成员包括普通函数,类定义,类的对象实例等等。静态库的另⼀个名字叫归档⽂件(archive),管理这种归档⽂件的⼯具叫 ar 。在下⾯的例⼦中,我们先创建两个对象模块,然后⽤其⽣成静态库。头⽂件 say.h包含函数 sayHello()的原型和类 Say 的定义: /* say.h */ #include char *string; public: Say(char *str) { string = str; } void sayThis(const char *str) { std::cout << str << \" from a static library\\n\"; } void sayString(void);}; 下⾯是⽂件say.cpp是我们要加⼊到静态库中的两个对象⽂件之⼀的源码。它包含 Say 类中 sayString()函数的定义体;类 Say 的⼀个实例 librarysay的声明也包含在内: /* say.cpp */#include \"say.h\" void Say::sayString(){ std::cout << string << \"\\n\";} Say librarysay(\"Library instance of Say\"); 源码⽂件 syshello.cpp 是我们要加⼊到静态库中的第⼆个对象⽂件的源码。它包含函数 sayhello() 的定义: /* sayhello.cpp */#include \"say.h\"void sayhello(){ std::cout << \"hello from a static library\\n\";} 下⾯的命令序列将源码⽂件编译成对象⽂件,命令 ar 将其存进库中: $ g++ -c sayhello.cpp$ g++ -c say.cpp $ ar -r libsay.a sayhello.o say.o 程序 ar 配合参数 -r 创建⼀个新库 libsay.a 并将命令⾏中列出的对象⽂件插⼊。采⽤这种⽅法,如果库不存在的话,参数 -r 将创建⼀个新的库,⽽如果库存在的话,将⽤新的模块替换原来的模块。下⾯是主程序 saymain.cpp,它调⽤库 libsay.a 中的代码: /* saymain.cpp */#include \"say.h\" int main(int argc,char *argv[]){ extern Say librarysay; Say localsay = Say(\"Local instance of Say\"); sayhello(); librarysay.sayThis(\"howdy\"); librarysay.sayString(); localsay.sayString(); return(0);} 该程序可以下⾯的命令来编译和链接: $ g++ saymain.cpp libsay.a -o saymain 程序运⾏时,产⽣以下输出:hello from a static libraryhowdy from a static library Library instance of SayLocal instance of Say 因篇幅问题不能全部显示,请点此查看更多更全内容