一、环境:openwrt+linux 2.6.31
1、内部toolchain
make menuconfig 内部toolchain配置如下: [*] Advanced configuration options (for developers) ---> [*] Toolchain Options --->
编出的toolchain为:staging_dir/toolchain-mips_gcc-4.6-linaro_uClibc-0.9.33.2目录
用该toolchain编出的firmware可以再设备中正常运行。
2、外部toolchain
目的:由于每次checkout代码都需要重新编toolchain,耗时很长,为了节省这部分时间,决定将上面已经编好的toolchain作为一个独立的目录,只要放置于编译环境的固定目录即可。
操作:
make menuconfig 外部toolchain配置如下: [*] Advanced configuration options (for developers) ---> [*] Toolchain Options --->
Base system ---> --- libc Configuration ---> libc shared library base directory配置为:
/opt/toolchain-mips_gcc-4.6-linaro_uClibc-0.9.33.2
Base system ---> --- libgcc Configuration ---> libgcc shared library base directory 配置为:
/opt/toolchain-mips_gcc-4.6-linaro_uClibc-0.9.33.2
Base system ---> --- libpthread Configuration ---> libpthread shared library base directory 配置为:
/opt/toolchain-mips_gcc-4.6-linaro_uClibc-0.9.33.2
注:其他配置默认。
配置完成,make成功。
3、运行
把生成的firmware文件放在设备中运行,启动时出现错误:kernel panic - not syncing: No init found. Try passing init= option to kernel.
从内核代码中找到该log的打印是在init/main.c
static noinline int init_post(void)
__releases(kernel_lock)
{
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Please be patient, while OpenWrt loads ...\n");
(void) sys_dup(0);
(void) sys_dup(0);
current->signal->flags |= SIGNAL_UNKILLABLE;
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
/*
* We disable the "init" processing command to workaround
* the bootloader implementation
* This needs to be removed in the long term as it removes
* the opportunity to modify the boot program
*/
run_init_process("/etc/preinit");
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
打印该log的原因是,执行系统的第一个应用程序init失败。可能的原因:
1、rootfs分区不对,init程序文件找不到;
2、init程序文件找到了,但执行错误(依赖的库文件有问题)
二、分析:
对比了两种toolchain编出的rootfs,发现用外部toolchain编出的rootfs中,少了/lib/libuClibc-0.9.33.2.so, /lib/ld-uClibc-0.9.33.2.so, /lib/ld-uClibc.so.0,三个库文件,看来是linux启动时在执行/sbin/init程序时由于缺少这些库文件导致运行出错,进而出现kernel panic。
需要找出缺少该文件的原因及解决方案。
线索:在make menuconfig 中配置Base system ---> --- libc Configuration ---> libc shared library files (use wildcards)有相关库的配置:
默认配置为:./lib/ld{-*.so,*.so.*}./lib/lib{anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}{-*.so,.so.*}
发现这些模糊配置没有匹配上面缺少的三个文件(/lib/libuClibc-0.9.33.2.so, /lib/ld-uClibc-0.9.33.2.so, /lib/ld-uClibc.so.0)
结论:看来是这些表达式的问题了。
三、解决方案
修改配置Base system ---> --- libc Configuration ---> libc shared library files (use wildcards)如下:
./lib/ld{-*.so,-uClibc.so.*,-linux*.so.*} ./lib/lib{uClibc,anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}{-*.so,.so.*}
该配置是属于CONFIG_LIBC_FILE_SPEC的,其定义是在package/toolchain/Makefile中,具体定义如下:
define Package/libc/install
for file in $(call qstrip,$(CONFIG_LIBC_FILE_SPEC)); do \
dir=`dirname $$$$file` ; \
$(INSTALL_DIR) $(1)/$$$$dir ; \
$(CP) $(call qstrip,$(CONFIG_LIBC_ROOT_DIR))/$$$$file $(1)/$$$$dir/ ; \
done ; \
exit 0
endef
看来就是这个package负责安装这些库文件的。
所以,执行make package/toolchain/clean && make package/toolchain/install V=s,完成后检查rootfs,发现缺少的三个文件出现了。
最后,重新make,将生成的firmware放在板子上运行,现在系统可以正常运行了。
四、总结
在更换toolchain时,容易出现库文件丢失的情况,导致系统无法正常启动。
所以在更换toolchain时,要谨慎比较前后的差异。