Skip to content

amamory-embedded/learning-yocto

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Learning Yocto

This tutorial goes through the process, step-by-step, of adding your own software into a Linux distribution generated by Yocto. It's initial goal was to document my own learning process, but, perhaps it can also be useful for other beginners in Yocto. This tutorial is not meant to be a complete Yocto reference. The idea is to be that initial little-push, so you can start figuring out the Yocto workflow.

Instalation

We use a docker container with Yocto and VNC installed. Check out the container manual to see it's features and how to install it. The first step once the docker image is install is to start its VNC. All the Linux image creation will be done using VNC.

Dependencies

This layer depends on:

  • URI: git://git.yoctoproject.org/poky

    • branch: master
    • revision: HEAD
  • URI: git://git.openembedded.org/meta-openembedded

    • layers: meta-oe
    • branch: master
    • revision: HEAD

Building the image for target board

In this tutorial we are assuming that the target board is a Raspbery Pi3, but it can easily be adapted for the other boards of the family.

Assuming you are already in the VNC, for actual deployment on a RPI3 processor, we need to change the MACHINE variable in ~/rpi/build/conf/local.conf to raspberrypi3 or raspberrypi3-64. In this tutorial we are assuming the former. If you have a different board, this is the place to specify it.

# This sets the default machine to be qemux86-64 if no other machine is selected:
MACHINE ??= "raspberrypi3"

Next, let's build the main parts of the Linux image: kernel, rootfs, etc. Later we build our custom recipes on top of this build. This step takes a long time ...

$ cd ~/rpi
$ source /opt/yocto/dunfell/src/poky/oe-init-build-env
$ cd ~/rpi/build
$ bitbake core-image-minimal -c populate_sdk
$ bitbake core-image-minimal

I am not sure if it is mandatory to include SDK (i.e. populate_sdk) in the image. This needs some additional testing in the future. In addition, there is other default Yocto images besides core-image-minimal. Check the reference images here.

Otherwise, if you want to just implement these examples and skip the step-by-step process, then run:

$ cd ~/rpi
$ source /opt/yocto/dunfell/src/poky/oe-init-build-env
$ cd ~/rpi/build
$ git clone -b dunfell https://github.com/amamory-embedded/learning-yocto.git meta-learning
$ bitbake-layers add-layer meta-learning
$ bitbake core-image-minimal -c populate_sdk
$ bitbake core-image-minimal

The last command bitbake core-image-minimal will create the packages and the image.

Add-ons and Configuration for Raspbery Pi 3

Although this tutorial is independent of board, we are using RPi3 due to its availability, pleanty of documentation, and easy access. If you want to have a more complete RPI3 configuration than the one provided by the standard core-image-minimal image, please check out the meta-myrpi. Note that this step is optional, but without it you will end up with a very simple RPi3 configuration, with basically only keyboard and HDMI.

Creating a Custom Layer

Everywhere you read about Yocto recommends that you create your own layer to deploy your software in the Linux image. So this section goes through this process of creating the layer where your recipes will be added.

$ bitbake-layers show-layers
$ bitbake-layers create-layer meta-learning
$ bitbake-layers add-layer meta-learning
$ bitbake-layers show-layers
NOTE: Starting bitbake server...
layer                 path                                      priority
==========================================================================
meta                  /opt/yocto/dunfell/src/poky/meta          5
meta-poky             /opt/yocto/dunfell/src/poky/meta-poky     5
meta-yocto-bsp        /opt/yocto/dunfell/src/poky/meta-yocto-bsp  5
meta-learning         /home/build/rpi/build/meta-learning           7
meta-raspberrypi      /opt/yocto/dunfell/src/meta-raspberrypi   9
meta-oe               /opt/yocto/dunfell/src/meta-openembedded/meta-oe  6
meta-networking       /opt/yocto/dunfell/src/meta-openembedded/meta-networking  5
meta-python           /opt/yocto/dunfell/src/meta-openembedded/meta-python
$ tree meta-learning/
meta-learning/
├── conf
│   └── layer.conf
├── COPYING.MIT
├── README
└── recipes-example
    └── example
        └── example_0.1.bb

Next, we start configuring the recipe as described below.

$ ~/rpi/build
$ cat meta-learning/recipes-example/example/example_0.1.bb
SUMMARY = "bitbake-layers recipe"
DESCRIPTION = "Recipe created by bitbake-layers"
LICENSE = "MIT"

do_compile() {
	echo "Example recipe created by bitbake-layers" >> ${WORKDIR}/example
}

do_install() {
	install -d ${D}${datadir}
	install -m 0644 ${WORKDIR}/example ${D}${datadir}
}

The rules do_compile and do_install are, in practice, only copying a file into the image. Next, the recipe is built.

$ cd ~/rpi/build
$ bitbake example
Parsing recipes: 100% |#################################################################################################################| Time: 0:00:20
Parsing of 2120 .bb files complete (0 cached, 2120 parsed). 3212 targets, 134 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION           = "1.46.0"
BUILD_SYS            = "x86_64-linux"
NATIVELSBSTRING      = "universal"
TARGET_SYS           = "arm-poky-linux-gnueabi"
MACHINE              = "raspberrypi3"
DISTRO               = "poky"
DISTRO_VERSION       = "3.1.12"
TUNE_FEATURES        = "arm vfp cortexa7 neon vfpv4 thumb callconvention-hard"
TARGET_FPU           = "hard"
meta                 
meta-poky            
meta-yocto-bsp       = "dunfell:cf5a00721f721d5077c73d1f4e812e5c79833fba"
meta-learning            = "<unknown>:<unknown>"
meta-raspberrypi     = "dunfell:934064a01903b2ba9a82be93b3f0efdb4543a0e8"
meta-oe              
meta-networking      
meta-python          = "dunfell:69f94af4d91215e7d4e225bab54bf3bcfee42f1c"

Initialising tasks: 100% |##############################################################################################################| Time: 0:00:00
Sstate summary: Wanted 7 Found 0 Missed 7 Current 134 (0% match, 95% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 570 tasks of which 554 didn't need to be rerun and all succeeded.

Run the following command to find out the recipe workdir:

$ bitbake -e example | grep ^WORKDIR=
WORKDIR="/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/example/0.1-r0"
$ find /mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/example/0.1-r0 -name example
...
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/example/0.1-r0/image/usr/share/example
$ cat /mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/example/0.1-r0/image/usr/share/example
Example recipe created by bitbake-layers

The file got deployed in the /usr/share directory. This link has more information about making a recipe that copies a file into the image.

Recipe Hello

As mentioned before, the previous recipe only copies a file into the Linux image. No code is actually compiled. The next step is to create a recipe that compiles a code. First, let's create a proper directory structure to save the new recipe:

$ cd ~/rpi/build
$ mkdir meta-learning/recipes-example/hello
$ cd meta-learning/recipes-example/hello
$ nano hello.bb
SUMMARY = "Simple helloworld application"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://helloworld.c"

TARGET_CC_ARCH += "${LDFLAGS}"

S = "${WORKDIR}"

do_compile() {
	${CC} helloworld.c -o helloworld
}

do_install() {
	install -d ${D}${bindir}
	install -m 0755 helloworld ${D}${bindir}
}

Check this other link to learn more about how to write do_install.

This is the place to store the source files:

$ mkdir files
$ cd files
$ nano helloworld.c

#include <stdio.h>
  
int main()
{
    printf("Hello World");
    return 0;
}

The resulting directory tree should be like this one:

:~/rpi/build/meta-learning/recipes-example/hello$ tree
.
├── files
│   └── helloworld.c
└── hello.bb

This recipe created is an example of a recipe where the code is locally stored within the recipe itself. This is not a usual configuration and is recommended only for testing purposes of small applications. Next, return to the build dir and compile the new recipe:

$ cd ~/rpi/build
$ bitbake hello
$ bitbake -e hello | grep ^WORKDIR=
WORKDIR="/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello/1.0-r0"
$ cd /mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello/1.0-r0
$ ll hello*
-rwxr-xr-x 1 build build 11556 Dec 17 20:08 helloworld*
-rw-r--r-- 1 build build    80 Dec 17 20:03 helloworld.c

To install this last application into a newly built image, we need to add the following lines into meta-learning/conf/local.conf:

# add here the name of the recipes to be included into the image
IMAGE_INSTALL_append = " example"
IMAGE_INSTALL_append = " hello"
...

Pay attention to the initial space before hello. This space is required.

Recipe HelloMake

The following recipe shows how to write a recipe for a project with Make. First, let's create a proper dir structure to save the new recipe:

$ cd ~/rpi/build
$ mkdir meta-learning/recipes-example/hellomake
$ cd meta-learning/recipes-example/hellomake
$ nano hellomake.bb
SUMMARY = "Simple helloworld application with Make"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://helloworld.c"

TARGET_CC_ARCH += "${LDFLAGS}"

S = "${WORKDIR}"

do_compile() {
	${CC} helloworld.c -o helloworld
}

do_install() {
	install -d ${D}${bindir}
	install -m 0755 helloworld ${D}${bindir}
}

This is the place to store the source file and the Makefile:

$ mkdir files
$ cd files
$ nano helloworld.c
#include <stdio.h>
  
int main()
{
    printf("Hello Make");
    return 0;
}
$ nano Makefile
....

Recipe HelloCMake

The next recipe shows how to write a recipe for a project with CMake. More info here. First, let's create a proper dir structure to save the new recipe:

$ cd ~/rpi/build
$ mkdir meta-learning/recipes-example/hellocmake
$ cd meta-learning/recipes-example/hellocmake
$ nano hellocmake.bb

SUMMARY = "Simple Hello World Cmake application"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "\
            file://CMakeLists.txt \
            file://hellocmake.cpp \
        "

S = "${WORKDIR}"

inherit cmake

EXTRA_OECMAKE = ""

This is the place to store the source file and the CMakeLists.txt:

$ mkdir files
$ cd files
$ nano hellocmake.c
#include <stdio.h>
  
int main()
{
    printf("Hello CMake");
    return 0;
}

$ nano CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project (hellocmake)
add_executable(hellocmake hellocmake.c)
install(TARGETS hellocmake RUNTIME DESTINATION bin)

Finally, let's build the recipe:

$ cd ~/rpi/build
$ bitbake hellocmake
$ bitbake -e hellocmake | grep ^WORKDIR=
WORKDIR="/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellocmake/1.0-r0"
$ cd /mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellocmake/1.0-r0
ll build/hello*
-rwxr-xr-x 1 build build 14024 Dec 17 20:45 build/hellocmake*

Recipe LibHello

This example shows how to build a library (shared or static), using cmake. Yocto requires a specific format for libraries, i.e., naming convention and also requirements from the building system, as seen next.

References:

First, create the directories as the previous examples for the recipe libhello. The recipe file has nothing especially related to a library.

$ nano hellolib.bb

SUMMARY = "Simple Hello Library with Cmake application"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "\
            file://CMakeLists.txt \
            file://hellolib.c \
            file://hello.h \
        "

S = "${WORKDIR}"

inherit cmake

EXTRA_OECMAKE = ""

The super fancy library:

$ nano files/hellolib.c
char * hello()
{
    return "My Lib";
}
$ nano files/hello.h
#ifndef _HELLOLIB_H
#define _HELLOLIB_H
char * hello();
#endif

And the cmake for building the library with Yocto. This cmake file is considerably more complex than the cmake for an application. This is because Yocto requires a specific format for libraries, i.e., name must be lib*. It also requires a library version and an install rule for the library and the headers (if the headers are available).

$ nano files/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
# the project version is required
project (hello VERSION 1.0 DESCRIPTION "My Hello Library")

# chooseee the library format: static or dynamic by
# replacing SHARED by STATIC to change the library type
add_library(${CMAKE_PROJECT_NAME} SHARED libhello.c)
#add_library(${CMAKE_PROJECT_NAME} STATIC libhello.c)

# VERSION and SOVERSION are required
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1
    PUBLIC_HEADER hello.h)

# replace LIBRARY by ARCHIVE depending on the library format
install(TARGETS ${CMAKE_PROJECT_NAME}
	DESTINATION /usr
	LIBRARY DESTINATION /usr/lib
	#ARCHIVE DESTINATION /usr/lib
	PUBLIC_HEADER DESTINATION /usr/include
)

# any addition file that needs to be installed
#install(FILES <filename> DESTINATION <dir>)

Note in the cmkae file that we are forcing the install to use the default paths for libraries and includes. This will make it easier to find them later in the next recipe.

Check it out for more cmake library configuration options.

Recipe HelloDep

This example creates an application that uses the library libhello defined in the previous section. So, we need to define a dependency among these two recipes. This example is also built with cmake.

First, create the directories as in the previous examples. Name the bitbake file as hellodep.bb. Note in the end of the files includes the dependency clauses among the recipes. DEPEDENCY is for build-time dependencies, while RDEPENDECY is for runtime.

SUMMARY = "Simple Hello World Cmake application that requires a library"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "\
            file://CMakeLists.txt \
            file://hellodep.c \
        "

S = "${WORKDIR}"

inherit cmake

EXTRA_OECMAKE = ""

DEPENDS += "libhello"
RDEPENDS_${PN} += "libhello"

Name the source code as hellodep.c

#include <stdio.h>
#include <hello.h>
  
int main()
{
    printf("Hello %s\n",hello());
    return 0;
}

And finally, the CMakeLists.txt file. Note that this cmake file is very simplified since libhello is deployed in the default /usr/lib and /usr/include directories. Otherwise, it's recommended to create a cmake module for the library so that the user applications can easily find the library with the cmake command find_package. See the comments in the CMakeLists.txt for further pointers.

cmake_minimum_required(VERSION 3.9)
project (hellodep)

# the source code to tha app
add_executable(${PROJECT_NAME} hellodep.c)

# libraries to be linked
target_link_libraries(${PROJECT_NAME} hello)

INSTALL(TARGETS ${PROJECT_NAME}
        RUNTIME DESTINATION bin
)

Now, let's build the new recipe. Sometimes, if you find an error while building a recipe, it's just a matter of cleaning it before building it again.

cd ~/rpi/build
bitbake hellodep -c cleanall
bitbake hellodep

Let's search the generated files for this new recipe:

$ find /mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/ -name "*hello*"
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/usr/include/hello.h
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/usr/lib/libhello.so
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/usr/lib/libhello.so.1.0
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/usr/lib/libhello.so.1
/mnt/yocto/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hellodep/1.0-r0/recipe-sysroot/sysroot-providers/libhello

We see the library, it's header file, both required to build hellodep. Next, make sure that the meta-learnning layer.conf file has the following lines to include the recipes to the image:

IMAGE_INSTALL_append = " libhello"
IMAGE_INSTALL_append = " hellodep"

Then build the Linux image again to include the new recipes into the image.

$ bitbake core-image-minimal
$ find /mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/ -name *hello*
...
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/lib/libhello.so.1.0
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/lib/libhello.so.1
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/hellodep

We can see that both the libhello shared library and the hellodep application were deployed into the image. Success!

Recipe HelloGit

As mentioned before, it's not recommended for actual deployment to combine the Yocto recipes and the source code. So, this new recipe shows how to separate these parts by linking the source code repository into the recipe.

Follow the previous steps to create a new recipe called hellogit. The directory files is not required in this configuration since it does not include source code.

This is the bitbake file called hellogit.bb. This recipe uses autoconf and make. Note that the variables SRCREV and SRC_URI define, respectively, the commit hash and the git repository URL.

DESCRIPTION = "Example Hello World application for Yocto build Using git and Autoconf."
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=0ec5801450d6b777d973eb956c021332"

SRCREV = "22f4bf448930e5d92195c36a10bdf3662c577699"
SRC_URI = "git://github.com/amamory-embedded/Hello-World-Autoconf.git"

S = "${WORKDIR}/git"

inherit autotools

PARALLEL_MAKE = ""

Now, let's test the recipe.

$ cd ~/rpi/build
$ bitbake hellogit

In the same directory of hellogit.bb, let's create another recipe called hellogitcmake.bb, which uses cmake instead of autoconf.

DESCRIPTION = "Example Hello World application for Yocto build Using git and Cmake."
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=3d7054b26bdd0f2f5fc6b2e53f28783d"

SRCREV = "47f73c318bb726bb2a5cf8e4d58204ba5fe3d207"
SRC_URI = "git://github.com/amamory-embedded/Hello-World-Cmake.git/;branch=main"

S = "${WORKDIR}/git"

inherit cmake

EXTRA_OECMAKE = ""

Note that this repository names the master branch as main, instead of master. This way, we have to specify the branch name. Other than that, we just have to update the hashes (the license and the repository hashes) and inherit cmake.

Recipe hello-mod

This example (originally from here) is located in recipes-kernel/hello-mod. It shows how to add a custom kernel module, in this case using make and git.

Building the Linux Image with the Custom Apps

Once all recipes we want to include in the image were tested separately, the next step is to actually incorporate them into the image. For this, edit meta-learning/conf/local.conf to include the following lines:

# add here the name of the recipes to be included into the image
IMAGE_INSTALL_append = " example"
IMAGE_INSTALL_append = " hello"
#IMAGE_INSTALL_append = " hellomake"
IMAGE_INSTALL_append = " hellocmake"
IMAGE_INSTALL_append = " libhello"
IMAGE_INSTALL_append = " hellodep"
IMAGE_INSTALL_append = " hellogit"
IMAGE_INSTALL_append = " hellogitcmake"

# my kernel recipes
MACHINE_EXTRA_RDEPENDS += "kernel-module-hello"

Next, time for building the recipes together.

$ cd ~/rpi/build
$ bitbake core-image-minimal
$ find /mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/ -name *hello*
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/lib/libhello.so.1.0
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/lib/libhello.so.1
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/hellodep
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/hellocmake
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/helloworld
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/hellogitcmake
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/bin/hellogit
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/lib/modules/5.4.72-v7/extra/hello.ko
$ find /mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/ -name example
/mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/usr/share/example

We can see all custom applications and libraries were deployed. We can also check the generated packages for all the custom recipes:

$ ll /mnt/yocto/tmp/work/raspberrypi3-poky-linux-gnueabi/core-image-minimal/1.0-r0/oe-rootfs-repo/cortexa7t2hf-neon-vfpv4/ | grep hello
-rw-r--r-- 3 build build      2144 Dec 17 20:08 hello_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      2380 Dec 17 20:45 hellocmake_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      4660 Dec 17 20:45 hellocmake-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       864 Dec 17 20:45 hellocmake-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       976 Dec 17 20:45 hellocmake-src_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      3632 Dec 17 20:08 hello-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      2208 Dec 20 10:50 hellodep_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      4712 Dec 20 10:50 hellodep-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       892 Dec 20 10:50 hellodep-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      1000 Dec 20 10:50 hellodep-src_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       856 Dec 17 20:08 hello-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      2196 Dec 18 19:33 hellogit_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      2192 Dec 20 15:32 hellogitcmake_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      4684 Dec 20 15:32 hellogitcmake-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       892 Dec 20 15:32 hellogitcmake-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      1012 Dec 20 15:32 hellogitcmake-src_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      3672 Dec 18 19:33 hellogit-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      1084 Dec 18 19:33 hellogit-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      1900 Dec 20 15:34 libhello1_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      2452 Dec 20 15:34 libhello-dbg_1.0-r0_armhf.deb
-rw-r--r-- 3 build build      1012 Dec 20 15:34 libhello-dev_1.0-r0_armhf.deb
-rw-r--r-- 3 build build       948 Dec 20 15:34 libhello-src_1.0-r0_armhf.deb

Running the Custom Apps with QEMU

For emulating the RPI3 processor with QEMU we need to change the MACHINE variable in ~/rpi/build/conf/local.conf. Comment the current assignment to this variable and add the following lines:

# This sets the default machine to be qemux86-64 if no other machine is selected:
MACHINE ??= "qemux86-64"

Rerun the full image build:

$ bitbake core-image-minimal

This process will take a while ... go for a cup of coffee or Check out more information on these links:

After finishing the image built process, run:

runqemu qemux86-64 slirp nographic

The boot process will start. When QEMU prompt appears, run:

root@qemux86-64:~# find /usr -name *hello*
/usr/lib/libhello.so.1.0
/usr/lib/libhello.so.1
/usr/bin/hellodep
/usr/bin/hellogitcmake
/usr/bin/hellogit
/usr/bin/hellocmake
/usr/bin/helloworld

We can check all applications generated by the custom recipes. Run poweroff when finishing with qemu.

Running the Custom Apps in the RPi3

After building the image for qemu, we are going to see two different images in the following directory:

~/rpi/build$ ls /mnt/yocto/tmp/deploy/images/
qemux86-64  raspberrypi3

For actual deployment on a RPI3 processor, we need to change the MACHINE variable in ~/rpi/build/conf/local.conf back to its original, raspberrypi3 or raspberrypi3-64. For example:

# This sets the default machine to be qemux86-64 if no other machine is selected:
MACHINE ??= "raspberrypi3"

It's also recommended to change the output format of the image by adding the following line of the same file:

IMAGE_FSTYPES ?= "tar.bz2 ext3 rpi-sdimg"

After building the image again (this time, it's quick), you will find the following file:

~/rpi/build$ find /mnt/yocto/tmp/deploy/images/raspberrypi3/ -name *.rpi-sdimg
/mnt/yocto/tmp/deploy/images/raspberrypi3/core-image-minimal-raspberrypi3-20211221153332.rootfs.rpi-sdimg
/mnt/yocto/tmp/deploy/images/raspberrypi3/core-image-minimal-raspberrypi3.rpi-sdimg

Remember that the /mnt/yocto/tmp is shared between the docker image and the host, so it's easy to burn the image file into an SD card.

Return to the host computer and run df to find out the SD card device (assuming it is /dev/sdb) and run:

$ sudo dd if=/<host mounting point>/deploy/images/raspberrypi3/core-image-minimal-raspberrypi3.rpi-sdimg of=/dev/sdb bs=4M

Check out more information on these links:

To Learn More

TO DO

Contributions

Did you find a bug in this tutorial ? Do you have some extensions or updates to add ? Please send me a Pull Request.