溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

嵌入式之 C 語(yǔ)言編譯器(五)

發(fā)布時(shí)間:2020-06-19 10:50:20 來(lái)源:網(wǎng)絡(luò) 閱讀:1488 作者:上帝之子521 欄目:系統(tǒng)運(yùn)維

        我們?cè)谇度胧降拈_發(fā)中經(jīng)常會(huì)見(jiàn)到 GCC 和 gcc,那么它們兩有何不同呢?GCC(GNU Compile Collection) 是指 GNU 編譯器集合,包含眾多語(yǔ)言的編譯器,如 C、C++、Java、D、Objective-C 等;而 gcc 則是特指 GCC 中的 C 語(yǔ)言編譯器。那么 GCC 與嵌入式的關(guān)系是怎樣的呢?多數(shù)嵌入式操作系統(tǒng)都是基于 GCC 進(jìn)行源碼編譯,如 Linux、VxWorks 以及 Android 等。在實(shí)際的開發(fā)中,內(nèi)核相關(guān)的開發(fā)用的是 gcc,而應(yīng)用開發(fā)用的是 gcc/g++/gdc 等。

        下來(lái)我們來(lái)看看一個(gè)嵌入式開發(fā)中的高端大氣上檔次的詞語(yǔ):交叉編譯。那么為什么會(huì)有交叉編譯呢?在以往的嵌入式設(shè)備往往都是資源受限的,不可能直接在嵌入式上直接對(duì)處理器進(jìn)行編程。那么此時(shí)的解決方案便是在開發(fā)主機(jī)(PC)上對(duì)源碼進(jìn)行編譯,最終生成目標(biāo)主機(jī)(嵌入式設(shè)備)的可執(zhí)行程序。gcc 是如何進(jìn)行交叉編譯的呢?1、配置目標(biāo)主機(jī)的編譯工具鏈(如arm-linux);2、配置工具鏈的具體版本:根據(jù)具體的目標(biāo)代碼選擇相應(yīng)的工具鏈版本,正確使用關(guān)于硬件體系的特殊編譯選項(xiàng)。下來(lái)我們來(lái)看看大型企業(yè)的嵌入式開發(fā)環(huán)境是怎樣的,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        這個(gè)服務(wù)器集群相當(dāng)于是我們自己公司的內(nèi)部服務(wù)器,版本控制則是指由原來(lái)的版本經(jīng)過(guò)我們一些代碼的修改之后產(chǎn)生的新版本,用于各個(gè)版本的控制的。文件追蹤則是指在服務(wù)器上面可以看到那部分的代碼是具體由哪個(gè)人進(jìn)行改寫的,可具體到文件以及部分代碼。我們來(lái)看看編譯器是怎樣的,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        編譯器其實(shí)是由預(yù)處理期、編譯器、匯編器以及鏈接器構(gòu)成的。我們平時(shí)所說(shuō)的由哪個(gè)編譯器編譯生成的文件,此時(shí)的編譯器便是指廣范圍的編譯器。那么狹義上的編譯器則是指我們?cè)谄綍r(shí)所聽(tīng)到的生產(chǎn)一個(gè)某語(yǔ)言的編譯器,此時(shí)的編譯器則是指將具體的語(yǔ)言翻譯成目標(biāo)平臺(tái)代碼而已。我們來(lái)看看一個(gè) .c 文件是怎樣編譯成 .o 文件的,具體步驟如下所示

嵌入式之 C 語(yǔ)言編譯器(五)

        我們看到并不是我們所想象的直接一步就由 .c 文件直接編譯成為 .o 可執(zhí)行文件了,而是經(jīng)過(guò)那么多的步驟才會(huì)生成最終的可執(zhí)行程序的。那么此時(shí)便擴(kuò)展一個(gè)問(wèn)題,我們是如何理解“多語(yǔ)言混合開發(fā)”?我們?cè)谄綍r(shí)可能會(huì)聽(tīng)到多語(yǔ)言混合開發(fā),是指由好幾種語(yǔ)言混合進(jìn)行一個(gè)應(yīng)用程序開發(fā)的。那么為什么會(huì)產(chǎn)生這種混合的開發(fā)方式呢?比如說(shuō)一個(gè)項(xiàng)目是由 C++ 完成的,但是其中的某些部分是可以通過(guò) C# 完成的,此時(shí)精通 C++ 的人很少(相應(yīng)工資就要的很高了),而 C# 的工程師由一大堆,我們就可以需要兩個(gè)精通 C++ 的工程師和好幾個(gè) C# 的工程師來(lái)共同完成這個(gè)項(xiàng)目,達(dá)到以最小的開支完成此項(xiàng)目的效果?;蛘呤悄銈冃〗M內(nèi)每個(gè)人擅長(zhǎng)的語(yǔ)言方向不一樣,為了發(fā)揮每個(gè)人的最大效率便可以采取這種混合開發(fā)的方式。下來(lái)我們來(lái)看看幾種多語(yǔ)言混合開發(fā)的方式

        方式一,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        此方式是通過(guò)由幾種語(yǔ)言經(jīng)過(guò)匯編得到目標(biāo)平臺(tái)的匯編語(yǔ)言,再由目標(biāo)平臺(tái)匯編器統(tǒng)一鏈接生成可執(zhí)行程序。行業(yè)典型的案例就是 .net framework,它便是由 C#、C++ 以及 VB 混合開發(fā)得到的,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        方式二,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        它是由各自的語(yǔ)言生成相應(yīng)的庫(kù)再通過(guò)目標(biāo)平臺(tái)鏈接器統(tǒng)一鏈接為可執(zhí)行程序。典型的案例便是 QQ 了,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        方式三,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        它是經(jīng)過(guò)各自的編譯器先生成可執(zhí)行程序 .exe,再通過(guò)進(jìn)程間通信協(xié)議進(jìn)而生成可執(zhí)行程序。行業(yè)案例:Eclipse,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        下來(lái)我們來(lái)看看 gcc 關(guān)鍵編譯選項(xiàng)。

        gcc 關(guān)鍵編譯選項(xiàng)一a> 預(yù)處理指令是:gcc -E file.c -o file.i;b > 編譯指令:gcc -S file.i -o file.s;c> 匯編指令:gcc -c file.s -o file.o。

        下來(lái)我們來(lái)看看效果分別是怎樣的


func.h 源碼

#include <stdio.h>

void func()
{
#ifdef TEST
    printf("TEST = %s\n", TEST);
#endif

    return;
}


test.c 源碼

#include <stdio.h>
#include "func.h"

int g_global = 0;
int g_test = 1;

int main(int argc, char *argv[])
{
    func();
    
    printf("&g_global = %p\n", &g_global);
    printf("&g_test = %p\n", &g_test);
    printf("&func = %p\n", &func);
    printf("&main = %p\n", &main);
    
    return 0;
}

        我們來(lái)看看預(yù)處理的效果,打開 test.i 文件看看,開頭是這樣的

嵌入式之 C 語(yǔ)言編譯器(五)

        第一行的 1 表示下面的內(nèi)容是屬于 test.c 文件的內(nèi)容,下面是一些頭文件的包含。

嵌入式之 C 語(yǔ)言編譯器(五)

        # 2 "test.c" 2 的意思是 test.c 頭文件的包含已經(jīng)結(jié)束了,# 1 "func.h" 1 表示 func.h 相關(guān)內(nèi)容的開始。最后便是 test.c 文件 main 函數(shù)的內(nèi)容了。下面看看編譯指令生成的 .s 文件

嵌入式之 C 語(yǔ)言編譯器(五)

        都是一些生成的匯編命令。下面來(lái)看看最后的匯編指令生成 .o 文件

嵌入式之 C 語(yǔ)言編譯器(五)

        gcc 關(guān)鍵編譯選項(xiàng)二:a> 生成映射文件:gcc -WI,-Map=test.map file.c;b> 宏定義:gcc -D'TEST="test"' file.c;c> 獲取系統(tǒng)頭文件路徑:gcc -v file.c。

        gcc 關(guān)鍵編譯選項(xiàng)三生成依賴關(guān)系。a> 獲取目標(biāo)完整的依賴關(guān)系:gcc -M test.c;b> 獲取目標(biāo)的部分依賴關(guān)系:gcc -MM test.c。

        下來(lái)我們來(lái)看看 -M 和 -MM 的效果分別是怎樣的,如下

嵌入式之 C 語(yǔ)言編譯器(五)

        我們看到包含了那么多的頭文件,它的格式類似于 makefile 中的目標(biāo)與依賴的關(guān)系。其中依賴是 test.c 和眾多的頭文件以及我們自己包含的 func.h 頭文件。再來(lái)看看 -MM 的效果

嵌入式之 C 語(yǔ)言編譯器(五)

        我們看到 -MM 的效果是指依賴于 test.c 和 func.h,并沒(méi)有那些別的頭文件。

        gcc 關(guān)鍵編譯選項(xiàng)四:指定庫(kù)文件及庫(kù)文件搜索路徑。-L 選項(xiàng)是指定庫(kù)文件的搜索路徑;-l 是指定庫(kù)文件,如 gcc test.c -L -lfunc。


func.c 源碼

#include <stdio.h>

void func()
{
#ifdef TEST
    printf("TEST = %s\n", TEST);
#endif

    return;
}


test.c 源碼

#include <stdio.h>

int g_global = 0;
int g_test = 1;

int main(int argc, char *argv[])
{
    func();
    
    printf("&g_global = %p\n", &g_global);
    printf("&g_test = %p\n", &g_test);
    printf("&func = %p\n", &func);
    printf("&main = %p\n", &main);
    
    return 0;
}

        編譯結(jié)果如下

嵌入式之 C 語(yǔ)言編譯器(五)

        我們看到經(jīng)過(guò) ar crs 命令將 func.o 打包成 libfunc.a 文件后,再通過(guò) gcc test.c -L. -lfunc 命令生成可執(zhí)行程序 a.out(其中 -L 后面的點(diǎn)代表在當(dāng)前目錄下)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI