1. 程式人生 > >在linux環境下編譯C++ 程式

在linux環境下編譯C++ 程式

在linux環境下編譯C++ 程式

單個原始檔生成可執行程式

下面是一個儲存在檔案 helloworld.cpp 中一個簡單的 C++ 程式的程式碼: 單個原始檔生成可執行程式

/* helloworld.cpp */
#include <iostream>
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.out
hello, world
更普遍的做法是通過 -o 選項指定可執行程式的檔名。下面的命令將產生名為 helloworld 的可執行檔案:

$ g++ helloworld.cpp -o helloworld

在命令列中輸入程式名可使之執行:

$ ./helloworld
hello, 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 <iostream>
class Speak
{
    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 <iostream>
void sayhello(void);
class Say {
    private:
        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 library
howdy from a static library
Library instance of SayLocal instance of Say