0%

解压方法之一 zip

.. _linux-beginner-zip:

:ref:unzip<linux-beginner-unzip>

.. note::
林花谢了春红,太匆匆。无奈朝来寒雨,晚来风。
李煜《相见欢·林花谢了春红》

Linux zip命令的功能是用于压缩文件,解压命令为unzip

通过zip命令可以将很多文件打包成.zip格式的压缩包,里面会包含文件的名称、路径、创建时间、上次修改时间、权限等信息,与tar命令相似。

对于类似文本文件而言,压缩比基本可以达到2:1到3:1.

官方的定义为:

zip - package and compress (archive) files

语法

zip的参数超级的多,各种设置也是很巧妙,不过常用的就几个,其他的放在后面再说。

1
$ zip  [-aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$] [--longoption ...]  [-b path] [-n suffixes] [-t date] [-tt date] [zipfile [file ...]]  [-xi list]

参数

  • -r--recurse-paths :遍历整个目录 for example:
  • -j--junk-paths: 仅保存文件名,而不保存路径。默认情况下zip将保存整个路径

参考实例

将指定目录及其内全部文件都打包成zip格式压缩包文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ zip -r backuptest.zip /etc
adding: etc/resolv.conf (stored 0%)
adding: etc/fonts/ (stored 0%)
adding: etc/fonts/conf.d/ (stored 0%)
adding: etc/fonts/conf.d/65-0-wqy-zenhei-sharp.conf (deflated 88%)
adding: etc/fonts/conf.d/59-liberation-mono.conf (deflated 57%)
adding: etc/fonts/conf.d/57-paratype-pt-sans.conf (deflated 66%)
adding: etc/fonts/conf.d/59-liberation-sans.conf (deflated 74%)
adding: etc/fonts/conf.d/65-0-ttf-arphic-uming.conf (deflated 87%)
adding: etc/fonts/conf.d/65-1-vlgothic-gothic.conf (deflated 74%)
adding: etc/fonts/conf.d/65-0-lohit-nepali.conf (deflated 57%)
adding: etc/fonts/conf.d/20-unhint-small-dejavu-sans.conf (deflated 43%)
adding: etc/fonts/conf.d/61-urw-d050000l.conf (deflated 71%)
adding: etc/fonts/conf.d/57-dejavu-sans.conf (deflated 77%)
...

zip还支持通配符的表达,比如将当前工作目录内所有以.jpg为后缀的文件打包:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ zip -r backuptest.zip *.jpg
adding: test0.jpg (deflated 56%)
adding: test10.jpg (deflated 56%)
adding: test12.jpg (deflated 56%)
adding: test14.jpg (deflated 56%)
adding: test16.jpg (deflated 56%)
adding: test18.jpg (deflated 56%)
adding: test20.jpg (deflated 56%)
adding: test2.jpg (deflated 56%)
adding: test22.jpg (deflated 56%)
adding: test24.jpg (deflated 56%)
adding: test26.jpg (deflated 56%)
adding: test28.jpg (deflated 56%)

仅保存文件名

zip默认情况下会保存路径信息,如果加上-j将不保存路径信息,而仅仅保存文件。
这个情况可以在希望把同一类文件放在一起时比较有用。

1
$ zip -j foo foo/*

GNU Automake 版本(version 1.16.1, 26 February 2018)

Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover texts,
and with no Back-Cover Texts. A copy of the license is included in
the section entitled “GNU Free Documentation License.”

2 Autotools 简介


如果以前没有接触过Automake,你可能大概也许知道它是 Autotools 工具集的一部分。

如果你已经开始研究诸如 configure,configure.ac,Makefile.in,Makefile.am,aclocal.m等,那么你可能已经看到他们被声明为 generated by Autoconf or Automake。

整套生成过程异常复杂,本章准备一点点介绍讲解出来。

Alexandre Duret-Lutz 的 Autotools 教程特别好,供参考
(http://www.lrde.epita.fr/~adl/autotools.html)。

2.1 GNU Build System 简介


作为一个开发人员,有一套构建系统是相当有必要的。

在Unix的世界里,一般使用make。所有的规则都在文件Makefile中描述。

比如程序prog链接到文件 main.o,foo.o,bar.o,文件 main.omain.c编译而成。

每次执行 make的时候,它都会读取Makefile,检查文件的修改日期,来决定哪些文件需要重新构建。

在不同的平台上进行编译的时候,Makefile 可能需要微调。

1991年David J. MacKenzie在厌倦反复修改 Makefile后,编写了一个支持20个平台的脚本。
这个脚本的文件称为 configure,可以自动调整 Makefile

现在编译软件包简化为 ./configure && make.

目前GNU项目已经标准化这个过程,安装只需要解压软件包,然后执行 ./configure && make && make install,即可安装。

Autotools 工具可以帮助我们构建自己的工具包。

Autoconf 主要完成configure, Automake 完成Makefile

2.2 GNU Build System的用例


随automake发布的还有一个示例程序 amhello-1.0.tar.gz ,一般位于
PREFIX/share/doc/automake/amhello-1.0.tar.gz,其中PREFIX为安装路径的前缀,

默认为/usr/local,还有一些发行版位于/usr

2.2.1 基本安装


最常见的安装如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~ % tar zxf amhello-1.0.tar.gz
~ % cd amhello-1.0
~/amhello-1.0 % ./configure
...
config.status: creating Makefile
config.status: creating src/Makefile
...
~/amhello-1.0 % make
...
~/amhello-1.0 % make check
...
~/amhello-1.0 % su
Password:
/home/adl/amhello-1.0 # make install
...
/home/adl/amhello-1.0 # exit
~/amhello-1.0 % make installcheck
...

我们首先解压文件,然后执行configure,将会创建Makefile文件,此时就可以执行make命令了。

make命令将编译程序、库和相关脚本。

make check会测试程序是否运行,不过需要编写测试用例。

当一切完成后,我们就可以使用make install来安装程序的,默认情况下降安装在目录/usr/local,比如:

  • 可执行程序在 /usr/local/bin,
  • 库文件在 /usr/local/lib

2.2.2 标准的 Makefile目标


前面我们接触了 make, make check, make install, 和 make installcheck.
这里的 check, installinstallcheck称为目标,而 make本身是 make all的缩写。
下面是一些常用的make命令:

  • make all :编译程序、库、文档等
  • make install :安装并拷贝相关文件到系统目录
  • make uninstall:清除安装的文件(需要在同一个目录执行)
  • make clean:清除由make生产的编译文件
  • make distclean:清除由configure创建的文件
  • make check:运行测试用例
  • make installcheck:检查安装的程序或库
  • make dist:从源码制作发布归档文件PACKAGE-VERSION.tar.gz

2.2.3 标准目录变量


GNU的编码标准也指定了安装的目录层,如下所示:

目录变量 默认值
prefix /usr/local
exec_prefix ${prefix}
bindir ${exec_prefix}/bin
libdir ${exec_prefix}/lib
includedir ${prefix}/include
datarootdir ${prefix}/share
datadir ${datarootdir}
mandir ${datarootdir}/man
infodir ${datarootdir}/info
docdir ${datarootdir}/doc/${PACKAGE}

安装的时候,安装的文件就会按照到上述变量的一个目录中。比如示例 amhello-1.0,可执行程序 hello将安装到BINDIRREADME安装到DOCDIR,默认路径为
/usr/local/share/doc/amhello.

如果希望安装到自己的目录,可以使用以下参数:

1
2
3
4
5
6
~/amhello-1.0 % ./configure --prefix ~/usr
...
~/amhello-1.0 % make
...
~/amhello-1.0 % make install
...

将安装为 ~/usr/bin/hello~/usr/share/doc/amhello/README.

更多参数可以使用 ./configure --help.

2.2.4 标准配置变量


GNU的编码标准也指定了编译中一系列的配置变量,如下所示:

变量 含义
CC C编译器
CFLAGS C编译器参数
CXX C++编译器
CXXFLAGS C++编译器参数
LDFLAGS 链接参数
CPPFLAGS C/C++预处理参数

configure一本都会设定好默认的参数值,不过如果希望覆盖默认参数,就需要修改这些值了比如通过 configure强制设定 gcc-3作为C编译器,使用 ~/usr/include的头文件编译,使用 ~/usr/lib的库进行连接。

1
~/amhello-1.0 % ./configure --prefix ~/usr CC=gcc-3 CPPFLAGS=-I$HOME/usr/include LDFLAGS=-L$HOME/usr/lib

这些变量均可以通过./configure --help查看

2.2.5 使用文件config.site重置默认的配置


在安装多个文件的时候,如果配置参数一致,那么创建一个通用的文件将十分简便。如果文件PREFIX/share/config.site存在,在configure的时候将自动导入这些参数。

重新调用上一节的命令:

1
2
~/amhello-1.0 % ./configure --prefix ~/usr CC=gcc-3 \
CPPFLAGS=-I$HOME/usr/include LDFLAGS=-L$HOME/usr/lib

此时我们就可以把下面的内容写入文件 ~/usr/share/config.site

 test -z "$CC" && CC=gcc-3
 test -z "$CPPFLAGS" && CPPFLAGS=-I$HOME/usr/include
 test -z "$LDFLAGS" && LDFLAGS=-L$HOME/usr/lib

然后,每次执行 configure都会load这个文件

1
2
3
~/amhello-1.0 % ./configure --prefix ~/usr
configure: loading site script /home/adl/usr/share/config.site
...

2.2.6 并行编译树(Parallel Build Trees) (又名VPATH Builds)


GNU Build System区分两个目录树:源码树和编译树。

源码树包含文件 configure及源码,编译树位于 configure运行的目录。一般编译树的布局与源码树类似。

正常情况下,我们可能会在源码树目录直接执行 configure命令,还有一种情况是如果希望保持源码树的整洁,在其他目录来进行编译,如下所示:

1
2
3
4
5
6
7
~ % tar zxf ~/amhello-1.0.tar.gz
~ % cd amhello-1.0
~/amhello-1.0 % mkdir build && cd build
~/amhello-1.0/build % ../configure
...
~/amhello-1.0/build % make
...

源码树与编译树的目录不同即被称为“parallel builds” 或 “VPATH builds”。

这个源码与编译不在同一个目录的方式对不同的配置参数进行编译特别方便,比如我们通过不同的配置参数来分别编译:

1
2
3
4
5
6
7
8
9
10
11
12
~ % tar zxf ~/amhello-1.0.tar.gz
~ % cd amhello-1.0
~/amhello-1.0 % mkdir debug optim && cd debug
~/amhello-1.0/debug % ../configure CFLAGS='-g -O0'
...
~/amhello-1.0/debug % make
...
~/amhello-1.0/debug % cd ../optim
~/amhello-1.0/optim % ../configure CFLAGS='-O3 -fomit-frame-pointer'
...
~/amhello-1.0/optim % make
...

对于网络文件系统,这种方式更方便了,比如我们在两个主机 HOST1HOST2上分别编译,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~ % cd /nfs/src
/nfs/src % tar zxf ~/amhello-1.0.tar.gz
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[HOST1] ~ % mkdir /tmp/amh && cd /tmp/amh
[HOST1] /tmp/amh % /nfs/src/amhello-1.0/configure
...
[HOST1] /tmp/amh % make && sudo make install
...
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[HOST2] ~ % mkdir /tmp/amh && cd /tmp/amh
[HOST2] /tmp/amh % /nfs/src/amhello-1.0/configure
...
[HOST2] /tmp/amh % make && sudo make install
...

这种情况下,不会对源码目录有任何特殊需求,就算是只读也可编译,这个功能最开始主要是因为当时FSF使用CD-ROM发布,而CD只能读取。

2.2.7 两步安装


GNU编译系统还支持两步安装,什么意思的,也就是区分两种类型的文件,架构相关的和架构无关的,可以通过不同的 Makefile 来完成相关安装。

其实对于我们平时使用的make install是由两部分组成的:

  • 架构相关的 install-exec
  • 架构无关的install-data

从GNU编译系统的角度来看,架构相关与架构无关主要是安装环境及变量不同。所以架构相关的我们使用 make install-exec来安装,架构无关的直接使用make install-data来安装。

举个例子来看看:有两台主机需要安装,假定 (1) 程序安装到 /usr, (2) 目录 /usr/share共享。

在第一台host上,执行On the first host we would run

1
2
3
4
5
[HOST1] ~ % mkdir /tmp/amh && cd /tmp/amh
[HOST1] /tmp/amh % /nfs/src/amhello-1.0/configure --prefix /usr
...
[HOST1] /tmp/amh % make && sudo make install
...

On the second host, however, we need only install the
architecture-specific files.

1
2
3
4
5
[HOST2] ~ % mkdir /tmp/amh && cd /tmp/amh
[HOST2] /tmp/amh % /nfs/src/amhello-1.0/configure --prefix /usr
...
[HOST2] /tmp/amh % make && sudo make install-exec
...

In packages that have installation checks, it would make sense to run
make installcheck to verify that the
package works correctly despite the apparent partial installation.

2.2.8 交叉编译


这个功能特别有用,我们可以在一个平台编译,而在另外一个平台运行。

其中参数为:

  • --build=BUILD:软件包的编译系统
  • --host=HOST:软件和库将要运行的系统

再加上 --host参数的时候, configure就会搜索这个平台的交叉编译套件。交叉编译工具一般在名字前有目标架构作为前缀,比如 MinGW32 编译环境被称为i586-mingw32msvc-gcc, i586-mingw32msvc-ld, i586-mingw32msvc-as等。

接下来的操作介绍如何在GNU/Linux上为 i586-mingw32msvc编译 amhello-1.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~/amhello-1.0 % ./configure --build i686-pc-linux-gnu --host i586-mingw32msvc
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for i586-mingw32msvc-strip... i586-mingw32msvc-strip
checking for i586-mingw32msvc-gcc... i586-mingw32msvc-gcc
checking for C compiler default output file name... a.exe
checking whether the C compiler works... yes
checking whether we are cross compiling... yes
checking for suffix of executables... .exe
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether i586-mingw32msvc-gcc accepts -g... yes
checking for i586-mingw32msvc-gcc option to accept ANSI C...
...
~/amhello-1.0 % make
...
~/amhello-1.0 % cd src; file hello.exe
hello.exe: MS Windows PE 32-bit Intel 80386 console executable not relocatable

2.2.9 安装时重命名程序


可以使用 configure的编译选项,在安装之前加上特定的前缀或后缀来避免与系统程序冲突。

  • --program-prefix=PREFIX:增加前缀
  • --program-suffix=SUFFIX:增加后缀
  • --program-transform-name=PROGRAM:安装时运行sed PROGRAM

比如下面的例子将安装 hello/usr/local/bin/test-hello

1
2
3
4
5
6
~/amhello-1.0 % ./configure --program-prefix test-
...
~/amhello-1.0 % make
...
~/amhello-1.0 % sudo make install
...

2.2.10 使用DESTDIR编译二进制包


单纯的GNU Build System的 make installmake uninstall接口并不能完全满足系统管理员的部署,比如我们希望在编译的时候安装指定路径,而在make的时候因为可能没有root权限暂时放在一个临时目录,然后再部署到其他机器。

比如像下面这个例子就很好的诠释了这个方法。

1
2
3
4
5
6
7
8
9
10
11
~/amhello-1.0 % ./configure --prefix /usr
...
~/amhello-1.0 % make
...
~/amhello-1.0 % make DESTDIR=$HOME/inst install
...
~/amhello-1.0 % cd ~/inst
~/inst % find . -type f -print > ../files.lst
~/inst % tar zcvf ~/amhello-1.0-i686.tar.gz `cat ../files.lst`
./usr/bin/hello
./usr/share/doc/amhello/README

然后,我们就可以把 amhello-1.0-i686.tar.gz解压到大部分主机的 /目录了。

注意使用cat ../files.lst而不是.是为了避免子目录的归档问题,保证在解压的时候按照预定的目录进行解压。

2.2.11 准备发布


make dist收集源码及必须的文件创建一个压缩包,名为 PACKAGE-VERSION.tar.gz

虽然也能满足大部分的功能,但是还有一个更有用的命令 make distcheck,这个命令也会像 make dist一样创建压缩包 PACKAGE-VERSION.tar.gz,并会做各种各样的检查以确保压缩包没有问题:

• 将运行所有的软件包命令,比如 make, make check, make installmake installcheck, 甚至是 make dist,来确保软件发布没有问题
• 测试只读源码树的VPATH编译
• 确保 make clean, make distclean, and make uninstall不忽略任何文件
• 检查 DESTDIR安装是否工作

所有的这些操作都在一个临时目录进行,所以并不需要root权限。

如果 make distcheck失败了,意味着其中的一个场景没有满足,可能不会影响程序的使用,不过最好根据失败的提示进一步改进得到一个完美的发布包。

2.2.12 自动依赖跟踪


Automake自动生成代码来解决依赖的问题。

configure执行的时候,我们可以看到这个过程:

1
2
3
4
~/amhello-1.0 % ./configure --prefix /usr
...
checking dependency style of gcc... gcc3
...

可以通过下面两个选项来使能或禁用依赖跟踪:

  • --disable-dependency-tracking :Speed up one-time builds.
  • --enable-dependency-tracking:Do not reject slow dependency extractors.

2.2.13 嵌套包


虽然并不推荐刚开始接触Autotools的时候就了解嵌套包,但是最为一个极具特性的功能还是需要了解一下的。

使用Autotools或者相关工具开发的时候可以任意潜逃子模块,比如包A的发布将需要字幕了的一个库,库B拥有自己的一套构建系统,那么包A的 configure脚本将先运行库B的 configure脚本,所以安装编译包A的同时也安装编译了库B。生成的包A的发型版也将包含库B。

当然还可以收集更多的包,GCC重度使用这个功能,这样就可以保证每个子模块均可以独立的开发了。

可以使用命令 configure --help=recursive来显示所有包含包的选项。

2.3 Autotools大有裨益


或许你只是希望完成一些可以通过自行编写 configure和 Makefile来完成的功能:

• 不需要特别多的功能
• 需要考虑移植的代价
• 随着GNU Coding Standards的改变需要及时升级配置文件

而 GNU Autotools 就把这些工作自己悄悄的做掉了,只需要关注你的代码即可。

2.4 经典Hello World小程序


本节中我们首先重新从头创建 amhello-1.0软件包,然后介绍下configure.acMakefile.am的含义。

2.4.1 创建 amhello-1.0.tar.gz


接下来我们从头创建 amhello-1.0.tar.gz ,这个压缩包很简单,我们只需要准备5个文件即可。
在一个空目录中创建以下文件:

src/main.c:程序 hello的源文件,我们把这个文件保存在 src/子目录,这样方便以后添加诸如man/data/的文件夹。

1
2
3
4
5
6
7
8
9
10
~/amhello % cat src/main.c
#include <config.h>
#include <stdio.h>
int
main (void)
{
puts ("Hello World!");
puts ("This is " PACKAGE_STRING ".");
return 0;
}

README:包含一些说明文档

1
2
3
~/amhello % cat README
This is a demonstration package for GNU Automake.
Type 'info Automake' to read the Automake manual.

Makefile.amsrc/Makefile.am包含Automake的指令

1
2
3
4
5
6
7
~/amhello % cat src/Makefile.am
bin_PROGRAMS = hello
hello_SOURCES = main.c
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
~/amhello % cat Makefile.am
SUBDIRS = src
dist_doc_DATA = README

configure.ac包含创建 configure脚本的Autoconf指令

1
2
3
4
5
6
7
8
9
10
~/amhello % cat configure.ac
AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
src/Makefile
])
AC_OUTPUT

准备好这些文件就可以运行 Autotools 了,使用 autoreconf指令:

1
2
3
4
5
~/amhello % autoreconf --install
configure.ac: installing './install-sh'
configure.ac: installing './missing'
configure.ac: installing './compile'
src/Makefile.am: installing './depcomp'

搞定,此时就完成了编译工作。

除了提示的添加的文件, autoreconf还会创建另外4个文件: configure, config.h.in,
Makefile.insrc/Makefile.in. configure将使用后面的3个文件来创建 config.h, Makefilesrc/Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
~/amhello % ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating config.h
config.status: executing depfiles commands

此时我们就可以看到已经创建了 Makefile, src/Makefileconfig.h

1
2
3
4
5
6
7
8
9
10
11
~/amhello % make
...
~/amhello % src/hello
Hello World!
This is amhello 1.0.
~/amhello % make distcheck
...
=============================================
amhello-1.0 archives ready for distribution:
amhello-1.0.tar.gz
=============================================

autoreconf只需要运行一次即可,在构建后环境,后续更改了 Makefile.amconfigure.ac,在 make的时候会自动重建需要的依赖。

autoreconfautoconf, automake等一些列命令的集合

其中 autoconf负责从configure.ac创建 configure

automakeconfigure.acMakefile.am创建 Makefile.in

2.4.2 configure.ac 配置详解


看看文件 configure.ac

 AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign])
 AC_PROG_CC
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([
  Makefile
  src/Makefile
 ])
 AC_OUTPUT

这个文件被 autoconf(创建 configure) 和automake(创建 Makefile.ins)读取。这个文件包含一系列的M4宏。

AC_开头的是Autoconf 宏,以 AM_开头的是Automake 宏。

configure.ac的前两行用于初始化 Autoconf 和Automake。 AC_INIT的参数为软件包,版本及联系邮箱(可以使用 ./configure --help来看到)。

记得邮箱要使用自己的

AM_INIT_AUTOMAKE的参数为automake的选项,比如 -Wall-Werror为打开所有的警告和错误报告。 foreign选项告诉Automake这个包不遵从GNU标准。GNU包需要包含ChangeLog, AUTHORS等文件。如果我们不希望
automake抱怨就需要加上这个选项。

AC_PROG_CC可以指定 configure脚本的C编译器。文件src/Makefile.in将使用这里定义的编译器来编译生成hello,当 configuresrc/Makefile.in创建src/Makefile的时候会用到。

选项 AC_CONFIG_HEADERS([config.h])将使 configure脚本创建一个文件config.h用于汇总configure.ac文件中所有定义的宏。在我们的例子中国呢,AC_INIT宏已经定义了一部分了。比如下面这个例子:

1
2
3
4
5
6
7
...
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "bug-automake@gnu.org"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "amhello 1.0"
...

我们可能注意到文件src/main.c 包含头文件config.h,这样就可以使用 PACKAGE_STRING

AC_CONFIG_FILES宏定义了configure需要从 *.in模版生成的文件。Automake将遍历需要的 Makefile.am文件,所以如果新增了一个文件夹,一定要记得添加 Makefile到这个列表。

AC_OUTPUT行为结束命令。

2.4.3 amhelloMakefile.am配置详解


接下来我们看看文件 src/Makefile.am,这个文件包含Automake编译安装 hello的指令。

bin_PROGRAMS = hello
hello_SOURCES = main.c

Makefile.amMakefile有相同的语法。automake在处理Makefile.am的时候,会拷贝整个文件到 Makefile.in

_PROGRAMS结尾的变量为 Makefiles将要编译的程序。还有其他后缀变量,比如 _SCRIPTS, _DATA, _LIBRARIES等,参考后面的章节。

bin_PROGRAMSbin部分表示 automake将把该程序安装到BINDIR。

注意此处省略了dir

程序需要从源码编译,所以对于每一个以 _PROGRAMS结尾的PROG都需要有一个变量为 PROG_SOURCES,后面将列出所有编译时需要的源文件。

Automake也会通过这个源码文件在打包 make dist的时候一起发布。

最后我们看看顶层目录的文件Makefile.am

SUBDIRS = src
dist_doc_DATA = README

SUBDIRS是一个特殊的变量,用来列出在处理当前目录之前 make需要遍历的目录。

dist_doc_DATA = README将会把文件 README发布和安装到DOCDIR。以 _DATA结尾的变量默认情况下在 make dist发布时是不包含的,所以我们新增了前缀dist_

GNU Automake 版本(version 1.16.1, 26 February 2018)

Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover texts,
and with no Back-Cover Texts. A copy of the license is included in
the section entitled “GNU Free Documentation License.”

简介

Automake从文件Makefile.am中自动生成Makefile.in

Makefile.am基本由make的一系列变量定义组成。

按照GNU Makefile的标准生成 ‘Makefile.in’十分复杂,而Automake就是希望解放这个工作。

linux服务器git pull/push时不输入密码

step1

先cd到根目录,执行git config –global credential.helper store命令

1
[root@iZ25mi9h7ayZ ~]# git config --global credential.helper store

step2

执行之后会在.gitconfig文件中多加红色字体项

1
2
3
4
5
[user]
name = shaoguangleo
email = xxxx@xxxx.com
[credential]
helper = store

step3

之后cd到项目目录,执行git pull命令,会提示输入账号密码。输完这一次以后就不再需要,并且会在根目录生成一个.git-credentials文件

1
2
3
4
5
[~/gittest]# git pull
Username for 'https://github.com': xxxx@xxxx.com
Password for 'https://shaoguangleo@github.com':
[~]# cat .git-credentials
https://Username:Password@github.com

step4

之后pull/push代码都不再需要输入账号密码了~

Linux查看内存信息(型号、大小、速率等)

安装工具dmidecode

1.查看内存槽及内存条

1
$ sudo dmidecode -t memory

2.查看内存的插槽数,已经使用多少插槽.每条内存多大

1
$ sudo dmidecode -t memory | grep Size

3.查看服务器型号、序列号

1
$ sudo dmidecode | grep "System Information" -A9 | egrep "Manufacturer|Product|Serial"

argsparse是python的命令行解析的标准模块,内置于python,不需要安装。
这个库可以让我们直接在命令行中就可以向程序中传入参数并让程序运行。

argparse定义四个步骤

  1. 导入argparse包 ——import argparse
  2. 创建一个命令行解析器对象 ——创建 ArgumentParser() 对象
  3. 给解析器添加命令行参数 ——调用add_argument() 方法添加参数
  4. 解析命令行的参数 ——使用 parse_args() 解析添加的参数

举个例子如下:

.. literalinclude:: ../../src/python-argparse.py

默认输出如下所示:

.. code::bash

$ python src/python-argparse.py
Namespace(name=’Zhang San’, age=18)
Name : Zhang San Age : 18

sgguo@LENOVO-P71-LEO MINGW64 ~/OneDrive/mycode/3-Minutes-Programming/python (master)
$ python src/python-argparse.py –help
usage: python-argparse.py [-h] [–name NAME] [–age AGE]

Demo of argparse

optional arguments:
-h, –help show this help message and exit
–name NAME
–age AGE

Python 编写一个自己的包

这个教程将会指导你开发一个属于自己的python包,
还包含如何添加必要的文件以及包的结构,
最后说说如何编译并上传该文件。

简单示例

假定工程的名称为:example_pkg,需要创建下列目录结构:

1
2
3
packaging_tutorial/
example_pkg/
__init__.py

下面所有的操作均在目录中packaging_tutorial进行。

example_pkg/init.py is required to import the directory as a package, and can simply be an empty file.

创建package文件

标准package起始最好包含以下文件,

1
2
3
4
5
6
7
packaging_tutorial/
example_pkg/
__init__.py
tests/
setup.py
LICENSE
README.md

创建test文件夹

tests/主要用来存放unit测试文件,此时先留空。

创建 setup.py

setup.py文件用于编译,内容主要包含package的名字、版本、描述等等信息。

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import setuptools

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="example-pkg-YOUR-USERNAME-HERE", # Replace with your own username
version="0.0.1",
author="Example Author",
author_email="author@example.com",
description="A small example package",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/pypa/sampleproject",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)

setup() 的几个最必须的参数如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name is the distribution name of your package. This can be any name as long as only contains letters, numbers, _ , and -. It also must not already be taken on pypi.org. Be sure to update this with your username, as this ensures you won’t try to upload a package with the same name as one which already exists when you upload the package.

version is the package version see PEP 440 for more details on versions.

author and author_email are used to identify the author of the package.

description is a short, one-sentence summary of the package.

long_description is a detailed description of the package. This is shown on the package detail package on the Python Package Index. In this case, the long description is loaded from README.md which is a common pattern.

long_description_content_type tells the index what type of markup is used for the long description. In this case, it’s Markdown.

url is the URL for the homepage of the project. For many projects, this will just be a link to GitHub, GitLab, Bitbucket, or similar code hosting service.

packages is a list of all Python import packages that should be included in the distribution package. Instead of listing each package manually, we can use find_packages() to automatically discover all packages and subpackages. In this case, the list of packages will be example_pkg as that’s the only package present.

classifiers gives the index and pip some additional metadata about your package. In this case, the package is only compatible with Python 3, is licensed under the MIT license, and is OS-independent. You should always include at least which version(s) of Python your package works on, which license your package is available under, and which operating systems your package will work on. For a complete list of classifiers, see https://pypi.org/classifiers/.

创建README.md

创建 README.md ,写上你准备写入的内容:

1
2
3
4
5
# Example Package

This is a simple example package. You can use
[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

创建LICENSE

比如使用MIT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Copyright (c) 2018 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

生成发布包

接下来我们生成发布的软件包

1
$ python3 setup.py sdist bdist_wheel

这个命令会生成两个文件:

1
2
3
dist/
example_pkg_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
example_pkg_YOUR_USERNAME_HERE-0.0.1.tar.gz

其中 tar.gz 文件为源码,.whl为编译的包。

比较新的pip可以直接按照whl格式的编译包。

一般而言,我们都需要上次源码以及编译包。

参考

代码参考 https://www.github.com/shaoguangleo/atas/python

锁屏利器Nearlock

给大家推荐一款Mac的锁屏利器Nearlock。

这个软件的slogan是Lock and unlock your Mac with your iPhone

不过这个有个硬性条件,就是需要同时拥有Mac和iPhone,Mac可以是MBP、MB、iMac、iWatch等系列产品。

Nearlock使用比较方便,软件通过蓝牙来判断Mac和iPhone的距离,从而通过设置来开启或者锁定Mac,这个对于临时有急事而又来不及锁屏的哥们来说还是很不错的,特别是进入办公室以后,做到座位上,不用任何操作,自动解锁,进入系统,OK,开始干活。

Nearlock有免费版,不过Pro版支持后台运行,喜欢就入手吧。

Mac OSX 安装Python3和pip3

Python2即将在2020年迎来它最后的时光,
或许现在你应该或者必须切换到Python3版本了。

下面简单说一下在Mac OSX上安装Python3和pip3的步骤

安装 python3

打开Python的 (官网)[https://www.python.org/] 下载python3的 OS X 版本,
应该是一个pkg文件。
双击安装,默认情况下会把pip3也安装上。

Python的版本可以通过下面的命令来查看。

1
$python3 --version

Install pip3:

pip3也可以通过下面的方式来安装:

1
2
$ curl https://pip.pypa.io/en/stable/installing/get-pip.py
$ python3 get-pip.py

可以通过下面的命令来确定pip3是否安装完成

1
$ which pip3

Python 格式化字符串

Python的格式化输出方法很多,相比较于C还是有很多便捷的方面。
下面开始说说。

格式化操作符 %

%是Python风格的字符串格式化字符串,与C语言中的printf函数的字符串类似。

下面是一些格式化的集合

格式化符号 说明
%c 转换成字符串
%r 优先使用repr函数进行字符串转换
%s 优先用str函数进行字符串转换
%d %i 转成有符号十进制
%u 转成无符号十进制
%o 转成无符号八进制
%x %X 转成无符号十六进制,x/X表示小大写
%e %E 转成科学计数法,e/E控制输出e/E
%f %F 转成浮点数
%g %G %e与%f的简写
%% 输出%

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = 'x'
string = 'hello world\n'
n = 12
f = 3.1415

print ('%c' % a)
print ('%r' % string)
print ('%s' % string)
print ('%d' % n)
print ('%i' % n)
print ('%u' % n)
print ('%o' % n)
print ('%x' % n)
print ('%X' % n)
print ('%f' % f)
print ('%F' % f)
print ('%e' % f)
print ('%E' % f)
print ('%g' % f)
print ('%G' % f)

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
x
'hello world\n'
hello world

12
12
12
14
c
C
3.141500
3.141500
3.141500e+00
3.141500E+00
3.1415
3.1415

这里比较需要留意的是str与repr两个内建函数之间的差异。

格式化操作符辅助符号

如果希望输出的时候美化输出,通常下面的一些辅助符号会起到比较好的作用。

辅助符 作用
* 定义宽度或者小数点精度
- 左对齐
+ 在正数前面加上加号+
# 在八进制前面显示0,十六进制前面加上0x或者0X,取决于用的是x还是X
0 显示的数字前面填充0而不是默认的空格
(var) 映射变量,通常用来吹了字段类型的参数
m.n m是显示的最小总宽度,n表示的是小数点后面的位数

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
n = 1234
f = 3.1415926
students = [{'name': 'Han Meimei', 'age': 17}, {'name': 'Li Lei', 'age': 18}, {'name': 'Wei Hua', 'age': 17}]

print('%d => hex => %x' % (n, n))
print('%d => hex => %X' % (n, n))
print('%d => hex => %#x' % (n, n))
print('%d => hex => %#X' % (n, n))
print('value f is %f' % f)
print('value f is %.4f' % f)
print('name: %10s, age: %10d' % (students[0]['name'], students[0]['age']))
print('name: %-10s, age: %-10d' % (students[1]['name'], students[1]['age']))
print('name: %*s, age: %0*d' % (10, students[1]['name'], 10, students[1]['age']))

for student in students:
print('%(name)s is %(age)d years old' % student)

输出结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
1234 => hex => 4d2
1234 => hex => 4D2
1234 => hex => 0x4d2
1234 => hex => 0X4D2
value f is 3.141593
value f is 3.1416
name: Han Meimei, age: 17
name: Li Lei , age: 18
name: Li Lei, age: 0000000018
Han Meimei is 17 years old
Li Lei is 18 years old
Wei Hua is 17 years old

字符串模板

示例如下:

1
2
3
4
5
6
7
from string import Template

s = Template('Hi, $name! $name is $age years old.')
print(s.substitute(name='Han Meimei', age='17'))

hmm = {'name' : 'Han Meimei', 'age': 17}
print(s.substitute(hmm))

输出结果如下:

1
2
Hi, Han Meimei! Han Meimei is 17 years old.
Hi, Han Meimei! Han Meimei is 17 years old.

字符串内建函数format

从Python2.6开始,新增了一种格式化字符串的字符串str.format,通过这个函数可以对字符串进行格式化处理。在format函数中,使用{}符号来当做格式化操作符。

示例如下:

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
30
31
32
33
34
35
36
37
38
# 位置参数

print('{0} is {1} years old.'.format('lily', 18))
print('{} is {} years old.'.format('lily', 18))
print('Hi {0}. {0} is {1} years old.'.format('lily', 18))

# 关键字参数
print('{name} is {age} years old'.format(name='lily', age=18))

# 下标参数
lily = ['lily', 18]
print('{0[0]} is {0[1]} years old'.format(lily))

# 填充与对齐
# ^<>分别表示居中、左对齐、右对齐,后面带宽度
# :后面带填充的字符,只能是一个字符,不知道的的话用空格填充

print('{:>8}'.format('3.14'))
print('{:<8}'.format('3.14'))
print('{:^8}'.format('3.14'))
print('{:0>8}'.format('3.14'))
print('{:a>8}'.format('3.14'))

# 浮点数精度
print('{:.4f}'.format(3.1415926))
print('{:0>10.4f}'.format(3.1415926))

# 进制
# b/d/o/x分别表示二进制、十进制、八进制、十六进制
print('{:b}'.format(12))
print('{:d}'.format(12))
print('{:o}'.format(12))
print('{:x}'.format(12))
print('{:#x}'.format(12))
print('{:#X}'.format(12))

# 千位分隔符
print('{:,}'.format(1230000000))

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
lily is 18 years old.
lily is 18 years old.
Hi lily. lily is 18 years old.
lily is 18 years old
lily is 18 years old
3.14
3.14
3.14
00003.14
aaaa3.14
3.1416
00003.1416
1100
12
14
c
0xc
0XC
1,230,000,000