关于源码包的基本知识
§·什么是程序
程序(Program)是为实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。为实现预期目的而进行操作的一系列语句和指令。
一般分为系统程序和应用程序两大类。
程序就是为使电子计算机执行一个或多个操作,或执行某一任务,按序设计的计算机指令的集合。
§·程序包的编译安装
※·为什么需要源码安装
1.最新的软件没有rpm包;
2.有的rpm包没有我们需要的功能;
3.程序最新版通常会发布源代码。
※·源码的rpm包:
一般为 .src.rpm结尾的包,例如:testapp-VERSION-release.src.rmp
使用rpmbuild命令制作二进制格式的rpm包,而后再安装
※·linux源代码生成二进制程序
·源代码 —> 预处理 —> 编译 —> 汇编 —> 连接 —> 可执行 —>二进制程序
源代码的组织格式:
·多文件:文件中的代码之间很可能存在跨文件依赖关系。手工的处理依赖关系很麻烦,我们可以通过工具来管理多文件的依赖关系:
·项目管理器:mask maven
C C++ : make java : maven
·那make程序如何知道多文件的依赖关系,或其他的相关多文件之间的关系呢
源代码提供一个东西指示make合适的编译:
Make (makefile)
( config —-> makefile.in(模板) —-> nakefile )
§·Linux程序源代码
·源代码:人类可以看懂的文本信息
·windows程序不开放源代码,如果我需要减少该软件的某些功能时,只有依赖软件供应商。
·Linux提供源代码,通过源代码我们知道开源软件到底做了哪些事情,我们还可以自行修 改程序代码,以符合个人的需求。
§·Linux中可执行文件
·一个文件能不能执行,看有没有执行权限。不过linux系统上真正认识可执行文件其实是二进制文件( binary program );
file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
·shell scripts 只是利用shell这个程序的功能进行一些判断,脚本在执行的过程中仍然会使用系统中已经编译好了的二进制程序。
file /root/bin/fact.sh
/root/bin/fact.sh: Bourne-Again shell script text executable
※·源代码编译为可执行二进制图解
思考问题:
1.何为源代码?源代码使用的什么语法?
通常源代码就是程序代码,写给人类看的程序语言,但是机器不认识,所以无法执行;
源代码一般文本文件就可以编辑,需要符合特定的语法格式。
例如:C 有c的语法格式,java有java的语法格式,
2.何为编译器?
编译器也是叫编译程序,将程序代码转译为机器看得懂的语言,就类似翻译者的角色。
3.何为函数库?
函数库:就是把函数放到库里面,供别人使用的一种方式。方法是把一些常用到的函数编完放到一个文件里供不同的人进行调用。调用的时候把它所在的文件名用#include<>加到里面就可以。
函数:完成某特定功能的代码片段
Linux中有许多的函数:三角函数,PAM模块
函数库分为动态库和静态函数库
4.何为二进制程序?
可执行文件,经过编译程序编程二进制程序后,机器看的懂所以可以执行的文件。
§·Linux中简单的C程序编译
※·单一程序:打印 hello world
◎·编辑程序代码,也就是源代码
使用vim编辑一个文件 hello.c
#include<stdio.h> int main(void) { printf("Hello World\n"); }
◎·开始编译与执行
[root@Centos7 c_dir]# gcc hello.c #gcc不带任何参数编译hello.c源代码 [root@Centos7 c_dir]# ls #生成的文件名默认为 a.out a.out hello.c [root@Centos7 c_dir]# ./a.out #执行a.out可执行文件 Hello World
◎·小结:
我们现在知道 hello.c为源代码(人类可读的), a.out为二进制程序(人类很难读的)
※·主 子程序链接:子程序的编译
◎·准备两个C语言的源代码
实现:thanks.c 主程序调用thanks_2.c这个子程序。代码如下:
[root@Centos7 c_dir]# cat thanks.c #include<stdio.h> int main(void){ printf("Hello World\n") thanks_2(); #调用thanks_2.c 子程序 } [root@Centos7 c_dir]# cat thanks_2.c #include<stdio.h> void thanks_2(void) { printf("Thank you!\n") }
◎·进行程序的编译与链接
[root@Centos7 c_dir]# ls a.out hello.c thanks_2.c thanks.c [root@Centos7 c_dir]# gcc -c thanks.c thanks_2.c #使用参数-c使生成的文件为源代码文件名 [root@Centos7 c_dir]# ls a.out hello.c thanks_2.c thanks_2.o thanks.c thanks.o #gcc -c生成的 .o文件后缀名 [root@Centos7 c_dir]# gcc -o thanks thanks.o thanks_2.o #链接两个.o文件生成程序名为 thanks [root@Centos7 c_dir]# ls a.out hello.c thanks thanks_2.c thanks_2.o thanks.c thanks.o #生成的二进制文件 thanks [root@Centos7 c_dir]# ./thanks #直接运行生成的二进制文件 thanks ,显示结果 Hello World Thank you!
◎·小结
简单的把两个文件链接成一个文件,并且制作成一个可执行的二进制文件
※·调用外部函数库的小程序
◎·准备源代码文件
申明一个变量,让变量的值为 sin90度,显示变量的数值
[root@Centos7 c_dir]# cat sin.c #include<stdio.h> int main(void) { float value; #申明变量 value = sin(3.14/2); #变量的值为 sin90度,函数中 90度表示为:3.14(180度)除以2 printf("%f\n",value); }
◎·编译源代码
[root@Centos7 c_dir]# gcc sin.c #使用默认编译 sin.c: In function ‘main’: sin.c:5:10: warning: incompatible implicit declaration of built-in function ‘sin’ [enabled by default] value = sin(3.14/2); ^ #编译报错了,提示:sin有问题,代表编译没有成功
分析错误原因:英文的大概意思是 提示没有sin相关定义的参考值。这个问题是因为C语言里面的sin函数是写在libm.so这个函数库中的,我们并没有在源代码中将这个函数库调用,导致我们编译时出错。
◎·编译时加入额外函数库链接的方式
root@Centos7 c_dir]# gcc sin.c -lm -L/lib -L/usr/lib -L/usr/lib64 #重点在于 -lm sin.c: In function ‘main’: sin.c:5:10: warning: incompatible implicit declaration of built-in function ‘sin’ [enabled by default] value = sin(3.14/2); ^ [root@Centos7 c_dir]# ls #虽然在编译时报错了,不过还是生成了默认的程序 a.out a.out hello.c sin.c thanks thanks_2.c thanks_2.o thanks.c thanks.o [root@Centos7 c_dir]# ./a.out #直接运行a.out得到我们需要的结果 1.000000
·特别注意:
使用gcc编译时所加入的那个-lm意义在于:
· -l :是加入某个函数库的意思,就是你需要调用函数库的时候就得使用 -l参数
· m : 表示libm.so这个函数库,libm.so 中lib 和。so后缀名是不需要写的,所以剩下的就为 m
· -L : 参数的意义为:libm.so在哪些目录下去找。
◎·编译时加入额外头文件
除了连接函数库之外,我们第一行在一句:【 #include<stdio.h> 】,这行说的是要将一些定义数据由 stdio.h这个档案读入,这包括printf的相关设定,这个文件在 /usr/include/stdio.h.
如果我们stdio.h不在默认路径下我们如何指定呢:
[root@Centos7 include]# gcc sin.c -lm -I/usr/include
◎·小结
·通过编译多个文件,编译时加入函数库,编译时加入额外的头文件,我们可以了解到,不同系统的函数库存放路径可能不同,不同系统的头文件路径不同,就会导致我们编译环境不同。
·不同的编译环境就会导致我们如果在不同机器上编译编译指定的 函数库 头文件的路径不同,导致编译后的程序只能在相同编译环境下的机器运行。
·也就是为什么有的开源软件只提供源代码,而不提供rpm包的原因。
·rpm包在对应的平台上直接安装即可,不需要编译,由于别人已经编译好了。
·源代码在理论上可以在不同平台上运行,只需要你编译指定需要相关库文件 头文件等等路径即可。
※·gcc编译与make编译
◎·gcc编译于make编译
·我们举一个案例:我们源代码有四个原始文件,比如: main.c haha.c sin_value.c cos_value.c
·main.c主要功能是让用户输入角度数据,调用其他的三个子程序计算;
·haha.c 输出一堆没有的信息;
·sin_value.c : 计算使用者输入的角度sin值;
·cos_value.c :计算使用者输入的角度cos值;
*·使用gcc编译
·如果我们使用gcc来编译,我们需要做一下步骤
1. 先迚行目标文件的编译,最终会有四个 *.o 的档名出现:
[root@www ~]# gcc -c main.c [root@www ~]# gcc -c haha.c [root@www ~]# gcc -c sin_value.c [root@www ~]# gcc -c cos_value.c
2. 再迚行连结成为执行档,并加入 libm 的数学凼式,以产生 main 执行档:
[root@www ~]# gcc -o main main.o haha.o sin_value.o cos_value.o \ > -lm -L/usr/lib -L/lib
小结:gcc需要编辑很多步,如果文件有修改,我们又得需要编译。如果源代码文件特别对,几百个,我们编译就会需要大量的时间,这时候make这个工具就出现了。
*·使用make编译
1. 先编辑 makefile 这个文件,内容只要写出 main 这个执行档案
[root@www ~]# vim makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 需要 <tab> 按键产生的空格。
2. 尝试使用 makefile 编写的规则进行编译的:
[root@www ~]# make cc -c -o main.o main.c cc -c -o haha.o haha.c cc -c -o sin_value.o sin_value.c cc -c -o cos_value.o cos_value.c gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此时 make 会去读取 makefile 的内容,并根据内容直接去开始编译文件!
3. 在不删除任何文件,只修改文件的内容后,重新编译
[root@www ~]# make make: `main' is up to date.
# 提示程序更新成功
◎·小结:
Make编译好处:
·简化编译时所需要的下达的指令;
·若在编译完成之后,修改了某个源代码文件,则make仅会针对被修改了的文件进行编译,其它的文件 不会被改动;
·最后可以依照相依性来更新程序
※·make的具体使用
◎·makefile基本语法
既然make可以直接读取makefile文件的内容,按照规则执行,那我们来了解下 makefile的基本语法。
··在 makefile 当中的 # 代表批注;
·· <tab> 需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符;
·· 目标 (target) 与相依文件(就是目标文件)之间需以『:』隔开。
# 1. 先编辑 makefile 来建立新的规则,此规则的标的名称为 clean :
[root@www ~]# vi makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm clean: rm -f main main.o haha.o sin_value.o cos_value.o
# 2. 以新的标的 (clean) 测试看看执行 make 的结果:
[root@www ~]# make clean <==就是这里!使用 make 以 clean 为标的 rm -rf main main.o haha.o sin_value.o cos_value.o
#3.我们先清理,在编译源码包
[root@www ~]# make clean main rm -rf main main.o haha.o sin_value.o cos_value.o cc -c -o main.o main.c cc -c -o haha.o haha.c cc -c -o sin_value.o sin_value.c cc -c -o cos_value.o cos_value.c gcc -o main main.o haha.o sin_value.o cos_value.o -lm
#4.使用脚本使得makefile文件更加简便
[root@www ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o main: ${OBJS} gcc -o main ${OBJS} ${LIBS} clean: rm -f main ${OBJS}
◎·makefile生成工具 configure程序
make会在当前目录下查找makefile或Makefile这个文本文件,通常情况下软件开发商会写一个软件来侦测程序来测试用户的作业环境,以及作业环境是否有软件开发商所需要的其他功能,该软件侦测完毕后蛮久会主动建立这个makefile的规则文件,通常这样的侦测软件名为 configure或者是config。
Configure软件侦测系统环境有一下几个方面:
·是否有合适的编译程序可以编译本软件的程序代码;
·是否已经存在本软件所需要的函数库,或其他需要的想依赖软件
·操作系统平台是否适合本软件,包括linux的内核版本;
·内核的表头定义当(header include)是否存在(驱动程序必须要的侦测)
◎·make编译工作图解
原创文章,作者:linux_root,如若转载,请注明出处:http://www.178linux.com/39335