UNIX/linux入门
UNIX哲学:
简单性、集中性、可重用组件、过滤器、开放的文件格式和灵活性。
Linux程序设计
linux程序
linux一个用程序表现为两种特殊的文件:可执行文件和脚本文件。可执行文件是计算机可以直接运行的程序。脚本文件是一组指令的集合,这些指令将由另一个程序(即解释器)来执行。
搜索路径由系统管理员配置,通常包含一些存储系统程序的标准路径,其中包括:
/bin: 二进制文件目录,用于存放启动系统时用到的二进制文件
/usr/bin:用户二进制文件目录,用于存放用户使用的标准程序
/usr/local/bin:本地二进制文件目录,用于存放特定软件安装的程序
开发系统引导
应用程序:
通常存放在系统为之保留的特定目录中。系统为正常使用提供的程序,包括用于程序开发的工具,都可在目录/usr/bin中找到;系统管理员为某个特定的主机或本地网络添加的程序通常在/usr/local/bin或/opt中找到。
系统管理员一般喜欢使用usr/local目录,因为它分离厂商提供及后续添加的文件与系统本身提供的应用程序。
GUN编写系统的驱动程序gcc一般位于/usr/bin或/usr/local/bin目录中,但它会从其他位置运行各种编译器支持的应用程序。对linux系统来说,这个位置可能是/usr/lib/gcc-lib/目录下的一个版本特定的子目录。
头文件:
对C语言来说,头文件几乎总是在/usr/include目录及其子目录下。那些依赖特定linux版本的头文件通常可在/usr/include/sys和/usr/include/linux中找到。
其他编程系统也有各自的include文件,并将其存储在可被相应编辑器自动搜索的目录里。例如S视窗系统的/usr/include/X11目录和GUN C++的/usr/include/g++目录。
调用C编译器时,可以使用-I来标志包含保存在子目录或非标准位置的include文件。
例如
gcc –I/usr/openwin/include fred.c
它指示编译器不仅在标准位置,也在/usr/openwin/include目录中查找程序fred.c中包含的头文件。
用grep命令搜索包含某些特定定义和函数原型的头文件是很方便的。例如
$ grep EXIT_ *.h
…
stdlib.h #define EXIT_FAILURE 1
stdlib.h #define EXIT_SUCCESS 0
…
$
grep命令在当前目录下的所有.h结尾的文件中搜索字符串EXIT_。本例中,它在stdlib.h文件中找到了我们需要的定义。
库文件
库是一组预先编译好的函数的集合,这些函数都是按照可重用的原则编写的。他们通常是由一组相互关联的函数组成并执行某项常见的任务。
标准系统库文件一般存储在/lib和/usr/lib目录中。
库文件的名字总是以lib开头,随后的部分指明这是什么库(例如,c代表C语言库,m代表数学库)。文件名的最后部分以.开始,然后给出库文件的类型。
.a 代表传统的静态函数库
.so 代表共享函数库
静态库
静态库也称作归档文件(archive),按惯例他们的文件都以.a结尾。比如,标准C语言函数库/usr/lib/libc.a
我们可以很容易地创建和维护自己的静态库,只要使用ar程序和gcc –c命令对函数分别进行编译。我们应该尽可能把函数分别保存到不同源文件中,如果函数需要访问公共数据,我们把它们放在同一个源文件中并使用在该文件中声明的静态变量。必须用-l选项指明标准C语言运行库外还需要使用的库。
实验:静态库
1) 创建各自源文件(分别命名为fred.c和bill.c)
#include<stdio.h>
voidfred(int arg)
{
printf("fred:you passed %d\n",arg);
}
#include<stdio.h>
int bill(char* arg)
{
printf("bill:you passed%s\n",arg);
}
2) 分别编译这些函数,产生目标文件。-c选项的作用是阻止编译器创建一个完成的程序。
$ chen123@ubuntu:~/C++/archive$gcc -c bill.c fred.c
$ chen123@ubuntu:~/C++/archive$ls *.o
bill.o fred.o
3)编写一个调用bill函数的程序。创建一个头文件来声明我们库文件中的函数,把头文件包含在源文件fred.c和bill.c中。
void bill(char*);
void fred(int);
4)调用程序(program.c)
#include"lib.h"
int main()
{
bill("hello world");
return 0;
}
5)编译并测试程序
$ chen123@ubuntu:~/C++/archive$ gcc -cprogram.c
$ chen123@ubuntu:~/C++/archive$ gcc -oprogram program.o bill.o
$ chen123@ubuntu:~/C++/archive$ ./program
bill:you passed hello world
6)命令创建并使用一个库文件。我们用ar程序创建一个归档文件并将目标文件添加进去。
chen123@ubuntu:~/C++/archive$ ar crvlibfoo.a bill.o fred.o
a - bill.o
a - fred.o
7)在编译器命令行的文件列表中添加该库文件以创建我们的程序
chen123@ubuntu:~/C++/archive$ gcc -oprogram program.o libfoo.a
chen123@ubuntu:~/C++/archive$ ./program
bill:you passed hello world
也可以用-l选项来访问我们的库函数,但是因为其未保存在标准位置,所以我们必须用-L选项来指示编译器在何处可以找到它,如下所示:
chen123@ubuntu:~/C++/archive$ gcc -o programprogram.o -L. –lfoo
其中-L.选项指示编译器在当前目录(.)中查找函数库。-lfoo选项指示编译器使用名为libfoo.a的函数库。
要查看目标文件(.o类型),函数库(.a)或者可执行文件可以用nm命令。我们查看program和libfoo.a,会看到函数库libfoo.a中包含fred和bill两个函数,而program里只包含函数bill。创建程序时,它只包含函数库中它是实际需要的函数。虽然程序中的头文件包含函数库中的所有函数声明,但这不讲整个函数库包含进最终的程序中。
动态库
静态库有一个缺点是,当我们同时运行许多应用程序并且它们使用都来自同一个函数库的函数时,就会在内存中有同一函数的多份拷贝,在程序文件自身中也有多份同样的拷贝,这将消耗大量宝贵的内存和磁盘空间。
共享库的保存位置和静态库是一样的,但共享库有不同的文件后缀。在典型的linux系统中,标准数学库的共享版本是/usr/lib/libm.so。
程序使用共享库时,它本身不再包含函数代码,而是引用运行时可访问的共享代码。当编译好的程序被装载到内存中执行时,函数引用被解析并产生对共享库的调用,如果有必要才被加载到内存中。通过这种方法,系统只保留共享库的一份拷贝并共许多应用程序同时使用,并且在磁盘上也仅保存一份。另外一个好处是共享库的跟新可以独立于依赖他的应用程序。
对linux系统来说,负责装载共享库并解析客户程序函数引用的程序是ld.so,也可能呢过是ld-linux.so.2.
我们可以用运行工具ldd
来查看程序需要的共享库。例如,
chen123@ubuntu:~/C++/archive$ ldd program
linux-gate.so.1=> (0x00392000)
libc.so.6=> /lib/i386-linux-gnu/libc.so.6 (0x001ec000)
/lib/ld-linux.so.2(0x00a90000)
在这个例子中,我们看到标准C语言函数库(libc)是共享的(.so),我们的程序要求使用的主板号是6。动态装载器是ld-linux.so.2.
获得帮助
可以使用man命令访问在线手册页,也可以用info在线文档系统。
阅读在线手册页时可以用空格读下一页,按Enter读下一行,按q退出。