gcc动态编译和静态编译方法
一.单个源.cpp文件生成可执行程序
下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码:
1 /* helloworld.cpp */ 2 #include <iostream> 3 int main() 4 { 5 std::cout << "hello, world" ; 6 return(0); 7 }
***** c++ helloworld.cpp -o hello -Wall
编译器c++ 通过检查命令行中指定的文件的后缀名可识别其为 C++ 源代码文件,同时打印提示信息。
编译器默认的动作:编译源代码文件生成对象文件(object file)
链接对象文件和 libstdc++ 库中的函数得到可执行程序。然后删除对象文件。
由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。
程序可以这样来运行:
***** ./hello
hello, world
程序c++/g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。
通过遵循源码的命名规范并指定对应库的名字,用 gcc 默认编译c文件,通过扩展来编译链接 C++ 程序也是可行的,
如下例所示:
***** gcc helloworld.cpp -lstdc++ -o helloworld
选项 -l (ell) 通过添加前缀 lib 和后缀 .a 将跟随它的名字变换为库的名字 libstdc++.a,而后它在标准库路径中查找该库。
gcc 的编译过程和输出文件与 c++/g++ 是完全相同的。
二.预编译处理和生成汇编代码
编译预处理 选项 -E 使 c++ 将源代码用编译预处理器处理后不再执行其他动作。
下面的命令预处理源码文件 helloworld.cpp 并将结果显示在标准输出中:
***** c++ -E helloworld.cpp
预处理后的版本将超过 12000 行。这主要是因为头文件 iostream 被包含进来,
而且它又包含了其他的头文件,除此之外,还有若干个处理输入和输出的类的定义。
预处理过的文件的 GCC 后缀为 .ii,它可以通过 -o 选项来生成,
例如:
***** gcc -E helloworld.cpp -o helloworld.ii
生成汇编代码 选项 -S 指示编译器将程序编译成汇编语言,输出汇编语言代码而后结束。
下面的命令将由 C++ 源码文件生成汇编语言文件 helloworld.s:
***** g++ -S helloworld.cpp 生成的汇编语言依赖于编译器的目标
三.多个源文件生成可执行程序de动态编译
如果多于一个的源码文件在 g++ 命令中指定,它们都将被编译并被链接成一个单一的可执行文件。
下面是一个名为 speak.h 的头文件;
它包含一个仅含有一个函数的类的定义: (示例来自:c++primer plus)
1 /* stack.h */ 2 3 #ifndef STACK_H_ #define STACK_H_ 4 5 typedef unsigned long Item; 6 7 class Stack 8 9 { 10 11 private: 12 13 enum {MAX=10}; 14 15 Item items[MAX]; 16 17 int top; 18 19 public: 20 21 Stack(); 22 23 bool isempty() const; 24 25 bool isfull() const; 26 27 bool push(const Item & item); 28 29 bool pop(Item & item); }; 30 31 #endif
下面列出的是文件 stack.cpp 的内容:
/* stack.cpp */ #include"stack.h" Stack::Stack() { top=0; } bool Stack::isempty() const { return top==0; } bool Stack::isfull() const { return top==MAX; } bool Stack::push(const Item&item) { if(top<MAX) { items[top++]=item; return true; } else return false; } bool Stack::pop(Item&item) { if(top>0) { item=items[--top]; return true; } else return false; }
文件 hellospeak.cpp 内是一个使用 stack 类的程序:
/* stacker.cpp*/ // stacker.cpp -- testing the Stack class #include <iostream> #include <cctype> // or ctype.h #include "stack.h" int main() { using namespace std; Stack st; // create an empty stack char ch; unsigned long po; cout << "Please enter A to add a purchase order, " << "P to process a PO, or Q to quit. "; while (cin >> ch && toupper(ch) != 'Q') { while (cin.get() != ' ') continue; if (!isalpha(ch)) { cout << 'a'; continue; } switch(ch) { case 'A': case 'a': cout << "Enter a PO number to add: "; cin >> po; if (st.isfull()) cout << "stack already full "; else st.push(po); break; case 'P': case 'p': if (st.isempty()) cout << "stack already empty "; else { st.pop(po); cout << "PO #" << po << " popped "; } break; } cout << "Please enter A to add a purchase order, " << "P to process a PO, or Q to quit. "; } cout << "Bye "; return 0; }
下面这条命令将上述两个源码文件编译链接成一个单一的可执行程序:
***** c++ stack.cpp stacker.cpp -o stacks
源文件生成对象文件
选项 -c 用来告诉编译器编译源代码但不要执行链接,输出结果为对象文件,后缀变为 .o。
例如,下面的命令将编译源码文件 hellospeak.cpp 并生成对象文件 hellospeak.o:
***** c++ -c stacker.cpp
命令 g++ 也能识别 .o 文件并将其作为输入文件传递给链接器。
下列命令将编译源码文件为对象文件并将其链接成单一的可执行程序:
***** c++ -c stacker.cpp
***** c++ -c stack.cpp
***** c++ stacker.o stack.o -o stacks
选项 -o 不仅仅能用来命名可执行文件。它也用来命名编译器输出的其他文件。
四.多个源文件生成可执行程序de静态编译
创建静态库
静态库是编译器生成的一系列对象文件的集合。
链接一个程序时用库中的对象文件还是目录中的对象文件都是一样的。
库中的成员包括普通函数,类定义,类的对象实例等等。
静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫 ar 。
在上面的例子中,我们先创建两个对象模块,然后用其生成静态库。
源码文件 stack.cpp 是我们要加入到静态库中的第一个对象文件的源码。
源码文件 stacker.cpp 是我们要加入到静态库中的第二个对象文件的源码。
下面的命令序列将源码文件编译成对象文件,命令 ar 将其存进库中:
***** c++ -c stack.cpp
***** c++ -c stacker.cpp
***** ar -r lib.a stack.o stacker.o
程序 ar 配合参数 -r 创建一个新库 lib.a 并将命令行中列出的对象文件插入。
采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,
而如果库存在的话,将用新的模块替换原来的模块。
如果有第三个.cpp文件(main函数),或者没有也可以直接编译前面的.cpp
该程序可以下面的命令来编译和链接:
***** c++ stacker.cpp lib.a -o main
刚刚学会的编译方式还是蛮好用的。
PS: powershall也是蛮好用的毕竟不是黑漆漆的界面了233333.