您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > 其它相关文档 > 2 - 多文件编译&库文件
多文件编译&头文件&库文件李岚多文件编译•将多个c文件编译成可执行文件–gccstackfunc.cstackmain.c-omain•上面的过程还可以使用如下步骤替代•gcc-cstackfunc.c•gcc-cstackmain.c•gccstackmain.ostackfunc.o-omain•用nm命令查看目标文件的符号表,会发现stackmain.o中有未定义的符号push、pop、is_empty、putchar,•nmstackmain.o–Uis_empty–00000000Tmain–Upop–Upush–Uputchar•nmstackfunc.o–00000045Tis_empty–0000002aTpop–00000000Tpush–00000200Cstack–00000000Dtop•Pushpopis_empty在stackfunc.o中实现了,链接生成可执行文件时可以做符号解析,而putchar是libc的库函数,在可执行文件stackmain中仍然是未定义的,要在程序运行时做动态链接刚刚程序完美吗?(头文件)•gcc-cstackmain.c-Wall–stackmain.c:Infunction‘main’:–stackmain.c:8:warning:implicitdeclarationoffunction‘push’–stackmain.c:12:warning:implicitdeclarationoffunction‘is_empty’–stackmain.c:13:warning:implicitdeclarationoffunction‘pop’为什么出现上面的警告?(头文件)•由于编译器在处理函数调用代码时没有找到函数原型,只好根据函数调用代码做隐式声明,把这三个函数声明为:•intpush(char);•intpop(void);•intis_empty(void);•在main中声明函数原型–externvoidpush(char);//函数声明extern可加可不加–externcharpop(void);–externintis_empty(void);–externinttop;//变量声明extern一定要加•这样即没有警告–root@ubuntu:/home/li/share/CodeTest/2linkertest/2#gccstackfunc.cstackmain.c-omain-Wall外部链接(头文件)•如果把stackmain.c和stackfunc.c链接在一起,如果push在stackmain.c和stackfunc.c中都有声明(在stackfunc.c中的声明同时也是定义),那么这些声明指的是同一个函数,链接之后是同一个GLOBAL符号,代表同一个地址。函数声明中的extern也可以省略不写,不写extern的函数声明也表示这个函数具有ExternalLinkage。头文件•将刚才的stackmain.c分成stacklilan.h和stackmain.c•编译–root@ubuntu:/home/li/share/CodeTest/2linkertest/3#gccstackfunc.cstackmain.c-omain-Wall静态库•把stackfunc.c拆成4个程序文件–gcc-cstack/stack.cstack/push.cstack/pop.cstack/is_empty.c•生成库文件–arrslibstacklilan.astack.opush.opop.ois_empty.o–ar:creatinglibstacklilan.a•或者–arrlibstacklilan1.astack.opush.opop.ois_empty.o–ar:creatinglibstacklilan1.a–ranliblibstacklilan1.a静态库•gccmain.c-L.-lstacklilan-Istack-omain•-L选项告诉编译器去哪里找需要的库文件,-L.表示在当前目录找。•-lstacklilan告诉编译器要链接libstacklilan库•-I选项告诉编译器去哪里找头文件(.h)。•编译器会在搜索路径以及-L选项指定的路径中查找用-l选项指定的库,比如-lstacklilan–gcc-print-search-dirs•编译器会首先找有没有共享库libstacklilan.so,如果有就链接它,•如果没有就找有没有静态库libstacklilan.a,如果有就链接它。•编译器优先考虑共享库动态库例1•查看程序so1.c,编译生成可执行文件so1–gccso1.c-oso1•lddso1•linux-gate.so.1=(0x00503000)•libc.so.6=/lib/libc.so.6(0x00bcb000)•/lib/ld-linux.so.2(0x0025d000)动态库例1•gcc-cso1.c-oso1.o•相当于:•ld/usr/lib/crt1.o/usr/lib/crti.oso1.o-oso1-lc-dynamic-linker/lib/ld-linux.so.2•在链接libc共享库时只是指定了动态链接器和该程序所需要的库文件,并没有真的做链接•可执行文件so1中调用的libc库函数仍然是未定义符号,要在运行时做动态链接。•在链接静态库时,链接器会把静态库中的目标文件取出来和可执行文件真正链接在一起。so1拆分成2个文件•catso1.c•#includestdio.h•voidprinthello(){•printf(helloworld\n);•}•intmain(){•printhello();•return0;•}catso1main.cintmain(){printhello();return0;}catso1fun.c#includestdio.hvoidprinthello(){printf(helloworld\n);}•生成动态库libsolilan.so–gcc-olibsolilan.so-fPIC-sharedso1fun.c•生成可执行文件–gcc-oso1main-L.-lsolilanso1main.c•./so1main运行程序出现问题•./so1main:errorwhileloadingsharedlibraries:libsolilan.so:cannotopensharedobjectfile:Nosuchfileordirectory•lddso1main–linux-gate.so.1=(0x0028a000)–libsolilan.so=notfound–libc.so.6=/lib/libc.so.6(0x00110000)–/lib/ld-linux.so.2(0x00b6d000)•sudogedit/etc/ld.so.conf–/home/li/share/CodeTest/2linkertest•sudoldconfig-v例•原来的堆栈文件•对比,生成可执行文件后重定位就定死了地址•gcc-c-gstack/stack.cstack/push.cstack/pop.cstack/is_empty.c•objdump-dSpush.o•gcc-gmain.cstack.opush.opop.ois_empty.o-Istack-omain•objdump-dSmain•gcc-c-g-fPICstack/stack.cstack/push.cstack/pop.cstack/is_empty.c(生成目标文件)•gcc-shared-olibstack.sostack.opush.opop.ois_empty.o(生成动态库文件)•gccmain.c-g-L.-lstack-Istack-omain(生成可执行文件)•./main出错•/home/li/share/CodeTest/2linkertest/5•首先在环境变量LD_LIBRARY_PATH所记录的路径中查找•然后从缓存文件/etc/ld.so.cache中查找。这个缓存文件由ldconfig命令读取配置文件/etc/ld.so.conf之后生成•如果上述步骤都找不到,则到默认的系统路径中查找,先是/usr/lib然后是/lib4种方法解决问题•方法1:在运行main时通过环境变量LD_LIBRARY_PATH把当前目录添加到共享库的搜索路径–$LD_LIBRARY_PATH=../main•方法2:把libstack.so所在目录的绝对路径(比如/home/li/share/CodeTest/2linkertest/5)添加到/etc/ld.so.conf中–Ldconfig-v•方法3:把libstack.so拷到/usr/lib或/lib目录•方法4:在编译可执行文件main的时候就把libstack.so的路径写死在可执行文件中共享库的命名•生成.o文件•gcc-c-g-fPICstack/stack.cstack/push.cstack/pop.cstack/is_empty.c•重新编译共享库,指定soname-realname•gcc-shared-Wl,-soname,libstack.so.1-olibstack.so.1.0stack.opush.opop.ois_empty.o(生成realname)•ls–is_empty.olibstack.so.1.0main.cpop.opush.ostackstack.o•Ldconfig(自动创建一个soname的符号链接)•ls-llibstack*–lrwxrwxrwx1rootroot152012-05-1908:55libstack.so.1-libstack.so.1.0–-rwxr-xr-x1rootroot90872012-05-1908:55libstack.so.1.0•gccmain.c-L.-lstack-Istack-omain–/usr/bin/ld:cannotfind-lstack–collect2:ldreturned1exitstatus•ln-slibstack.so.1.0libstack.so–(创建一个linkername的符号链接)引导扇区•boot.S•Makefile•Solrex_x86.ld加载最简单的操作系统内核•再建一个文件,将其通过引导扇区加载入内存,然后将控制权交给它---内核•loader.S•Makefile•solrex_x86_boot.ld•solrex_x86_dos.ld•boot.S
本文标题:2 - 多文件编译&库文件
链接地址:https://www.777doc.com/doc-3223472 .html