1. 重要目录
当我们进入Linux系统后,像在Windows命令提示符下运行程序那样,我们与Shell程序(通常为bash)交互,shell程序在指定的目录集下寻找我们期望的程序文件。这些目录通常存放在Shell变量PATH中,这与windows系统是一样的。搜索路径PATH由系统管理员配置,通常会包含一些系统程序的标准存放目录。包括:
/bin 系统引导程序
/usr/bin 系统程序
/usr/local/bin 用户程序
/sbin:/usr/sbin 系统管理程序
->/opt 一些系统组件或第三方的应用程序可能放在该子目录中
安装程序有时会通过安装脚本将自己的目录添加到PATH变量中。在PATH变量中,不同的目录以冒号分隔。 在命令行下输入echo $PATH ,屏幕上就会打印出当前用户的PATH变量值,例如:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
下面我们通过实例说说PATH变量的作用
输入以下程序
/*******test.c*******/
#include<stdio.h》
int main()
{
printf("Hello World!/n");
exit(0)
}
编译链接生成可执行文件:
cc -o test test.c
这样在当前目录下就生成了一个test文件,如果我们直接在命令行下输入test运行该程序,是不会得到预期的效果的,原因就在于PATH变量中并不包含当前目录,因而Shell找不到该文件。此外,如果PATH变量中的某目录中包含名为test的可执行文件,那么这个“test"文件就会解释执行,还有就是Shell会优先执行PATH变量前面目录下的文件,也就是说即使PATH变量中包含了当前目录,但如果位于该目录前面的目录中有同样的可执行文件,那么我们的文件仍然得不到执行。为了避免这种潜在的问题,我们可以在要执行的文件名前面加上“./”前缀,表示执行当前目录下的文件,并且可以避免向PATH变量中添加当前目录。
把当前目录添加到PATH中:
export PATH=$PWD:$PATH
注意:我们往往喜欢以test作为测试的可执行程序的名字,但如果当你把当前路径添加到PATH变量中后程序还是没有执行,那你不妨试试将程序更名,如:mv test mytest。
2. 头文件
在C语言或其它一些编程语言中,我们需要头文件提供常量的定义和系统或者库函数调用的声明。在C语言中,头文件通常位于/usr/include目录或其子目录下,当我们编译连接程序的时候,编译器会自动到该目录下寻找相应的头文件。如果我们需要用到不在该目录下的头文件,我们在编译的时候可以通过-I( i 的大写)参数加以说明。例如:
cc -I /usr/openwin/include test.c
我们可以通过grep命令来寻找相关的常量定义和函数声明,例如我们可以通过下面的命令找出关于exit常量的定义:
grep EXIT_ /usr/include/*.h
按Enter键后,我们就可以看到我们期望的定义了
/usr/include/stdlib.h:#define EXIT_FAILURE 1 /*Failing exit status.*/
/usr/include/stdlib.h:#define EXIT_SUCCESS 0 /*Successful exit status.*/
3. 库文件
库文件是一些预编译函数的集合。标准系统程序库通常存放在/lib和/usr/lib目录下。默认情况下,C编译器通常只寻找标准的C库文件,如果希望编译器找到我们的库文件,仅仅把库文件放在标准目录下是不够的,它们需要遵循专门的命名规范,并且在命令行被引用。库文件通常以lib开头,然后才是代表库文件用途的名称(比如说用C表示C程序库文件,用m表示数学函数的库文件),并且以后缀名来区分不同的库文件类型。传统的静态库文件通常以.a作为后缀,而动态库文件则以.so作为后缀。
我们可以通过-l(小写的L)来给出相应库文件的以用,例如:
cc -o test test.c -lm
或者:
cc -o test test.c /usr/lib/libm.a
尽管编译器通常会在标准的库文件目录下需找相应的库文件(本例为/usr/lib),我们还可以通过-L参数来加以说明。例如:
cc -o test test.c -L /usr/lib test.c -lm
3.1 静态库的一个实例
分别创建以下文件
/*************Alice.c******************/
# include <stdio.h>
void Alice(char * str)
{
printf("Alice Say: %s/n",str);
}
/*************Blob.c******************/
# include <stdio.h>
void Blob(char * str)
{
printf("Blob Say: %s/n",str);
}
/*************say.h******************/
void Alice(char *str);
void Blob(char *str);
/*************saytest.c******************/
#include "say.h"
int main()
{
Alice("Hello World!");
Blob("Nice to meet you!");
}
编译:
cc -c Alice.c Blob.c saytest.c
生成库文件:
ar -r libtest.a Alice.o Blob.o
链接:
cc -o saytest saytest.o libtest.a
于是,在当前目录下就生成了可执行文件 saytest,在命令行下输入:./saytest即可运行该文件。
注:C编译器首先会在当前目录下寻找用到的头文件和静态库文件,上面的链接命令等同于:cc -o saytest saytest.o -L . -ltest
3.2 动态库文件
动态库一般以.so结尾,就是shared object的意思。下面我们将上例中的目标文件编译生成成动态库文件,并链接调用。
生成动态库文件:
cc -shared -o libtest.so Alice.o Blob.o
链接:
cc -o saytest saytest.o libtest.so
这时,在当前目录下就生成了可执行文件 saytest,可是当我们在命令行下输入./saytest运行该文件时系统却报错找不到libtest.so
./test: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
这说明当程序运行的时候并没有在当前目录下寻找相应的动态库文件。实施上,可执行文件会在系统环境变量LD_LIBRARY_PATH中列出的目录下寻找相关动态库的实现,如果找不到就会报错。因此,我们可以将当前目录添加到变量LD_LIBRARY_PATH中:
export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
这样,当我们再次输入./saytest的时候,程序正常运行,在屏幕打印出:
Alice: Say Hello World!
Blob: Say Nice to meet you!
用nm和ld命令可分别列出相应文件引用的静态库文件和动态库文件。