本帖最后由 51hei单片 于 2016-3-12 23:48 编辑
随笔记:为了尽快熟悉 OpenWRT,手里没有详细的系统的学习资料,只能从网上查阅相关资料,这里看一下,那里看一下。
随手记录这些基础的知识点,有些我自己也不太明白,先记下。
一、OpenWRT 开机流程(这部分有些地方衔接不上,所以写的比较乱,只能大体知道流程。)
-----------------------------------------------------------------
openwrt\package\boot\uboot-sun5i\env.cfg
-----------------------------------------------------------------
init=/etc/preinit
root@TinaLinux:/# cat /proc/cmdline
cat /proc/cmdline
console=ttyS3,115200 root=/dev/nandd rootwait init=/etc/preinit ion_cma_512m=32m ion_cma_1g=176m ion_carveout_512m=32m ion_carveout_1g=150m coherent_pool=4m loglevel=8 partitions=boot-res@nanda:env@nandb:boot@nandc:rootfs@nandd:rootfs_data@nande:private@nandf:UDISK@nandg
-----------------------------------------------------------------
/package/base-files/files/etc/preinit
/etc/preinit
preinit:是一系列脚本的入口
-----------------------------------------------------------------
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
[ -z "$PREINIT" ] && exec /sbin/init
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
pi_ifname=
pi_ip=192.168.1.1
pi_broadcast=192.168.1.255
pi_netmask=255.255.255.0
fs_failsafe_ifname=
fs_failsafe_ip=192.168.1.1
fs_failsafe_broadcast=192.168.1.255
fs_failsafe_netmask=255.255.255.0
fs_failsafe_wait_timeout=2
pi_suppress_stderr="y"
pi_init_suppress_stderr="y"
pi_init_path="/bin:/sbin:/usr/bin:/usr/sbin"
pi_init_cmd="/sbin/init"
// 执行以下脚本,这样以下之后的函数函数才可以使用
. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.sh
// 初始化5个函数队列,相当于5种类型的脚本, boot_hook_init 在 preinit.sh 实现
boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root
// 循环执行 /lib/preinit 目录下面的脚本
for pi_source_file in /lib/preinit/*; do
. $pi_source_file
done
/* 暂且不知道是什么意思 这些脚本全都是在往函数队列里面添加已经实现的函数
// 以文件开头数字的顺序执行
/lib/preinit/02_default_set_state
boot_hook_add preinit_main define_default_set_state
/lib/preinit/10_indicate_failsafe
boot_hook_add failsafe indicate_failsafe
/lib/preinit/10_indicate_preinit
boot_hook_add preinit_main preinit_ip
boot_hook_add preinit_main pi_indicate_preinit
/lib/preinit/30_failsafe_wait
boot_hook_add preinit_main failsafe_wait
/lib/preinit/40_run_failsafe_hook
boot_hook_add preinit_main run_failsafe_hook
/lib/preinit/50_indicate_regular_preinit
boot_hook_add preinit_main indicate_regular_preinit
/lib/preinit/70_initramfs_test
boot_hook_add preinit_main initramfs_test
/lib/preinit/79_format_partition
[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main do_format_filesystem
/lib/preinit/80_mount_root
[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main do_mount_root
/lib/preinit/99_10_failsafe_login
boot_hook_add failsafe failsafe_netlogin
boot_hook_add failsafe failsafe_shell
/lib/preinit/99_10_run_init
boot_hook_add preinit_main run_init
*/
// 运行 preinit_essential 函数队列
boot_run_hook preinit_essential
pi_mount_skip_next=false
pi_jffs2_mount_success=false
pi_failsafe_net_message=false
// 运行 preinit_main 函数队列
boot_run_hook preinit_main
-----------------------------------------------------------------
-----------------------------------------------------------------
openwrt\package\base-files\files\etc\inittab
/etc/inittab : 由 busybox 的 init 程序分析 (/sbin/init)
inittab 为 linux 初始化文件系统时 init 初始化程序用到的配置文件。 这个文件负责
设置 init 初始化程序初始化脚本在哪里;每个运行级初始化时运行的命令; 开机、关机、重
启对应的命令;各运行级登陆时所运行的命令。
如果存在/etc/inittab 文件,Busybox init 程序解析它,然后按照它的指示创建各种
子进程,否则使用默认的配置创建子进程。 /etc/inittab 文件中每个条目用来定义一个子进
程,并确定它的启动方法,格式如下:
<id> : <runlevels> : <action> : <process>
1、 id :表示这个子进程要使用的控制台,如果省略,则使用与 init 进程一样的控制台.
2、 runlevels:这个字段没有意义,可以省略。在 linux 有意义.
3、 action:表示 init 进程如何控制这个子进程,具体取值见下表.
4、 process:要执行的程序,它可以是可执行程序,也可以是脚本.如果 process 字段前
有“ -”字符,这个程序被称为“交互的”
【 attention】 action 取值
----------------------------------------
sysinit 系统启动后最先执行:
指定初始化脚本路径,只执行一次,init 进程等待它结束才继续执行其它动作
wait 系统执行完 sysinit 进程后:
只执行一次,init 进程等待它结束才继续执行其它动作
once 系统执行完 wait 进程后
只执行一次,init 进程不等待它结束
respawn 启动完 once 进程后
init 进程监测发现子进程退出时,重新启动它,永不结束.如 Shell 命令解释器
askfirst 启动完 respawn 进程后
与 respawn 类似,不过init 进程先输出“ Pleasepress Enter toactivate this
console”,等用户输入回车后才启动子进程
shutdown 当系统关机时
即重启、关闭系统时执行的程序
restart 系统重启时
init 进程重启时执行的程序,通常是 init 程序本身先重新读取、解析/etc/inittab
文件,再执行 restart 程序
ctrl+alt+del 按 下 Ctrl+Alt+Del 键时
按 Ctrl+Alt+Del 组合键时执行的程序
-----------------------------------------------------------------
// sysinit 系统初始化运行 /etc/init.d/rcS S boot
::sysinit:/etc/init.d/rcS S boot
// shutdown 系统重启或者关机运行的脚本
::shutdown:/etc/init.d/rcS K shutdown
// 登录串口的时候
::askconsole:/bin/ash --login
从上面的分析可以看出它在开机启动的时候执行/etc/init.d/rcS 脚本,以前是有
/etc/init.d/rcS 脚本的,现在的 openwrt 已经去掉了这个脚本文件,只要有 rcS S boot
这几个参数就可以,但是功能是有的就是按顺序执行/etc/rc.d 下面的各个脚本,以 S 开
头代表启动的时候执行的脚本,与命令行中的 S 对应,以 K 开头的代表关机的时候需要
执行的脚本,与命令行中的 K 对应
/etc/rc.d 里面的脚本是在 install 时拷贝到 /etc/init.d 下,然后通过 /etc/rc.common 脚本
将 init.d 的脚本链接到 /etc/rc.d 目录,并且根据这些脚本中的 START 和 STOP 的关键字,添加
K${STOP} 和 S${START} 的前缀,这样就决定了脚本的先后的运行次序。
openwrt\staging_dir\target-arm_cortex-a8+neon_uClibc-0.9.33.2_eabi\root-sun5i\etc\init.d
root@TinaLinux:/etc/rc.d# ll
ll
drwxr-xr-x 2 root root 306 Dec 23 2015 .
drwxr-xr-x 1 root root 1024 Jan 1 1970 ..
lrwxrwxrwx 1 root root 13 Dec 23 2015 K89log -> ../init.d/log
lrwxrwxrwx 1 root root 17 Dec 23 2015 K90network -> ../init.d/network
lrwxrwxrwx 1 root root 14 Dec 23 2015 K98boot -> ../init.d/boot
lrwxrwxrwx 1 root root 14 Dec 23 2015 K99adbd -> ../init.d/adbd
lrwxrwxrwx 1 root root 16 Dec 23 2015 K99umount -> ../init.d/umount
lrwxrwxrwx 1 root root 20 Dec 23 2015 S00sysfixtime -> ../init.d/sysfixtime
lrwxrwxrwx 1 root root 14 Dec 23 2015 S10boot -> ../init.d/boot
lrwxrwxrwx 1 root root 16 Dec 23 2015 S10system -> ../init.d/system
lrwxrwxrwx 1 root root 16 Dec 23 2015 S11sysctl -> ../init.d/sysctl
lrwxrwxrwx 1 root root 13 Dec 23 2015 S12log -> ../init.d/log
lrwxrwxrwx 1 root root 17 Dec 23 2015 S20network -> ../init.d/network
lrwxrwxrwx 1 root root 15 Dec 23 2015 S40fstab -> ../init.d/fstab
lrwxrwxrwx 1 root root 14 Dec 23 2015 S50cron -> ../init.d/cron
lrwxrwxrwx 1 root root 16 Dec 23 2015 S50telnet -> ../init.d/telnet
lrwxrwxrwx 1 root root 14 Dec 23 2015 S95done -> ../init.d/done
lrwxrwxrwx 1 root root 13 Dec 23 2015 S96led -> ../init.d/led
lrwxrwxrwx 1 root root 17 Dec 23 2015 S98sysntpd -> ../init.d/sysntpd
lrwxrwxrwx 1 root root 14 Dec 23 2015 S99adbd -> ../init.d/adbd
preinit 主要是完成系统的初始化(如文件系统的准备、模块的加载)
rcS 主要是依次启动各个模块
二、 应用程序\Makefile\开机自启动
1、实现一个简单的应用程序,开机自启动,实现在根目录建立一个名为 temp_file_zhc 的文件
步骤1:在openwrt\package 建立zhc_application\zhc_test\src
步骤2:在 zhc_test\src中建立 main.c 源文件,内容如下
------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#define __ISDEBUG__
#ifdef __ISDEBUG__
#define dprintf(format,...) printf(&quot; -->[%s] Fun:%s, Line:%05d, &quot;format&quot; <--\n&quot;,strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') : __FILE__ ,__func__ , __LINE__,##__VA_ARGS__)
#else
#define dprintf(format,...)
#endif
int main(void)
{
dprintf(&quot;zhc_test app ~~~~~&quot;);
system(&quot;echo 12 > temp_file_zhc&quot;);
dprintf(&quot;zxxxxxx ~~~~~&quot;);
return 0;
}
------------------------------------------------------
步骤3:在 zhc_test\src中建立 makefile 文件,内容如下
------------------------------------------------------
TARGET = zhc_test
INCLUDES += -I. -Icommon/
LIBS += -lpthread -lm -lrt
SRCS = main.c
OBJS = $(SRCS:.c=.o)
%.o: %.c
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
all:$(TARGET)
clean:
rm -rf $(TARGET) *.o *.a *~
cd common && rm -f *.o *.a *.bak *~ .depend
------------------------------------------------------
步骤4:在 zhc_test 建立 makefile 文件,内容如下
------------------------------------------------------
# 这些 makefile 字文件确立软件包加入 OpenWrt 的方式和方法
include $(TOPDIR)/rules.mk
# PKG_NAME : 包名
# PKG_VERSION : 软件包版本号
# PKG_RELEASE : Makefile 的版本号
PKG_NAME:=zhc_test
PKG_VERSION:=0.0.1
PKG_RELEASE:=1
# 软件包编译目录
# 它的父目录为$(BUILD_DIR)。如果不指定
# 默认为$(BUILD_DIR)/$( PKG_NAME)/$( PKG_VERSION)
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
# 一般在软包的基本信息完成后再引入
include $(INCLUDE_DIR)/package.mk
# 应用程序编译包以 &quot;Package/&quot; 开头,然后接着软件名(可以与软件包名不一样)
# SECTION : 包的类型
# CATEGORY : 包的分类,在 make menuconfig 的菜单显示的名字
# TITLE : 用于在 make menuconfig 对该软件包的简述
# DEPENDS : 表示依赖其他软件。即如编译或安装需要其他软件时需要说明。如果
# 存在多个依赖,则每个依赖需要用空格分开。依赖前使用+号表示默认
# 为显示,即对象沒有选中时也会显示,使用@则默认为不显示,即当依
# 赖对象选中后才显示。
define Package/zhc_test
SECTION:=utils
CATEGORY:=Zhc_Bin
TITLE:=is zhc test bin file
DEPENDS:=+libpthread
endef
# 软件包的详细描述
define Package/zhc_test/description
is 11111111111111111111111111
endef
# 编译准备方法
# 对于网上下载的软件包不需要再描述
# 对于非网上下载或自行开发的软件包必须说明编译准备方法
# 以下为一般的编译准备方法,按 OpenWrt 的习惯,一般把自己设计的程序全部放在 src 目录下
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
# 编译方法,如果不定义将使用默认的编译方法 Build/Compile/Default
# 自行开发的软件考虑使用下面的定义
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC=&quot;$(TARGET_CC)&quot; \
CFLAGS=&quot;$(TARGET_CFLAGS)&quot; -Wall \
LDFLAGS=&quot;$(TARGET_LDFLAGS)&quot; \
LIBS=&quot;-lpthread&quot; \
all
endef
# 软件包的安装方法
# 包括一系列拷贝编译好的文件到指定位置。
# 调用时会带一个参数,就是嵌入系统的镜像文件系统目录
# 因此 $(1) 表示嵌入系统的镜像目录。一般可以采用下面的方法
# INSTALL_DIR\INSTALL_BIN : 在 $(TOPDIR)/rules.mk 定义
# INSTALL_DIR : INSTALL_DIR :=install -d -m0755 意思是创建所属用户可读写
# 其他用户可读可执行的目录
# INSTALL_BIN : INSTALL_BIN :=install -m0755 意思是编译好的文件存放到镜像文件目录
define Package/zhc_test/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/zhc_test $(1)/bin/
endef
# PDF 文档描述,在 boot 阶段启动 (未验证)
#define Package/zhc_test/install
# $(INCLUDE_DIR) $(1)/sbin/ $(1)/etc/config/ $(1)/etc/init.d/
# $(INSTALL_BIN) $(PKG_BUILD_DIR)/zhc_test $(1)/sbin/
# $(INCLUDE_DIR) ./files/zhc_test.config $(1)/etc/config/zhc_test
# $(INSTALL_BIN) ./files/zhc_test.init $(1)/etc/init.d/zhc_test
#endef
# 完成前面定义后,必须使用 eval 函数实现各种定义(感觉就像是这句才是真正执行上面的动作)
$(eval $(call BuildPackage,zhc_test))
------------------------------------------------------
【注意】以上步骤可以在 sdk 中编译出来,但是在源码目录中编译会出现如下提示:
make[1]: Entering directory `/home/zhangfuliang/work/r8_tina/openwrt'
make[2]: Entering directory `/home/zhangfuliang/work/r8_tina/openwrt/package/zhc_application/zhc_test'
WARNING: skipping zhc_test -- package not selected
make[2]: Leaving directory `/home/zhangfuliang/work/r8_tina/openwrt/package/zhc_application/zhc_test'
make[1]: Leaving directory `/home/zhangfuliang/work/r8_tina/openwrt'
步骤5: 编译进固件 此步骤是为了将该应用程序编译进固件
在 openwrt 根目录执行 make menuconfig
将 ZHC_BIN--> []zhc_test 修改为 ZHC_BIN-->zhc_test
步骤6: 修改 rc.local 实现开机自启动(可以添加各种 linux 命令)
文件在: openwrt/package/base-files/files/etc
------------------------------------------------------
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
./bin/zhc_test &
exit 0
------------------------------------------------------
步骤7: make V=s 编译即可
2、实现一个简单的应用程序,编译一个独立于固件的应用程序
步骤1:参照上述 步骤1~步骤4
步骤2:编译进固件 此步骤是为了将该应用程序编译进固件
在 openwrt 根目录执行 make menuconfig
将 ZHC_BIN--> []zhc_test 修改为 ZHC_BIN--> [M]zhc_test
步骤3:导入脚本命令,仅第一次进入终端时需要
. scripts/setenv.sh
步骤4:两种方式编译
方法1:在源码根目录下编译指定的应用程序
minstall 路径/my_bin
方法2:
进入到需要编译的源码目录 -> mm
编译出来的文件放在:openwrt/bin/sun5i/packages/base/zhc_test_0.0.1-1_sun5i.ipk
步骤5:将文件通过 adb push 到板子中并安装
opkg install zhc_test_0.0.1-1_sun5i.ipk
然后无论在哪个路径下,可以直接通过敲 zhc_test 即可执行该程序。 |