狗年的初一大概是我过的最纠结的一次新年了。一个看起来毫不讲理的BUG,陪着我度过了青岛的三天三夜。明天就要回家了,今天写篇,描述下这个编译错误,记录下这几天做过的尝试。
1 初读
前一篇学习笔记已经记录了VLC-Android初步安装配置的一些内容。大概扫了一眼发现竟然找不到任何vlc的实现或者库文件!有的只是一些外部的框架或者接口……难道我要重新从头边学边改一遍吗T^T
万幸,VLC并没有这么残忍。
在compile.sh里有这么一段:
####################
# Fetch VLC source #
####################
TESTED_HASH=f7fc778
if [ ! -d "vlc" ]; then
diagnostic "VLC source not found, cloning"
git clone https://git.videolan.org/git/vlc/vlc-3.0.git vlc
checkfail "vlc source: git clone failed"
fi
diagnostic "VLC source found"
cd vlc
if ! git cat-file -e ${TESTED_HASH}; then
cat 1>&2 << EOF
***
*** Error: Your vlc checkout does not contain the latest tested commit: ${TESTED_HASH}
***
EOF
exit 1
fi
if [ "$RELEASE" = 1 ]; then
git reset --hard ${TESTED_HASH}
fi
cd ..
这里的主要目的就是clone指定版本的VLC源码,之后作为源码的一部分整体进行编译。
这里有必要提一下另一个文件:compile-libvlc.sh,这个文件的主要任务是管理刚刚下载的VLC源码,把VLC作为lib文件加入项目,通过参数设置并执行我们之前vlc正常编译的过程,最终生成 libvlc.so,libvlcjni.so两个核心的依赖。
看到了 .so文件的生成依然使用的是vlc的源码长舒了一口气,这样按理说我们只要屏蔽了vlc源码的下载校验,然后把之前更改好的vlc项目放进去执行编译,就可以把我们的补丁带进移动端。
那么,动手吧。
2 磕绊
理想总是很美好,BUG总会在你最兴高采烈的时候和你谈谈人生。
编译的过程中像往常一样报了一个很不起眼的错:
checking for iconv... no, consider installing GNU libiconv
configure: error: iconv() not found
make: *** [.zvbi] Error 1
contribs: make failed
第一反应是有库没有安装,iconv是交叉编译时在 ./bootstrap 中新打开的参数:--enable-iconv . 那会不会是提到的libiconv库没有安装?
用 apt-cache search 查了一下有关的包:
libiconv-hook-dev - header files of libiconv-hook
libiconv-hook1 - extension of iconv for libapache-mod-encoding
好像只有这两个像一点,但又不是我们需要的包。上网找了一下发现是有libiconv源码可以自己编译安装,安装完后使用 ln 命令链接到我们需要的地方就好。
最开始我也是这么做的,但后来在查找PATH的时候偶然看到了:
PKG_CONFIG_LIBDIR=$VLC_SRC_DIR/contrib/$TARGET_TUPLE/lib/pkgconfig \
PKG_CONFIG_PATH=$VLC_SRC_DIR/contrib/$TARGET_TUPLE/lib/pkgconfig \
PATH=../contrib/bin:$PATH \
PKG_CONFIG是依赖查询的路径,而这里把/vlc/contrib加入了查询,进入contrib目录,发现在对应的ABI目录下多了很多原本没有安装过的依赖,突然想起来第一次compile的时候下载了很多东西,路径的话是在/vlc/contrib/tarballs里:
里面明显是有libiconv的!找了一下iconv,.h .a .la 一应俱全...Excuse me??
3 崩坏
这是编译的时候报错的log(vlc):
.../vlc/conftest.c:46: undefined reference to `libiconv_open'
.../vlc/conftest.c:47: undefined reference to `libiconv'
.../vlc/conftest.c:48: undefined reference to `libiconv_close'
collect2: error: ld returned 1 exit status
log很符合编译过程中缺失iconv()函数的现象,但上面提到的三个函数在iconv.h中都有明确定义,为什么会找不到呢???
hwren@hwren-PC:~/Documents/vlc-android$ which iconv
/usr/local/bin/iconv
hwren@hwren-PC:~/Documents/vlc-android$ iconv --version
iconv (GNU libiconv 1.15)
Copyright (C) 2000-2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
作者 Bruno Haible。
这是我自己安装的iconv,也能正常使用,到处都有还说找不到这就很不友好了哇T^T
3.1 尝试升级
官方给的Android编译说明中有这么一条说明:
大概意思就是,出现了返回1的Error的时候,你可以升级一下依赖试试。
虽然我出错的不是dvdnav,但依然觉得,嗯...你说的有道理。
于是傻傻的 sudo apt upgrade 了一下:
结果并没有起到什么作用,重新运行了一下 vlc/extra/tools/bootstrap ,发现还是不行:
cmake too old
protoc too old
看到 vlc/extra/tools 已经准备好了依赖的源码,顺手就给编译安装了。
重新 bootstrap,没问题了,不禁开始思考我的那么些流量都干了啥...
重新执行了一次 compile.sh ,看后面长度就知道,问题并没有解决。
3.2 尝试指定路径
前面提到了安装了很多iconv,所以感觉会不会是因为路径的问题,隐约记得之前有过冲突导致无法找到的案例:按路径找到了一个依赖,实际的定义却被覆盖到了另一个地方,导致的函数丢失。
在 vlc/configure 里注意到了有这样的参数:
--with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib
--without-libiconv-prefix don't search for libiconv in includedir and libdir
于是在compile-libvlc.sh中添加了
###########################
# VLC CONFIGURE ARGUMENTS #
###########################
VLC_CONFIGURE_ARGS="\
--with-libiconv-prefix='/usr/local/bin/iconv' \
... "
强制指定了iconv的目录位置,很高兴的跑去重新compile.sh(甚至还顺手删了临时文件)
哥们你好,我们又见面了。
同理尝试了without-libiconv-prefix,结果依然。
3.3 去pkg-config看看
既然提到有使用pkg-config去进行定位,那自然应该留有对应的 .pc 文件作为线索,进入到保存索引的目录:vlc/contrib/arm-linux-androideabi/lib/pkgconfig,琳琅满目眼花缭乱的一堆pc文件里,唯独找不见iconv.pc
嗯...突然兴奋.jpg
立马比对着其他的pc文件写了一个iconv的(毕竟iconv除了pc都不缺)
prefix=/usr/local/bin/iconv
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: iconv
Description: GNU libiconv 1.15
Version: 1.15
Libs: -L${exec_prefix}/lib -liconv -lm
Cflags: -I${prefix}/include
手动添加了PKG_CONFIG_PATH之后尝试查找iconv:
hwren@hwren-PC:~/Documents/vlc-android/vlc-android$ export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/hwren/Documents/vlc-android/vlc-android/vlc/contrib/arm-linux-androideabi/lib/pkgconfig
hwren@hwren-PC:~/Documents/vlc-android/vlc-android$ pkg-config --libs iconv
-L/home/hwren/Documents/vlc-android/vlc-android/vlc/contrib/arm-linux-androideabi/lib -liconv -lm
明显是找到了!
但依然不能解决问题...
大过年的,心塞......
3.4 尝试追踪check的过程
回到问题出现的原因,check的过程中无法找到iconv,那百般尝试失败后只能老老实实看一下到底是怎么check的iconv。
首先是起点:compile.sh,进入下一层的位置:
############
# Make VLC #
############
diagnostic "Configuring"
OPTS="-a ${ANDROID_ABI}"
if [ "$RELEASE" = 1 ]; then
OPTS="$OPTS release"
fi
if [ "$CHROME_OS" = 1 ]; then
OPTS="$OPTS -c"
fi
if [ "$ASAN" = 1 ]; then
OPTS="$OPTS --asan"
fi
if [ "$NO_ML" = 1 ]; then
OPTS="$OPTS --no-ml"
fi
./compile-libvlc.sh $OPTS
这里进入了第二层:compile-libvlc.sh,这个脚本首先设置了一大堆编译过程中需要的功能(作为Args),之后将这些Args加到脚本上进行编译
###########################
# Build buildsystem tools #
###########################
export PATH="`pwd`/extras/tools/build/bin:$PATH"
echo "Building tools"
cd extras/tools
./bootstrap
checkfail "buildsystem tools: bootstrap failed"
make $MAKEFLAGS
make $MAKEFLAGS .gas
checkfail "buildsystem tools: make"
cd ../..
#############
# BOOTSTRAP #
#############
if [ ! -f configure ]; then
echo "Bootstraping"
./bootstrap
checkfail "vlc: bootstrap failed"
fi
在这里执行了 bootstrap,参数为 VLC_BOOTSTRAP_ARGS,并把刚刚提到的一些缺失的依赖安装进去。之后继续执行Contribs,完成后进入Configure阶段:
if [ ! -e ./config.h -o "$RELEASE" = 1 ]; then
CFLAGS="${VLC_CFLAGS} ${EXTRA_CFLAGS}" \
CXXFLAGS="${VLC_CXXFLAGS} ${EXTRA_CFLAGS} ${EXTRA_CXXFLAGS}" \
CC="${CROSS_TOOLS}clang" \
CXX="${CROSS_TOOLS}clang++" \
NM="${CROSS_TOOLS}nm" \
STRIP="${CROSS_TOOLS}strip" \
RANLIB="${CROSS_TOOLS}ranlib" \
AR="${CROSS_TOOLS}ar" \
PKG_CONFIG_LIBDIR=$VLC_SRC_DIR/contrib/$TARGET_TUPLE/lib/pkgconfig \
PKG_CONFIG_PATH=$VLC_SRC_DIR/contrib/$TARGET_TUPLE/lib/pkgconfig \
PATH=../contrib/bin:$PATH \
sh ../configure --host=$TARGET_TUPLE --build=x86_64-unknown-linux \
--with-contrib=${VLC_SRC_DIR}/contrib/${TARGET_TUPLE} \
${EXTRA_PARAMS} ${VLC_CONFIGURE_ARGS} ${OPTS}
checkfail "vlc: configure failed"
fi
这里补充了刚刚提到的PKG_CONFIG_PATH,带着一堆参数进入了 configure 里。
Configure啊...好长好长的,盯电脑盯到眼睛疼
其中主要涉及到LIBiconv的地方就是通过各种情况下的判断给LIBICONV路径赋值。
并不觉得有什么异常。
这个过程中突然发现一个很奇怪的现象:添加pkgconfig路径后把参数复制出来单独直接执行vlc源码编译,最终结果竟然成功通过了Configure!?
当然在make的过程中出现了新的错误:
access/live555.cpp:59:24: fatal error: liveMedia.hh: 没有那个文件或目录
#include
但这个现象很耐人寻味。
4 计划
很明显问题并没有解决完,师兄也把这次当做练手的机会基本不理我...搞清楚编译的整个过程对我而言算是研究入门很难的一关,但往往探索的过程总是会收获很多。接下来的计划嘛:
- 考虑完全屏蔽掉vlc编译,使用单独的编译好的vlc作为依赖,直接生成 .so文件
- 尝试不作任何更改,重新编译最原始的VLC-Android项目
- 解决make过程中出现的新问题
明天就回家了,终于可以放过我的流量了。