gcc頭文件編譯
1. gcc編譯時所用的頭文件是哪個
gcc 編譯器對 C 語言源程序進行編譯時,它會根據你的源程序中的:#include 的頭文件(例如:最常使用的:stdio.h、string.h、stdlib.h 等),來進行使用和編譯。
2. 關於在linux下用gcc編譯頭文件的問題。
我用一個例子來告訴你怎麼樣在 C++ 里使用C的頭文件/函數。
比方說我有一個C的頭文件叫 c.h, C的源碼文件叫 c.c,內容分別是
c.h:
#ifndef _ASDFD_INCLUDED_
#define _ASDFD_INCLUDED_
#include <stdio.h>
extern int test(int a);
#endif
c.c:
#include "c.h"
int test(int a)
{
printf("A = %d\n", a);
return a*a;
}
現在我想在c++中使用c.c中提供的函數test(),我的c++文件名字叫 a.cpp,那麼裡面跟C有關的部分就要用 extern "C" {} 大括弧括起來,看看我的
a.cpp:
#include <iostream>
using namespace std;
extern "C"
{
#include "c.h"
}
int main()
{
int b = 12;
b = test(b);
cout<<"b = "<<b<<endl;
return 0;
}
看到了吧,#include "c.h" 被 extern "C" {}括起來了。
然後是如何編譯,先把C文件編出目標文件(.o)來
gcc -c c.c
你會看到生成了 c.o,其實,有目標文件就夠了,如果你一定要做成(靜態/動態)庫文件,也是可以的,不過我這里就不深入了,做成庫和直接用目標文件對解決你的問題沒有任何區別。
然後再編譯C++文件,也就是我的 a.cpp
g++ -o hello a.cpp c.o
看到了吧,我在編譯 a.cpp 的時候把C生成的 c.o也加上了。 然後生成 可執行的 hello, 運行
./hello
就可以看到
A = 12
b = 144
關於創建靜態庫,假定你有3個C文件, a.c, b.c, c.c 提供了你C++要用到的介面,那麼可以把這三個C文件編譯出來的目標文件放到一個庫文件里供C++使用,方法為
先編譯出目標文件
gcc -c a.c b.c c.c
這時候你應該看到有 a.o b.o c.o了
然後創建庫文件
ar cr libtest.a a.o b.o c.o
這三個目標文件就放入 libtest.a 這個靜態庫中了,然後編譯C++程序 (你的C++程序應該已經按照我前面說的用 extern "C" 把C的介面都括起來了),假定你的 libtest.a 放在 /home/aaa/lib下
g++ -o my.exe my.cpp -L/home/aaa/lib -ltest
就會生成可執行文件 my.exe了。
3. gcc編譯器頭文件處理
兩次相對比一下,第二次增加了以下函數的實現,這部分是要編譯成機器指令的,所以第二次這部分相當於是增加的。
intprintf(constchar*__format,...)
{
registerint__retval;
__builtin_va_list__local_argv;__builtin_va_start(__local_argv,__format);
__retval=__mingw_vprintf(__format,__local_argv);
__builtin_va_end(__local_argv);
return__retval;
}
那第二次減少了哪些呢?一點都沒有,因為stdio這個頭文件聲明的函數和變數,都是在一個庫中實現的,根本就不會包含在你的exe中,所以加不加stdio頭文件沒有區別。
要想驗證這個也很簡單:代碼1
#include<stdio.h>
intmain(){return0;}
代碼2:
intmain(){return0;}
比較這兩次產生的exe是否一致即可。
注意,不能帶有-g選項,-g選項會生成一些額外的調試信息
4. 請問如何用GCC編譯自己定義的頭文件謝謝。
gcc -o main /home/mike/main.cpp -I /home/mike/
5. Objective c中,linux下gcc 編譯頭文件的命令是什麼
預處理對頭文件、宏定義等進行處理,生成
.i
的默認文件,命令:gcc
-E
test.c>test.i
6. gcc 在編譯時如何去尋找所需要的頭文件
當我們給
$ gcc -o foo.o foo.c
gcc怎麼知道去哪裡找foo.c裡面所include的header文件,連結資料庫與系統定義呢? 總共有下列來源指定gcc去那找。
當初在編譯時指定的(在~gcc/gcc/collect2.c:locatelib()
寫在specs內的
後來用-D -I -L指定的
gcc環境變數設定(編譯的時候)
ld.so的環境變數(這是run time的時候)
在
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.9.5/
裡面有個很重要的specs這個檔案 gcc根據這個檔,做一些內定的動作。 通常系統上的specs內定裝起來是在
/usr/lib/gcc-lib/xxxx-gnulibc/version/
specs檔看起來是像這樣
*asm:
%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}
*asm_final:
%|
*cpp:
%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:
-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}
*cc1:
%(cc1_cpu) %{profile:-p}
*cc1plus:
*endfile:
%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s
*link:
-m elf_i386 %{shared:-shared} %{!shared: %{!ibcs: %{!static:
%{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker
/lib/ld-linux.so.2}} %{static:-static}}}
*lib:
%{shared: -lc --version-script libgcc.map%s} %{!shared: %{mieee-fp:-lieee}
%{pthread:-lpthread} %{profile:-lc_p} %{!profile: -lc}}
*libgcc:
-lgcc
*startfile:
%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s}
%{!profile:crt1.o%s}}}} crti.o%s %{!shared:crtbegin.o%s}
%{shared:crtbeginS.o%s}
*switches_need_spaces:
*signed_char:
%{funsigned-char:-D__CHAR_UNSIGNED__}
*predefines:
-D__ELF__ -Dunix -Di386 -D__i386__ -Dlinux -Asystem(posix)
*cross_compile:
0
*version:
egcs-2.91.66
*multilib:
. ;
*multilib_defaults:
*multilib_extra:
*multilib_matches:
*linker:
collect2
*cpp_cpu_default:
-D__tune_i386__
*cpp_cpu:
-Asystem(unix) -Acpu(i386) -Amachine(i386) %{!ansi:-Di386}
-D__i386 -D__i386__ %{march=i486:-D__i486 -D__i486__}
%{march=pentium|march=i586:-D__pentium -D__pentium__ }
%{march=pentiumpro|march=i686:-D__pentiumpro -D__pentiumpro__ }
%{m386|mcpu=i386:-D__tune_i386__ } %{m486|mcpu=i486:-D__tune_i486__ }
%{mpentium|mcpu=pentium|mcpu=i586:-D__tune_pentium__ }
%{mpentiumpro|mcpu=pentiumpro|mcpu=i686:-D__tune_pentiumpro__ }
%{!mcpu*:%{!m386:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}}
*cc1_cpu:
%{!mcpu*: %{m386:-mcpu=i386} %{mno-486:-mcpu=i386 -march=i386}
%{m486:-mcpu=i486} %{mno-386:-mcpu=i486 -march=i486}
%{mno-pentium:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium}
%{mno-pentiumpro:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}}
在shell下用這行,-E 表示只做到preprocess就好
$ echo 'main(){}' | gcc -E -v -
你會看到gcc去讀specs檔
Reading specs from /usr/lib/gcc-lib/i386-linux/2.95.2/specs
gcc version 2.95.2 20000220 (Debian GNU/Linux)
/usr/lib/gcc-lib/i386-linux/2.95.2/cpp -lang-c -v -D__GNUC__=2 -D__GNUC_MINOR__=95 -D__ELF__ -Dunix -D__i386__ -Dlinux -D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__linux -Asystem(posix) -Acpu(i386) -Amachine(i386) -Di386 -D__i386 -D__i386__ -
GNU CPP version 2.95.2 20000220 (Debian GNU/Linux) (i386 Linux/ELF)
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
/usr/include
End of search list.
The following default directories have been omitted from the search path:
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include
End of omitted list.
# 1 ""
main(){}
所以有內定的定義,(就是用在#if defined #ifndef #define這些東西, 如果有定義這個字元串,就去編譯等等。) -Dxxxx -Dxxxx -Axxxx。 還有內定的include文件的搜尋路徑
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include
但是如果裝gcc的時候,是有給定的prefix的話,那麼就是
/usr/include
prefix/include
prefix/xxx-xxx-xxx-gnulibc/include
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.8.1/include
所以header file的搜尋會從-I開始然後找gcc的環境變數 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH 再找上述的內定目錄
函式庫
當我們用到數學函式cos(),cos這個symbol,gcc並不曉它到底是什麼東西, 是變數,是函式,要預留多少空間給他等等,完全沒有任何訊息,你必須標頭 檔要#include ,gcc才知道。而且因為specs這個檔裡面只有要 link -lc也就是只有libc.so這個檔內的symbol會被搜尋, 像printf scanf等都在這裡面,可是像cos()等就沒有了, 所以函式庫的選項要多加 -lm ,這時ld才會來找libm這個函式庫,
編譯的時候,gcc會去找-L,再找gcc的環境變數LIBRARY_PATH,再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程序內的, gcc環境變數與pass給ld的機制在~gcc/gcc/collect2.c下找得到。 這上面只是搜尋路徑而已,如果要不加-lm 也能正確的主動搜尋某個特定的lib,例如libm, 就要去在specs這個檔案改一下,把math這個函式庫加進自動聯結函式庫 之一。就不用寫-lm了。
RUN TIME的時候, 如果編譯時沒有指定-static這個選項,其實可執行文件並不是真的可執行, 它必須在執行(run time)時需要ld.so來做最後的連結動作,建造一個可執行的 image丟到內存。如果是靜態連結,編譯時ld會去找libm.a的檔 。如果是動態連結去找libm.so。 所以每次有新改版程序, 或新加動態函式庫如果不在原本的/etc/ld.so.conf搜尋路徑中,都要把路徑 加進來,然後用
ldconfig -v
會重建cache並且顯示它所參照的函式庫。Run Time時ld.so才找得到lib"執行"。 ld與ld.so不一樣喔。
一些重要的程序
ld :Link Editor 連結各obj寫進一個可執行檔(executable)。
ldd :秀出一個執行文件用了那些動態函式庫。
ld.so :Dynamic Linker, 動態連結的話,是由ld.so完成執行時期symbol的
:參照與連結。
ld-linux.so :ELF文件的動態連結,跟ld.so一樣。只是ld.so是給a.out format的。
:新的glicb2的ld-linux.so.2已經跟ld.so.2結合成單一程序了。
ldconfig :根據/etc/ld.so.conf內的目錄,做出動態連結所需的cache檔。
ld 就是負責各個函式庫文件的信息寫進最後可執行檔(executable),所以它叫做 link editor,編譯時根據flags -L搜尋需要的lib,gcc也會把他的設定pass下來。 ld.so ld-linux.so.2是負責最後動態連結,叫做dynamic linker, RUN Time 執行程序時,它根據這個順序搜尋函式庫。
LD_LIBRARY_PATH 或LD_AOUT_LIBRARY_PATH環境變數所指的路徑
ldconfig所建立的cache
/lib /usr/lib內的檔
來找程序所需要的動態函式庫
ldconfig會根據/etc/ld.so.conf這個檔的設定,加上內定的兩個目錄 /lib /usr/lib來設定ld.so要用到所需要的連結 以及連結的cache到/etc/ld.so.cache。 所以如果換了新的函式庫,新的kernel,內部的標頭檔可能會有變化, 都要跟著改變讓gcc正確的找到,喔不,應該是cpp, ld, ld.so能正確的找到。 不然編出來的執行檔可能是錯誤的,執行時還可能segmentation fault。
7. 如何解決gcc編譯c程序找不到頭文件的問題
剛裝好的GCC什麼都不能編譯,因為沒有一些必須的
頭文件
,所以要安裝build-essential,安裝了這個包會安裝上g++,libc6-dev,linux-libc-dev,libstdc++6-4.1-dev等好多必須的軟體和頭文件。
8. 關於在linux下用gcc編譯頭文件
首先,確定你的頭文件都用宏隔開了,防止了重復定義。例如,在file.h 中的開頭就是
#ifndef __FILE__HEAD___
#define __FILE__HEAD___
//頭文件中的內容
#endif //__FILE__HEAD___
之後,
file.h中用到了list.h ,所以file.h中#include "list.h"//假設頭文件都在同一目錄下
list.h中用到了preapre.h 所以list.h中#include "prepare.h"
prepare.h中用到了node.h 所以prepare.h中#include "node.h"
在某些情況下,由於代碼組織等的問題,還是會出現編譯問題,這個就是代碼組織技巧的問題了,要根據具體代碼具體判斷了。
另外,准確的說頭文件只是在編譯的第一步,預處理的時候使用了,真正被「編」的應該是源文件,這個是編譯原理方面的問題了。
9. gcc編譯線程程序,為什麼要加-lpthread,頭文件已經包含了<pthread.h>了啊
-lpthread是鏈接庫,
<pthread.h>只有申明,實現部分都在庫裡面。
創建線程時一般是把函數的指針做參數,所以要加一個取地址符號。
ret=pthread_create(&id,NULL,(void *)&thread,NULL);
另外,建議要檢查一下創建線程的返回值ret是否成功,防止影響後面的代碼。
(9)gcc頭文件編譯擴展閱讀:
每個語言編譯器都是獨立程序,此程序可處理輸入的原始碼,並輸出組合語言碼。全部的語言編譯器都擁有共通的中介架構:一個前端解析符合此語言的原始碼,並產生一抽象語法樹,以及一翻譯此語法樹成為GCC的暫存器轉換語言〈RTL〉的後端。
編譯器最佳化與靜態程序碼解析技術(例如FORTIFY_SOURCE,一個試圖發現緩沖區溢位〈buffer overflow〉的編譯器)在此階段應用於程序碼上。最後,適用於此硬體架構的組合語言程序碼以Jack Davidson與Chris Fraser發明的演算法產出。