makepkg 是 slackware 中用来制作软件包的工具, 中文注释的代码如下:
#!/bin/sh# 检查 tar 的版本 TAR=tar-1.13 umask 022 $TAR --help 1> /dev/null 2> /dev/null if [ ! $? = 0 ]; then TAR=tar fi if [ ! "`LC_MESSAGES=C $TAR --version`" = "tar (GNU tar) 1.13Copyright (C) 1988, 92,93,94,95,96,97,98, 1999 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.Written by John Gilmore and Jay Fenlason." ]; then echo "WARNING: pkgtools are unstable with tar > 1.13." echo " You should provide a \"tar-1.13\" in your \$PATH." sleep 5 fi# 这个函数读取一个文件, 将文件中记录的符号链接及对应的目标逐行读取出来, # 以产生建立符号链接的命令 # 所读取的文件的内容格式为: 链接名 -> 链接目标名 # 详细情况可以参考后面使用此函数的部分. make_install_script() { # 逐行处理 COUNT=1 LINE="`sed -n "$COUNT p" $1`" while [ ! "$LINE" = "" ]; do # 取出链接名, 得到其所在目录(LINKGOESIN) # 这个地方并没有考虑到一个比较少见的情况: # 如果一个链接名中含有空格, # 那么这里的 LINKGOESIN 和下面的 LINKNAMEIS, LINKPOINTSTO 都会不正确 LINKGOESIN="`echo "$LINE" | cut -f 1 -d " "`" LINKGOESIN="`dirname $LINKGOESIN`" # 取出链接名, 得到其文件名(LINKNAMEIS) LINKNAMEIS="`echo "$LINE" | cut -f 1 -d ' '`" LINKNAMEIS="`basename "$LINKNAMEIS"`" # 获得链接的目标 LINKPOINTSTO="`echo "$LINE" | cut -f 3 -d ' '`" # 生成用于产生符号链接的 shell 命令, 以便存入 install/doinst.sh echo "( cd $LINKGOESIN ; rm -rf $LINKNAMEIS )" echo "( cd $LINKGOESIN ; ln -sf $LINKPOINTSTO $LINKNAMEIS )" # 处理下一行 COUNT=`expr $COUNT + 1` LINE="`sed -n "$COUNT p" $1`" done }# 使用帮助 # -l, --linkadd 是否把符号链接的处理放到 install/doinst.sh 中 # -p, --prepend 如果已存在 install/doinst.sh, 把处理符号链接的命令放到 # 已存在内容的前面 # -c, --chown 改变文件属主和访问权限 usage() { cat << EOFUsage: makepkg package_name.tgzMakes a Slackware compatible "*.tgz" package containing the contents of the current and all subdirectories. If symbolic links exist, they will be removed and an installation script will be made to recreate them later. This script will be called "install/doinst.sh". You may add any of your own ash-compatible shell scripts to this file and rebuild the package if you wish.options: -l, --linkadd y|n (moves symlinks into doinst.sh: recommended) -p, --prepend (prepend rather than append symlinks to an existing doinst.sh. Useful to link libraries needed by programs in the doinst.sh script) -c, --chown y|n (resets all permissions to root:root 755 - not generally recommended)If these options are not set, makepkg will prompt as appropriate. EOF }TMP=/tmp# 参数处理 while [ 0 ]; do # 检查是否用参数指定了 linkadd if [ "$1" = "--linkadd" -o "$1" = "-l" ]; then if [ "$2" = "y" ]; then LINKADD=y elif [ "$2" = "n" ]; then LINKADD=n else usage exit 2 fi shift 2 # 检查是否用参数指定了 chown elif [ "$1" = "--chown" -o "$1" = "-c" ]; then if [ "$2" = "y" ]; then CHOWN=y elif [ "$2" = "n" ]; then CHOWN=n else usage exit 2 fi shift 2 # 检查是否用参数指定了 prepend elif [ "$1" = "-p" -o "$1" = "--prepend" ]; then PREPEND=y shift 1 # 检查是否有 -h, -H, --help, 如果有, 则显示帮助信息, 然后退出. elif [ "$1" = "-h" -o "$1" = "-H" -o "$1" = "--help" -o $# = 0 ]; then usage exit 0 else break fi doneecho echo "Slackware package maker, version 2.1." # 根据给定的文件名来提取存放位置及包文件名 PACKAGE_NAME=$1 TARGET_NAME="`dirname $PACKAGE_NAME`" PACKAGE_NAME="`basename $PACKAGE_NAME`" TAR_NAME="`basename $PACKAGE_NAME .tgz`" echo echo "Searching for symbolic links:" # 创建临时文件, 使用 mktemp 以避免已存在文件的问题 INST=`mktemp $TMP/makepkg.XXXXXX` # 查指符号链接, 以便产生 "install/doinst.sh" # 先是用 find . -type l 来查找当前目录下的符号链接 # 然后用 ls 显示出来, 限定 time style 利于后面的 cut 来进行控制 # 这里的 ls 命令需要 coreutils-5.0 或者以上的版本 # 后面的 while read ... done 其实是和 installpkg 中的 crunch 函数是一样的 # 不过此处没有把它放到函数里面去. # cut -f 8- -d ' ' 是以一个空格为界, 取第 8 段及之后的部分: # ./链接名 -> 链接目标 # 然后使用 cut -b3- 来去掉前 2 个字节(./) find . -type l -exec ls -l --time-style=long-iso {} \; | while read foo ; do echo $foo ; done | cut -f 8- -d ' ' | cut -b3- | tee $INST if [ ! "`cat $INST`" = "" ]; then echo echo "Making symbolic link creation script:" # 产生生成符号链接的命令, 并存入 doinst.sh(不是 install/doinst.sh) make_install_script $INST | tee doinst.sh fi echo # 存在符号链接时询问是否建立安装脚本(处理符号链接的命令) if [ ! "`cat $INST`" = "" ]; then # 如果存在 install/doinst.sh, 则询问是否将产生的安装脚本添加到已经存在的 install/doinst.sh 中 if [ -r install/doinst.sh ]; then echo "Unless your existing installation script already contains the code" echo "to create these links, you should append these lines to your existing" echo "install script. Now's your chance. :^)" echo echo "Would you like to add this stuff to the existing install script and" echo -n "remove the symbolic links ([y]es, [n]o)? " # 不存在 install/doinst.sh, 则是询问是否产生安装脚本 else echo "It is recommended that you make these lines your new installation script." echo echo "Would you like to make this stuff the install script for this package" echo -n "and remove the symbolic links ([y]es, [n]o)? " fi # 如果没有用参数指定 linkadd, 那么则读取用户输入, 否则直接输出之前的选择, 并继续 if [ ! "$LINKADD" ]; then read LINKADD; echo else echo $LINKADD echo fi # linkadd 的情况下, 处理所产生的命令(产生符号链接的命令) if [ "$LINKADD" = "y" ]; then # 存在 install/doinst.sh if [ -r install/doinst.sh ]; then UPDATE="t" # 如果用户选择了 --prepend 选项, # 则将新产生的安装脚本放至已存在的 install/doinst.sh 的开头 # 否则直接扔到已经 install/doinst.sh 的末尾 if [ "$PREPEND" = "y" ]; then touch install/doinst.sh mv install/doinst.sh install/doinst.sh.shipped cat doinst.sh > install/doinst.sh echo "" >> install/doinst.sh cat install/doinst.sh.shipped >> install/doinst.sh rm -f install/doinst.sh.shipped else cat doinst.sh >> install/doinst.sh fi # 不存在 install/doinst.sh 则直接将 doinst.sh 填入 install/doinst.sh else mkdir -p install cat doinst.sh > install/doinst.sh fi echo # 删除符号链接 echo "Removing symbolic links:" find . -type l -exec rm -v {} \; echo # 输出提示信息 if [ "$UPDATE" = "t" ]; then if [ "$PREPEND" = "y" ]; then echo "Updating your ./install/doinst.sh (prepending symlinks)..." else echo "Updating your ./install/doinst.sh..." fi else echo "Creating your new ./install/doinst.sh..." fi fi # 没有在当前目录找到符号链接, 直接给出提示 else echo "No symbolic links were found, so we won't make an installation script." echo "You can make your own later in ./install/doinst.sh and rebuild the" echo "package if you like." fi # 删除临时文件 rm -f doinst.sh $INST# chown 的相关处理, 非必要的 # 有些软件需要特定的用户组或权限设置, 那样的话, 这一步就不能做 echo echo "This next step is optional - you can set the directories in your package" echo "to some sane permissions. If any of the directories in your package have" echo "special permissions, then DO NOT reset them here!" echo echo "Would you like to reset all directory permissions to 755 (drwxr-xr-x) and" echo -n "directory ownerships to root.root ([y]es, [n]o)? " # 根据是否已经选择了 chown 来决定是要求用户输入还是直接输出选择结果 if [ ! "$CHOWN" ]; then read CHOWN; echo else echo $CHOWN echo fi # 根据用户选择, 进行权限设置 # 可以看出此处只修改了目录的权限和属主信息 if [ "$CHOWN" = "y" ]; then find . -type d -exec chmod -v 755 {} \; find . -type d -exec chown -v root.root {} \; fi # 打包 echo echo "Creating tar file $TAR_NAME.tar..." echo # 从上面可以知道, $TAR_NAME.tar 只是个文件名, 并没有包含目录信息, # 所以这里是把当前目录打包, 并存入当前目录下的 $TAR_NAME.tar # 于是就会有这样的情况, tar 会不会把 $TAR_NAME.tar 本身再打包呢? # 实际上 tar 会给出个提示, 说 $TAR_NAME.tar 就是打包的文件本身, 所以不打包它. # 这算是个错误提示, 只不过在 slackware 打包的时候用了 v 参数, 所以会显示打包了哪些文件, # 于是通常用户是注意不到这个信息的 $TAR cvf $TAR_NAME.tar . # 对空文件进行提示 find . -type f -size 0c | while read file ; do echo "WARNING: zero length file $file" done find . -type f -name '*.gz' -size 20c | while read file ; do echo "WARNING: possible empty gzipped file $file" done # 压缩 echo echo "Gzipping $TAR_NAME.tar..." gzip -9 $TAR_NAME.tar echo echo "Renaming $TAR_NAME.tar.gz to $PACKAGE_NAME..." # 把 $TAR_NAME.tar.gz 改名为指定的包文件名 mv $TAR_NAME.tar.gz $PACKAGE_NAME # 如果指定存放包的位置不是当前目录, 则把它移动指定目录 if [ ! "$TARGET_NAME" = "." ]; then echo echo "Moving $PACKAGE_NAME to $TARGET_NAME..." mv $PACKAGE_NAME $TARGET_NAME fi # 创建完成, 给个提示 echo echo "Package creation complete." echo