作者:reille
本博客网址:
http://blog.csdn.net/reille/,转载本博客原创文章请注明出处。
本文内容概要: 7z具有很高的压缩率,这对存储空间资源比较敏感的嵌入式系统是很有用处的,相对于其它压缩软件,如tar命令,7z命令可以节省很大一部分存储空间。本文即说明在宿主机linux中7z命令的安装、交叉编译7z命令从而可在嵌入式arm平台上使用该命令、7z命令的使用等。
开发环境:
宿 主 机:window XP;
虚 拟 机:ubuntu9.10;
交叉编译器:arm-uclibc-gcc (3.3版本)
———————————————————————————————————————————————————————————————————
1. 宿主机安装7z命令
宿主机上安装7z命令有两种方式。
1.1 在线安装
如果你的宿主机Linux可以连接外网,推荐用这种方式,方便简单,执行命令:sudo apt-get install p7zip即可在线安装7z命令。
1.2 安装包安装
7z提供了线下的程序安装包,也可自己编译安装。这里讲的是用7z提供的bin包来安装。
宿主机linux一般是X86的,而7z提供编译好了的bin包,可以很方便的安装。步骤如下:
1) 去网站
http://sourceforge.net/projects/p7zip/files/或
http://sourceforge.net/projects/p7zip/files/p7zip/上下载p7zip的包,当前最新版本是9.20.1;
2) 找到对应版本号进去,页面会提供两个供你下载,一个是bin包,另一个是源码包,这里下的是bin包(事实上还是把两个包都下载下来吧,后面移植到嵌入式linux平台要用到源码包的),以9.20.1为例,下载的包名称是:p7zip_9.20.1_x86_linux_bin.tar.bz2;
3) 在Linux上执行下面命令(解压和安装):
tar xjvf p7zip_9.20.1_x86_linux_bin.tar.bz2
cd p7zip_9.20.1
sh install.sh
到此,就安装完成了。
2. 7z命令的使用
2.1 解压缩7z文件
7za x phpMyAdmin-3.3.8.1-all-languages.7z -r -o./7za x phpMyAdmin-3.3.8.1-all-languages.7z -r -o./
参数含义:
x 代表解压缩文件,并且是按原始目录解压(还有个参数 e 也是解压缩文件,但其会将所有文件都解压到根下,而不是自己原有的文件夹下)
phpMyAdmin-3.3.8.1-all-languages.7z 是压缩文件,这里我用phpadmin做测试。这里默认使用当前目录下的phpMyAdmin-3.3.8.1-all-languages.7z
-r 表示递归解压缩所有的子文件夹
-o 是指定解压到的目录,
-o后是没有空格的直接接目录
2.2 压缩文件/文件夹
7za a -t7z -r Mytest.7z /opt/phpMyAdmin-3.3.8.1-all-languages/*
参数含义:
a 代表添加文件/文件夹到压缩包
-t 是指定压缩类型,这里定为7z
-r 表示递归所有的子文件夹
Mytest.7z 是压缩好后的压缩包名
3. 7z交叉移植到arm-linux平台
有两种7z命令移植到arm-linux平台:一种是完整功能版本的7z命令移植;另一种精简版本的7z命令的移植(实际上只有解压7z格式包功能),下面分别进行说明。
3.1 完整功能7z命令即7za的移植
解压源码包
p7zip_9.20.1_src_all.tar.bz2后,进入源码包,会发现有一个makefile和n多其它平台的makefile:makefile.aix_gcc、makefile.linux_s390x 、makefile.linux_cross_arm等。其中,makefile.linux_cross_arm就是我们要的makefile文件。此我,源码目录中提供了readme文件,其中有说明如下:
According to your OS, copy makefile.linux,
makefile.freebsd, makefile.cygwin, ...
over makefile.machine
其中的 makefile.machine 就是平台相关性选项。所以我们可以这样做 :
编辑makefile.linux_cross_arm文件 ,指定其中的编译器路径,如下打红 {MOD}地方所示:
#
# makefile for Linux (CROSS ARM)
#
OPTFLAGS=-O
ALLFLAGS=${OPTFLAGS} -pipe -s
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-DNDEBUG -D_REENTRANT -DENV_UNIX
-D_7ZIP_LARGE_PAGES
$(LOCAL_FLAGS)
CXX=
/usr/local/arm-uclibc/bin/arm-uclibc-g++ $(ALLFLAGS)
CC=
/usr/local/arm-uclibc/bin/arm-uclibc-gcc $(ALLFLAGS)
CC_SHARED=-fPIC -DPIC
LINK_SHARED=-fPIC -DPIC -shared
LOCAL_LIBS=-lpthread
LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
OBJ_CRC32=$(OBJ_CRC32_C)
注:用这个编译器,会有一个错误:提示wine_date_and_time.cpp中112行的timegm未定义,可以在config.h的31行,把那个宏定义取消即可正常编译通过。
然后:
$ mv makefile.machine makefile.machine.bak
$ ln -s makefile.linux_cross_arm makefile.machine
$ make
make后,可以bin目录下看到有一个7za的文件,这就是我们要的,把其放到arm板上,即可正常运行。
完整功能版本的7z命令,交叉编译出来的7z命令即7za,其大小为1.38M,不同的编译器可能编译出来的大小有点出入,比如我在公司编译的是1.7M多。
3.2 精简功能7z命令即7zDec的移植
很显然,交叉编译的完整功能7za命令太大,达到了1M多,这对于嵌入式根文件系统来说,一般情况下是不能接收的。但如果从源码包
p7zip_9.20.1_src_all.tar.bz2中进行裁减,发现难度很大。
幸好,7z开源项目提供了精简功能7z命令即7zDec。
交叉编译后的大小为50KB左右。
1) 下载LZMA-SDK源码包,下载地址:
http://www.7-zip.org/sdk.html,当前最新版本是9.20,即lzma920.tar.bz2包;
2) 解压:把源码包的程序文件解压到文件夹:lzma920中;
3) 解压后,建议先查看下其中的说明文件:7zC.txt和lzma.txt两文件;
4) 进入目录:lzma920/C/Util/7z,可以看到其中有两个makefile文件:makefile和makefile.gcc,因为是在linux下,所以用makefile.gcc这个makefile文件;
5) 更改makefile.gcc文件,更改如下:
PROG = 7zDec
CXX = /usr/local/arm-uclibc/bin/arm-uclibc-g++
STRIP = /usr/local/arm-uclibc/bin/arm-uclibc-strip
LIB =
RM = rm -f
CFLAGS = -c -O2 -Wall
OBJS = 7zMain.o 7zAlloc.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o 7zIn.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o
all: $(PROG)
$(PROG): $(OBJS)
$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
$(STRIP) $(PROG)
7zMain.o: 7zMain.c
$(CXX) $(CFLAGS) 7zMain.c
7zAlloc.o: ../../7zAlloc.c
$(CXX) $(CFLAGS) ../../7zAlloc.c
7zBuf.o: ../../7zBuf.c
$(CXX) $(CFLAGS) ../../7zBuf.c
7zBuf2.o: ../../7zBuf2.c
$(CXX) $(CFLAGS) ../../7zBuf2.c
7zCrc.o: ../../7zCrc.c
$(CXX) $(CFLAGS) ../../7zCrc.c
7zCrcOpt.o: ../../7zCrc.c
$(CXX) $(CFLAGS) ../../7zCrcOpt.c
7zDec.o: ../../7zDec.c
$(CXX) $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT ../../7zDec.c
7zIn.o: ../../7zIn.c
$(CXX) $(CFLAGS) ../../7zIn.c
CpuArch.o: ../../CpuArch.c
$(CXX) $(CFLAGS) ../../CpuArch.c
LzmaDec.o: ../../LzmaDec.c
$(CXX) $(CFLAGS) ../../LzmaDec.c
Lzma2Dec.o: ../../Lzma2Dec.c
$(CXX) $(CFLAGS) ../../Lzma2Dec.c
Bra.o: ../../Bra.c
$(CXX) $(CFLAGS) ../../Bra.c
Bra86.o: ../../Bra86.c
$(CXX) $(CFLAGS) ../../Bra86.c
Bcj2.o: ../../Bcj2.c
$(CXX) $(CFLAGS) ../../Bcj2.c
Ppmd7.o: ../../Ppmd7.c
$(CXX) $(CFLAGS) ../../Ppmd7.c
Ppmd7Dec.o: ../../Ppmd7Dec.c
$(CXX) $(CFLAGS) ../../Ppmd7Dec.c
7zFile.o: ../../7zFile.c
$(CXX) $(CFLAGS) ../../7zFile.c
7zStream.o: ../../7zStream.c
$(CXX) $(CFLAGS) ../../7zStream.c
clean:
-$(RM) $(PROG) $(OBJS)
6) 编译:make -f makefile.gcc或make -f makefile.gcc clean all;则会在lzma920/C/Util/7z/目录下生成一个名为7zDec的可执行文件,即移植到精简功能版本7z命令。
7) 7zDec命令默认只支持完整7za命令的三个选项,如下所示:
e: Extract files from archive (without using directory names)
l: List contents of archive
t: Test integrity of archive
x: eXtract files with full paths
而不支持"-o"选项,即 指定解压目录 功能,因为在使用过程中有这个需求,因此,对7zDec命令添加了7za命令中的“-o”选项功能。在lzma920/C/Util/7z/目录下,编辑7zMain.c文件,修改main函数如下:
int MY_CDECL main(int numargs, char *args[])
{
CFileInStream archiveStream;
CLookToRead lookStream;
CSzArEx db;
SRes res;
ISzAlloc allocImp;
ISzAlloc allocTempImp;
UInt16 *temp = NULL;
size_t tempSize = 0;
// add start by gyr 2011.11.19
UInt16 *name = NULL;
UInt16 *outPath = NULL;
size_t outPathLen = 0;
// add end by gyr 2011.11.19
printf("
7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "
");
if (numargs == 1)
{
printf(
"Usage: 7zDec
"
"
"
" e: Extract files from archive (without using directory names)
"
" l: List contents of archive
"
" t: Test integrity of archive
"
" x: eXtract files with full paths
"
" -o{Directory}: set Output directory"); // add by gyr 2011.11.19
return 0;
}
if (numargs < 3)
{
PrintError("incorrect command");
return 1;
}
// add start by gyr 2011.11.19
if (numargs == 4 && strstr(args[3], "-o") != NULL)
{
size_t outPathLenTemp = strlen(args[3]);
if (outPathLenTemp <= 2)
{
PrintError("set Output directory Error");
return 1;
}
outPathLen = outPathLenTemp - 2;
if (args[3][outPathLenTemp-1] != '/')
{
outPathLen = outPathLen + 1;
}
outPath = (UInt16 *)SzAlloc(NULL, outPathLen * sizeof(outPath[0]));
if (outPath == NULL)
{
PrintError("can not allocate memory for set output dirctory");
return 1;
}
int j = 0;
for (j=2; jIsDir && !fullPaths)
continue;
len = SzArEx_GetFileNameUtf16(&db, i, NULL);
if (len > tempSize)
{
SzFree(NULL, temp);
tempSize = len;
temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
if (temp == 0)
{
res = SZ_ERROR_MEM;
break;
}
}
SzArEx_GetFileNameUtf16(&db, i, temp);
if (listCommand)
{
char attr[8], s[32], t[32];
GetAttribString(f->AttribDefined ? f->Attrib : 0, f->IsDir, attr);
UInt64ToStr(f->Size, s);
if (f->MTimeDefined)
ConvertFileTimeToString(&f->MTime, t);
else
{
size_t j;
for (j = 0; j < 19; j++)
t[j] = ' ';
t[j] = '