前言

继上次解决了使用 WSL 编译 OpenWrt 遇到的文件系统大小写不敏感问题后,使用 WSL 编译 OpenWrt 的进度一直停滞不前,因为遇到了一个非常难解决的问题,网上没有任何相关资料,也一直没有找对方向,在经过各种折腾后差点放弃。

错误日志

Applying ./patches/200-do-not-override-silent-rules.patch using plaintext:
patching file m4/silent.m4
touch /mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1/.preparedc9098c8b9dd1c3c16d780bf0f98d7590_66645
17399ebbbc92a37c5bb081b5c53
(cd /mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1; AUTOM4TE=/mnt/e/Downloads/OpenWrt/lede/staging_d
ir/host/bin/autom4te AUTOCONF=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoconf AUTOMAKE=/mnt/e/Download
s/OpenWrt/lede/staging_dir/host/bin/automake ACLOCAL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/aclocal AU
TOHEADER=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoheader LIBTOOLIZE=/mnt/e/Downloads/OpenWrt/lede/st
aging_dir/host/bin/libtoolize LIBTOOL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/libtool M4=/mnt/e/Downloa
ds/OpenWrt/lede/staging_dir/host/bin/m4 AUTOPOINT=true STAGING_DIR="" ./bootstrap)
mv: cannot move 'bin/aclocal.tmp2' to 'bin/aclocal.tmp': Permission denied
Makefile:51: recipe for target '/mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1/.configured' failed  
make[3]: *** [/mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1/.configured] Error 1
make[3]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede/tools/automake'
time: tools/automake/compile#0.20#1.85#2.00
tools/Makefile:155: recipe for target 'tools/automake/compile' failed
make[2]: *** [tools/automake/compile] Error 2
make[2]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
tools/Makefile:153: recipe for target '/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_c
ompile_yynyyyyynyyyyynyyynnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy' failed
make[1]: *** [/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_compile_yynyyyyynyyyyynyyy
nnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy] Error 2
make[1]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
/mnt/e/Downloads/OpenWrt/lede/include/toplevel.mk:216: recipe for target 'world' failed
make: *** [world] Error 2

分析日志

其中mv: cannot move 'bin/aclocal.tmp2' to 'bin/aclocal.tmp': Permission denied是错误的关键,没有权限。

解决方案

修改代码折腾失败,于是决定换个思路解决问题。

mv命令需要目标路径或文件有写入权限,那么这里导致这个错误的原因应该是aclocal.tmp这个而文件没有写入权限。文件路径应该是相对路径,所以想定位到文件就要找执行mv命令的来源,所以继续往上看执行了什么命令。

(cd /mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1; AUTOM4TE=/mnt/e/Downloads/OpenWrt/lede/staging_d
ir/host/bin/autom4te AUTOCONF=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoconf AUTOMAKE=/mnt/e/Download
s/OpenWrt/lede/staging_dir/host/bin/automake ACLOCAL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/aclocal AU
TOHEADER=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoheader LIBTOOLIZE=/mnt/e/Downloads/OpenWrt/lede/st
aging_dir/host/bin/libtoolize LIBTOOL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/libtool M4=/mnt/e/Downloa
ds/OpenWrt/lede/staging_dir/host/bin/m4 AUTOPOINT=true STAGING_DIR="" ./bootstrap)

其中 /mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1 是路径,中间的内容是变量赋值,可忽略。最后的 ./bootstrap 是关键了,说明执行了这个文件,mv命令极有可能跟这个文件相关。

结合前面的相对路径,找到了aclocal.tmp,经过确认文件确实没有写入权限,然后赋予写入权限后再继续编译,还是遇到同样的错误。再次查看文件权限,结果写入权限又没有,这个文件似乎在生成的时候就去掉了写入权限。

用 VSCODE 打开 bootstrap 这个文件发现它是个脚本在这个文件中尝试搜索mv,找到了下面这部分代码:

# Create temporary replacement for aclocal and automake.
for p in bin/aclocal bin/automake; do
  dosubst $p.in $p.tmp
  $PERL -w bin/gen-perl-protos $p.tmp > $p.tmp2
  mv -f $p.tmp2 $p.tmp
done

其中mv -f $p.tmp2 $p.tmp就是没有权限运行的命令,dosubst $p.in $p.tmp是生成aclocal.tmp文件的命令,至于如何生成dosubst应该是关键,继续尝试搜索。

dosubst ()
{
  rm -f $2
  in=`echo $1 | sed 's,^.*/,,'`
  sed -e "s%@APIVERSION@%$APIVERSION%g" \
      -e "s%@PACKAGE@%$PACKAGE%g" \
      -e "s%@PERL@%$PERL%g" \
      -e "s%@SHELL@%$BOOTSTRAP_SHELL%g" \
      -e "s%@VERSION@%$VERSION%g" \
      -e "s%@datadir@%$datadir%g" \
      -e "s%@RELEASE_YEAR@%$RELEASE_YEAR%g" \
      -e "s%@configure_input@%Generated from $in; do not edit by hand.%g" \
      $1 > $2
  chmod a-w $2
}

在最后我发现了去掉写入权限的命令chmod a-w $2,这也就石锤了我前面对于文件生成时去掉写入权限的猜测。

mv需要写入权限,但在mv之前又去掉写入权限,这是什么操作?搞不懂这是什么操作,但在纯 Linux 环境下又没有这样的错误产生。难道是问题在 WSL 本身?

删除aclocal.tmp,去掉chmod a-w $2。继续编译,紧接着又出现了错误。

make[3]: Entering directory '/mnt/e/Downloads/OpenWrt/lede/tools/automake'
(cd /mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1; AUTOM4TE=/mnt/e/Downloads/OpenWrt/lede/staging_d
ir/host/bin/autom4te AUTOCONF=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoconf AUTOMAKE=/mnt/e/Download
s/OpenWrt/lede/staging_dir/host/bin/automake ACLOCAL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/aclocal AU
TOHEADER=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/autoheader LIBTOOLIZE=/mnt/e/Downloads/OpenWrt/lede/st
aging_dir/host/bin/libtoolize LIBTOOL=/mnt/e/Downloads/OpenWrt/lede/staging_dir/host/bin/libtool M4=/mnt/e/Downloa
ds/OpenWrt/lede/staging_dir/host/bin/m4 AUTOPOINT=true STAGING_DIR="" ./bootstrap)
./bootstrap: 113: ./bootstrap: cannot create t/testsuite-part.tmp: Permission denied
Makefile:51: recipe for target '/mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1/.configured' failed  
make[3]: *** [/mnt/e/Downloads/OpenWrt/lede/build_dir/host/automake-1.15.1/.configured] Error 2
make[3]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede/tools/automake'
time: tools/automake/compile#0.06#1.26#1.35
tools/Makefile:155: recipe for target 'tools/automake/compile' failed
make[2]: *** [tools/automake/compile] Error 2
make[2]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
tools/Makefile:153: recipe for target '/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_c
ompile_yynyyyyynyyyyynyyynnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy' failed
make[1]: *** [/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_compile_yynyyyyynyyyyynyyy
nnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy] Error 2
make[1]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
/mnt/e/Downloads/OpenWrt/lede/include/toplevel.mk:216: recipe for target 'world' failed
make: *** [world] Error 2
./bootstrap: 113: ./bootstrap: cannot create t/t/testsuite-part.tmp: Permission denied

这句很明显,113行创建文件没有权限,testsuite-part.tmp应该是之前已经存在了,而且同样也去掉了吸入权限。

# Create required makefile snippets.
$PERL ./gen-testsuite-part > t/testsuite-part.tmp
chmod a-w t/testsuite-part.tmp
mv -f t/testsuite-part.tmp t/testsuite-part.am

删除
rm -rf testsuite-part.tmp testsuite-part.am,去除bootstrap文件中的chmod a-w t/testsuite-part.tmp

继续编译,此时aotumake这个过程已经没有报错了,然而新的问题有来了。

make[3]: Entering directory '/mnt/e/Downloads/OpenWrt/lede/tools/libtool'
. /mnt/e/Downloads/OpenWrt/lede/include/shell.sh; xzcat /mnt/e/Downloads/OpenWrt/lede/dl/libtool-2.4.tar.xz | tar 
-C /mnt/e/Downloads/OpenWrt/lede/build_dir/host/libtool-2.4/.. -xf -
[ ! -d ./src/ ] || cp -fpR ./src/* /mnt/e/Downloads/OpenWrt/lede/build_dir/host/libtool-2.4

Applying ./patches/000-relocatable.patch using plaintext: 
patching file libltdl/config/general.m4sh
patching file libtoolize.in
patching file libtoolize.m4sh
patching file libltdl/m4/libtool.m4

Applying ./patches/001-fix-func_append.patch using plaintext:
patching file libltdl/config/ltmain.m4sh
File libltdl/config/ltmain.sh is read-only; trying to patch anyway
patching file libltdl/config/ltmain.sh
patch: **** Can't rename file libltdl/config/ltmain.sh.oEDquqA to libltdl/config/ltmain.sh : Permission denied    
Patch failed!  Please fix ./patches/001-fix-func_append.patch!
Makefile:42: recipe for target '/mnt/e/Downloads/OpenWrt/lede/build_dir/host/libtool-2.4/.prepared1aaf1a9c5b84ab76
468a9eff1f438fa6_6664517399ebbbc92a37c5bb081b5c53' failed
make[3]: *** [/mnt/e/Downloads/OpenWrt/lede/build_dir/host/libtool-2.4/.prepared1aaf1a9c5b84ab76468a9eff1f438fa6_6
664517399ebbbc92a37c5bb081b5c53] Error 1
make[3]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede/tools/libtool'
time: tools/libtool/compile#0.10#1.45#1.53
tools/Makefile:155: recipe for target 'tools/libtool/compile' failed
make[2]: *** [tools/libtool/compile] Error 2
make[2]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
tools/Makefile:153: recipe for target '/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_c
ompile_yynyyyyynyyyyynyyynnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy' failed
make[1]: *** [/mnt/e/Downloads/OpenWrt/lede/staging_dir/target-x86_64_musl/stamp/.tools_compile_yynyyyyynyyyyynyyy
nnyyyynyyyyyyyyyyyyyyyyyyynynnyyynnyy] Error 2
make[1]: Leaving directory '/mnt/e/Downloads/OpenWrt/lede'
/mnt/e/Downloads/OpenWrt/lede/include/toplevel.mk:216: recipe for target 'world' failed
make: *** [world] Error 2

关键信息在这里,又是没权限

patch: **** Can't rename file libltdl/config/ltmain.sh.oEDquqA to libltdl/config/ltmain.sh : Permission denied

进行到这里其实我已经完全没有耐心了,决定换个思路解决问题。

尝试在相同版本的 Ubuntu 虚拟机中使用相同编译配置进行编译,顺利编译成功了,我想这个问题的根源应该在 WSL。

虽然 WSL 可以直接访问 Windows 下的文件,但文件权限全是777,这可以通过设置 DrvFs 的挂载参数解决,但即使设置了正确的权限编译还是失败,而且是相同的错误日志。

通过搜索关于 WSL 编译 OpenWrt 的文章发现大佬们编译都是在用户主目录中进行的。但是 WSL 的默认安装目录在 C 盘(系统盘,固态硬盘),抛开容量不谈,在用户主目录下进行编译这样的大量读写操作,势必会影响到硬盘寿命,并间接影响系统稳定性,所以我没有直接尝试。而是把用户主目录进行了转移,结果编译失败,错误日志依然相同。

结合上面的这些情况,我猜测问题根源是 WSL 无法真正的控制 Windows 下的文件权限,毕竟跨文件系统了,后面搜索到的相关资料也验证了我的猜测。所以想尝试在 WSL 文件系统以外的目录编译暂时是不可能的了,只能等微软官方去解决跨文件系统的权限问题。

既然不能直接在 WSL 中选择编译目录,那是否能把 WSL 从系统盘中转移到其它目录呢?通过万能的 Google 搜索,答案是可以的。最后经过各种尝试发现使用 LxRunOffline 转移 WSL 目录是最好的解决方案。

转移完 WSL 目录,最终在用户主目录下编译成功。至此,这个问题以曲线救国的方式得到了解决。