首页/新闻资讯/正文详情

Buildroot 开机自启动:让你的 ARM64 程序随 Linux 启动运行

发布时间:2026/11/5 7:51:51 来源:云帆数科 栏目:资讯中心
Buildroot 开机自启动:让你的 ARM64 程序随 Linux 启动运行
Buildroot 开机自启动让你的 ARM64 程序随 Linux 启动运行每次启动 QEMU都要登录系统再手动输入/usr/bin/debug_demo。学习时这样做没问题但如果这是一个采集数据、监测状态的设备难道每次开机都要有人敲命令吗这一篇让程序随 Linux 启动自动运行并且能查看状态、读取日志、停止和重新启动。继续使用前四篇的 Ubuntu、QEMU 和 Buildroot 环境不需要开发板。我们不把命令临时塞进旧镜像而是让 Buildroot 软件包同时安装程序和启动脚本。这样重新构建镜像后自启动能力也能保留下来。一、这次要完成什么前四篇依次解决了启动 ARM64 Linux、远程调试程序、添加自定义软件包以及保存 defconfig 并在新目录重建系统。如果还没有建立外部软件包目录请先完成第三篇《告别手动复制在 Buildroot 中添加自己的 ARM64 软件包》再按第四篇《Buildroot 配置怎么备份用 defconfig 在新目录重建 ARM64 系统》准备新输出目录。本篇从这套已构建成功的环境继续不是从空目录开始搭建。本篇接着完成下面的流程Buildroot 安装程序和启动脚本 - 生成 rootfs 镜像 - QEMU 启动 Linux - init 调用启动脚本 - debug_demo 在后台定期写入日志最终检查四件事开机后不手动启动应用就能查到服务进程及其日志。再执行一次start不会重复启动实例。可以执行stop、start、restart和status。正常重启系统后程序再次自动运行。开机自启动不等于进程守护。本文的脚本负责启动和停止不会在程序崩溃后自动拉起它也不提供健康检查或故障恢复。二、沿用新输出目录先备份文件项目本文使用的环境开发主机Ubuntu 20.04 x86_64 虚拟机Buildroot2025.02.8源码位于~/buildroot-2025.02.8输出目录上篇已构建的~/buildroot-output-arm64-demo外部目录~/buildroot-external-demo标识为ARM64_DEMO自定义包debug-demo目标程序/usr/bin/debug_demo本篇启动方式BusyBox init 与/etc/init.d/脚本默认在 Ubuntu 主机执行命令。只有明确标注“QEMU 目标端”的命令才在 ARM64 Linux 内执行。不要把这些 Bash 命令直接复制到 Windows PowerShell。先关闭仍在使用该镜像的 QEMU在目标端执行poweroff系统关机后若 QEMU 未退出再按CtrlA松开后按X。生成镜像时不要让 QEMU 同时写入它也不要从主机挂载正在使用的镜像。在 Ubuntu 终端重新设置变量不依赖上次终端留下的环境exportDEMO_OUT$HOME/buildroot-output-arm64-democd~/buildroot-2025.02.8printfDEMO_OUT%s\n$DEMO_OUTtest-f$DEMO_OUT/.configecho$?grep-E^BR2_(INIT_BUSYBOX|PACKAGE_BUSYBOX|PACKAGE_DEBUG_DEMO)$DEMO_OUT/.config预期文件检查返回0三个配置项均为y。如果目录不存在先完成上一篇的新目录构建如果使用的是 systemd 或其他 init请先停止套用本篇步骤不要直接切换 init 后继续增量构建。备份将要修改的外部文件和当前配置BACKUP_DIR$HOME/debug-demo-before-autostart-$(date%Y%m%d-%H%M%S)mkdir-p$BACKUP_DIRcp-a$HOME/buildroot-external-demo$BACKUP_DIR/cp-p$DEMO_OUT/.config$BACKUP_DIR/buildroot.configprintfBackup: %s\n$BACKUP_DIR下面会覆盖示例源码和包规则。已有其他改动的读者应先比较后合并不要直接覆盖。无需执行make clean、make distclean也不要重新加载官方 defconfig。三、先弄清是谁启动了应用Ubuntu 主机的服务管理方式不代表 QEMU 内的目标系统也一样。本篇只针对已经确认的 BusyBox init启动链路如下Linux 内核 - /sbin/initPID 1BusyBox init - /etc/inittab - /etc/init.d/rcS - /etc/init.d/S99debug-demo startBuildroot 2025.02.8 的默认 BusyBoxinittab会在系统初始化时执行rcS。rcS按文件名顺序处理/etc/init.d/S??*对本文这种不带.sh后缀的脚本传入start参数。正常关机时rcK反向遍历这些脚本并传入stop。S99debug-demo中的99让它排在较后的启动位置但编号不是依赖管理它不保证网络已经连通也不保证某个外设就绪。本例不依赖网络或硬件。先检查上篇生成的目标文件确认没有被自定义 overlay 替换成另一套启动流程grep-n/etc/init.d/rc[SK]$DEMO_OUT/target/etc/inittabcat$DEMO_OUT/target/etc/init.d/rcScat$DEMO_OUT/target/etc/init.d/rcKgrep-E^CONFIG_(START_STOP_DAEMON|FEATURE_START_STOP_DAEMON_FANCY|READLINK|SLEEP)y$\$DEMO_OUT/build/busybox-*/.config最后一项预期能找到四个已启用的 BusyBox 配置启动管理工具、支持后台启动和写 PID 文件的扩展选项以及脚本使用的readlink、sleep。如果构建目录已清理先恢复构建如果选项缺失先补齐并保存自定义 BusyBox 配置、重建验证不要假设主机上的同名命令能替代目标端工具。本次检查 BusyBox 构建配置的实际输出如下四个必需选项均已启用CONFIG_READLINKy CONFIG_SLEEPy CONFIG_START_STOP_DAEMONy CONFIG_FEATURE_START_STOP_DAEMON_FANCYy四、让原程序增加持续运行模式原来的程序算完数组总和就退出。这样的程序也可以开机执行但不方便观察持续运行、停止和重启。这次保留无参数时的v2输出新增--service模式每两秒写一条日志收到SIGTERM或SIGINT后退出。程序本身不 fork后台运行交给启动工具处理。在Ubuntu 主机执行完整代码块cd~/buildroot-external-democatsrc/debug-demo/debug_demo.cEOF #include signal.h #include stdio.h #include string.h #include unistd.h static volatile sig_atomic_t running 1; static void handle_signal(int signal_number) { (void)signal_number; running 0; } int compute_total(const int *values, int count) { int total 0; for (int index 0; index count; index) { total values[index]; } return total; } int main(int argc, char *argv[]) { const int values[] {10, 20, 30, 40}; int result compute_total(values, 4); if (argc 1) { printf(debug-demo package v2: total %d\n, result); return 0; } if (argc ! 2 || strcmp(argv[1], --service) ! 0) { fprintf(stderr, Usage: %s [--service]\n, argv[0]); return 1; } struct sigaction action {0}; action.sa_handler handle_signal; sigemptyset(action.sa_mask); if (sigaction(SIGTERM, action, NULL) ! 0 || sigaction(SIGINT, action, NULL) ! 0) { perror(sigaction); return 1; } FILE *log_file fopen(/var/log/debug-demo.log, a); if (log_file NULL) { perror(open log); return 1; } unsigned long tick 0; while (running) { if (fprintf(log_file, debug-demo service: pid%ld tick%lu total%d\n, (long)getpid(), tick, result) 0 || fflush(log_file) ! 0) { fclose(log_file); return 1; } sleep(2); } if (fprintf(log_file, debug-demo service: pid%ld stopped\n, (long)getpid()) 0) { fclose(log_file); return 1; } return fclose(log_file) 0 ? 0 : 1; } EOF这里有三个设计点信号处理函数只修改退出标志不在其中调用printf或操作日志。每条日志后调用fflush把 C 库缓冲区中的内容交给系统便于及时查看它不等于保证掉电后数据仍在磁盘上。服务直接打开日志文件不依赖后台启动后的标准输出。BusyBox 的后台启动会处理标准输入输出不能简单假定在启动命令后加重定向就一定能收集应用日志。日志路径先固定为/var/log/debug-demo.log本篇按 root 运行。它是短时间实验方案没有日志轮转不能无限运行默认文件系统中该路径还可能位于易失存储重启后日志不一定保留。生产环境应另外设计日志限额、权限和持久化。五、编写可启动、停止和查状态的脚本本篇只新增一个外部文件package/debug-demo/S99debug-demo。它最终由软件包安装到目标系统的/etc/init.d/。仍在Ubuntu 主机的~/buildroot-external-demo中执行catpackage/debug-demo/S99debug-demoEOF #!/bin/sh DAEMON/usr/bin/debug_demo PIDFILE/var/run/debug-demo.pid is_running() { [ -r $PIDFILE ] || return 1 PID$(cat $PIDFILE) || return 1 case $PID in |*[!0-9]*) return 1 ;; esac [ $PID -gt 1 ] || return 1 kill -0 $PID 2/dev/null || return 1 [ $(readlink /proc/$PID/exe) $DAEMON ] } start() { if is_running; then echo debug-demo already running (pid $PID) return 0 fi [ -x $DAEMON ] || return 1 mkdir -p /var/run /var/log || return 1 rm -f $PIDFILE || return 1 start-stop-daemon -S -b -m -p $PIDFILE -x $DAEMON -- --service || return 1 sleep 1 if is_running; then echo debug-demo started (pid $PID) return 0 fi echo debug-demo failed to start; check executable, arguments and log directory 2 return 1 } stop() { if ! is_running; then rm -f $PIDFILE || return 1 echo debug-demo not running return 0 fi start-stop-daemon -K -p $PIDFILE -x $DAEMON -s TERM || return 1 attempts0 while is_running; do if [ $attempts -ge 5 ]; then echo debug-demo did not stop; keeping PID file 2 return 1 fi sleep 1 attempts$((attempts 1)) done rm -f $PIDFILE || return 1 echo debug-demo stopped } case $1 in start) start ;; stop) stop ;; restart) stop start ;; status) if is_running; then echo debug-demo running (pid $PID) else echo debug-demo not running exit 1 fi ;; *) echo Usage: $0 {start|stop|restart|status} 2 exit 1 ;; esac EOFchmod0755 package/debug-demo/S99debug-demosh-npackage/debug-demo/S99debug-demoecho$?语法检查预期返回0。它只验证 shell 语法不能证明 ARM64 系统上的启动流程已经成功。文件应使用 LF 换行不要把脚本保存成 Windows 的 CRLF 格式。start-stop-daemon是启动和停止进程的工具名字里有 daemon并不代表它会常驻监控程序参数本文中的作用-S/-K启动 / 向匹配进程发信号-b后台启动避免常驻程序阻塞rcS-m -p启动时创建指定的 PID 文件-x指定可执行文件停止时与 PID 一起用于匹配-s TERM发送正常终止信号让应用处理退出-- --service将--service传给应用不再作为工具选项解析PID 是进程编号。只看到 PID 文件存在并不能说明程序还活着所以脚本同时检查进程及/proc/PID/exe。停止后最多等待约五秒超时就报错并保留 PID 文件不直接强制杀死进程。这个脚本的边界它面向单人、顺序操作的实验启动后的一秒检查只是存活检查不是业务就绪通知。它没有并发控制锁也不能消除所有 PID 复用竞争不要同时调用多个start/restart不要手工删除运行中服务的 PID 文件也不要绕过脚本另开--service实例。六、让软件包安装启动脚本不改外部目录的external.desc、顶层Config.in或external.mk也不新增第二个软件包。在原规则中增加DEBUG_DEMO_INSTALL_INIT_SYSV。下面给出完整文件方便与第三篇对照define内的命令保持 Tab 缩进catpackage/debug-demo/debug-demo.mkEOF DEBUG_DEMO_VERSION 1.0 DEBUG_DEMO_SITE $(BR2_EXTERNAL_ARM64_DEMO_PATH)/src/debug-demo DEBUG_DEMO_SITE_METHOD local define DEBUG_DEMO_BUILD_CMDS $(TARGET_CC) $(TARGET_CFLAGS) -Wall -Wextra -O0 -g -gdwarf-4 \ -fno-omit-frame-pointer $(D)/debug_demo.c \ -o $(D)/debug_demo $(TARGET_LDFLAGS) endef define DEBUG_DEMO_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(D)/debug_demo \ $(TARGET_DIR)/usr/bin/debug_demo endef define DEBUG_DEMO_INSTALL_INIT_SYSV $(INSTALL) -D -m 0755 $(DEBUG_DEMO_PKGDIR)/S99debug-demo \ $(TARGET_DIR)/etc/init.d/S99debug-demo endef $(eval $(generic-package)) EOF虽然接口名带SYSV它也适用于 Buildroot 的 BusyBox init。Buildroot 根据所选 init 执行对应安装接口并不是只认 Linux 主机上的服务管理器。这里沿用前文的调试编译参数-O0会覆盖前面$(TARGET_CFLAGS)中的优化级别。如果其中启用了_FORTIFY_SOURCE可能出现_FORTIFY_SOURCE requires compiling with optimization (-O)告警表示该程序的这项加固未生效不等于本次编译失败仍需检查构建返回码及目标端运行结果。本文保留这组已实测参数不把它作为生产配置推荐。用于生产环境时应重新评估优化和加固选项并重新构建、验证而不是仅屏蔽告警。$(DEBUG_DEMO_PKGDIR)指向包规则所在目录里面有启动脚本$(D)指向应用源码同步后的构建目录。两者用途不同。启动脚本不需要复制到src/debug-demo/也不需要再放进 overlay。本次没有改变 Buildroot 配置选择原来的BR2_PACKAGE_DEBUG_DEMOy仍然有效因此不必为了新增脚本重新保存 defconfig。但必须保存更新后的源码、包规则及启动脚本defconfig 本身不包含它们。七、重建软件包再生成镜像回到Ubuntu 主机的 Buildroot 源码目录cd~/buildroot-2025.02.8makeO${DEMO_OUT:?请先设置 DEMO_OUT}\BR2_EXTERNAL$HOME/buildroot-external-demodebug-demo-rebuildV1echo$?确认返回0后再生成镜像makeO${DEMO_OUT:?请先设置 DEMO_OUT}\BR2_EXTERNAL$HOME/buildroot-external-demo-j2echo$?${DEMO_OUT:?...}会在变量未设置或为空时阻止命令执行避免把空值传给O。每个echo $?都必须紧接着被检查的命令执行有非零返回码就先处理错误不要继续启动旧镜像。本例使用本地源码包debug-demo-rebuild会重新同步源码、编译和安装。后面的完整make才负责更新 rootfs 镜像不能省略。检查产物file$DEMO_OUT/target/usr/bin/debug_demols-l$DEMO_OUT/target/etc/init.d/S99debug-demosh-n$DEMO_OUT/target/etc/init.d/S99debug-demoecho$?cmp$HOME/buildroot-external-demo/package/debug-demo/S99debug-demo\$DEMO_OUT/target/etc/init.d/S99debug-demoecho$?ls-lh$DEMO_OUT/images/Image$DEMO_OUT/images/rootfs.ext2本次检查结果如下程序为 ARM64 ELF 文件启动脚本具有可执行权限sh -n和cmp均返回0说明脚本通过语法检查且安装后的内容与外部目录中的源文件一致。下面保留实际终端记录embedembedtest:~/buildroot-2025.02.8$ file $DEMO_OUT/target/usr/bin/debug_demo /home/embed/buildroot-output-arm64-demo/target/usr/bin/debug_demo: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 6.12.0, stripped embedembedtest:~/buildroot-2025.02.8$ ls -l $DEMO_OUT/target/etc/init.d/S99debug-demo -rwxr-xr-x 1 embed embed 1731 Oct 17 04:42 /home/embed/buildroot-output-arm64-demo/target/etc/init.d/S99debug-demo embedembedtest:~/buildroot-2025.02.8$ sh -n $DEMO_OUT/target/etc/init.d/S99debug-demo embedembedtest:~/buildroot-2025.02.8$ echo $? 0 embedembedtest:~/buildroot-2025.02.8$ cmp $HOME/buildroot-external-demo/package/debug-demo/S99debug-demo \ $DEMO_OUT/target/etc/init.d/S99debug-demo embedembedtest:~/buildroot-2025.02.8$ echo $? 0 embedembedtest:~/buildroot-2025.02.8$ ls -lh $DEMO_OUT/images/Image $DEMO_OUT/images/rootfs.ext2 -rw-r--r-- 1 embed embed 12M Oct 15 20:36 /home/embed/buildroot-output-arm64-demo/images/Image -rw-r--r-- 1 embed embed 60M Oct 17 04:48 /home/embed/buildroot-output-arm64-demo/images/rootfs.ext2stripped表示目标程序的调试符号已被剥除不影响正常运行。rootfs 镜像的修改时间已更新而内核Image仍保留此前的时间这是正常的本次只修改应用和启动脚本不需要重新编译内核。以上记录确认了主机端产物但未包含完整make的返回码。target/是构建过程中的目标目录镜像时间更新也不能单独证明其中的内容正确是否能够开机自动运行仍需启动 QEMU 验证。如果脚本比较不一致检查已有 overlay 或后处理脚本是否覆盖了/etc/init.d/S99debug-demo。也不要让 overlay 中的旧程序覆盖/usr/bin/debug_demo。八、启动 QEMU先验证自动运行确认没有其他 QEMU 使用同一镜像或占用本机端口5000。在Ubuntu 主机执行/usr/bin/qemu-system-aarch64\-Mvirt\-cpucortex-a53\-smp2\-m1G\-nographic\-kernel${DEMO_OUT:?请先设置 DEMO_OUT}/images/Image\-appendrootwait root/dev/vda consolettyAMA0\-drivefile$DEMO_OUT/images/rootfs.ext2,ifnone,formatraw,idhd0\-devicevirtio-blk-device,drivehd0\-netdevuser,idnet0,hostfwdtcp:127.0.0.1:5000-:2345\-devicevirtio-net-device,netdevnet0端口转发只是保留前文的调试入口本篇启动服务不依赖它。无需运行 gdbserver。以root登录后先不要执行start也不要手动运行--service。直接在QEMU 目标端检查uname-mreadlink /proc/1/exe start-stop-daemon--help/etc/init.d/S99debug-demo statusecho$?cat/var/run/debug-demo.pidps|grep[d]ebug_demotail-n5/var/log/debug-demo.log本次登录后按上述步骤检查实际记录如下。为便于阅读省略了较长的start-stop-daemon --help输出本次目标端为 BusyBox v1.37.0帮助信息确认支持脚本使用的-S、-K、-b、-m、-p、-x和-s选项。# uname -m aarch64 # readlink /proc/1/exe /bin/busybox # /etc/init.d/S99debug-demo status debug-demo running (pid 121) # echo $? 0 # cat /var/run/debug-demo.pid 121 # ps | grep [d]ebug_demo 121 root /usr/bin/debug_demo --service # tail -n 5 /var/log/debug-demo.log debug-demo service: pid121 tick12 total100 debug-demo service: pid121 tick13 total100 debug-demo service: pid121 tick14 total100 debug-demo service: pid121 tick15 total100 debug-demo service: pid121 tick16 total100这份记录确认了以下结果系统架构为aarch64PID 1 运行的是/bin/busybox。服务状态查询返回0状态输出、PID 文件和进程列表中的 PID 均为121。进程以/usr/bin/debug_demo --service运行列表中显示一个服务实例对应日志的tick从12连续递增到16求和结果均为100。结合本节登录后未手动启动应用的操作过程这说明本次开机后服务已自动运行并多次写入日志。PID 和 tick 是本次运行值不是其他实验必须一致的固定值。这次记录只展示了一次tail的结果。过几秒再次执行tail -n 5 /var/log/debug-demo.log还应确认当前 PID 的tick继续增长以验证后续仍在运行。重复启动、停止和重启行为继续在下一节检查不能由这份记录一并判定通过。九、验证重复启动、停止、重启和兼容性以下命令都在QEMU 目标端执行每组执行后先核对结果再继续。1. 重复 start不增加实例before_pid$(cat/var/run/debug-demo.pid)/etc/init.d/S99debug-demo startecho$?after_pid$(cat/var/run/debug-demo.pid)test$before_pid$after_pidecho$?ps|grep[d]ebug_demo本次重复执行start的实际记录如下# before_pid$(cat /var/run/debug-demo.pid) # /etc/init.d/S99debug-demo start debug-demo already running (pid 121) # echo $? 0 # after_pid$(cat /var/run/debug-demo.pid) # test $before_pid $after_pid # echo $? 0 # ps | grep [d]ebug_demo 121 root /usr/bin/debug_demo --service脚本提示服务已运行并返回0启动前后的 PID 比较也返回0进程列表仍只有 PID 为121的一个服务实例。这说明本次顺序重复启动检查通过没有产生额外实例。PID 相同与实例数量需要一起检查这个结果不代表同时调用多个start的并发场景也已验证。2. stop 后进程退出且日志停止增长/etc/init.d/S99debug-demo stopecho$?/etc/init.d/S99debug-demo statusecho$?test!-e/var/run/debug-demo.pidecho$?ps|grep[d]ebug_demotail-n5/var/log/debug-demo.log本次停止服务的实际记录如下# /etc/init.d/S99debug-demo stop stopped /usr/bin/debug_demo (pid 121) debug-demo stopped # echo $? 0 # /etc/init.d/S99debug-demo status debug-demo not running # echo $? 1 # test ! -e /var/run/debug-demo.pid # echo $? 0 # ps | grep [d]ebug_demo # tail -n 5 /var/log/debug-demo.log debug-demo service: pid121 tick136 total100 debug-demo service: pid121 tick137 total100 debug-demo service: pid121 tick138 total100 debug-demo service: pid121 tick139 total100 debug-demo service: pid121 stopped停止命令返回0随后状态查询显示未运行PID 文件不存在的检查返回0进程查询也没有输出。日志最后一行为 PID121的stopped说明程序执行了退出日志逻辑结合进程检查可确认本次服务已停止。这份记录只展示了停止后的一次日志查看。继续下一步启动服务前过几秒再执行tail -n 5 /var/log/debug-demo.log确认末尾仍为同一条stopped补充验证停止后日志不再增长。此处status返回1是脚本定义的“未运行”不是停止失败。它只是本例约定不是完整的 LSB 服务状态码实现。3. 再次 start并测试 restart/etc/init.d/S99debug-demo startecho$?/etc/init.d/S99debug-demo restartecho$?/etc/init.d/S99debug-demo statusecho$?cat/var/run/debug-demo.pidps|grep[d]ebug_demotail-n8/var/log/debug-demo.log本次再次启动并执行restart的实际记录如下# /etc/init.d/S99debug-demo start debug-demo started (pid 161) # echo $? 0 # /etc/init.d/S99debug-demo restart stopped /usr/bin/debug_demo (pid 161) debug-demo stopped debug-demo started (pid 175) # echo $? 0 # /etc/init.d/S99debug-demo status debug-demo running (pid 175) # echo $? 0 # cat /var/run/debug-demo.pid 175 # ps | grep [d]ebug_demo 175 root /usr/bin/debug_demo --service # tail -n 8 /var/log/debug-demo.log debug-demo service: pid121 tick137 total100 debug-demo service: pid121 tick138 total100 debug-demo service: pid121 tick139 total100 debug-demo service: pid121 stopped debug-demo service: pid161 tick0 total100 debug-demo service: pid161 stopped debug-demo service: pid175 tick0 total100 debug-demo service: pid175 tick1 total100start、restart和随后的status均返回0。再次启动时的 PID 为161执行restart后该实例停止新实例以 PID175运行。状态输出、PID 文件和进程列表一致最后只显示一个服务实例。日志记录了 PID161从tick0开始写入并停止以及 PID175从tick0重新计数并增长到1确认本次再次启动和服务重启检查通过。前面的 PID121记录是追加保留的历史日志不代表旧进程仍在运行。PID 以实际运行结果为准不要求与本文一致这里验证的是应用服务重启系统重启后自动运行仍需第五小节验证。4. 不带参数仍保留原来的功能/usr/bin/debug_demoecho$?本次不带参数运行的实际结果如下# /usr/bin/debug_demo debug-demo package v2: total 100 # echo $? 0程序仍输出原来的v2求和结果并以状态码0退出说明新增--service模式后无参数运行方式仍然可用。这次运行是短暂的前台求和程序不是额外的常驻服务。5. 正常重启后再次自动运行先保留本轮日志与终端记录再在QEMU 目标端的#提示符下执行不要在 Ubuntu 主机执行reboot第一步根据终端画面判断是否需要重新启动 QEMU。如果出现新的 Linux 启动信息随后显示login:说明目标系统已在原 QEMU 中重新启动。输入root登录直接进入第二步不要再执行 QEMU 启动命令。如果 QEMU 已退出回到 Ubuntu 的embedembedtest:...$提示符才在Ubuntu 主机执行下面的命令重新启动同一镜像。若此前使用了其他输出目录请把DEMO_OUT设为此前实际使用的目录。exportDEMO_OUT$HOME/buildroot-output-arm64-demo/usr/bin/qemu-system-aarch64\-Mvirt\-cpucortex-a53\-smp2\-m1G\-nographic\-kernel${DEMO_OUT:?请先设置 DEMO_OUT}/images/Image\-appendrootwait root/dev/vda consolettyAMA0\-drivefile$DEMO_OUT/images/rootfs.ext2,ifnone,formatraw,idhd0\-devicevirtio-blk-device,drivehd0\-netdevuser,idnet0,hostfwdtcp:127.0.0.1:5000-:2345\-devicevirtio-net-device,netdevnet0启动后在login:处输入root。如果画面停住既没有登录提示也没有回到 Ubuntu 提示符先保留最后的输出排查不要另开一个使用同一可写镜像的 QEMU。这一步不需要重新编译或生成镜像。第二步登录后直接检查不手动启动应用。不要执行/etc/init.d/S99debug-demo start也不要执行/usr/bin/debug_demo --service否则无法用这次检查判断是否为开机自动运行。在QEMU 目标端执行/etc/init.d/S99debug-demo statusecho$?cat/var/run/debug-demo.pidps|grep[d]ebug_demotail-n5/var/log/debug-demo.log本次重启后登录未手动启动应用第二步的实际检查结果如下# /etc/init.d/S99debug-demo status debug-demo running (pid 121) # echo $? 0 # cat /var/run/debug-demo.pid 121 # ps | grep [d]ebug_demo 121 root /usr/bin/debug_demo --service # tail -n 5 /var/log/debug-demo.log debug-demo service: pid121 tick114 total100 debug-demo service: pid121 tick115 total100 debug-demo service: pid121 tick116 total100 debug-demo service: pid121 tick117 total100 debug-demo service: pid121 tick118 total100状态查询返回0状态输出、PID 文件和进程列表中的 PID 均为121且只显示一个服务实例。对应日志包含连续的tick114至118求和结果均为100。结合本次重启后未手动启动应用的操作过程说明服务已再次自动运行下一步继续通过间隔查看日志确认它仍在输出。本次 PID 与首次开机时同为121是正常现象系统重新启动后可能分配相同的进程编号不能只靠 PID 是否变化判断系统是否重启。第三步间隔查看日志确认程序仍在运行。过几秒后在QEMU 目标端再次执行tail-n5/var/log/debug-demo.log比较两次输出确认当前服务 PID 对应的tick继续增长total仍为100。保存重启过程、状态检查和两次日志输出作为本项实测记录若服务未运行先保留失败输出不要手动启动后将其记为自启动验证通过。本次间隔查看日志的实际结果如下# tail -n 5 /var/log/debug-demo.log debug-demo service: pid121 tick152 total100 debug-demo service: pid121 tick153 total100 debug-demo service: pid121 tick154 total100 debug-demo service: pid121 tick155 total100 debug-demo service: pid121 tick156 total100与第二步相比日志中的 PID 仍为121最新tick从118增长到156total始终为100。结合重启后未手动启动应用、状态查询返回0及进程检查结果本次系统重启后自动运行和日志继续增长的验证通过这不代表已完成长期稳定性测试。默认/var/log可能是易失目录不要求重启前后的日志都保留本次要确认的是新一轮启动后服务存在并在写入新的日志。十、遇到问题先查这些现象优先检查启动停住迟迟没有登录提示是否直接在启动脚本前台执行了无限循环程序是否漏了后台启动选项镜像里没有启动脚本是否启用 BusyBox init安装接口是否位于generic-package之前是否重建包及镜像Permission denied或not found脚本是否为 0755、LF 换行首行是否为#!/bin/sh程序及动态加载器是否存在提示不认识-b或-m目标 BusyBox 是否启用对应扩展功能不要拿 Ubuntu 主机工具的参数能力作判断status未运行、没有日志检查/var/log是否可写、空间是否耗尽、程序是否为新版本先看启动错误start成功却不再更新日志启动检查不是持续健康检查重新检查进程和实际日志程序可能之后退出改完源码仍是旧行为是否始终使用相同O是否完成包重建和镜像生成QEMU 是否启动了旧镜像关机没有执行自定义停止逻辑核对目标/etc/inittab的 shutdown 项、rcK和脚本权限是否被 overlay 改写启动失败时可以先通过脚本停止服务并确认没有残留实例再在目标端前台运行/usr/bin/debug_demo --service。此时初始化错误会显示在终端正常运行的日志仍写入文件检查后用CtrlC退出。不要在服务已经运行时直接再启动一个实例。如果改过 BusyBox 自身配置仅保存 Buildroot defconfig 不够还需保存并引用自定义 BusyBox 配置。本文主线假定这些工具已经存在没有替你完成这项配置迁移。十一、小结这一篇把程序从“登录后手动运行”推进到“系统开机自动运行”源码提供持续运行模式 启动脚本管理进程 软件包安装程序和脚本 QEMU 验证启动、停止及重启需要保留的仍是外部目录中的实际文件而不只是镜像或 defconfig。本篇修改源码、修改包规则并新增启动脚本没有引入 systemd 或新的硬件要求。本次实验验证了开机自动运行、顺序重复启动不增加实例、停止与重新启动、无参数运行兼容性以及系统重启后的自动运行和日志更新。这个脚本适合入门实验但还不具备异常退出后自动恢复、日志轮转等长期运行能力。下一步才是更接近长期运行设备的问题程序异常退出如何恢复日志怎样限额以及服务如何以更小权限运行。本篇完成了从软件包集成到开机运行、状态查询、停止及重启的基础实践实测结果与验证边界见前文。参考资料Buildroot 2025.02.8 通用软件包接口INSTALL_INIT_SYSV、包目录变量及安装流程。Buildroot 2025.02.8 BusyBox inittab启动及关机阶段调用入口。Buildroot 2025.02.8 rcS 与 rcK启动脚本调用顺序和参数。

相关推荐

用Scenario Skills生成生产级图片:GPT Image、Gemini Nano Banana等8大模型家族的实战选择
用Scenario Skills生成生产级图片:GPT Image、Gemini Nano Banana等8大模型家族的实战选择

用Scenario Skills生成生产级图片:GPT Image、Gemini Nano Banana等8大模型家族的实战选择 【免费下载链接】skills Get production-ready images, video, audio, and 3D from any AI agent: skills that pick the right model, price before spending, and keep ch… · 2026/11/5 7:50:50

MinIO源码深度解读-第14章第14节-性能调优实战-网络磁盘到代码的全方位优化指南
MinIO源码深度解读-第14章第14节-性能调优实战-网络磁盘到代码的全方位优化指南

MinIO源码深度解读 - 第14章第14节:性能调优实战——网络、磁盘、代码全方位优化指南 生产环境的 MinIO 需要精心调优才能达到最佳性能。本文从网络、磁盘到代码层面全面分析性能优化。 本文导航 性能基准数据磁盘优化网络优化代码层优化配置调优 性能基准数据 在… · 2026/11/5 7:49:50

MinIO源码深度解读-第15章第2节-Kubernetes部署进阶-Operator与GitOps自动化运维实践
MinIO源码深度解读-第15章第2节-Kubernetes部署进阶-Operator与GitOps自动化运维实践

MinIO源码深度解读 - 第15章第2节:Kubernetes 部署进阶——Operator 与 GitOps 自动化运维实践 从裸机到 Kubernetes 是 MinIO 生产化的分水岭。本文深入 MinIO Operator 的 CRD 设计、有状态管理策略和 GitOps 自动化实践。 本文导航 K8s 部署架构MinIO Operator … · 2026/11/5 7:49:50

【Java基础知识】方法与注释
【Java基础知识】方法与注释

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:43:30

【Java基础知识】进制转换
【Java基础知识】进制转换

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:43:30

【Java基础知识】字面量与变量
【Java基础知识】字面量与变量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:43:30

kafka--基础知识点--0
kafka--基础知识点--0

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:43:30

如何用AI新闻雷达Horizon打造你的专属信息过滤系统
如何用AI新闻雷达Horizon打造你的专属信息过滤系统

如何用AI新闻雷达Horizon打造你的专属信息过滤系统 【免费下载链接】Horizon 📡 Your own AI-powered news radar. Generates daily briefings in English & Chinese. | 用 AI 构建你专属的新闻雷达 项目地址: https://gitcode.com/GitHub_Trending/horizon39… · 2026/11/5 8:41:27

SuperSplat 新手排错指南:3D Gaussian Splat 编辑器常见 5 类坑一次讲清
SuperSplat 新手排错指南:3D Gaussian Splat 编辑器常见 5 类坑一次讲清

SuperSplat 新手排错指南:3D Gaussian Splat 编辑器常见 5 类坑一次讲清 【免费下载链接】super-splat 3D Gaussian Splat Editor 项目地址: https://gitcode.com/gh_mirrors/su/super-splat 第一次把 SuperSplat 跑起来就卡住了?先别急着怀疑人生… · 2026/11/5 8:41:27

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码