kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

objcopy命令介绍

objcopy把一种目标文件中的内容复制到另一种类型的目标文件中.

(1)将图像编译到可执行文件内

Q: 如何将一个二进制文件,比如图片,词典一类的东西做为.o文件,直接链接到可执行文件内部呢?
A:

1
2
3
4
5
6
$ objcopy -I binary -O elf32-i386 -B i386 14_95_13.jpg image.o
$ gcc image.o tt.o -o tt
$ nm tt | grep 14_95
0805d6c7 D _binary_14_95_13_jpg_end
00014213 A _binary_14_95_13_jpg_size
080494b4 D _binary_14_95_13_jpg_start

(2)使用objcopy把不用的信息去掉:

1
$ objcopy -R .comment -R .note halo halo.min

(3)

1
2
3
4
$ objcopy -R .note -R .comment -S -O binary xyb xyb.bin
-R .note -R .comment 表示移掉 .note 与 .comment 段
-S 表示移出所有的标志及重定位信息
-O binary xyb xyb.bin 表示由xyb生成二进制文件xyb.bin

objcopy工具使用指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
objcopy Utility
objcopy [ -F bfdname | --target=bfdname ]
[ -I bfdname | --input-target=bfdname ]
[ -O bfdname | --output-target= bfdname ]
[ -S | --strip-all ] [ -g | --strip-debug ]
[ -K symbolname | --keep-symbol= symbolname ]
[ -N symbolname | --strip-symbol= symbolname ]
[ -L symbolname | --localize-symbol= symbolname ]
[ -W symbolname | --weaken-symbol= symbolname ]
[ -x | --discard-all ] [ -X | --discard-locals ]
[ -b byte | --byte= byte ]
[ -i interleave | --interleave= interleave ]
[ -R sectionname | --remove-section= sectionname ]
[ -p | --preserve-dates ] [ --debugging ]
[ --gap-fill= val ] [ --pad-to= address ]
[ --set-start= val ] [ --adjust-start= incr ]
[ --change-address= incr ]
[ --change-section-address= section{=,+,-} val ]
[ --change-warnings ] [ --no-change-warnings ]
[ --set-section-flags= section= flags ]
[ --add-section= sectionname= filename ]
[ --change-leading char ] [--remove-leading-char ]
[ --weaken ]
[ -v | --verbose ] [ -V | --version ] [ --help ]
input-file [ outfile ]  

GNU实用工具程序objcopy的作用是拷贝一个目标文件的内容到另一个目标文件中。Objcopy使用GNU BFD库去读或写目标文件。Objcopy可以使用不同于源目标文件的格式来写目的目标文件(也即是说可以将一种格式的目标文件转换成另一种格式的目标文 件)。通过以上命令行选项可以控制Objcopy的具体操作。

Objcopy在进行目标文件的转换时,将生成一个临时文件,转换完成后就将这个临 时文件删掉。Objcopy使用BFD做转换工作。如果没有明确地格式要求,则Objcopy将访问所有在BFD库中已经描述了的并且它可以识别的格式, 请参见《GNUpro Decelopment Tools》中“using ld”一章中“BFD库”部分和“BFD库中规范的目标文件格式”部分。

通过使用srec作为输出目标(使用命令行选项-o srec),Objcopy可以产生S记录格式文件。

通过使用binary作为输出目标(使用命令行选项-o binary),Objcopy可以产生原始的二进制文件。使用Objcopy产生一个原始的二进制文件,实质上是进行了一回输入目标文件内容的内存转 储。所有的符号和重定位信息都将被丢弃。内存转储起始于输入目标文件中那些将要拷贝到输出目标文件去的部分的最小虚地址处。

使用Objcopy生成S记录格式文件或者原始的二进制文件的过程中,-S选项和-R选项可能会比较有用。-S选项是用来删掉包含调试信息的部分,-R选项是用来删掉包含了二进制文件不需要的内容的那些部分。

input-file
outfile
参数input-file和outfile分别表示输入目标文件(源目标文件)和输出目标 文件(目的目标文件)。如果在命令行中没有明确地指定outfile,那么Objcopy将创建一个临时文件来存放目标结果,然后使用input- file的名字来重命名这个临时文件(这时候,原来的input-file将被覆盖)。

-I bfdname
–input-target=bfdname
明确告诉Objcopy,源文件的格式是什么,bfdname是BFD库中描述的标准格式名。这样做要比“让Objcopy自己去分析源文件的格式,然后去和BFD中描述的各种格式比较,通过而得知源文件的目标格式名”的方法要高效得多。

-O bfdname
–output-target= bfdname
使用指定的格式来写输出文件(即目标文件),bfdname是BFD库中描述的标准格式名。

-F bfdname
–target= bfdname
明确告诉Objcopy,源文件的格式是什么,同时也使用这个格式来写输出文件(即目标文件),也就是说将源目标文件中的内容拷贝到目的目标文件的过程中,只进行拷贝不做格式转换,源目标文件是什么格式,目的目标文件就是什么格式。

-R sectionname
–remove-section= sectionname
从输出文件中删掉所有名为sectionname的段。这个选项可以多次使用。
注意:不恰当地使用这个选项可能会导致输出文件不可用。

-S
–strip-all (strip 剥去、剥)
不从源文件中拷贝重定位信息和符号信息到输出文件(目的文件)中去。

-g
–strip-debug
不从源文件中拷贝调试符号到输出文件(目的文件)中去。

–strip-undeeded
剥去所有在重定位处理时所不需要的符号。

-K symbolname
–keep-symbol= symbolname
仅从源文件中拷贝名为symbolname的符号。这个选项可以多次使用。

-N symbolname
–strip-symbol= symbolname
不从源文件中拷贝名为symbolname的符号。这个选项可以多次使用。它可以和其他的strip选项联合起来使用(除了-K symbolname | –keep-symbol= symbolname外)。

-L symbolname
–localize-symbol= symbolname
使名为symbolname的符号在文件内局部化,以便该符号在该文件外部是不可见的。这个选项可以多次使用。

-W symbolname
-weaken-symbol= symbolname
弱化名为symbolname的符号。这个选项可以多次使用。

-x
–discard-all (discard 丢弃、抛弃)
不从源文件中拷贝非全局符号。

-X
–discard-locals
不从源文件中拷贝又编译器生成的局部符号(这些符号通常是L或 . 开头的)。

-b byte
–byte= byte
Keep only every byte of the input file (header data is not affected). byte can be
in the range from 0 to interleave-1, where interleave is given by the -i or
–interleave option, or the default of 4. This option is useful for creating files to
program ROM . It is typically used with an srec output target.

-i interleave
–interleave= interleave (interleave 隔行、交叉)
Only copy one out of every interleave bytes. Select which byte to copy with the
-b or –byte option. The default is 4. objcopy ignores this option if you do not
specify either -b or –byte.

-p
–preserve-dates (preserve 保存、保持)
设置输出文件的访问和修改日期和输入文件相同。

[ –debugging ]
如果可能的话,转换调试信息。因为只有特定的调试格式被支持,以及这个转换过程要耗费一定的时间,所以这个选项不是默认的。

–gap-fill= val
使用内容val填充段与段之间的空隙。通过增加段的大小,在地址较低的一段附加空间中填充内容val来完成这一选项的功能。

–pad-to= address
填充输出文件到虚拟地址address。通过增加输出文件中最后一个段的大小,在输出文件中最后一 段的末尾和address之间的这段附加空间中,用–gap-fill= val选项中指定的内容val来填充(默认内容是0,即没有使用–gap-fill= val选项的情况下)。

–set-start= val
设置新文件(应该是输出文件吧?)的起始地址为val。不是所有的目标文件格式都支持设置起始地址。

–change-start = incr
–adjust-start= incr
通过增加值incr来改变起始地址。不是所有的目标文件格式都支持设置起始地址。

–change-addresses incr
–adjust-vma incr
Change the VMA and LMA addresses of all sections, section., as well as the
start address, by adding incr. Some object file formats do not permit section
addresses to be changed arbitrarily.

通过加上一个值incr,改变所有段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址),以及起始地址。某些目标文件格式不允许随便更改段的地址。

–change-section-address section{=,+,-} val
–adjust-section-vma section{=,+,-} val
设置或者改变名为section的段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)。如果这个选项中使用的是“=”,那么名为section的段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么上述两个地址将被设置或者改变成这两个地址的当前值减去或加上 val后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被 使用。

这里的段地址设置和改变都是输出文件中的段相对于输入文件中的段而言的。例如:
(1)–change-section-address .text = 10000
这里是指将输入文件(即源文件)中名为.text的段拷贝到输出文件中后,输出文件中的.text段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将都被设置成10000。
(2)–change-section-address .text + 100
这 里是指将输入文件(即源文件)中名为.text的段拷贝到输出文件中后,输出文件中的.text段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将都被设置成以前输入文件中.text段的地址(当前地址)加上100后的值。

–change-section-lma section{=,+,-} val
仅设置或者改变名为section的段的 LMA(Load Memory Address装载地址)。一个段的LMA是程序被加载时,该段将被加载到的一段内存空间的首地址。通常LMA和VMA(Virtual Memory Address运行时地址)是相同的,但是在某些系统中,特别是在那些程序放在ROM的系统中,LMA和VMA是不相同的。如果这个选项中使用的是 “=”,那么名为section的段的LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么LMA将被设置或者改变成这两个地址的当前值减去或加上val 后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被使用。

–change-section-vma section{=,+,-} val
仅设置或者改变名为section的段的 VMA(Load Memory Address装载地址)。一个段的VMA是程序运行时,该段的定位地址。通常VMA和LMA(Virtual Memory Address运行时地址)是相同的,但是在某些系统中,特别是在那些程序放在ROM的系统中,LMA和VMA是不相同的。如果这个选项中使用的是 “=”,那么名为section的段的LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么LMA将被设置或者改变成这两个地址的当前值减去或加上val 后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被使用。

–change-warnings
–adjust-warnings
如果命令行中使用了–change- section-address section{=,+,-} val或者–adjust-section-vma section{=,+,-} val,又或者–change-section-lma section{=,+,-} val,又或者–change-section-vma section{=,+,-} val,并且输入文件中名为section的段不存在,则Objcopy发出警告。这是默认的选项。

–no-chagne-warnings
–no-adjust-warnings
如果命令行中使用了–change- section-address section{=,+,-} val或者–adjust-section-vma section{=,+,-} val,又或者–change-section-lma section{=,+,-} val,又或者–change-section-vma section{=,+,-} val,即使输入文件中名为section的段不存在, Objcopy也不会发出警告。

–set-section-flags section=flags
为section的段设置一个标识。这个flags变量的可以取逗号分隔的多个标识名字符串(这些标识名字符串是能够被Objcopy程序所识别的),合法的标识名有alloc,load,readonly,code,data和rom。 You can set the contents flag for a section which does not havecontents, but it is not meaningful to clear the contents flag of a section which does have contents; just remove the section instead. Not all flags are meaningful for all object file formats.

–add-section sectionname=filename
进行目标文件拷贝的过程中,在输出文件中增加一个名为 sectionname的新段。这个新增加的段的内容从文件filename得到。这个新增加的段的大小就是这个文件filename的大小。只要输出文 件的格式允许该文件的段可以有任意的段名(段名不是标准的,固定的),这个选项才能使用。

–change-leading-char
Some object file formats use special characters at the start of symbols. The most
common such character is underscore, which compilers often add before every
symbol. This option tells objcopy to change the leading character of every
symbol when it converts between object file formats. If the object file formats use
the same leading character, this option has no effect. Otherwise, it will add a
character, or remove a character, or change a character, as appropriate.

–remove-leading-char
If the first character of a global symbol is a special symbol leading character used
by the object file format, remove the character. The most common symbol leading
character is underscore. This option will remove a leading underscore from all
global symbols. This can be useful if you want to link together objects of different
file formats with different conventions for symbol names.

–weaken
Change all global symbols in the file to be weak. This can be useful when building
an object that will be linked against other objects using the -R option to the linker.
This option is only effective when using an object file format that supports weak
symbols.

-V
–version
Show the version number of objcopy.

-v
–verbose
Verbose output: list all object files modified. In the case of archives, objcopy -V
lists all members of the archive.

–help
Show a summary of the options to objcopy.

对库和可执行文件进行裁减

如果生成的可执行文件或库比较大,这时候就可以使用strip命令进行裁减,在嵌入式开发中,如果使用的交叉编译工具是arm-linux,则命令 是arm-linux-strip,如果是arm-uclibc-linux,则命令是arm-uclibc-linux-strip.

因为开发板上的空间本来就很少,使用这个命令可以进一步减少可执行文件的大小,从而可以在开发板上可以存放更过的可执行文件。

  • 主要是把编译的库文件或者可执行文件里的一些调试信息和符号信息去除。

    使用strip对库文件、可执行文件进行操作,库文件、可执行文件中的一些与正常运行无关的调试信息和符号信息会被剔除掉,而且操作前和操作后文件的大小 变化特别明显,一般可以减少1/3或更多,所以在嵌入式的平台上是非常有用的。但是在开发过程并不提倡这一做法,因为使用strip后,使用gdb时就无法获得调试信息了

用法: strip [options] file(s)
strip一般有以下选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-I --input-target= 假定输入文件的格式为
-O --output-target= 以格式创建输出文件
-F --target= 设置输入、输出的文件格式为
-p --preserve-dates 复制上次修改或者操作的时间到输出文件中
-R --remove-section= 删除输出文件中段信息
-s --strip-all 删除所有符号信息和重定位信息
-g -S -d --strip-debug 删除所有调试信息和段信息
--strip-unneeded 删除所有重定位中不需要的符号信息
--only-keep-debug 删除调试信息以外的其他所有信息
-N --strip-symbol= 不拷贝符号信息
-K --keep-symbol= 不去除符号信息
-w --wildcard 在符号中使用通配符
-x --discard-all 去除所有非全局符号
-X --discard-locals 去除所有编译产生的符号
-v --verbose 列出所有修改过的所有目标文件
-V --version 显示版本号
-h --help 显示帮助
-o 把输出的文件名修改成

find命令

执行

1
find ./ -type f -name *.php

的时候,报下面的错误:

1
2
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

多文件的查找的时候需要增加单引号,一直是使用的双引号,没想到找多文件的时候居然要单引号.

1
find ./ -type f -name '*.php'
find和其他命令共用
1
2
3
4
5
6
7
8
9
10
11
12
find ... | while read line; do
  echo "$line"
   ....
done

find . -name '*.dem' | while read line; do ll -h "$line"; done

统计目录并按行数排序(按行大小排序):
find . -name '*.java' | xargs wc -l | sort -n

统计目录并按文件名排序:
find . -name '*.java' | xargs wc -l | sort -k2

由于find具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。即使系统中含有网络文件系统(NFS),find命令在该文件系统中同样有效,只你具有相应的权限。在运行一个非常消耗资源的find命令时,很多人都倾向于把它放在后台执行,因为遍 历一个大的文件系统可能会花费很长的时间。

一、find 命令格式

1、find命令的一般形式为:
1
find pathname -options [-print -exec -ok ...]
2、find命令的参数;
1
2
3
4
pathname: find命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录。
-print: find命令将匹配的文件输出到标准输出。
-exec: find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为'command' {} \;,注意'{}'和'\;'之间的空格。
-ok: 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。
3、find命令选项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-name            按照文件名查找文件。
-perm         按照文件权限来查找文件。
-prune            使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略。
-user         按照文件属主来查找文件。
-group            按照文件所属的组来查找文件。
-mtime -n +n  按照文件的更改时间来查找文件, – n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项。
-nogroup      查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。
-nouser           查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
-newer file1 ! file2  查找更改时间比文件file1新但比文件file2旧的文件。
-type         查找某一类型的文件,诸如:
	b – 块设备文件。
	d – 目录。
	c – 字符设备文件。
	p – 管道文件。
	l – 符号链接文件。
	f – 普通文件。
-size n:[c]     查找文件长度为n块的文件,带有c时表示文件长度以字节计。
-depth:         在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
-fstype:        查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息。
-mount:         在查找文件时不跨越文件系统mount点。
-follow:        如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
-cpio:          对匹配的文件使用cpio命令,将这些文件备份到磁带设备中。
另外,下面三个的区别:
-amin n           查找系统中最后N分钟访问的文件
-atime n      查找系统中最后n*24小时访问的文件
-cmin n           查找系统中最后N分钟被改变文件状态的文件
-ctime n      查找系统中最后n*24小时被改变文件状态的文件
-mmin n           查找系统中最后N分钟被改变文件数据的文件
-mtime n      查找系统中最后n*24小时被改变文件数据的文件
4、使用exec或ok来执行shell命令

使用find时,只要把想要的操作写在一个文件里,就可以用exec来配合find查找,很方便的
在有些操作系统中只允许-exec选项执行诸如l s或ls -l这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。建议在真正执行rm命令删除文件之前,最好先用ls命令看一下,确认它们是所要删除的文件。

exec选项后面跟随着所要执行的命令或脚本,然后是一对儿{},一个空格和一个\,最后是一个分号。为了使用exec选项,必须要同时使用print选项。如果验证一下find命令,会发现该命令只输出从当前路径起的相对路径及文件名。

例如:为了用ls -l命令列出所匹配到的文件,可以把ls -l命令放在find命令的-exec选项中

1
2
3
4
find . -type f -exec ls -l {} \;
-rw-r–r– 1 root root 34928 2003-02-25 ./conf/httpd.conf
-rw-r–r– 1 root root 12959 2003-02-25 ./conf/magic
-rw-r–r– 1 root root 180 2003-02-25 ./conf.d/README

上面的例子中,find命令匹配到了当前目录下的所有普通文件,并在-exec选项中使用ls -l命令将它们列出。

在/logs目录中查找更改时间在5日以前的文件并删除它们:

1
$ find logs -type f -mtime +5 -exec rm {} \;

记住:在shell中用任何方式删除文件之前,应当先查看相应的文件,一定要小心!当使用诸如mv或rm命令时,可以使用-exec选项的安全模式。它将在对每个匹配到的文件进行操作之前提示你。

在下面的例子中, find命令在当前目录中查找所有文件名以.LOG结尾、更改时间在5日以上的文件,并删除它们,只不过在删除之前先给出提示。

1
2
3
$ find . -name '*.conf' -mtime +5 -ok rm {} \;
< rm … ./conf/httpd.conf > ? n
按y键删除文件,按n键不删除。

任何形式的命令都可以在-exec选项中使用。

在下面的例子中我们使用grep命令。find命令首先匹配所有文件名为“ passwd*”的文件,例如passwd、passwd.old、passwd.bak,然后执行grep命令看看在这些文件中是否存在一个sam用户。

1
2
find /etc -name 'passwd*' -exec grep 'sam' {} \;
sam:x:501:501::/usr/sam:/bin/bash

二、xargs

1
xargs – build and execute command lines from standard input

在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现 溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。

find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。

在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。

来看看xargs命令是如何同find命令一起使用的,并给出一些例子。

下面的例子查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件

1
2
3
4
$ find . -type f -print | xargs file
./.kde/Autostart/Autorun.desktop: UTF-8 Unicode English text
./.kde/Autostart/.directory: ISO-8859 text\
......

在整个系统中查找内存信息转储文件(core dump) ,然后把结果保存到/tmp/core.log 文件中:

1
$ find / -name 'core' -print | xargs echo '' >/tmp/core.log

上面这个执行太慢,我改成在当前目录下查找

1
2
3
$ find . -name 'file*' -print | xargs echo '' > /temp/core.log
$ cat /temp/core.log
./file6

在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限:

1
2
3
4
5
6
7
8
9
10
$ ls -l
drwxrwxrwx 2 sam adm 4096 10月 30 20:14 file6
-rwxrwxrwx 2 sam adm 0 10月 31 01:01 http3.conf
-rwxrwxrwx 2 sam adm 0 10月 31 01:01 httpd.conf

$ find . -perm -7 -print | xargs chmod o-w
$ ls -l
drwxrwxr-x 2 sam adm 4096 10月 30 20:14 file6
-rwxrwxr-x 2 sam adm 0 10月 31 01:01 http3.conf
-rwxrwxr-x 2 sam adm 0 10月 31 01:01 httpd.conf

用grep命令在所有的普通文件中搜索hostname这个词:

1
2
3
$ find . -type f -print | xargs grep 'hostname'
./httpd1.conf:# different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames on your

用grep命令在当前目录下的所有普通文件中搜索hostnames这个词:

1
2
3
$ find . -name \* -type f -print | xargs grep 'hostnames'
./httpd1.conf:# different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames on your

注意,在上面的例子中, \用来取消find命令中的*在shell中的特殊含义。
find命令配合使用exec和xargs可以使用户对所匹配到的文件执行几乎所有的命令。

Linux RPM 命令使用

如何解压RPM包

有时我们需要RPM包中的某个文件,如何解压RPM包呢?RPM包括是使用cpio格式打包的,因此可以先转成cpio然后解压,如下所示:
rpm2cpio xxx.rpm | cpio -div

rpm 命令

二进制包(Binary)以及源代码包(Source)两种。二进制包可以直接安装在计算机中,而源代码包将会由 RPM自动编译、安装。源代码包经常以src.rpm作为后缀名。

常用命令组合:
1
2
3
4
5
6
7
-ivh:安装显示安装进度--install--verbose--hash
-Uvh:升级软件包--Update;
-qpl: 列出RPM软件包内的文件信息[Query Package list];
-qpi:列出RPM软件包的描述信息[Query Package install package(s)];
-qf:查找指定文件属于哪个RPM软件包[Query File];
-Va:校验所有的 RPM软件包,查找丢失的文件[View Lost];
-e:删除包

rpm -ivh –test gaim-1.3.0-1.fc4.i386.rpm    //用来检查依赖关系;并不是真正的安装;

常用参数:

Install/Upgrade/Erase options:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-i, --install                     install package(s)
-v, --verbose                     provide more detailed output
-h, --hash                        print hash marks as package installs (good with -v)
-e, --erase                       erase (uninstall) package
-U, --upgrade=<packagefile>+      upgrade package(s)
--replacepkge                    无论软件包是否已被安装,都强行安装软件包
--test                            安装测试,并不实际安装
--nodeps                          忽略软件包的依赖关系强行安装
--force                           忽略软件包及文件的冲突

Query options (with -q or --query):
-a, --all                         query/verify all packages
-p, --package                     query/verify a package file
-l, --list                        list files in package
-d, --docfiles                    list all documentation files
-f, --file                        query/verify package(s) owning file

rpm 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost  src]# rpm -qpR awstats-6.8-1.noarch.rpm
/bin/sh
/usr/bin/perl
config(awstats)  = 6.8-1
perl >= 0:5.005
perl(LWP::UserAgent)
perl(POSIX)
perl(Socket)
perl(Time::Local)
perl(strict)
perl(vars)
rpmlib(CompressedFileNames)  <= 3.0.4-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmbuild SPEC文件说明

在rpmbuild -ba时,遇到如下错误:
ERROR: No build ID note found in /home/wuyang/rpmbuild/BUILDROOT/******
error: Bad exit status from /var/tmp/rpm-tmp.BPd1OI (%install) 解决方法是在.spec文件中任意位置添加如下参数:
%define debug_install_post %{rpmconfigdir}/find-debuginfo.sh %{?find_debuginfo_opts} “%{_builddir}/%{?buildsubdir}” %{nil}


rpmbuild源代码打包

将源代码打包,如 stardict-2.0.tar.gz,并将文件放到spec文件Source段所描述的路径下,通常为/usr/src/redhat /SOURCES/目录下(不同的Linux发布版本略有不同,如OpenSUSE为 /usr/src/packages/SOURCES/)

rpmbuild -ba ‘spec文件路径’
(rpmbuild常用参数: -bb 只编译二进制rpm包 -bs 只编译源码rpm包 -ba 同时编译二进制和源码rpm包)
build完后,可以在/usr/src/redhat/RPMS/下找到二进制rpm包,rpm包按照其对应的cpu体系结构分类,通常在/usr/src/redhat/RPMS/i386目录下
/usr/src/redhat/SRPMS/下找到源码rpm包,此时由于是源代码,所以无须按体系结构分类。


一、关键字

spec脚本包括很多关键字,主要有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Name: 软件包的名称,后面可使用%{name}的方式引用
Summary: 软件包的内容概要
Version: 软件的实际版本号,例如:1.0.1等,后面可使用%{version}引用
Release: 发布序列号,例如:1linuxing等,标明第几次打包,后面可使用%{release}引用
Group: 软件分组,建议使用标准分组
License: 软件授权方式,通常就是GPL
Source: 源代码包,可以带多个用Source1、Source2等源,后面也可以用%{source1}、%{source2}引用
BuildRoot: 这个是安装或编译时使用的“虚拟目录”,考虑到多用户的环境,一般定义为:
%{_tmppath}/%{name}-%{version}-%{release}-root
%{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n}
该参数非常重要,因为在生成rpm的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作。
后面可使用$RPM_BUILD_ROOT方式引用。
URL: 软件的主页
Vendor: 发行商或打包组织的信息,例如RedFlag Co,Ltd
Disstribution: 发行版标识
Patch: 补丁源码,可使用Patch1、Patch2等标识多个补丁,使用%patch0或%{patch0}引用
Prefix: %{_prefix} 这个主要是为了解决今后安装rpm包时,并不一定把软件安装到rpm中打包的目录的情况。这样,必须在这里定义该标识,并在编写%install脚本的时候引用,才能实现rpm安装时重新指定位置的功能
Prefix: %{_sysconfdir} 这个原因和上面的一样,但由于%{_prefix}指/usr,而对于其他的文件,例如/etc下的配置文件,则需要用%{_sysconfdir}标识
Build Arch: 指编译的目标处理器架构,noarch标识不指定,但通常都是以/usr/lib/rpm/marcros中的内容为默认值
Requires: 该rpm包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本,例如:
libpng-devel >= 1.0.20 zlib
※“>=”号两边需用空格隔开,而不同软件名称也用空格分开
还有例如PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是针对不同阶段的依赖指定
Provides: 指明本软件一些特定的功能,以便其他rpm识别
Packager: 打包者的信息
%description 软件的详细说明

二、spec脚本主体

spec脚本的主体中也包括了很多关键字和描述。

%prep 预处理脚本
%setup -n %{name}-%{version} 把源码包解压并放好

通常是从/usr/src/asianux/SOURCES里的包解压到/usr/src/asianux/BUILD/%{name}-%{version}中。
一般用%setup -c就可以了,但有两种情况:一就是同时编译多个源码包,二就是源码的tar包的名称与解压出来的目录不一致,此时,就需要使用-n参数指定一下了。

1
2
3
4
5
6
7
8
9
10
11
%setup 不加任何选项,仅将软件包打开。
%setup -n newdir 将软件包解压在newdir目录。
%setup -c 解压缩之前先产生目录。
%setup -b num 将第num个source文件解压缩。
%setup -T 不使用default的解压缩操作。
%setup -T -b 0 将第0个源代码文件解压缩。
%setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。
%patch 最简单的补丁方式,自动指定patch level。
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。
%patch -s 不显示打补丁时的信息。
%patch -T 将所有打补丁时产生的输出文件删除。
%patch 打补丁

通常补丁都会一起在源码tar.gz包中,或放到SOURCES目录下。一般参数为:
%patch -p1 使用前面定义的Patch补丁进行,-p1是忽略patch的第一层目录
%Patch2 -p1 -b xxx.patch 打上指定的补丁,-b是指生成备份文件

%configure 这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置

在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。 另一种不标准的写法是,可参考源码中的参数自定义,例如:
CFLAGS=“$RPM_OPT_FLAGS” CXXFLAGS=“$RPM_OPT_FLAGS” ./configure –prefix=%{_prefix}

%build 开始构建包

在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make的工作,常见写法:
make %{?_smp_mflags} OPTIMIZE=“%{optflags}”

都是一些优化参数,定义在/usr/lib/rpm/marcros中

%install 开始把软件安装到虚拟的根目录中

在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make install的操作。这个很重要,因为如果这里的路径不对的话,则下面%file中寻找文件的时候就会失败。常见内容有:
%makeinstall 这不是关键字,而是rpm定义的标准宏命令。也可以使用非标准写法:
make DESTDIR=$RPM_BUILD_ROOT install

make prefix=$RPM_BUILD_ROOT install
需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:
install -d $RPM_BUILD_ROOT/ cp -a * $RPM_BUILD_ROOT/

%clean 清理临时文件

通常内容为: [ “$RPM_BUILD_ROOT” != “/” ] && rm -rf “$RPM_BUILD_ROOT” rm -rf $RPM_BUILD_DIR/%{name}-%{version}

※注意区分$RPM_BUILD_ROOT和$RPM_BUILD_DIR:

$RPM_BUILD_ROOT是指开头定义的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/asianux/BUILD,其中,前面的才是%file需要的。
%pre rpm安装前执行的脚本
%post rpm安装后执行的脚本
%preun rpm卸载前执行的脚本
%postun rpm卸载后执行的脚本

%preun %postun 的区别是什么呢?

前者在升级的时候会执行,后者在升级rpm包的时候不会执行

%files 定义那些文件或目录会放入rpm中

这里会在虚拟根目录下进行,千万不要写绝对路径,而应用宏或变量表示相对路径。如果描述为目录,表示目录中除%exclude外的所有文件。
%defattr (-,root,root) 指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755
%exclude 列出不想打包到rpm中的文件
※小心,如果%exclude指定的文件不存在,也会出错的。

%changelog 变更日志

※特别需要注意的是:%install部分使用的是绝对路径,而%file部分使用则是相对路径,虽然其描述的是同一个地方。千万不要写错。

三、其他

1. 扩展

虽然上面的范例很简陋,而且缺少%build部分,但实际上只要记住两点:
a)就是%build和%install的过程中,都必须把编译和安装的文件定义到“虚拟根目录”中。
b)就是%file中必须明白,用的是相对目录

2. 一些rpm相关信息

rpm软件包系统的标准分组:/usr/share/doc/rpm-4.3.3/GROUPS
各种宏定义: /usr/lib/rpm/macros
已经安装的rpm包数据库: /var/lib/rpm
如果要避免生成debuginfo包:这个是默认会生成的rpm包。则可以使用下面的命令:
echo ‘%debug_package %{nil}’ >> ~/.rpmmacros
如果rpm包已经做好,但在安装的时候想修改默认路径,则可以:
rpm -ivh –prefix=/opt/usr xxx.rpm
又或者同时修改多个路径:
rpm xxx.rpm –relocate=/usr=/opt/usr –relocate=/etc=/usr/etc

3. 制作补丁

详细看参考:[原]使用diff同patch工具

4. 关于rpm中的执行脚本

如果正在制作的rpm包是准备作为放到系统安装光盘中的话,则需要考虑rpm中定义的脚本是否有问题。由于系统在安装的时候只是依赖于一个小环境进行,而该环境与实际安装完的环境有很大的区别,所以,大部分的脚本在该安装环境中都是无法生效,甚至会带来麻烦的。
所以,对于这样的,需要放到安装光盘中的套件,不加入执行脚本是较佳的方法。
另外,为提供操作中可参考的信息,rpm还提供了一种信号机制:不同的操作会返回不同的信息,并放到默认变量$1中。
0代表卸载、1代表安装、2代表升级
可这样使用:

1
2
3
4
%postun
if [ "$1" = "0" ]; then
/sbin/ldconfig
fi