参考:http://www.network-theory.co.uk/docs/gccintro/gccintro_17.html
1. include的文件在哪找,找不到会如何?
工具: gcc -H -fsyntax-only test.c
用“”引入的话,首先在当前目录查找,然后在系统目录查找;使用<>引入的话,直接在系统目录查找。
首先研究#include <stdio.h> ,发现stdio.h在 /usr/include 下
即,/usr/include 是一个默认路径。
还有个目录类似 /usr/include/x86_64-linux-gnu/sys/cdefs.h,如果要引入 cdefs.h 应该 #include<sys/cdefs.h>
这也就是说, /usr/include/x86_64-linux-gnu/ 是默认的系统路径。
还有个目录类似 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h,如果要引入 stddef.h ,用 #include <stddef.h>
这也就是说, /usr/lib/gcc/x86_64-linux-gnu/4.8/include/ 是一个默认路径。
在编译时,可以使用 -I参数指定include 路径,该路径会搜索“”包含的头文件。参考 http://mathlab.utsc.utoronto.ca/courses/cscd43w17/csc443clean/tutorials/leveldb.html
参考: http://www.network-theory.co.uk/docs/gccintro/gccintro_21.html
2. 假设include找到了,那么编译就可以完成。那么运行时,如何load include里面声明的函数?
当对libfuse-2.9.2进行make install后,几个相关的包如libfuse.so.2被拷贝到了/usr/local/lib目录下。此时,对ssfs进行make和make install均可以成功,但是在运行时却出现错误,提示:
./ssfs: error while loading shared libraries: libfuse.so.2: cannot open shared object file: No such file or directory
将libfuse.so.2拷贝到/usr/lib目录下可以解决这一问题。
按照https://unix.stackexchange.com/questions/22926/where-do-executables-look-for-shared-objects-at-runtime来看,/usr/local/lib也在默认的搜索路径,因为 /etc/ld.so.conf的内容是
include /etc/ld.so.conf.d/*.conf,而leveldb@river:/etc/ld.so.conf.d$ cat libc.conf 的内容是 /usr/local/lib。
因此,这个问题可能是 /etc/ld.so.conf的内容没有被系统正常识别。
根据https://unix.stackexchange.com/questions/67781/use-shared-libraries-in-usr-local-lib的第二个回答,确实是没有被识别,使用sudo ldconfig会自动将 /etc/ld.so.conf.d/*.conf的条目加入load缓存。将/usr/lib里的库改名,仍热可以正确运行 sudo ./ssfs /mnt -f 了。
3. 上述1中的系统include在linux系统的目录下可以找到。那么这些文件与 glibc源文件里的include内容有何区别呢?
答:glibc源文件是用来编译glibc库的。比如,glibc实现了一个函数f1(), 该函数的具体实现在glibc的源文件xx.c里。glibc的另一个源文件需要用到函数f1(),那么需要一个头文件来包含f1()的形式,这个头文件就在glibc的源文件里。 当这个些glibc的源文件被编译好为一个libc.so 的库后,其他程序需要使用里面的函数f1(),就需要知道该函数的形式,那么需要一个头文件来包含这个形式,这个头文件被放在系统的/usr/include/下面。
总结一下就是,glibc源文件里的头文件是给glibc源代码用的,而系统/usr/include/下的头文件是给用户程序用的。
4. 静态与动态链接
5. 环境变量
系统有很多环境变量,比如$PATH 决定了从shell输入的命令在哪些路径下寻找。
对于编译器来说,可以设置搜寻头文件路径的环境变量。对于连接器来说,也可以设置搜寻库路径的环境变量。