Yocto
Yocto系列讲解[入门篇] 1 - 快速入门熟悉Yocto的构建
Yocto系列讲解[入门篇] 2 - 演示运行qemux86-64虚拟机
Yocto系列讲解[理论篇] 3 - meta layer recipe class概念介绍
Yocto系列讲解[入门篇] 4 - 创建自己的meta layer
Yocto系列讲解[入门篇] 5 - 在meta-mylayer中添加helloworld recipe
Yocto系列讲解[理论篇] 6 - yocto是什么,学习它不难
Yocto系列讲解[实战篇] 7 - 开发工具devtool实操(创建新项目helloyocto)
Yocto系列讲解[实战篇] 8 - 开发工具devtool实操(添加git项目learnyocto)
Yocto系列讲解[实战篇] 9 - devtool验证并将learnyocto添加到meta-mylayer中
Yocto系列讲解[实战篇] 10 - 在qemux86机器运行时安装程序
Yocto系列讲解[实战篇] 11 - 在qemux86机器运行时卸载删除程序
Yocto系列讲解[实战篇]12 - 修改开源项目的代码(1)
Yocto系列讲解[技巧篇]13 - devtool修改workspace目录位置
Yocto系列讲解[技巧篇]14 - devtool edit-recipe命令(编辑bb文件命令)
本文档使用 MrDoc 发布
-
+
首页
Yocto系列讲解[入门篇] 5 - 在meta-mylayer中添加helloworld recipe
### 前言 在前面的一篇[yocto-第4篇-创建自己的meta layer](https://blog.csdn.net/fulinus/category_10445379.html)中,我们已经在`poky`目录中添加了自己的一个`meta layer`,即`meta-mylayer`,而且在该`layer`中还有一个自动生成的`recipe`,即`example`,没有任何源码仅仅是有一个可以`bitbake`的`example.bb`文件,用于输出编译信息。 对于绝大部分小白盆友而言,如何快速添加一个项目,哪怕是一个`helloworld`项目,也是对于自己初识`yocto`想快速上手的一个也非常有用的示例和帮助,因为一个好的例子胜过千言万语。诚然,关于`yocto`如何添加`helloworld`项目在其他博文中也可以看到,但是应该没有本篇全面和系统化,考虑到项目有多种构建系统,比如`Makefile`、`Autotools`和`Cmake`等构建的项目。我将在本篇中尽可能为大家展示出来。 ### 创建项目的recipes 首先我们考虑下这个`helloworld`项目源代码放在哪里?git服务器或者本地?当然都是可以的(本专利其他系列有讲到)。这里先考虑将源代码(毕竟源文件很少)放到`meta-mylayer`目录中。之前的文章中我们说了`recipes`是放在`meta layer`目录下的,因此,我们也在`meta-mylayer`目录中创建一个`recipe`, 参考下面: poky]$ cd meta-mylayer/ meta-mylayer]$ mkdir recipes-helloworld meta-mylayer]$ cd recipes-helloworld/ 见上面,我们将会在`recipes-helloworld`目录中放置若干种方式构建的`helloworld`项目。 ### 由Makefile构建的项目 1. 创建一个`Makefile`方式构建的`helloworld`项目,为了区分后面的构建系统项目,这里我们将目录名定为`hellowolrd-m`,参考如下过程: ```shell recipes-helloworld]$ mkdir helloworld-m/helloworld recipes-helloworld]$ cd hellowolrd-m/helloworld ``` 2. 并新建一个`helloworld.c`文件: ```C //helloworld.c #include <stdio.h> int main (int argc, char **argv) { printf("Hello World!\n"); return 0; } /* ----- End of main() ----- */ ``` 这个程序很简单,C程序内容也不是本篇的关注点,尽量简单哈。如果大家遇到复杂的情况不清楚怎么弄可以在评论区里面留言。 3. 新建一个`Makefile`文件: ```makefile TARGET = helloworld all := $(TARGET) CFLAGS ?= -Wall -O bindir = $(DESTDIR)/usr/bin/ OBJS = helloworld.o $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ install: install -d $(bindir) install -m 0755 $(TARGET) $(bindir) uninstall: ${RM} $(bindir)/$(TARGET) clean: $(RM) $(TARGET) $(OBJS) .PHONY: all clean install uninstall ``` 4. 在添加bb文件之前,可以先自己手动验证是否有问题,如果没有问题了,我们再继续下一步: ```shell helloworld]$ ls helloworld.c Makefile helloworld]$ make cc -Wall -O -c -o helloworld.o helloworld.c cc -Wall -O helloworld.o -o helloworld helloworld]$ ./helloworld Hello World! helloworld]$ make clean rm -f helloworld helloworld.o helloworld]$ ls helloworld.c Makefile ``` OK~ 上面验证的结果正常,下一步就是写一个`recipe`的bb文件了: 5. 新建一个bb文件,文件名就叫`helloworld-m.bb`,注意文件名中下划线"_"是分隔`recipe`名和版本的,`不能`出现`helloworld_m.bb`的名字,这样一来m就成版本号了。 ```shell helloworld]$ cd ../ helloworld-m]$ vim helloworld-m.bb # helloworld application SUMMARY = "helloworld of makefile recipe" #概要 DESCRIPTION = "My hello world application" #描述 LICENSE = "CLOSED" #关闭license FILESEXTRAPATHS_prepend := "${THISDIR}/:" #文件额外的搜索路径 SRC_URI = "file://helloworld/" #指定源码路径 S = "${WORKDIR}/helloworld" CFLAGS_append = "-Wall -O -g" EXTRA_OEMAKE = "'CC=${CC}' 'CFLAGS=${CFLAGS}'" EXTRA_OEMAKE_append = " 'LDFLAGS=${LDFLAGS}'" EXTRA_OEMAKE_append = " 'DESTDIR=${D}'" do_install () { oe_runmake install } # if no install target in makefile, using this do_install #do_install () { #install -d ${D}${bindir}/ #install -m 0755 ${S}/helloworld ${D}${bindir}/ #} # if no LDFLAGS, using this #INSANE_SKIP_${PN} += "ldflags" FILES_${PN} = "${bindir}/" ``` 这里不细讲bb文件了,关于bb文件的内容和变量等知识,我都放在后面的文章中有讲解,大家这里先了解有个印象即可。 6. 查看文件拓扑结构: ```shell meta-mylayer]$ tree recipes-helloworld/ recipes-helloworld/ └── helloworld-m ├── helloworld │ ├── helloworld.c │ └── Makefile └── helloworld-m.bb 2 directories, 3 files ``` 7. 开始编译 ```shell poky]$ source oe-init-build-env build]$ bitbake helloworld-m ``` 8. 查看编译结果: ```shell build]$ ls tmp/work/core2-64-poky-linux/helloworld-m/1.0-r0/ configure.sstate helloworld packages-split pseudo sysroot-destdir debugsources.list image pkgdata recipe-sysroot temp deploy-ipks license-destdir pkgdata-pdata-input recipe-sysroot-native deploy-source-date-epoch package pkgdata-sysroot source-date-epoch build]$ file tmp/work/core2-64-poky-linux/helloworld-m/1.0-r0/image/usr/bin/helloworld tmp/work/core2-64-poky-linux/helloworld-m/1.0-r0/image/usr/bin/helloworld: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-x86-64.so.2, BuildID[sha1]=641c84dfe75480fef888339aa2c782566d48a106, for GNU/Linux 3.2.0, not stripped ``` OK~ 上面讲解用`Makefile`文件构建的项目,并如何在`yocto`中添加`recipe`的工作到这里就告一段落! _注意:我们的工作到这里并还没有真正完成,如果编译`target`(比如`bitbake core-image-sato`),在文件系统的/usr/bin/目录下没有相应的`helloworld`执行程序。后面再讲。文末再讲如何安装到文件系统中。_ ### 由Autotools(Makefile.am)构建的项目 可能你并没有听说过`Autotools`,但是如果项目当中存在`configure.ac`、`Makefile.am`等文件的时候,你可能会有印象,不错`configure.ac`和`Makefile.am`就是`Autotools`构建项目的配置文件。 1. 新建的`recipe`的子目录,新建对应的新目录名为`helloworld-a`,过程参考如下: ```shell recipes-helloworld]$ mkdir helloworld-a recipes-helloworld]$ cd helloworld-a/ ``` 2.将上一篇的`helloworld`项目复制到该目录,并做增删操作 ```shell helloworld-a]$ cp -rf ../helloworld-m/helloworld . helloworld-a]$ cd helloworld/ helloworld]$ rm Makefile helloworld]$ mkdir src helloworld]$ mv helloworld.c src/ helloworld]$ vim src/helloworld.c ``` 实际上我们也可以不用将源码文件放到`src`目录下,这里只是尽可能向正规的做法靠拢。 3. 修改代码: ```c #include <stdio.h> #include <config.h> //添加了这个 int main (int argc, char **argv) { printf("Hello World and Autotools\n"); return 0; } /* ----- End of main() ----- */ ``` 4. 在`helloworld`目录中新建一个`README`文件(当然有没有这个文件也没关系): ```shell helloworld]$ vim README This is a demonstration package for GNU Automake. Type 'info Automake' to read the Automake manual. ``` 5. 在项目根目录和`src`目录中新建两个`Makefile.am`和`src/Makefile.am`(包含`Automake`指令语句) 新建`Makefile.am`文件 ```shell helloworld]$ vim Makefile.am SUBDIRS = src dist_doc_DATA = README ``` 新建`src/Makefile.am`文件 ```shell helloworld]$ vim src/Makefile.am bin_PROGRAMS = helloworlda #命名为helloworlda是为了区别上面的/usr/bin/helloworld,以免冲突 helloworlda_SOURCES = helloworld.c ``` 6. 新建`configure.ac`文件(该文件内包含创建`configure`脚本的`Autoconf`指令)。 ```shell helloworld]$ vim configure.ac AC_INIT([helloworld], [1.0], [fulinux@sina.com]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_PROG_CC AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([ Makefile src/Makefile ]) AC_OUTPUT ``` 一旦有了这五个文件,就可以运行`Autotools`来实例化构建系统了。 ```shell recipes-helloworld]$ tree helloworld-a/helloworld/ helloworld-a/helloworld/ ├── configure.ac ├── Makefile.am ├── README └── src ├── helloworld.c └── Makefile.am 1 directory, 5 files ``` 7. 本地构建系统实例化和编译演示 使用`autoreconf`命令执行此操作来实例化构建系统,我们首先在本地中验证下。如下所示: ```shell helloworld]$ autoreconf --install configure.ac:3: installing './compile' configure.ac:2: installing './install-sh' configure.ac:2: installing './missing' src/Makefile.am: installing './depcomp' helloworld]$ ls aclocal.m4 compile configure depcomp Makefile.am missing autom4te.cache config.h.in configure.ac install-sh Makefile.in src ``` 此时构建系统已完成。除了上面命令输出中提到的三个脚本之外,还可以看到`autoreconf`还创建了四个其他文件:`configure`、`config.h.In`、`Makefile.In`和`src/Makefile.In`。后三个文件是模板,它们将通过在`config.h`、`Makefile`和`src/Makefile`下进行配置来适应系统。运行如下命令: ```shell helloworld]$ ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether make supports nested variables... yes checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for style of include used by make... GNU checking dependency style of gcc... gcc3 checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating src/Makefile config.status: creating config.h config.status: executing depfiles commands ``` 在`configure`运行之后,可以看到生成了`Makefile`、`src/Makefile`和`config.h`。现在我们可以调用make命令编译了: ```shell helloworld]$ make make all-recursive make[1]: Entering directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld' Making all in src make[2]: Entering directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld/src' gcc -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT helloworld.o -MD -MP -MF .deps/helloworld.Tpo -c -o helloworld.o helloworld.c mv -f .deps/helloworld.Tpo .deps/helloworld.Po gcc -g -O2 -o helloworld helloworld.o make[2]: Leaving directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld/src' make[2]: Entering directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld' make[2]: Leaving directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld' make[1]: Leaving directory '/home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-a/helloworld' ``` 8. 运行演示: ```shell helloworld]$ ./src/helloworld Hello World and Autotools ``` 9. 清理编译生成的文件: 可以编译和运行后,最后就是清理和删除一些编译生成的文件: ```shell helloworld]$ make distclean ``` 当然更绝做法的是: ```shell helloworld]$ rm aclocal.m4 compile configure depcomp missing autom4te.cache config.h.in install-sh Makefile.in -rf helloworld]$ rm src/Makefile.in ``` 最后只保留一开始的5个文件。 10. 添加recipe的bb文件,如下: ```shell helloworld]$ cd ../ helloworld-a]$ cat helloworld-a.bb # helloworld application SUMMARY = "helloworld of Autotools recipe" DESCRIPTION = "My hello world application" LICENSE = "CLOSED" inherit autotools #继承了autotools, 这个是重点 FILESEXTRAPATHS_prepend := "${THISDIR}/:" SRC_URI = "file://helloworld/" S = "${WORKDIR}/helloworld" #CFLAGS_append = "-Wall -O -g" FILES_${PN} = "${bindir}/" ``` 上面是不是很简单,没有前面的bb文件中的一些变量和函数了,不用修改`do_make()`或`do_install()`等函数的原因都是因为继承了`autotools`,继承的这个`class`类做了`autotools`构建编译过程中的各项任务,是不是很简单~ 11. `bitbake`编译演示: ```shell poky]$ source oe-init-build-env build]$ bitbake helloworld-a ``` 12. 结果浏览: ```shell build]$ ls tmp/work/core2-64-poky-linux/helloworld-a/1.0-r0/helloworld/ aclocal.m4 compile config.h.in configure depcomp m4 Makefile.in README autom4te.cache config.guess config.sub configure.ac install-sh Makefile.am missing src ``` 上面可见bitbake的过程中已经自己执行了`autoreconf`命令,是不是很简单呢? ```shell build]$ ls tmp/work/core2-64-poky-linux/helloworld-a/1.0-r0/image/usr/bin/ helloworlda ``` 文末再讲如何安装到文件系统中。使用`Autotools`工具构建的项目就完成了~ ### 由Cmake(CMakeLists.txt)构建的项目 现在讲`Cmake`工具构建的项目,这个也是本专栏推荐的方式,后续的很多示例项目都是用CMake构建的,这方面的教程网上也有,大家感兴趣的也可以了解下~ 1. 首先我们就是新建一个目录用来放这个`recipe`,目录名为`helloworld-c`: ```shell recipes-helloworld]$ mkdir helloworld-c ``` 2. 将初始的`helloworld`项目复制到`helloworld-c`目录中: ```shell recipes-helloworld]$ cp helloworld-m/helloworld helloworld-c/ -rf ``` 3. 增删`helloworld`项目目录结果: ```shell recipes-helloworld]$ cd helloworld-c/helloworld/ helloworld]$ rm Makefile helloworld]$ mkdir src helloworld]$ mv helloworld.c src/ helloworld]$ vim src/helloworld.c ``` ```c #include <stdio.h> int main (int argc, char **argv) { printf("Hello World and Cmake\n"); return 0; } /* ----- End of main() ----- */ ``` 4. 改造`helloworld`项目为由`Cmake`构建: ```shell helloworld]$ vim CMakeLists.txt project(helloworld C) cmake_minimum_required(VERSION 2.6.3) add_subdirectory(src) helloworld]$ cat src/CMakeLists.txt add_executable (helloworldc helloworld.c) install(TARGETS helloworldc DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) ``` 5. OK, 就添加了这两个文件,拓扑结构如下: ```shell helloworld]$ tree . . ├── CMakeLists.txt └── src ├── CMakeLists.txt └── helloworld.c 1 directory, 3 files ``` 6. 本地编译演示,确保`Cmake`构建的项目没问题: ```shell helloworld]$ mkdir build helloworld]$ cd build/ build]$ cmake .. -- The C compiler identification is GNU 5.4.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/peeta/poky/meta-mylayer/recipes-helloworld/helloworld-c/helloworld/build build]$ make Scanning dependencies of target helloworldc [ 50%] Building C object src/CMakeFiles/helloworldc.dir/helloworld.c.o [100%] Linking C executable helloworldc [100%] Built target helloworldc ``` 7. 运行演示: ```shell build]$ ./src/helloworldc Hello World and Cmake ``` 8. 清理编译内容,删除`build`目录 ```shell helloworld]$ rm -rf build/ ``` 9. 添加`recipe`的bb文件,如下: ```shell helloworld]$ cd .. helloworld-c]$ cat helloworld-c.bb # helloworld application SUMMARY = "helloworld of Autotools recipe" DESCRIPTION = "My hello world application" LICENSE = "CLOSED" inherit cmake #继承了这个 FILESEXTRAPATHS_prepend := "${THISDIR}/:" SRC_URI = "file://helloworld/" S = "${WORKDIR}/helloworld" #CFLAGS_append = "-Wall -O -g" FILES_${PN} = "${bindir}/" ``` 这个bb文件基本上和`Autotools`使用的bb文件类似,只是继承的`autotools`改成了`cmake`。 10. `bitbake`编译演示: ```shell build]$ bitbake helloworld-c ``` 11. 结果浏览: ```shell build]$ ls tmp/work/core2-64-poky-linux/helloworld-c/1.0-r0/image/usr/bin/ helloworldc ``` 到这里,我们使用`Cmake`工具构建的项目就完成了~ ### 关于bb文件所处的位置问题 从上面我们看到了三个bb文件的路径是这样的: ```shell meta-mylayer/recipes-helloworld/helloworld-a/helloworld-a.bb meta-mylayer/recipes-helloworld/helloworld-m/helloworld-m.bb meta-mylayer/recipes-helloworld/helloworld-c/helloworld-c.bb ``` 如果,自己做个测试将bb文件放在这个`meta-mylayer/recipes-helloworld/`目录下,再`bitbake`编译,会发现找不到对于的`recipe`。这是为啥呢? 这个是由于`meta-mylayer/conf/layer.conf`配置文件中定义了bb文件搜索路径的结果,看下面: ```shell poky]$ cat meta-mylayer/conf/layer.conf ... # We have recipes-* directories, add to BBFILES BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ ${LAYERDIR}/recipes-*/*/*.bbappend" ... ``` 即只在`meta-mylayer/recipes-helloworld/xxx/`目录下查找bb文件。 ### 安装执行程序到文件系统中 我们看下这么个情况: ```shell poky]$ source oe-init-build-env build]$ bitbake core-image-sato -c cleansstate build]$ bitbake core-image-sato ``` 编译完成后,看下文件系统中是否有helloworld等程序: ```shell build]$ ls tmp-qemux86-64/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworld* ls: cannot access 'tmp-qemux86-64/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworld*': No such file or directory ``` 没有helloworld等文件或者目录。 这个是什么原因?poky目录下有很多的recipes,并不是所有的recipes都会编译和安装,需要将需要的recipes和我们的目标(当前是core-image-sato 或者 core-image-minimal)关联起来,怎么关联呢? #### 关联的方法1 第一个方法就是在`conf/local.conf`文件中添加这个关联关系: ```shell build]$ vim conf/local.conf ... IMAGE_INSTALL += "helloworld-m" IMAGE_INSTALL += "helloworld-a" IMAGE_INSTALL += "helloworld-c" ``` 但是我们知道,build目录是临时的目录,这是一种临时的做法。 #### 关联的方法2 添加一个目标的`bbappend`文件,例如我们的这个目标`core-image-sato`的bb文件是: ```shell meta/recipes-sato/images/core-image-sato.bb ``` 我需要做的只是在自己的`meta-mylayer`中创建相应的`recipe` `bbappend`文件,如下所示: ```shell meta-mylayer]$ mkdir -p recipes-sato/images/ meta-mylayer]$ vim recipes-sato/images/core-image-sato.bbappend IMAGE_INSTALL += "helloworld-m" IMAGE_INSTALL += "helloworld-a" IMAGE_INSTALL += "helloworld-c" ``` 同时,我们将前面`conf/local.conf`文件中添加的三个语句删除掉,然后编译演示: ```shell poky]$ source oe-init-build-env build]$ bitbake core-image-sato ``` 看下编译后的文件系统中是否有这个`helloworld`等文件: ```shell build]$ ls tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworld* tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworld tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworlda tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/usr/bin/helloworldc ``` 可见是有点,下面我们运行看看效果(在`Ubuntu`桌面的终端中执行):  或者这样: ```shell build]$ ssh-keygen -f "/home/peeta/.ssh/known_hosts" -R 192.168.7.2 build]$ ssh root@192.168.7.2 root@qemux86-64:~# helloworld Hello World! root@qemux86-64:~# helloworlda Hello World and Autotools root@qemux86-64:~# helloworldc Hello World and Cmake root@qemux86-64:~# ``` 结果展示都表明我们的`helloworld`程序都安装到文件系统中了。 ### 构建只有源码的项目 这一节是后面加上的,有些项目特别特别简单,就行上面的例子一样就只单单只有一个源文件,然后还要费那么大的精力去写这些或者那些编译脚本,太麻烦了。这里将介绍如何在yocto中构建极少数源文件又不依赖编译脚本的项目来添加一个recipe。 1. 首先创建一个`recipe`目录,取名`helloworld-o`吧,这里的o表示only source file的意思哈 ```shell recipes-helloworld]$ mkdir helloworld-o recipes-helloworld]$ cd helloworld-o/ helloworld-o]$ mkdir files ``` 2. 复制一个源文件到该目录: ```shell helloworld-o]$ cp ../helloworld-m/helloworld/helloworld.c files/ ``` 3. 写一个bb文件: ```shell SUMMARY = "Simple helloworld application" SECTION = "examples" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI = "file://helloworld.c" S = "${WORKDIR}" B = "${S}" do_compile () { ${CC} ${CFLAGS} ${LDFLAGS} helloworld.c -o helloworld } do_install () { install -d ${D}${bindir} install -m 0755 helloworld ${D}${bindir} } FILES_${PN} = "${bindir}" ``` 4. bitbake编译演示,以及结果: ```shell build]$ bitbake helloworld-o build]$ ls tmp/work/core2-64-poky-linux/helloworld-o/1.0-r0/image/usr/bin/helloworld tmp-qemux86-64/work/core2-64-poky-linux/helloworld-o/1.0-r0/image/usr/bin/helloworld ```
admin
2024年2月5日 10:02
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码