gcc 命令行參數詳解

1、gcc包含的c/c++編譯器

gcc、cc、c++、g++
gcc和cc是一樣的,c++和g++是一樣的,一般c程序就用gcc編譯,c++程序就用g++編譯

2、gcc的基本用法

gcc test.c這樣將編譯出一個名爲a.out的程序
gcc test.c -o test這樣將編譯出一個名爲test的程序
-o參數用來指定生成程序的名字

3、爲什麼會出現undefined reference to 'xxxxx'錯誤?

首先這是鏈接錯誤,不是編譯錯誤,也就是說如果只有這個錯誤,說明你的程序源碼本身沒有問題,是你用編譯器編譯時參數用得不對,你沒有指定鏈接程序要用到得庫,比如你的程序裏用到了一些數學函數,那麼你就要在編譯參數裏指定程序要鏈接數學庫,方法是在編譯命令行里加入-lm

4、-l參數和-L參數

-l參數就是用來指定程序要鏈接的庫,-l參數緊接着就是庫名,那麼庫名跟真正的庫文件名有什麼關係呢?-lname,在連接時,裝載名字爲“libname.a”的函數庫:-lm表示連接名爲“libm.a”的數學函數庫。就拿數學庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了

好了現在我們知道怎麼得到庫名,當我們自已要用到一個第三方提供的庫名字libtest.so,那麼我們只要把libtest.so拷貝到/usr/lib裏,編譯時加上-ltest參數,我們就能用上libtest.so庫了(當然要用libtest.so庫裏的函數,我們還需要與libtest.so配套的頭文件)

放在/lib和/usr/lib和/usr/local/lib裏的庫直接用-l參數就能鏈接了,但如果庫文件沒放在這三個目錄裏,而是放在其他目錄裏,這時我們只用-l參數的話,鏈接還是會出錯,出錯信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是鏈接程序ld在那3個目錄裏找不到libxxx.so,這時另外一個參數-L就派上用場了,比如常用的X11的庫,它在/usr/X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數,-L參數跟着的是庫文件所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數就是-L/aaa/bbb/ccc -ltest

另外,大部分libxxxx.so只是一個鏈接,以RH9爲例,比如libm.so它鏈接到/lib/libm.s
o.x,/lib/libm.so.6又鏈接到/lib/libm-2.3.2.so,

如果沒有這樣的鏈接,還是會出錯,因爲ld只會找libxxxx.so,所以如果你要用到xxxx
庫,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一個鏈接就可以了
ln -s libxxxx-x.x.x.so libxxxx.so

手工來寫鏈接參數總是很麻煩的,還好很多庫開發包提供了生成鏈接參數的程序,名字一般叫xxxx-config,一般放在/usr/bin目錄下,比如

gtk1.2的鏈接參數生成程序是gtk-config,執行gtk-config --libs就能得到以下輸出"-
L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic

-lgmodule -lglib -ldl -lXi -lXext -lX11 -lm",這就是編譯一個gtk1.2程序所需的g
tk鏈接參數,xxx-config除了--libs參數外還有一個參數是--cflags用來生成頭文
件包含目錄的,也就是-I參數,在下面我們將會講到。你可以試試執行gtk-config 
--libs --cflags,看看輸出結果

現在的問題就是怎樣用這些輸出結果了,最笨的方法就是複製粘貼或者照抄,聰明的辦
法是在編譯命令行里加入這個`xxxx-config --libs --cflags`,比如編譯一個gtk程序:gcc gtktest.c `gtk-config --libs --cflags`這樣
就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。

除了xxx-config以外,現在新的開發包一般都用pkg-config來生成鏈接參數,使用方法
跟xxx-config類似,但xxx-config是針對特定的開發包,但pkg-config包含很多開發包的鏈接參數的生成,用pkg-config --list-all命令可以列出所支持的所有開發包,pkg-config的用法就是pkg -config pagName --libs --cflags,其中pagName是包名,是pkg-config--list-all裏列出名單中的一個,比如gtk1.2的名字就是gtk+,pkg-

config gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一樣的。比如:
gcc gtktest.c `pkg-config gtk+ --libs --cflags`


5、-include和-I參數

-include用來包含頭文件,但一般情況下包含頭文件都在源碼裏用#include xxxxxx實現,-include參數很少用。-I參數是用來指定頭文件目錄,/usr/include目錄一般是不用指定的,gcc知道去那裏找,但是如果頭文件不在/usr/include裏我們就要用-I參數指定了,比如頭文件放在/myinclude目錄裏,那編譯命令行就要加上-I/myinclude參數了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I參數可以用相對路徑,比如頭文件在當前目錄,可以用-I.來指定。上面我們提到的--cflags參數就是用來生成-I參數的

6、-O參數

這是一個程序優化參數,一般用-O2就是,用來優化程序用的,比如gcc test.c -O2,優化得到的程序比沒優化的要小,執行速度可能也有所提高

7、-shared參數
編譯動態庫時要用到,比如gcc -shared test.c -o libtest.so

8、幾個相關的環境變量
PKG_CONFIG_PATH:用來指定pkg-config用到的pc文件的路徑,默認是/usr/lib/pkgconf
ig,pc文件是文本文件,擴展名是.pc,裏面定義開發包的安裝路徑,Libs參數和Cflags參數等等。
CC:用來指定c編譯器
CXX:用來指定cxx編譯器
LIBS:跟上面的--libs作用差不多
CFLAGS:跟上面的--cflags作用差不多
CC,CXX,LIBS,CFLAGS手動編譯時一般用不上,在做configure時有時用到,一般情況
下不用管
環境變量設定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx

9、關於交叉編譯

交叉編譯通俗地講就是在一種平臺上編譯出能運行在體系結構不同的另一種平臺上,比
如在我們地PC平臺(X86 CPU)上編譯出能運行在sparc

CPU平臺上的程序,編譯得到的程序在X86 CPU平臺上是不能運行的,必須放到sparc CPU平臺上才能運行。當然兩個平臺用的都是linux

這種方法在異平臺移植和嵌入式開發時用得非常普遍

相對與交叉編譯,我們平常做的編譯就叫本地編譯,也就是在當前平臺編譯,編譯得到
的程序也是在本地執行

用來編譯這種程序的編譯器就叫交叉編譯器,相對來說,用來做本地編譯的就叫本地編
譯器,一般用的都是gcc,但這種gcc跟本地的gcc編譯器

是不一樣的,需要在編譯gcc時用特定的configure參數才能得到支持交叉編譯的gcc

爲了不跟本地編譯器混淆,交叉編譯器的名字一般都有前綴,比如sparc-xxxx-linux-gn
u-gcc,sparc-xxxx-linux-gnu-g++ 等等

10、交叉編譯器的使用方法
使用方法跟本地的gcc差不多,但有一點特殊的是:必須用-L和-I參數指定編譯器用spar
c系統的庫和頭文件,不能用本地(X86)的庫(頭文件有時可以用本地的)

例子:
sparc-xxxx-linux-gnu-gcc test.c -L/path/to/sparcLib -I/path/to/sparcInclude


 

gcc與g++
Linux 中最重要的軟件開發工具是 GCC。GCC 是 GNU 的 C 和 C++ 編譯器。實際上,GCC 能夠編譯三種語言:C、C++ 和 Object C(C 語言的一種面向對象擴展)。利用 gcc 命令可同時編譯並連接 C 和 C++ 源程序。
GCC 可同時用來編譯 C 程序和 C++ 程序。一般來說,C 編譯器通過源文件的後綴名來判斷是 C 程序還是 C++ 程序。在 Linux 中,C 源文件的後綴名爲 .c,而 C++ 源文件的後綴名爲 .C 或 .cpp。
gcc 命令只能編譯 C++ 源文件,而不能自動和 C++ 程序使用的庫連接。因此,通常使用 g++ 命令來完成 C++ 程序的編譯和連接,該程序會自動調用 gcc 實現編譯。
選項 解釋
-ansi 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特色,
例如 asm 或 typeof 關鍵詞。
-c 只編譯並生成目標文件。
-DMACRO 以字符串“1”定義 MACRO 宏。
-DMACRO=DEFN 以字符串“DEFN”定義 MACRO 宏。
-E 只運行 C 預編譯器。
-g 生成調試信息。GNU 調試器可利用該信息。
-IDIRECTORY 指定額外的頭文件搜索路徑DIRECTORY。
-LDIRECTORY 指定額外的函數庫搜索路徑DIRECTORY。
-lLIBRARY 連接時搜索指定的函數庫LIBRARY。
-m486 針對 486 進行代碼優化。
-o FILE 生成指定的輸出文件。用在生成可執行文件時。
-O0 不進行優化處理。
-O 或 -O1 優化生成代碼。
-O2 進一步優化。
-O3 比 -O2 更進一步優化,包括 inline 函數。
-shared 生成共享目標文件。通常用在建立共享庫時。
-static 禁止使用共享連接。
-UMACRO 取消對 MACRO 宏的定義。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
例子:

GCC編譯OpengL: gcc hello.c -o hello -L/usr/X11R6/lib/ -lGL -lGLU -lglut

11、基本用法

一般用作C語言編譯器時是gcc,而用作C++語言編譯器時是g++。
其語法結構爲:

       gcc [-c|-S|-E] [-std=standard]
           [-g] [-pg] [-Olevel]
           [-Wwarn...] [-pedantic]
           [-Idir...] [-Ldir...]
           [-Dmacro[=defn]...] [-Umacro]
           [-foption...] [-mmachine-option...]
           [-o outfile] infile...
雖然看起來選項非常多,好象挺高深的。但只有一個infile是必需選項,故我們初學者只需要知道這樣的形式就行了:
gcc source-files
即用任何一種文本編譯器編寫C語言源程序,保存爲一個UNIX下格式的文本文件,比如文件名爲test.c,那麼用下面這個命令把源程序變成可執行程序就行了:
gcc test.c
如果你是用Windows下的文件編輯軟件寫的源程序,在用gcc編譯之前最好用命令dos2unix轉換一下文件格式。因爲早期的gcc版本不能識別windows下的文件格式。會報奇怪的錯誤。
dos2unix命令由軟件包tofrodos提供,軟件包信息如下:
Description: Converts DOS <-> Unix text files, alias tofromdos
 DOS text files traditionally have CR/LF (carriage return/line feed) pairs
 as their new line delimiters while Unix text files traditionally have
 LFs (line feeds) to terminate each line.
 .
 Tofrodos comprises one program, "fromdos" alias "todos", which converts
 text files to and from these formats. Use "fromdos" to convert DOS
 text files to the Unix format, and "todos" to convert Unix text files
 to the DOS format.
 .
 This functionality is also available via the dos2unix/unix2dos symlinks.
 .
  Homepage: http://www.thefreecountry.com/tofrodos/index.shtml
即實現Windows文本文件格式和Linux文本文件格式的轉換。
因爲Windows下文本文件以CR和LF行結束符,而Linux下文本文件以LF作爲行結束符。所以在Linux下編寫的文本文件到Windows下用記事本等軟件打開時會出現所有內容擠在一行的現象。
用C語言的習慣來說就是:Windows下文本文件行結束符是'\r'和'\n'而Linux下是'\n',即Windows下是十六進制的0x0d和0x0a,而Linux下是0x0a
用上面的編譯命令:
gcc test.c
將在當前目錄下產生一個可執行程序a.out,要運行程序試試?輸入命令:
./a.out
如果想要產生一個自己命令的程序,即程序名不是默認的a.out,可以用這種命令格式:
gcc -o out-file source-file
比如:
gcc -o myprog test.c
將到源程序test.c變成一個可執行程序myprog,運行這個命令看看你的成果吧:
./myprog

12、編譯多個文件
如果你的程序源代碼比較多,並且分在幾個源文件裏面,互相之前有調用現象,就要用gcc編譯多個源文件了。命令格式如下:
gcc -o out-file source-file-a source-file-b source-file-c ...
可以把所有源代碼文件聯合編譯生成一個程序out-file

13、代碼風格
很多人都會講代碼風格問題,但這應該是機器做的事而不是人做的事!
Linux下有一個很好的軟件indent可以用來把代碼按照一定的風格進行整理。該軟件包信息如下:
Description: C language source code formatting program
 The `indent' program changes the appearance of a C program by
 inserting or deleting whitespace.
 .
 `indent' also provides options for controlling the alignment of braces and
 declarations, program indenting, and other stylistic parameters, including
 formatting of both C and C++ comments.
比如我們編寫了一個源程序test.c,代碼格式比較亂,如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
        int port = 0;
    printf("program begin\n");
    if (argc != 3) {
        printf("程序參數個數不對!正確輸入方法如下:\n%s ip-address port\n", argv[0]);
exit(0);
        }
    if(atoi(argv[2]) <0 || atoi(argv[2]) > 65535) {printf("端口輸入不對!應該是0-65535的值。程序取默認值3456\n"); port = 3456;}
    else port = atoi(argv[2]);
    printf("命令如下:%s %s %d\n", argv[0], argv[1], port);
    return 0;
}
用indent命令格式化一下,命令如下:
indent test.c
源代碼變成下面的樣子了:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int
main (int argc, char **argv)
{
  int port = 0;
  printf ("program begin\n");
  if (argc != 3)
    {
      printf
        ("程序參數個數不對!正確輸入方法如下:\n%s ip-address port\n",
         argv[0]);
      exit (0);
    }
  if (atoi (argv[2]) < 0 || atoi (argv[2]) > 65535)
    {
      printf
        ("端口輸入不對!應該是0-65535的值。程序取默認值3456\n");
      port = 3456;
    }
  else
    port = atoi (argv[2]);
  printf ("命令如下:%s %s %d\n", argv[0], argv[1], port);
  return 0;
}
這種代碼風格是GNU的風格,是indent的默認格式。
但我們多數寫程序的人可能都是學的Kernighan & Ritchie代碼風格,用如下命令格式化:
indent -kr test.c
代碼格式化成這樣了:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int port = 0;
    printf("program begin\n");
    if (argc != 3) {
        printf
            ("程序參數個數不對!正確輸入方法如下:\n%s ip-address port\n",
             argv[0]);
        exit(0);
    }
    if (atoi(argv[2]) < 0 || atoi(argv[2]) > 65535) {
        printf
            ("端口輸入不對!應該是0-65535的值。程序取默認值3456\n");
        port = 3456;
    } else
        port = atoi(argv[2]);
    printf("命令如下:%s %s %d\n", argv[0], argv[1], port);
    return 0;
}
記住:本該機器來做的事,不要手工去做!
當然,如果你用indent格式化時報錯或格式化後發現不對勁,一定是你的代碼裏有問題,比如少了一個“}“

14、養成好的習慣
大家都寫C程序,可有人的代碼總會有問題,而寫得好一點的就會基本沒錯誤。
這需要一個慢慢練習的過程,但作爲初學者,你在編譯程序時就加上gcc的-Wall選項吧。即命令格式爲:
gcc -Wall -o out-file source-file
這樣,程序中每行代碼有問題都有提到提示。初學者把每個Warning和Error都弄清楚對養成好的編程習慣是相當有用的。

15、爲調試程序作準備
可能我們的程序編譯通過了,也生成了可執行程序,但可能運行的時候出錯,甚至剛開始運行一段時間都沒問題後來某一天出了問題。
有些問題一看錯誤提示就明白了。但有些可能花較長時間都想不明白,只能調試程序了。
爲了保證可以調試程序,我們在用gcc編譯程序時要加上-g選項,即命令格式如下:
gcc -Wall -g -o out-file source-file
這個命令就會把源代碼編譯產生的可執行程序里加上調試信息,如果程序出錯出現Core dump文件時可以從Core dump文件裏快速定位到程序哪行出了問題。
發佈了72 篇原創文章 · 獲贊 4 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章