感谢支持
我们一直在努力

Linux基础知识 – 程序编译与函数库

程序编译与函数库

前面提到过对于机器来说只能识别0,1,我们如果让机器运行必须输入机器能够识别的语言,可是机器语言不利于人们使用可理解,因此科学家就开发出人类能看的懂的程序语言,然后再创造出“编译器”将程序语言转换为机器语言。

C语言就是我们能够看懂的机器语言,gcc就是Linux下编译器。我们通常C语言写的程序通过gcc编译后,就能成为机器能够识别的语言

gcc程序编译
如果LINUX 系统中为安装GCC编译器,可以使用下面命令安装

[root@bogon ~]# yum install gcc

gcc常用语法
语法:

gcc  –c  file.c

仅将源代码编译成目标文件。并不会进行链接以及生成可执行文件

gcc –o 执行文件名 源代码文件

直接生成指定名称的执行文件。但不会生成目标文件

gcc –o 执行文件名 目标文件

通过目标文件生成可执行文件

gcc [其他编译操作]  –L库文件路径

查找库文件的路径默认是/usr/lib 与/ib

gcc  [其他编译操作] –I包含文件路径

查找包含文件的路径默认是/usr/include

gcc  [其他编译操作] –Wall

更加严谨的编译方式,会输出很多警告信息

gcc  -O  [其他编译操作]

编译时依据操作环境优化执行速度

gcc  [其他编译操作] –l库文件名称

编译时引入其他的库文件,其中库文件lib与扩展名不需要写。如引入libm.so文件,可写成-lm

单一程序编译
 

1.      编写C语言程序l

[root@bogon code]# vim hello.c
#include <stdio.h>
int main(void)
{
  printf(“hello world!”);
}
 

2.      编译

[root@bogon code]# gcc hello.c
[root@bogon code]# ll hello.c a.out
-rwxr-xr-x 1 root root 4947 04-05 16:07 a.out
-rw-r–r– 1 root root  66 04-05 16:07 hello.c
 

说明:默认gcc编译器编译出来的执行文件a.out, 可以使用-o来制定编译后生产的执行文件名称

[root@bogon code]# gcc -o hello hello.c
[root@bogon code]# ll hello
-rwxr-xr-x 1 root root 4947 04-05 16:11 hello
 

3.      执行

[root@bogon code]# ./a.out
hello world!

[root@bogon code]# ./hello
hello world!
 

多文件程序编译
假设我们有A.c ,B.c两个程序文件,并且他们之间存在函数调用,那么当其中有一个文件更改了。是不是需要将这两个文件都重新编译?当然不需要,这就需要引入目标文件

目标文件:编译器编译源代码后生成的文件,目标文件从结构上讲,它是已经编译后的可执行文件格式,只是没有经过链接的过程。

接着上面的说,当B.c文件更改时,我们执行重新编译B文件生产目标文件。再讲整体链接即可

1.      编写C语言程序

File:A.c
#include <stdio.h>
#include “B.c”
int main ()
{
printf(“这是第一个文件\n”);
method();
}

File:B.c
#include <stdio.h>
void method(void)
{
 printf(“这是第二个文件!\n”;)
}2.      编译

root@bogon code]# gcc -c A.c B.c -I./
[root@bogon code]# ll
-rw-r–r– 1 root root  81 04-05 16:35 A.c
-rw-r–r– 1 root root  912 04-05 16:35 A.o
-rw-r–r– 1 root root  80 04-05 16:34 B.c
-rw-r–r– 1 root root  860 04-05 16:35 B.o3.    链接

[root@bogon code]# gcc -o result A.o B.o4.      执行

[root@bogon code]# ./result
这是第一个文件
这是第二个文件!5.  更改B.c文件

#include <stdio.h>
void method(void)
{
 printf(“这是更改后第二个文件!\n”;)
}6.      重新编译链接执行

[root@bogon code]# gcc -c B.c =>只编译了B这个文件
[root@bogon code]# gcc -o result A.o B.o
[root@bogon code]# ./result
这是第一个文件
这是更改后第二个文件!
 

调用外部函数库
 
1.      编写C语言程序

#include<stdio.h>
#include<math.h>
 
int main ()
{
  float val=sin(3.14);
  printf(“val值是:%f\n”,val);
}2.      编译与执行

[root@bogon code]# gcc -o sinmath sinmath.c -lm
[root@bogon code]# ./sinmath
val值是:0.001593
 

函数库介绍
函数库依照是否编译到程序内部可分为

静态函数库:通常以.a为扩展名,编译时会整合到程序文件中

动态函数库:通常以.so为扩展名,编译时会不会整合到程序文件中,只是在程序文件中存在一个指向的位置

因此程序执行时是不需要静态函数库的,但是需要动态函数库,使用动态函数库的好处再在可以减少程序文件的大小

动态函数库加载内存
我们知道内存的访问速度是硬盘的好几倍,如果先将动态函数库加载到内存中,那么在使用动态函数库时就会,就会提高很多效率

语法:ldconfig[-f 需要缓存函数库信息所在文件] [-C 已缓存函数库信息所在文件]

            ldconfig –p 列出已缓存函数库信息

需要缓存函数库信息所在文件:在这个文件中记录所有需要缓存的的函数库默认值是

/etc/ ld.so.conf

举例:查看下我的系统下缓存的函数库

[root@bogon etc]# vim ld.so.conf
include ld.so.conf.d/*.conf

[root@bogon etc]# cd ld.so.conf.d/
[root@bogon ld.so.conf.d]# ll
-rw-r–r– 1 root root  15 2013-01-23 mysql-i386.conf
-rw-r–r– 1 root root  17 2013-01-09 openais-athlon.conf
-rw-r–r– 1 root root  20 2012-08-20 qt-i386.conf
-rw-r–r– 1 root root 276 02-22 19:23 vmware-tools-libraries.conf
-rw-r–r– 1 root root  19 2013-08-07 xulrunner-32.conf
[root@bogon ld.so.conf.d]# vim mysql-i386.conf
[root@bogon ld.so.conf.d]# ll /usr/lib/mysql
lrwxrwxrwx 1 root root      26 02-18 20:03 libmysqlclient_r.so.15 -> libmysqlclient_r.so.15.0.0
-rwxr-xr-x 1 root root 1460684 2013-01-23 libmysqlclient_r.so.15.0.0
lrwxrwxrwx 1 root root      24 02-18 20:03 libmysqlclient.so.15 -> libmysqlclient.so.15.0.0
-rwxr-xr-x 1 root root 1452764 2013-01-23 libmysqlclient.so.15.0.0
-rwxr-xr-x 1 root root  13220 2013-01-23 mysqlbug
-rwxr-xr-x 1 root root    6215 2013-01-23 mysql_config
 

已缓存函数库信息所在文件:这个文件中记录了已经缓存的函数库,默认文件为

/etc/ld.so.cache ,通过-p查询到的信息就是从这个文件读取而来

举例:查看所有已缓存的函数库

[root@bogon ld.so.conf.d]# ldconfig -p|more
947 libs found in cache `/etc/ld.so.cache’
        libz.so.1 (libc6) => /lib/libz.so.1
        libz.so.1 (libc6) => /usr/lib/libz.so.1
        libx11globalcomm.so.1 (libc6) => /usr/lib/libx11globalcomm.so.1
  ……..查看程序所包含的动态函数库
语法:ldd –v文件名

-v:列出所有函数库信息

举例:

[root@bogon ld.so.conf.d]# ldd  /usr/bin/passwd
        linux-gate.so.1 =>  (0x00ddc000)
        libuser.so.1 => /usr/lib/libuser.so.1 (0x007c5000)
        libcrypt.so.1 => /lib/libcrypt.so.1 (0x05c74000)
      ……
 

make编译
如果一个程序中有很多文件,那么还像上面那样讲每个文件列出来在进行编译就会很麻烦。因此这种时候就需要使用make工具了

Make编译好处

简化编译时所需的指令

若在编译完成后,修改了某个源文件,只会针对修改的文件编译

Make使用方法

Make是有个二进制文件,其会查找当前目录下的Makefile文件,根据其里面定义的内容执行操作。 Makefile里面包含了若干目标与操作

其基本关于规则如下

目标:

<tab>操作

REST2HTML=html.py –compact-lists –date –generator

all: user_manual.html dev_manual.html

user_manual.html: user_manual.rst
        $(REST2HTML) user_manual.rst user_manual.html

dev_manual.html: dev_manual.rst
        $(REST2HTML) dev_manual.rst dev_manual.html

clean:
        rm *.html
 

以上内容分为三个目标all,user_manual.html,clean,其下面分别对应的是其操作

我们可以通过make 后面参数为目标进行执行。如:make clean

Tarball的安装
由于Unix like具有很多种。因此一个软件安装包不可能适用所有所本,因此有时我们需要根据软件提供者提供的源码自行编译,以满足在自己的操作系统上运行

大部分软件开发包编译与安装的流程大致是这样的

1.      讲压缩文件解压缩

2.      解压缩后执行里面的configure文件,其作用就是建立makefile文件

3.      Make clean:清理一些上次操作的残留

4.      Make :默认操作进行编译的行为

5.      Make install:安装

说明:安装前如果有安装文档最好先查阅

3-4步骤 不一定都存在。可查看makefile内容判断具体包括哪些目标

举例:

[root@bogon shared]# tar -zxvf ntp-4.2.4p7.tar.gz -C /tmp
…..
[root@bogon ntp-4.2.4p7]# ./configure –prefix=/usr/loacl/ntp
=> –prefix=/usr/loacl/ntp为指定安装目录
[root@bogon ntp-4.2.4p7]# ll Makefile
-rw-r–r– 1 root 6011 23950 04-05 21:40 Makefile
=>生成了Makefile文件
root@bogon ntp-4.2.4p7]# ll Makefile
root@bogon ntp-4.2.4p7]# make clean
root@bogon ntp-4.2.4p7]# make
root@bogon ntp-4.2.4p7]# make install

13、RAID 10
a> 嵌套式RAID,可细分为1+0和0+1;
b> 需要至少4块磁盘组成,存储效率为(100/N)%,N为镜像数;
c> 性能和冗余兼顾,就是利用率稍低;
d> 创建软RAID 10时一般先创建2个RAID 1,然后在此基础上创建RAID 10;

14、嵌套式RAID一般还有RAID 50和RAID 53;

15、较少实际应用的RAID是RAID2、3、4,因为RAID5已经涵盖了所需的功能。因此RAID2、3、4大多只在研究领域有实现,而实际应用上则以RAID5或RAID6为主。

16、RAID DP(dual parity)是NetApp公司设计的系统,是使用RAID4(而非传说的RAID 6,因为它的校验盘是独立的)的设计概念,尽量每次只与2块盘打交道。此种RAID和RAID 6一样也允许同时坏2块盘,它们开发多年的文件系统WAFL为RAID DP做了专门优化,效率高于RAID 6;

17、优化RAID参数(条带化参数):
a> 调整条带化参数对RAID有很大的影响,适用于RAID 0、RAID 5、RAID 6;
b> chunk-size。RAID写满一个chunk size才会移动到下一块磁盘去,有时候它直接就是条带化的粒度。chunk size应该是block size的整数倍;
c> 减小chunk-size意味着文件会分成更多片,分布在更多的物理磁盘上。这样会提高传输效率,但是可能会降低定位寻道的效率(有些硬件实现会等填满一个条带才真正写入,这样会抵消一些定位寻道的消耗);
d> 增大chunk-size会得到以上相反的效果;
e> stride(步进值)是类ext2文件系统的一个值,用于在类ext2数据结构里seek,它这样指定:mke2fs -E stride=N。N(也就是步进值)应该被指定为 chunk-size / filesystem block size(文件系统的block size)。(mke2fs -j -b 4096 -E stride=16 /dev/md0)
f> 以上2个值调校对了,可以提高RAID的在多个磁盘上的并行效率,从而让整个RAID的性能随物理磁盘数量提升而提升;

18、更多RAID原理可见http://blog.chinaunix.net/space.php?uid=20023853&do=blog&id=1738605;

19、软RAID的信息可在系统中以下几个地方查看:
a> /proc/mdstat。这里方便看新建、重建的进度条,以及哪块盘坏了等;
b> mdadm –detail /dev/md0。显示详细信息;
c> /sys/block/mdX/md。这里方便看到cache_size等信息(别处没有的);

20、Major/Minor号。linux系统中前者代表设备类型/驱动,后者是同种类型/驱动的多个设备在系统中的ID号;

21、RAID技术最初由IBM公司而非贝尔实验室发明(http://en.wikipedia.org/wiki/RAID#History);

22、RAID是支持在线扩容的

23、硬盘出场基本都是有坏道的,但是厂商会预留一部分磁道(而且通常在外圈)出来以顶替坏道消耗的容量。相较而言,企业级硬盘预留的容量较家用级硬盘大,这是它更贵寿命更长的原因之一;

24、RHEL下软RAID的配置文件(用于开机自动发现RAID)在/etc/mdadm.conf。此文件可以这么生成:mdadm –verbose –examine –scan > /etc/mdadm.conf。此文件中还需配置RAID坏了时如何mail通知管理员;

25、Critical Section中存储了RAID中数据的MeteData。它是元数据,如果它丢了,RAID中的数据就全丢了。各种RAID中,只有RAID 1的Critical Section是写在磁盘尾上的(其它都写在磁盘头),因此RAID 1较为适合做系统盘(易恢复MeteData)。

26、软RAID重组(reshape)(比方说往里加盘,或是更改chunk size或RAID级别)时,如果想保留原数据,则备份Critical Section十分重要。重组的内部过程是这样的:
a> 将RAID设为只读;
b> 备份Critical Section;
c> 重定义RAID;
d> 成功的话删除原Critical Section,恢复可写;

27、最好手工指定Critical Section备份位置(最好备份到将要改变的RAID之外的地方),因为如果reshape失败Critical Section是需要手工恢复的。如果没有手工制定位置,Critical Section会被存在RAID的备盘上,如果RAID没有备盘则会存放在内存中(易丢失,危险);

28、如果RAID改变了(比如拉伸),记得之上的filesystem也要做出相应的改变(比如说拉神);

29、系统启动脚本rc.sysinit中启动服务的顺序默认是这样的:udev->selinux->time->hostname->lvm->软RAID。所以在lvm上做RAID比较合理,除非手动改启动脚本;

30、扩大RAID 5的容量,可以通过逐步把RAID 5中的每块硬盘换成更大容量的盘的方式来完成(别忘记resize filesystem);

31、同台机器上不同的软RAID组间可以共享备盘

32、如果要在机器间迁移软RAID,记得迁移之前要把要迁移的RAID改成一个目标机器上不存在(也就不冲突)的RAID设备名(mdX)。改名的时候可以用Minor号来指认要改名的RAID;

33、Bitmap用于记录本块物理磁盘的每个block是否跟整个RAID同步着呢。它会被周期性地写入。启用它可以极大加快RAID的恢复过程;

34、Bitmap可以存放在RAID内或RAID外。如果告诉RAID把Bitmap存在RAID外,给的绝对路径又是在RAID内的,RAID会死锁。如果存在RAID外的话,只支持extX的文件系统;

35、在活动的RAID上加Bitmap的前提是它的Superblock是好的;

36、可以启用Write Behind机制,如果启用了Bitmap的话。这样就会在指定磁盘成功写入后就会给应用程序返回成功,另外的盘会异步写入数据,这对RAID 1特别有用;

37、RAID机制不会去主动检测坏块。只有在被迫读到坏块读不出来时它才会去尝试修复(找备块替代),要是那磁盘修复不了了(备块用光了),那就会把那块盘标志为错误,然后踢出RAID,启用备盘;

38、因为RAID对坏块是消极处理的,所以在RAID 5重建的过程中就很有可能发现隐藏的坏块,从而导致RAID恢复失败。磁盘容量越大,此风险越大;

39、用crontab定期检查一下RAID坏块是个不错的建议。在Kernel 2.6.16后我们可以这样触发检查:echo check >> /sys/block/mdX/md/sync_action。

赞(0) 打赏
转载请注明出处:服务器评测 » Linux基础知识 – 程序编译与函数库
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏