使用autotools自动生成Makefile并在此之上使用dh-make生成可发布的deb程序包(详解)...

一、前言

本文将介绍如何使用autotools生成一个Makefile文件,并在此基础上使用dh-make和debuild生成一个可发布的deb程序包,这也是我们在Linux下开发应用程序以及想要发布应用程序需要做的。

无论是在Linux还是在Unix环境中,make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件,我们都经常要用到make或 make install。利用make工具,我们可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的应用程序,使用make和 Makefile工具就可以轻而易举的理顺各个源文件之间纷繁复杂的相互关系。其中Makefile 文件是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有的文件都需要重新编译,Makefile中纪录有文件的信息,在make时会决定在链接的时候需要重新编译哪些文件。


  Makefile的基本结构不是很复杂,但当一个程序开发人员开始写Makefile时,经常会怀疑自己写的是否符合惯例,而且自己写的Makefile经常和自己的开发环境相关联,当系统环境变量或路径发生了变化后,Makefile可能还要跟着修改。所以 手动编写Makefile,对任何程序员都是一场挑战 。幸而有GNU 提供的Autoconf及Automake这两套工具可以然我们自动生成Makefile。

  使用automake,程序开发人员只需要写一些简单的含有预定义宏的文件,由autoconf根据这个宏文件生成configure,由automake根据另一个宏文件生成Makefile.in,再使用configure依据Makefile.in来生成一个符合惯例的Makefile。本文将介绍如何利用 GNU Autotools工具来协助我们自动产生 Makefile文件,生成Makefile文件后,我们将接着介绍如何使用dh-make和debuild创建一个Debian的安装包文件(deb)。这个deb文件可以拷贝到别的电脑上使用dpkg安装使用(如果足够好,可以发布!)。

这是使用autotools生成Makefile文件的大体步骤。



二、环境安装

我使用的是Ubuntu 13.04(32bit),使用apt-get 安装以下工具: automake,dh-make ,devscripts。
使用 apt-get install automake 将安装 autoconf{a} automake autotools-dev{a} 三个包。
使用 apt-get install dh-make 将安装 debhelper dh-make html2text三个包。
使用 apt-get install devscripts ,这个是使用debuild所需要的。




三、具体步骤

3.1、起步,创建hello.c

在当前目录下创建一个名为hello的子目录。进入文件夹并新建一个标准的Hello World的C代码hello.c
#include <stdio.h>
int main(int argc, char ** argv){
printf("hello,world\n");
return 0;
}
此时,文件夹下只有一个hello.c文件,


3.2、创建一个 Makefile.am 文件

automake根据configure.in中的宏并在perl的帮助下把Makefile.am转成Makefile.in文件。Makefile.am 文件定义所要产生的目标。我们要填写的 Makefile.am 内容为以下两句:
bin_PROGRAMS=beep // bin_PROGRAMS:定义要产生的可执行程序的文件名
beep_SOURCES=hello.c // beep_SOURCES:定义“beep”这个可执行程序所需要的原始文件。如果“beep”这个程序是由多个原始文件产生的,必须把它所用到的所有原始文件都列出来,并以空白符隔开。假设“beep”还需要“hello.c”、“main.c”、“hello.h”3个文件,则定义beep_SOURCES= hello.c main.c hello.h。如果定义多个可执行文件,则对每个可执行程序都要定义相应的filename_SOURCES,其中filename为要生成的可执行程序的文件名。


所以,beep 可以替换为你想要生成的二进制可执行文件名(后面生成deb文件也是一样的名称),如果我最终我们生成的应用名为long.deb,上面两句就写成:
bin_PROGRAMS=long
long_SOURCES=hello.c
当前我们目录下只有:hello.c Makefile.am 两个文件
zhouyl@zhouyl:/tmp/hello$ vim Makefile.am
zhouyl@zhouyl:/tmp/hello$ ls
hello.c Makefile.am


3.3、执行autoscan命令

执行autoscan命令,会生成一个configure.scan文件,将configure.scan改名为configure.in
zhouyl@zhouyl:/tmp/hello$ autoscan
zhouyl@zhouyl:/tmp/hello$ ls
autoscan.log configure.scan hello.c Makefile.am
zhouyl@zhouyl:/tmp/hello$ mv configure.scan configure.in
zhouyl@zhouyl:/tmp/hello$ ls

autoscan.log configure.in hello.c Makefile.am


configure.in 文件的内容是一系列GNU m4 的宏,这些宏经autoconf处理后会变成检查系统特性的Shell脚本。configure.in文件中宏的顺序并没有特别的规定,但是每一个configure.in 文件必须以宏AC_INIT开头,以宏AC_OUTPUT结束。


3.4、打开configure.in并修改

打开configure.in文件我们会看到自动生成的configure.in(scan)包括以下内容:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69]) // 此行是描述需要的工具兼容性,如我们使用的是autotools工具版本是2.69,这个自动生成不要修改
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) // 此行是描述我们要生成的应用的信息,包括:应用名,版本号以及维护人邮箱(直译为反馈bug地址)。比如我们需要将此行修改成 AC_INIT([beep], [0.1], [reaper888@yeah.net])
//下面两行形容的是软件包的地址和名称,以便autotools开始工作
AC_CONFIG_SRCDIR([hello.c])

AC_CONFIG_HEADERS([config.h])


// 在这我们需要加入一行“ AM_INIT_AUTOMAKE ”,如果没有此行,在部分系统生成Makefile时会报错而且生成不了Makefile文件。
# Checks for programs.
AC_PROG_CC // 这句高速autotools使用默认的编译器和binutils,当然你也可以传入类似于“ AC_PROG_CC([gcc gcc-4.7]) ”的参数,我们不传参,使用默认即可

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
// 下面不变
AC_CONFIG_FILES([Makefile]) // 设置configure命令所要产生的文件。我们最终期望产生Makefile

AC_OUTPUT


所以,经过修改后,我们的configure.in文件是:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([beep], [0.1], [reaper888@yeah.net])
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE
# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT



3.5、 执行autoheader和aclocal命令

autoheader是用来映射头文件,aclocal用来设置所有的宏(执行aclocal会产生aclocal.m4文件,如果没有特别的要求,无需修改它。用 aclocal产生的宏将会提示automake如何动作。)。
zhouyl@zhouyl:/tmp/hello$ ls
autoscan.log configure.in hello.c Makefile.am
zhouyl@zhouyl:/tmp/hello$ autoheader
zhouyl@zhouyl:/tmp/hello$ ls
autom4te.cache autoscan.log config.h.in configure.in hello.c Makefile.am
zhouyl@zhouyl:/tmp/hello$ aclocal
zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure.in hello.c Makefile.am
zhouyl@zhouyl:/tmp/hello$


3.6、使用automake命令了:

zhouyl@zhouyl:/tmp/hello$ automake
configure.in:8: required file `./install-sh' not found
configure.in:8: `automake --add-missing' can install `install-sh'
configure.in:8: required file `./missing' not found
configure.in:8: `automake --add-missing' can install `missing'
Makefile.am: required file `./INSTALL' not found
Makefile.am: `automake --add-missing' can install `INSTALL'
Makefile.am: required file `./NEWS' not found
Makefile.am: required file `./README' not found
Makefile.am: required file `./AUTHORS' not found
Makefile.am: required file `./ChangeLog' not found
Makefile.am: required file `./COPYING' not found
Makefile.am: `automake --add-missing' can install `COPYING'
所以,根据提示,我们缺少 NEWS、README、AUTHORS、ChangeLog和COPYING,而使用automake --add-missing会生成COPYING,所以在此之前我们需要手动添加这几个文件:
zhouyl@zhouyl:/tmp/hello$ touch NEWS README AUTHORS ChangeLog
zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autom4te.cache ChangeLog configure.in Makefile.am README
AUTHORS autoscan.log config.h.in hello.c NEWS

注:这是我在演示如何使用autotools,如果是你真得要发布软件,请仔细填写这几个文件,而不是使用touch生成一个空文件。


现在我们可以使用automake --add-missing:
zhouyl@zhouyl:/tmp/hello$ automake --add-missing
configure.in:8: installing `./install-sh'
configure.in:8: installing `./missing'
Makefile.am: installing `./INSTALL'
Makefile.am: installing `./COPYING' using GNU General Public License v3 file
Makefile.am: Consider adding the COPYING file to the version control system
Makefile.am: for your code, to avoid questions about which license your project uses.
zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autom4te.cache ChangeLog configure.in hello.c install-sh Makefile.in NEWS
AUTHORS autoscan.log config.h.in COPYING INSTALL Makefile.am missing README
会发现,现在使用automake很顺利,而且生成了INSTALL、COPYING等文件。


3.7、使用autoconf

zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autom4te.cache ChangeLog configure.in hello.c install-sh Makefile.in NEWS
AUTHORS autoscan.log config.h.in COPYING INSTALL Makefile.am missing README
zhouyl@zhouyl:/tmp/hello$ autoconf
zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autom4te.cache ChangeLog configure COPYING INSTALL Makefile.am missing README
AUTHORS autoscan.log config.h.in configure.in hello.c install-sh Makefile.in NEWS
所以,我们可以看到,使用autoconf命令生成了configure。


3.8、./configure , make

接下来的工作无非就是使用configure,生成make文件:
zhouyl@zhouyl:/tmp/hello$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
……(a lot of cheaking)
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
zhouyl@zhouyl:/tmp/hello$ls
aclocal.m4 autoscan.log config.h.in configure depcomp install-sh Makefile.in README
AUTHORS ChangeLog config.log configure.in hello.c Makefile missing stamp-h1
autom4te.cache config.h config.status COPYING INSTALL Makefile.am NEWS


所以,使用./configure生成了Makefile、config.h和其他一些文件。


因为此时Makefile文件已经生成,所以我们可以使用make命令了:
zhouyl@zhouyl:/tmp/hello$ make
(CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/bash /tmp/hello/missing --run autoheader)
rm -f stamp-h1
touch config.h.in
cd . && /bin/bash ./config.status config.h
config.status: creating config.h
make all-am
make[1]: 正在进入目录 `/tmp/hello'
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c
mv -f .deps/hello.Tpo .deps/hello.Po
gcc -g -O2 -o beep hello.o
make[1]:正在离开目录 `/tmp/hello'
zhouyl@zhouyl:/tmp/hello$ ls // 使用make命令后,生成了二进制可执行文件,因为我们在上面已经指定,所以生成的可执行文件名不是hello而是beep
aclocal.m4 autoscan.log config.h config.log configure.in hello.c install-sh Makefile.in README
AUTHORS beep config.h.in config.status COPYING hello.o Makefile missing stamp-h1
autom4te.cache ChangeLog config.h.in~ configure depcomp INSTALL Makefile.am NEWS
dslab@Raring-Ringtail:/tmp/hello$ ./beep // 运行二进制可执行文件,得正确的执行结果
hello,world


分析一下可以发现,我们这一步的步骤大致是这样的:
Makefile.in -----+ +-> Makefile -----+-> make -> binary
src/Makefile.in -+-> ./configure -+-> src/Makefile -+

config.h.in -----+ +-> config.h -----+


其实此时,在当前目录下有Makefile文件,我们可以做的工作有:
* make all:产生设定的目标,即生成所有的可执行文件。使用make也可以达到此目的。
* make clean:删除之前编译时生成的可执行文件及目标文件(形如*.o的中间文件)。
* make distclean:除了删除可执行文件和目标文件以外,把configure所产生的 Makefile文件也清除掉。通常在发布软件前执行该命令。
* make install:将使用make all或make命令产生的可执行文件以软件的形式安装到系统中。若使用bin_PROGRAMS宏,程序将会被安装到 /usr/local/bin下,否则安装到预定义的目录下。
* make dist:将程序和相关的文档包装为一个压缩文档以供发布。执行完该命令,在当前目录下会产生一个名为PACKAGE-VERSION.tar.gz的文件。PACKAGE 和 VERSION 这两个参数是来自configure.in文件中的AM_INIT_AUTOMAKE(PACKAGE,
VERSION)。如在上个例子中执行make dist命令,会产生名为“hello-1.0.tar.gz”的文件。
* make distcheck:与make dist类似,但是加入了检查包装以后的压缩文件是否正常。

======================= 下面步骤是生成deb程序包,Debian系专属 ==================================

3.9、make dist 提取源程序包

下面,我们做的可是高端大气上档次的工作 -- 生成可发布的Debian应用包 -- deb文件。(Debian系Linux专属哦)
首先,我们使用“ make dist ”命令,make dist将程序和相关的文档包装为一个压缩文档以供发布。从此,你将再也不想手动写Makefile!!
zhouyl@zhouyl:/tmp/hello$ make dist
if test -d "beep-0.1"; then find "beep-0.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "beep-0.1" || { sleep 5 && rm -rf "beep-0.1"; }; else :; fi
test -d "beep-0.1" || mkdir "beep-0.1"
test -n "" \
|| find "beep-0.1" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec /bin/bash /tmp/hello/install-sh -c -m a+r {} {} \; \
|| chmod -R a+r "beep-0.1"
tardir=beep-0.1 && ${TAR-tar} chof - "$tardir" | GZIP=--best gzip -c >beep-0.1.tar.gz
if test -d "beep-0.1"; then find "beep-0.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "beep-0.1" || { sleep 5 && rm -rf "beep-0.1"; }; else :; fi
zhouyl@zhouyl:/tmp/hello$ ls
aclocal.m4 autoscan.log config.h config.status COPYING install-sh Makefile.in README
AUTHORS beep-0.1.tar.gz config.h.in configure hello.c Makefile missing stamp-h1
autom4te.cache ChangeLog config.log configure.in INSTALL Makefile.am NEWS
我们可以看到,目录里多了个beep-0.1.tar.gz文件。这就是我们后续工作的核心


3.10、切换新的工作目录:

zhouyl@zhouyl:/tmp/hello$ mkdir ../hello_deb
zhouyl@zhouyl:/tmp/hello$ cd ../hello_deb/
zhouyl@zhouyl:/tmp/hello_deb$ cp ../hello/beep-0.1.tar.gz ./
zhouyl@zhouyl:/tmp/hello_deb$ ls
beep-0.1.tar.gz
zhouyl@zhouyl:/tmp/hello_deb$ tar -xzf beep-0.1.tar.gz
zhouyl@zhouyl:/tmp/hello_deb$ ls
beep-0.1 beep-0.1.tar.gz
zhouyl@zhouyl:/tmp/hello_deb$ cd beep-0.1/
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ ls
aclocal.m4 ChangeLog configure COPYING install-sh Makefile.in NEWS
AUTHORS config.h.in configure.in INSTALL Makefile.am missing README


3.11、使用dh_make创建debian文件目录:

为了创建一个Debian包,我们首先要创建一个Debian控制文件,所以我们需要先配置dh_make,最基本的我们需要先配置如下两个选项(当然,还有其他更多的选项,现在我们就配置最简单的):
export DEBFULLNAME="your name"
export DEBEMAIL="a@b.com"
在此我们需要配置Debian包的维护人名称和邮箱,比如我就可以写:
export DEBFULLNAME="Zhouyl"

export DEBEMAIL="reaper888@yeah.net"


做好上述步骤后,我们可以使用“ dh_make --single -copyright=gpl3 -f ../beep-0.1.tar.gz ” ,会提示一些确认信息,其中需要选择"single" (s)型包。
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ export DEBFULLNAME="Zhouyl"
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ export DEBEMAIL="reaper888@yeah.net"
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ dh_make --single -copyright=gpl3 -f ../beep-0.1.tar.gz
Maintainer name : Zhouyl
Email-Address : reaper888@yeah.net
Date : Mon, 14 Oct 2013 10:03:41 +0800
Package Name : beep
Version : 0.1
License : gpl3
Type of Package : Single
Hit <enter> to confirm:
Done. Please edit the files in the debian/ subdirectory now. beep
uses a configure script, so you probably don't have to edit the Makefiles.


3.12、编辑debian/control文件

现在我们ls下当前目录,会发现当前目录下多了一个debian目录,我们cd进debian目录,打开control文件:
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ cd debian/
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1/debian$ vim control
----- 下面是control内容
Source: beep // 程序包名
Section: unknown // 使用 unknown 或者misc 都可以,建议使用 misc
Priority: extra
Maintainer: Zhouyl <reaper888@yeah.net>
Build-Depends: debhelper (>= 8.0.0), autotools-dev
Standards-Version: 3.9.4
Homepage: <insert the upstream URL, if relevant> // 如果你的程序有官方网站,在此编辑上网站地址
#Vcs-Git: git://git.debian.org/collab-maint/beep.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/beep.git;a=summary


Package: beep
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>





3.13、使用debuild生成deb应用包

cd ..进入beep-0.1目录,使用debuild命令
dslab@Raring-Ringtail:/tmp/hello_deb/beep-0.1/debian$ cd ..
dslab@Raring-Ringtail:/tmp/hello_deb/beep-0.1$ debuild
dpkg-buildpackage -rfakeroot -D -us -uc
dpkg-buildpackage: 源码包 beep
dpkg-buildpackage: 源码版本 0.1-1
dpkg-buildpackage: 源码修改者 Zhouyl <reaper888@yeah.net>
dpkg-source --before-build beep-0.1
dpkg-buildpackage: 主机架构 i386
……
gpg: “Zhouyl <reaper888@yeah.net>”已跳过:私钥不可用
gpg: /tmp/debsign.rFNS3UeK/beep_0.1-1.dsc: clearsign failed: 私钥不可用
debsign: gpg error occurred! Aborting....
debuild: fatal error at line 1278:
running debsign failed
所以,此时因为需要gpg密钥,而当前还没设置(为不可用的),所以遇到错误并退出,我们使用 gpg --gen-key 命令:
zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$ gpg --gen-key
gpg (GnuPG) 1.4.12; Copyright (C) 2012 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

请选择您要使用的密钥种类:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (仅用于签名)
(4) RSA (仅用于签名)
您的选择?
RSA 密钥长度应在 1024 位与 4096 位之间。
您想要用多大的密钥尺寸?(2048)
您所要求的密钥尺寸是 2048 位
请设定这把密钥的有效期限。
0 = 密钥永不过期
<n> = 密钥在 n 天后过期
<n>w = 密钥在 n 周后过期
<n>m = 密钥在 n 月后过期
<n>y = 密钥在 n 年后过期
密钥的有效期限是?(0)
密钥永远不会过期
以上正确吗?(y/n) y

您需要一个用户标识来辨识您的密钥;本软件会用真实姓名、注释和电子邮件地址组合
成用户标识,如下所示:
“Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>”

真实姓名: Zhouyl
电子邮件地址: reaper888@yeah.net
注释: hello for test
您选定了这个用户标识:
“Zhouyl (hello for test) <reaper888@yeah.net>”

更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? O
您需要一个密码来保护您的私钥。

我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动
鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。

随机字节不够多。请再做一些其他的琐事,以使操作系统能搜集到更多的熵!
(还需要278字节)




^[[A^[[A^[[B+++++
...+++++
我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动
鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。
........+++++
...+++++
gpg: /home/dslab/.gnupg/trustdb.gpg:建立了信任度数据库
gpg: 密钥 A5318445 被标记为绝对信任
公钥和私钥已经生成并经签名。

gpg: 正在检查信任度数据库
gpg: 需要 3 份勉强信任和 1 份完全信任,PGP 信任模型
gpg: 深度:0 有效性: 1 已签名: 0 信任度:0-,0q,0n,0m,0f,1u
pub 2048R/A5318445 2013-10-14
密钥指纹 = CD58 76C8 BE9C 242E ADEA F277 FE5D 11BB A531 8445
uid Zhouyl (hello for test) <reaper888@yeah.net>
sub 2048R/0FCA8EE0 2013-10-14

zhouyl@zhouyl:/tmp/hello_deb/beep-0.1$


在使用gpg --gen-key创建密钥时,使用默认即可,在需要传入姓名邮箱时你输入自己的信息即可,如果在下面运行时遇到我上述错误时“ 我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。 ”(英文系统为:Not enough random bytes available. Please do some other work to give the OS a chance to collect more entropy! (Need 284 more bytes)),不要惊慌,因为创建密钥时为了提高安全等级,会需要从系统中的随机数熵池中选择随机数熵从而生成足够好的密钥,从而达到更好的加密效果(我们的Linux中使用所有的操作作为随机数熵的源,比如说键盘输入、鼠标移动以及网卡收包等,这些都是很随机的,所以当前报错随机熵不够,我们只需要手动添加随机熵即可,比如说多移动鼠标,多敲打键盘,最有效的方法是:打开另一个终端,使用“ find / ” 命令(多开几个会更快),这些会很快的添加随机数熵池,上面创建密钥会很快就继续进行)。


此时,我们继续使用debuild创建deb程序包即可。
zhouyl@zhouyl:/tmp/hello_deb/$ ls
beep-0.1 beep_0.1-1.dsc beep_0.1-1_i386.changes beep_0.1.orig.tar.gz

beep_0.1-1.debian.tar.gz beep_0.1-1_i386.build beep_0.1-1_i386.deb beep-0.1.tar.gz



=====================
部分引用自:
【1】http://www.cnblogs.com/phinecos/archive/2008/11/27/1342381.html
【2】http://www.ibm.com/developerworks/cn/linux/l-makefile/
【3】http://www.yesky.com/120/1865620.shtml

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值