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发明的算法产出。