为什么在checkinstall调用的脚本中,mkdir -p命令不能正常工作?

10

我正在尝试使用checkinstall编译打包Quarter

如果我按照标准的./configure && make && sudo make install操作,一切都很顺利。

$ wget http://ftp.coin3d.org/coin/src/all/Quarter-1.0.0.tar.gz
$ tar xzf Quarter-1.0.0.tar.gz
$ cd Quarter-1.0.0
$ ./configure
$ make
$ sudo make install

但是,当我使用checkinstall时,它在一个应该完美地工作的mkdir -p上失败了。它失败的方式正好与没有给出-p选项时一样。这是我正在使用的checkinstall命令行:

$ checkinstall -D -y --install=no --pkgname=libquarter --pkgversion=1.0.0 \
  --arch=i386 --pkglicense=GPL --maintainer=me@example.com --reset-uids=yes

这是失败:

....
/bin/bash ../../../cfg/mkinstalldirs /usr/local/include/Quarter/devices
mkdir -p -- /usr/local/include/Quarter/devices
mkdir: cannot create directory `/usr/local/include/Quarter': No such file or directory
make[4]: *** [install-libdevicesincHEADERS] Error 1
....

这是脚本的相关部分:
$ cat cfg/mkinstalldirs
....
case $dirmode in
  '')
    if mkdir -p -- . 2>/dev/null; then
      echo "mkdir -p -- $*"
      exec mkdir -p -- "$@"
    fi
    ;;
....

我不明白为什么要有那个exec -- 那不保证脚本剩余部分(在esac后面)永远不会执行吗?(如果if测试通过,那么脚本假定mkdir -p正常工作,因此一旦它执行了真正的mkdir -p,它就可以退出;否则,脚本的剩余部分将实现适当的mkdir -p行为。)我也不明白为什么在echo中使用"$*",在下一行中使用"$@",但似乎无关紧要 -- 因为这个脚本只用一个参数调用。(Tom在注释中解释了这一点。)如果我在echoexec之间添加两行代码,即mkdir -p -- "$@",然后echo "Now doing the exec mkdir...",那么它的工作方式就像这样 -- 更好了,但仍然令人困惑:
/bin/bash ../../../cfg/mkinstalldirs /usr/local/include/Quarter/devices
mkdir -p -- /usr/local/include/Quarter/devices
mkdir: cannot create directory `/usr/local/include/Quarter': No such file or directory
Now doing the exec mkdir...
 /usr/bin/install -c -m 644 InputDevice.h /usr/local/include/Quarter/devices/InputDevice.h
.... finishes successfully!

现在,两次执行mkdir命令使其工作的事实告诉我这不是权限问题(此外,这会生成一个与mkdir不同的诊断,而且这是以sudo身份运行的,并且它实际上是在/var/tmp/...中工作而不是真正的/usr/local/...)。我认为正在发生的是第一次mkdir调用(我添加的那个)实际上只创建了Quarter目录并退出,然后当第二个mkdir运行时,它能够创建devices子目录,因为Quarter目录已经存在。但是为什么mkdir会这样工作呢?我的解决方法是以某种方式修补mkinstalldirs脚本,但我真的很好奇为什么会出现这种情况!这是在Win7上运行的VirtualBox中的Ubuntu 10.10客户机,通过apt-get安装了checkinstall版本1.6.2。

编辑: 我进行了一些测试,以确定在此环境中什么有效,什么无法实现...

mkdir -p /foo works correctly
mkdir -p /foo && mkdir -p /foo/bar works correctly
mkdir -p foo/bar works correctly
mkdir /foo/bar failed as expected (correct)
mkdir foo/bar failed as expected (correct)
mkdir -p /foo/bar fails

奇怪的是,-p 对于相对路径名有效,但对于绝对路径名无效。或者正确的区别是,在“chroot”树之外(如果它确实在使用chroot),-p 可以工作,但在其中则不能。
我还验证了尽管失败了,它仍然能够创建第一个目录层级。
仍然是个谜。

"你的意思是“它实际上是在 /tmp/… 中工作,而不是真正的 /usr/local/…”?是 chroot 吗?" - Tom Anderson
就我所知,我想在echo中使用$*是为了让echo只接收一个参数,其中包含整个命令行,而不是如果使用$@将会得到N个参数,每个参数对应一个参数。这只是一个非常微小的整洁和高效的事情。虽然它坐在$@的旁边看起来很奇怪。 - Tom Anderson
@Tom,那应该是我的猜测。我需要使用sudo才能使其正常工作,但它并没有进行真正的安装(这正是我想要的,因为我只想创建软件包)。不确定为什么我必须使用sudo,但我可以接受。感谢您对$*和$@的解释! - Dan
@tom,"$*"和"$@"之间有区别。 - Foo Bah
1
这是一个错误。 (This is a bug.) - Aryeh Leib Taurog
显示剩余2条评论
3个回答

23
使用
checkinstall --fstrans=no

应该解决这个问题。

或者

Set "TRANSLATE=0"

/etc/checkinstallrc 文件中进行设置,然后重试。


这个问题在很久以前就被修复了,但它仍未包含在发布版本中。无论如何,这是一个很好的提示。 - 10robinho
显然,如果您没有根访问权限,这对于需要文件系统翻译的情况是无效的。这不是一个解决方法,而是一个非常有限制性的解决方案。 - Niklas Holm

2

mkdir -p 的工作方式不像预期的那样,因为它是 checkinstall 版本的 mkdir,而不是“真正的” mkdir。可能是 checkinstall 中存在一些 bug,导致其工作方式有所不同。

这个补丁可以解决这个 bug:

./configure
sed -i 's/if mkdir .*-p --.*; then/if false; then ## &/' cfg/mkinstalldirs
....

0
sed -i -e 's/TRANSLATE=1/TRANSLATE=0/g' /etc/checkinstallrc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接