linux 程序,linux新手知识
Linux程序
Linux程序由两部分组成:可执行文件和脚本。可执行文件是可以由我们的计算机直接运行的程序,它们对应于。Windows下的exe程序。脚本是另一个程序的指令集,要一步一步解释。它们对应于。蝙蝠还是。Windows下的cmd文件。
Linux下的可执行文件或脚本不需要特殊的文件名或扩展名。文件系统的属性可以用来表明它是一个可运行的程序。在Linux下,我们可以用编译后的程序替换脚本,而不会影响其他程序或调用它们的其他用户。其实两者在用户层面并没有实质性的区别。
当我们登录Linux系统时,我们与一个Shell程序(通常是Bash)进行交互,这个Shell就像Windows下的命令行一样运行。他通过在指定的目录中搜索返回我们指定的程序名。要搜索的目录存储在名为PATH的Shell变量中。这和Windows类似。这个搜索目录(我们通常可以添加我们自己的目录)是由我们的系统管理员配置的,并且通常包含一个导致标准系统程序被存储的目录。它们通常包含以下目录:
/bin:二进制文件,系统启动时要使用的程序。
/usr/bin:用户二进制文件,用户可以使用的标准程序。
/usr/local:本地二进制文件,要安装的特殊程序。
以管理员用户(如root)身份登录时,使用的路径变量将包括系统管理程序包含的位置,如/sbin和/usr/sbin。
可选的系统组件或第三方程序也会安装在/opt子目录下,安装程序会以用户安装脚本的形式添加到PATH变量中。
这里要注意的是,和Unix一样,Linux中使用冒号(:)来分隔PATH变量中的项,和分号(;)不一样。例如,路径变量的以下示例:
/usr/local/bin:/usr/bin:/bin:/usr/x11r 6/bin:/usr/games
c编译器
在Linux系统上,当我们使用c89、cc或gcc时,我们总是指系统的编译器,通常是GNU C编译器或gcc。在Unix系统上,C编译器通常是cc。
让我们开始编写、编译和运行我们的第一个Linux程序。也许最好的一个是最著名的HelloWorld。
以下是Hello.c的源代码:
#inclue stdio.h
int main()
{
printf( Hello World/n );
退出(0);
}
2编译链接运行程序:
$gcc -o Hello Hello.c
$ ./你好
你好世界
$
他是如何工作的?
我们调用GNU C编译器将我们的C源代码转换成一个可运行的文件。当我们运行这个程序时,他会打印出一个问候语。这是最简单的程序示例,但是如果我们可以更进一步,我们可以编译和运行其他程序示例。如果这个命令不起作用,我们必须确保C编译器已经安装在我们的系统中。比如在很多Linux发行版中,有一个安装选项叫做软件开发,我们必须选择。
因为这是我们运行的第一个程序,所以我们想指出一些东西。Hello程序通常位于我们用户的主目录中。如果我们的Shell变量不包含对用户主目录的引用,Shell将找不到这个程序。另外,如果PATH变量中的一个目录也包含一个名为Hello的程序,那么这个命令将会运行。如果PATH变量的目录位于用户的主目录之前,也会发生这种情况。为了避免这个问题,我们可以在程序前面加上一个./。这将表明Shell要执行的程序位于我们的当前目录中。
如果我们不通过-o name选项告知生成的可执行文件的名称,编译器会将生成的可执行文件命名为a.out .(参考汇编输出)。如果我们记得我们已经编译了一个程序但是找不到,那么我们一定要记得寻找a.out文件。在Unix的早期,在系统上玩游戏的人经常以A.out的形式运行这些游戏程序,以避免被系统管理员发现,所以
系统开发路线图
对于一个Linux开发者来说,知道一些开发工具和资源在哪里是非常重要的。让我们在下一节看看一些重要的目录和文件。
程序
程序将存储在它们的目录中。系统日常使用的程序,包括程序,都位于/usr/bin目录下。系统管理员为主机或本地网络添加的程序通常位于/usr/local/bin或/opt中。
系统管理员更喜欢/usr/local目录,因为后面添加的一些程序可以保存在这个目录下,从而实现与系统提供的程序的分离。这样保存/usr的组织很有用,这样在更新系统时只需要保留/usr/local目录中的内容。所以我们推荐的方法是把自己编译运行的程序和要访问的文件放在/usr/local目录下。
其他功能和程序系统有自己的目录结构和程序目录。主要的是X Window系统,通常安装在/usr/X11目录下。
头文件
对于C或其他语言的程序,需要使用头文件来提供常量的定义以及系统和库函数调用。对于C,这些头文件位于/usr/include目录及其子目录中。我们也可以在/usr/include/sys和/usr/include/中使用它们。基于我们正在运行的linux的典型头文件可以在Linux目录中找到。其他程序系统和包含文件存储在编译器可以自动找到的目录中。比如X Window系统的头文件在/usr/include/X11目录,GNU C的头文件在/usr/include/g目录。
我们可以通过为C编译器指定-I标志来指定包含文件是否在子目录中。例如:
$ gcc-I/usr/open win/include Fred . c
这将使编译器在编译fred.c文件时在/usr/openwin/include目录中查找头文件。我们还可以在C编译器的手册页中获得更详细的内容。
我们可以使用grep命令来查找特定定义和函数原型的头文件。如果我们想知道由#define定义并用于从程序返回的退出状态的名称,我们可以简单地输入/usr/include目录并使用grep命令进行相应的搜索:
$ grep EXIT_*。h
在这里,grep查找所有以。h表示当前目录中的字符串EXITu。在这个例子中,这个命令将在文件stdlib.h中找到我们需要的定义.
库文件
库是为代码重用而编写的预编译函数的集合。通常,它们是用于执行共同任务的相关功能的集合。库文件的例子包括一些秘密处理函数(比如curses和ncruses库)和用于数据库访问的库(比如dbm库)。
标准系统的库文件通常位于/lib和/usr/lib目录中。C编译器(或者更准确地说,链接器)需要被告知要查找哪些库文件。默认情况下,它只查找标准C库。这是电脑慢,CPU贵的时代遗留下来的。将库文件放在标准目录中并希望编译器能够找到它们是不够的。库文件需要遵循特定的命名约定,并由命令行指定。
文件名通常以lib开头。文件的其余部分表明库是什么(例如,C是指C库,M是指算术库)。最后一部分从。要指示库的类型:传统的静态图书馆。so共享库
库通常以静态和共享的形式存在。我们可以运行ls /usr/lib来查看运行结果。我们可以通过指定编译器的完整路径或使用-l标志来指定编译器查找的路径。如下例所示:
$ gcc-o Fred Fred . c/usr/lib/libm . a
这个命令会告诉编译器fred.c程序生成fred程序,通过同时搜索标准C库和算术库来解决函数引用的问题。我们也可以使用下面的命令来达到同样的结果:
$ gcc -o弗雷德弗雷德. c -lm
-lm(L和M之间没有空格)是libm.a库的缩写,位于库目录(/usr/lib)。-lm选项的另一个优点是,如果有共享库,编译器会自动选择共享库。
虽然可以在标准位置找到头文件形式的库文件,但是我们可以使用-L选项添加另一个目录进行检查。例如:
$ gcc-o X11 Fred-L/usr/open win/lib X11 Fred . c-lX11
该命令将使用/usr/openwin/lib目录中的libX11版本库编译和链接x11fred程序。
静态库:
最简单的库格式只是一组处于备用状态的目标文件。当一个程序想要使用存储在库中的函数时,它需要包含定义这个函数的头文件。编译器和连接器可以小心地处理它,把程序代码和程序库组成一个单独的可执行程序。我们必须使用-l选项来指示除了标准C运行时之外还需要哪些库文件。
静态库也称为文档,通常是以结尾的文件名。答:例如,标准C库与X11库/usr/lib/libc.a与/usr/X11/lib/libx11.a .
我们可以很容易地使用ar(archive)来创建和维护自己的静态库,这样就可以使用gcc -c来编译函数。我们应该尽可能将函数放在单独的源文件中。如果函数需要访问常规数据,我们可以将它们放在同一个源文件中,并在该文件中用静态变量声明它们。
让我们创建一个只包含两个函数的小型静态库,然后在一个例子中使用它。这个函数叫做fred和bill,它只打印问候。
1.首先,我们分别创建名为fred.c和bill.c的源文件。下面是第一个文件:
#包含stdio.h
void fred(int arg)
{
printf(fred:您通过了%d/n ,arg);
}
下面是第二个:
#包含stdio.h
作废票据(char *arg)
{
printf(bill:你通过了%s/n ,arg);
}
我们可以分别编译这些函数来创建目标文件,这样它就可以包含在库中。我们可以通过C编译器的-c选项做到这一点,它可以防止C编译器试图创建一个完整的程序。试图创建一个完整的程序会得到一个失败消息,因为我们还没有定义主函数。
$ gcc -c票据
$ ls *。o
比尔奥弗雷德奥
现在让我们写一个程序来调用bill函数。首先,我们最好为我们的库创建一个头文件。这将在我们的库中声明该函数,并被所有想要使用我们的库的程序包含。我们最好在fred.c和bill.c文件中也包含这个头文件。这将有助于发现错误。
/*
*这是lib.h,它为用户声明了函数fred和bill
*/
作废票据(char *);
void Fred(int);
调用程序(program.c)也相当简单。它包含这个库的头文件,并从这个库中调用它的一个函数。
#包含“lib.h”
int main()
{
比尔(‘你好世界’);
退出(0);
}
现在我们可以编译这个程序并测试它。这一次,我们将展示我们将目标文件指定给编译器,以便编译器可以编译并链接我们之前编译的目标文件bill.o。
$ cgcc -c程序
$ cgcc -o program program.o bill.o
$ ./程序
比尔:我们经过了你好世界
$
现在让我们创建并使用这个库。我们使用ar程序创建文档,并将我们的目标文件添加到其中。这个程序被称为ar,因为它可以创建档案或收藏,并将单个文件放在一个大文件中。在这里,我们应该注意,我们可以使用ar程序来存档任何类型的文件。
$ ar crv lib foo . a bill o Fred . o
一张账单
阿弗雷德
这样,我们就创建了这个库,并向其中添加了两个目标文件。为了成功地使用这个库,一些系统,尤其是那些由Berkeley Unix开发的系统,需要为这个库创建一个目录。我们可以在这里使用ranlib命令。在Linux中,当我们使用GNU软件开发工具时,这一步是不必要的(但不是有害的)。
$ ranlib libfoo.a
现在我们准备好了,随时可以使用。我们可以添加一个文件列表,供编译器用来创建我们的程序,如下所示:
$ gcc -o程序program.o libfoo.a
$ ./程序
比尔:你通过了“你好世界”
$
我们也可以使用-l选项来访问我们的库,但是因为它不是任何标准的位置,我们需要使用-L选项来告诉编译器它在哪里:
$ gcc -o程序program.o -L. -lfoo
这里,-L选项告诉编译器在当前目录中查找库。lfoo选项告诉编译器使用名为libfoo.a的库.
要检查目标文件、库或可执行程序中包含哪些函数,我们可以使用nm命令。如果我们查看program和lib.a,我们可以看到库包含fred和bill函数,但程序只包含一个。当这个程序被创建时,它将只包含一个他可以从库中实际使用的函数。它包含一个头文件,声明了库中的所有函数,但最终的程序不会包含整个库文件。
共享库
静态库有一个缺点:如果我们想同时运行很多程序,而他们又想使用同一个库中的函数,那么我们就需要在内存中有同一个函数的多个副本,在他们的程序中也有多个副本。这将浪费大量宝贵的内存和磁盘空间。
许多Unix和Linux系统支持共享库来解决这个问题。共享库与静态库位于同一位置,但它们有不同的文件名后缀。在典型的Linux系统上,标准数学库的共享版本是/usr/lib/libm.so .
当一个程序想要使用共享库时,它链接共享库的方式是不包含函数代码,而是引用运行时可以访问的共享代码。当结果程序加载到内存中运行时,函数引用调用共享库,这样共享库就会在需要的时候加载到内存中。
这样,系统只需要在磁盘上维护和保存一个共享库,可以被很多程序同时使用。共享库的另一个优点是它可以独立于依赖它的程序进行更新。需要时,使用从/usr/lib/libm.so到/usr/lib/libm.soN的系统链接。当Linux启动一个程序时,它会决定该程序所需的共享库的版本,从而阻止新版本。
对于Linux系统,程序会小心翼翼的加载共享库,客户端程序函数引用的,需要为共享库查找的其他位置是由/etc/ld.so.conf文件配置的,有变化时需要由ldconfig生成。
我们可以通过实用程序ldd检查一个程序所需的共享库。例如,如果我们在示例程序中运行这个程序,我们将得到以下输出:
$ ldd计划
libc . so . 6=/lib/libc . so . 6(0x 4002 a000)
/lib/LD-Linux . so . 2=/lib/LD-Linux . so . 2(0x 40000000)
在这个例子中,我们可以看到标准的C库是共享的。我们程序的要求版本是6。其他Unix系统将有类似的程序来访问共享库。我们需要检查我们的系统文档以获得更详细的信息。