Linux下安装软件的方式分为源代码安装和二进制安装
- 源代码安装,即使用应用程序源代码进行编译安装
- 二进制安装,例如red hat发行的 .rpm包、debian发行的 .deb包
源代码安装
用c语言为例
#include <stdio.h>
int main(){
printf("hello world");
return 1;
}
使用gcc进行编译。 gcc a.c 然后当前目录会生成一个a.out 文件 然 ./a.out就执行了 输出 hello world
上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。
- gcc最开始是c语言的编译器,后来随着发展已经支持很多种语言了。
- gcc -E 预处理 gcc -E a.c -o a.i 将预处理命令行输出到 a.i文件
- gcc -S a.i -o a.s -S 指令是将预编译的指令变成汇编代码。
- gcc -c test.s -o test.o -c操作将其编译成目标文件,gas汇编器负责将其编译为目标文件
- gcc test.o -o test 连接负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。以上操作gcc a.h就完成了。
对于源代码安装以nginx为例
1.wget http://nginx.org/download/nginx-1.18.0.tar.gz
2.tar -zxvf nginx-1.18.0.tar.gz
#然后看下configure文件,一般这个文件就是这个包的安装脚本(也可以叫别的名)
3.vim configure 看下发现 原来是shell脚本 #!/bin/sh
一般情况下 --prefix=/usr/local/nginx 其实就是指定安装路径。./configure --help 看具体参数
4. ./configure --prefix=/home/zhangyong/nginx --without-http_rewrite_module --without-http_gzip_module
configure会生成一个makefile文件 (#只是测试具体--参数有待补充)
makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
5.make #make命令是一个解释Makefile中指令的命令工具。 编译源代码
6.make install #make install是用来安装的(具体以makefile写的为准),它也从Makefile中读取指令,安装到指定的位置。
关于configure执行完会生成 objs目录和 Makefile文件。环境检测、参数解析、目录生成、Makefile文件的生成等。 objs文件内容如下:
- src目录存放编译时产生的目标文件
- ngx_modules.c是一个很重要的文件,是用来定义ngx_modules数组的。这个数组用于指明每个模块在nginx中的优先级,越靠前优先级越高,当一个请求同时符合多个模块的处理规则的时候,就按照ngx_modules数组的顺序来选择最靠前的一个。所以说,ngx_modules数组的先后顺序很重要,不正确的顺序会导致nginx错误。
- autoconf.err保存的是configure的执行结果。
- Makefile文件用于编译nginx工程以及在加入install参数后安装nginx
make
代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build),make是最常用的构建工具。make是一个命令工具,是一个解释makefile中指令的命令工具。make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译。主要是编写Makefile文件
Makefile
makefile的格式如下
<target> : <prerequisites>
[tab] <commands>
上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。
"目标"是必需的,不可省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。下面是demo 可以 make targets 运行看结果
- .PHONY是指定后面的为伪目标,不然如果有同名文件该不识别命令了。
- 前置条件的多个target之间空格,命令前面tab键(如果想用其他代替tab符,.RECIPEPREFIX = > 指定>为[tab])、 前置条件就是一个beforeAction
- 命令中每个shell命令是独立存在的,make test 不会输出环境变量zy 但是加上 ; \ 就可以了 make test-dev \是换行主要 ; 分号起作用
- make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。
.PHONY: build package
default: #如果没指定target, make 就走第一个target
echo "if nothing do default"
build:
echo "this is build"
package: default build
echo "this is package"
test:
export zy=zhangyong
echo "$$zy"
test-dev:
export zy=zhang; \
echo "$$zy" # $$引用环境变量
test-echo:
@echo "this is echoing" #@符号是不打印这个命令,默认make会将这行命令打印出来。
var1=123
var2=$(var1)
var3:=$(var1)123 # :=是扩展变量,此时下面那个var1 赋值不会被引用
var6:=$(var1)
var4=666
var4?=$(var1) # ?=如果变量之前定义过,则不执行当前赋值
var5=777
var5+=$(var1) # +=追加
var1=444
tvar:
echo "$(var1) $(var2) $(var3) $(var6) $(var4) $(var5)"
foo=a.java b.java c.java
bar=$(foo:%.java=%.class) #字符串替换
tget:
echo "$(foo) $(bar)"
tspecial:tget tvar
echo "第一个依赖对象$<"; echo "目标$@"; echo "所有依赖对象$^";
asd=100
ifeq ($(asd),100) #判断变量asd是否等于100 ifeq (<arg1>, <arg2>) 还有ifneq 如果不等
dd="asd100"
else
dd="hello"
endif
ifdef var1 #判断是否为空 还有 ifndef <variable-name>
ss="123"
endif
tif:
echo "$(dd)"
goal:
echo "$(MAKECMDGOALS)" #输出当前执行的命令的target make goal ===> goal
tdir:
-mkdir dir # - 忽略错误
%.o: %.c
@#外面执行make $(ls *.c |sed 's/c/o/g ') 来进行模式规则执行,将所有.c通过command编译成.o
$(CC) $(CFLAGS) $< -c
wild:
ifneq ($(wildcard *.c),) #wildcard列出匹配的文件/目录 当前demo测试是否为空
echo $(wildcard *.c)
else
-mkdir nodir
endif
关于函数
a=a.java b.java
b=$(subst v,m, $(a)) #$(subst <from>,<to>,<text>)
c=$(patsubst %.java,%.net,$(a)) #$(patsubst <pattern>,<replacement>,<text>)
d=$(strip " s1s2s " ) #$(strip <string>) 去首尾空格
e=$(findstring a,abcda) #$(findstring <find>,<in>)查找字符串函数
f=$(filter %.c %.s, a.c b.s c.h d.java) #$(filter <pattern...>,<text>) 以 <pattern> 模式过滤 <text> 字符串中的单词,保留符合模式 <pattern> 的单词。可以有多个模式
g=$(filter-out %.c %.s, a.c b.s c.h d.java) #$(filter-out <pattern...>,<text>) 反过滤函数
h=$(sort b a c) #$(sort <list>) 排序
i=$(dir src/a home/b) #$(dir <names...>)取目录名
j=$(notdir src/a home/b) #$(notdir <names...>) 取文件名
k=$(suffix zhang.txt) #取後缀函数——suffix。$(suffix <names...>) 可变形参
l=$(basename zhang.txt) #取前缀函数——basename。$(basename <names...>)
ttttt=a b c d
m=$(foreach key,$(ttttt),$(key).java) #$(foreach <var>,<list>,<text>)
n=$(if 1=1,n=1,n=2)
res= $(1)---$(2)
o=$(call res,qq,ww) #call函数是唯一一个可以用来创建新的参数化的函数。$(call <expression>,<parm1>,<parm2>,...,<parmn>)
p=$(origin o) #origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的$(origin <variable>)
q=$(shell echo "hello world") #shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令
build:
@echo "$(b) $(c) $(d) $(e) $(f) $(g) $(h) $(i) $(j) $(k) $(l) $(m) $(n) $(o) $(p) $(q)"
a.jama b.jama a.net b.net s1s2s a a.c b.s c.h d.java a b c src/ home/ a b .txt zhang a.java b.java c.java d.java n=1 qq---ww file hello world
参考:https://seisman.github.io/how-to-write-makefile/introduction.html