程序編譯過程詳解


程序編譯

1. Linux下的程序編譯

GCC(GNU Compiler Collection),是符合GPL和LGPL許可證發行的自由軟件,也是類Unix和Mac OS X的標准編譯器。GCC可處理C (gcc)、C++(g++)、Java等語言。

Intel Composer XE 2013,Intel公司為x86平台編譯器,針對Intel專門做了優化,在其他平台上表現也不錯。

PGI Accelerator,支持CUDA Fortran。已經被Nvidia收購。

2. 串行程序的編譯和執行

程序編譯流程如下

  • 編譯:將源文件編譯成目標文件
  • 連接:將目標文件連接成可執行文件
  • 執行

Linux系統中,可執行文件沒有同一的后綴,系統從文件屬性來區分。源代碼和目標文件的后綴名要保持同意規范,以便區分識別。

#include<stdio.h>
int main()
{
	printf("Hello,World.\n");
    return 0;
}
gcc hello.c										#編譯
./a.out											#執行

gcc hello.c -o hello							#自動執行了編譯和連接
./hello

如果可執行文件的目錄加入了PATH環境變量,可以直接使用可執行文件名。
export PATH=$PATH:/home/mzy
#待定,無法成功運行

gcc -c hello.c									#1.只執行編譯,不執行連接,生成hello.o
gcc -o hello hello.o							#2.連接目標文件,生成可執行文件

2.1多個源文件的編譯

主程序源文件main.c

#include<stdio.h>
int main ()
{
    int sum=0,r,i;
    for (i = 1;i <= 10; ++i)
    {
        r = fun(i);
        sum += r;
    }
    printf("sum is %d\n",sum);
    return 0;
}

子函數源文件fun.c

int fun(int i)
{
    int res = i * i;
    return res;
}
gcc -o sum main.c fun.c							#同時編譯多個源文件
./sum											#執行(自動執行了連接動作,自動刪除了中間過程所產生的目標文件main.o和fun.o)

#也可以將源文件分別編譯,最后再連接成可執行文件
gcc -c main.c
gcc -c fun.c
gcc -o sum main.o fun.o
./sum											#手動編譯時目標文件不會消失


2.2 多個源文件使用頭文件的例子

主程序文件main.c

#include<stdio.h>
#include"myhead.h"
int main()
{
    printf(STRING);
    return 0;
}

頭文件myhead.h

#dedine STRING "Hello,Multi sources\n"
#編譯時使用-I參數指定頭文件搜索路徑
gcc -c -I /home/mzy main.c
gcc -o Mut main.o

#也可以將以上兩句話融合
gcc -o Multi -I /home/mzy main.c

2.3 Linux下函數庫文件介紹

2.3.1 靜態庫與動態庫

靜態庫

  • 命名規范為libXXX.a
  • 庫函數會被連接進可執行程序,可執行文件體積較大
  • 可執行文件運行時,不需要從磁盤載入庫函數,執行效率較高
  • 庫函數更新后,需要重新編譯可執行程序

動態庫

  • 命名規范為libXXX.so
  • 庫函數不被連接進可執行程序,可執行文件體積較小
  • 可執行文件運行時,庫函數動態載入
  • 使用靈活,庫函數更新后,不需要重新編譯可執行程序
2.3.2 使用頭文件

默認搜索頭文件的目錄優先級:

  1. 源文件所在目錄(要求源文件中用#include "..." 格式指定)
  2. INCLUDE之類的環境變量指定的目錄
  3. 編譯器自己的頭文件目錄
  4. /usr/include操作系統頭文件目錄

如果想自己指定頭文件搜索路徑可以使用 -I 參數

  • 用 -I 指定的目錄優先級比默認搜索目錄高
  • -I 參數可以指定多個 -I -I ...
2.3.3 庫函數的生成(靜態庫)

子函數fun1.c

int fun1 (int i)
{
    return i+i;
}

子函數fun2.c

int fun2 (int i)
{
    return i*i;
}
#編譯子函數源代碼
gcc -c fun1.c
gcc -c fun2.c
#使用ar命令將目標文件打包成靜態庫.a
ar cr libtest.a fun1.o fun2.o

2.3.4 庫函數的生成(動態庫)
#編譯子函數源碼,必須要使用-fPIC(Position-independent code)參數
gcc -c -fPIC fun1.c
gcc -c -fPIC fun2.c
#使用編譯器-shared參數將目標文件連接成動態庫.so
gcc -o libtest.so -shared fun1.o fun2.o
2.3.5 庫函數的使用

主函數main.c,調用之前定義的fun1和fun2子函數

#include<stdio.h>
int main ()
{
    int i = 10,sum,product;
    sum = fun1(i);
    product = fun2(i);
    printf("the sum is %d,the product is %d\n",sum,product);
    return 0;
}
  1. gcc -c是編譯,gcc -o才是連接。gcc -o時程序自動被編譯,並且會刪除中間產生的.o文件(目標文件)

  2. gcc -c -<參數> <要被編譯的文件1> <要被編譯的文件2> ...

    gcc -c -I <頭文件的指定路徑> <要被編譯的文件>

  3. gcc -o <想要生成的可執行文件名> <需要的文件1> <需要的文件2>

    gcc -o <可執行文件名> -I <頭文件路徑> <需要被編譯連接的文件1> <需要被編譯連接的文件2> ...

    (因為-o參數默認會進行編譯,所以上一行命令能夠被執行。)

  4. ar cr libXXX.a <目標文件1> <目標文件2> ... #編譯成靜態庫

    gcc -o <可執行文件名> <靜態庫的路徑/libXXX.a> #在同級目錄下也可以不寫路徑

  5. gcc -c -fPIC fun1.c #編譯成動態庫時必須指定-fPIC參數

    gcc -c -fPIC fun2.c

    gcc -o libXXX.so -shared <目標文件1> <目標文件2> #用-shared參數將目標文件連接成動態庫.so

    2.3.5.1 庫函數的使用方式一:直接使用

    gcc -c <需要編譯的文件1> <需要編譯的文件2> ...

    gcc -o <可執行文件名> <目標文件1> <目標文件2> <路徑/libXXX.a> #當目標文件和靜態庫在同一目錄時,可省略靜態庫的路徑

    gcc -o <可執行文件名> <目標文件1> <目標文件2> <路徑/libXXX.so> #不能省略動態庫的路徑,即使目標文件和動態庫文件在同一目錄下。

    2.3.5.2 庫函數的使用方式二:在指定路徑下搜索

    使用編譯器的-L -lXXX 參數,表示在指定庫函數路徑下搜索名為libXXX.so或libXXX.a的庫文件。

    • 如果庫函數路徑下同時有靜態庫和動態庫,會選擇動態庫
    • -L 可以指定多次 -L -L ...
    • -L 指定的目錄的搜索優先級最高
    • 如果在-L的目錄中沒有找到庫函數,或者沒有指定-L,編譯器還會根據以下優先級從高到低搜索。
      1. LIBRARY_PATH(靜態庫)、LD_LIBRARY_PATH(動態庫)環境變量指定路徑
      2. 系統配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
      3. 系統的/lib(64)、/usr/lib(64)等操作系統庫文件目錄
    gcc -c <源文件>
    gcc -o <可執行文件名> <目標文件> -L <庫文件所在路徑> -ltest
    

    ./Main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

    PS:如何解決在-L參數的指定目錄下找不到動態庫的情況?

    動態鏈接庫的文件可能出現了問題,將文件加入到動態庫的環境變量的路徑中,

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/mzy
    #-L的目錄中未找到庫函數就會到動態庫的環境變量中去找,避免了找不到文件的情況。
    

3.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM