Install Packages from a Development Host
Runtime package installation is useful for quickly testing and debugging
software without rebuilding and flashing a complete image. This tutorial uses
nano to demonstrate two methods:
- Copy one package to the board with ADB and install it locally.
- Install the package by name from an indexed HTTP feed on the development host.
These changes are temporary development changes. A package installed at runtime is not automatically included after flashing a new image. Add required production packages to the image configuration instead.
The HTTP example uses unsigned packages on a trusted development network. Bind the server only to the relevant LAN address and do not use this setup as a production update service.
Before You Start
You need a completed image build, the matching image running on the board, ADB access, and a network connection between the development host and target for the HTTP method.
The package backend determines the generated package format and target package
manager. It can vary between BSPs, image configurations, and releases, so check
the selected build configuration instead of assuming a particular backend.
This tutorial provides IPK with opkg and DEB with apt examples.
The current default Grinn Genio BSP and Grinn Astra BSP image configurations enable the
package-management image feature. A custom image or configuration can change
or remove it, so confirm that the expected package manager is available on the
running target before continuing.
If the package manager is absent, add the following setting to the image or kas configuration, rebuild the image, and flash it before continuing:
EXTRA_IMAGE_FEATURES:append = " package-management"
The leading space in the appended value is required.
Confirm ADB and the expected package manager:
adb devices -l
- IPK (opkg)
- DEB (apt)
adb shell 'command -v opkg && opkg --version'
adb shell 'command -v apt-get && apt-get --version | sed -n "1p"'
1. Configure the BSP Workspace
Run host build commands from the root of the selected BSP workspace. The IPK
(opkg) examples below use Grinn Genio BSP, and the DEB (apt) examples use
Grinn Astra BSP.
- IPK (opkg)
- DEB (apt)
export KAS_CONFIG="meta-grinn-genio/kas/default.yml"
export KAS_MACHINE=grinn-genio-700-sbc
export KAS_CONTAINER_IMAGE_DISTRO=debian-bookworm
export PACKAGE=nano
export KAS_CONFIG="meta-grinn-astra/kas/default.yml"
export KAS_MACHINE=grinn-astra-1680-sbc
export KAS_CONTAINER_IMAGE_DISTRO=debian-bookworm
export PACKAGE=nano
If the running image was built with kas extensions, include the same extensions
in KAS_CONFIG.
This tutorial uses nano as the example and assumes it is not already
installed on the target.
2. Build the Package
Build the recipe using the same configuration as the running image:
kas-container build --target "$PACKAGE" "$KAS_CONFIG"
Here, --target nano selects the BitBake recipe. It does not refer to the
physical board, rebuild the complete image, or install anything on the board.
Yocto places generated packages under build/tmp/deploy. List the package for
the selected backend:
- IPK (opkg)
- DEB (apt)
ls -1 build/tmp/deploy/ipk/*/"${PACKAGE}"_*.ipk
Example output:
build/tmp/deploy/ipk/armv8a/nano_7.2-r0_armv8a.ipk
Copy the displayed path into PACKAGE_FILE:
export PACKAGE_FILE="$PWD/build/tmp/deploy/ipk/armv8a/<selected-package>.ipk"
ls -1 build/tmp/deploy/deb/*/"${PACKAGE}"_*.deb
Copy the path for the current machine and architecture into PACKAGE_FILE:
export PACKAGE_FILE="$PWD/build/tmp/deploy/deb/<architecture>/<selected-package>.deb"
If the package is not under the expected deployment directory, search the current build as a fallback:
find build/tmp/deploy -type f \
\( -name "${PACKAGE}_*.ipk" -o -name "${PACKAGE}_*.deb" \) -print
3. Method 1: Install One Local Package through ADB
This method is useful for one package whose required dependencies are already installed. ADB copies the file; the target package manager performs and records the installation.
- IPK (opkg)
- DEB (apt)
adb push "$PACKAGE_FILE" /tmp/nano.ipk
adb shell 'opkg install /tmp/nano.ipk
nano --version | sed -n "1p"'
Example output:
GNU nano, version 7.2
adb push "$PACKAGE_FILE" /tmp/nano.deb
adb shell 'apt-get install -y /tmp/nano.deb
nano --version | sed -n "1p"'
Remove the test package and transferred file before continuing to the HTTP method:
- IPK (opkg)
- DEB (apt)
adb shell 'opkg remove nano
rm -f /tmp/nano.ipk'
adb shell 'apt-get remove -y nano
rm -f /tmp/nano.deb'
4. Generate the Package Feed
Generate package indexes after the package build finishes:
kas-container shell "$KAS_CONFIG" -c 'bitbake package-index'
package-index scans packages already present in the deployment directory. It
does not build every available recipe.
Set the feed root and list its indexes:
- IPK (opkg)
- DEB (apt)
export FEED_ROOT="$PWD/build/tmp/deploy/ipk"
ls -1 "$FEED_ROOT"/*/Packages.gz
The Grinn Genio BSP example uses the all, armv8a, and
grinn_genio_700_sbc feed directories. Do not use x86_64-nativesdk; it
contains SDK host packages rather than target packages.
export FEED_ROOT="$PWD/build/tmp/deploy/deb"
ls -1 "$FEED_ROOT"/*/Packages.gz
Use the architecture and machine feed directories produced by the current Grinn Astra BSP build.
5. Serve the Feed over HTTP
The development host and board must be connected to the same trusted LAN.
Replace <target-ip> with the board's address, then use the address after
src as <host-lan-ip>:
ip -4 route get <target-ip>
From the feed root, start the HTTP server on that host address:
cd "$FEED_ROOT"
python3 -m http.server 8000 --bind <host-lan-ip>
Keep this terminal open while installing the package. The target must be able to reach TCP port 8000, and the host firewall must permit the connection on the selected interface.
If an existing LAN is unavailable, a direct Ethernet cable can also carry the feed. Configure non-conflicting static addresses on the host and target, bind the server to the host's direct-cable address, and allow TCP port 8000 through the host firewall when required. Remove temporary network and firewall settings after the exercise. This tutorial assumes an existing LAN and does not change network configuration.
Before configuring the package manager, verify HTTP access from the target.
Replace <feed-directory> with one of the directories containing
Packages.gz:
timeout 15 wget -O /tmp/Packages.gz \
http://<host-lan-ip>:8000/<feed-directory>/Packages.gz
gzip -t /tmp/Packages.gz
rm -f /tmp/Packages.gz
6. Install from the HTTP Feed
Open a shell on the target in another terminal:
adb shell
Configure only the feed directories required by the selected target.
- IPK (opkg)
- DEB (apt)
First, set the feed address and paths for the temporary configuration. Keeping
the downloaded package lists under /tmp avoids replacing the target's
existing feed metadata:
export FEED_BASE_URL=http://<host-lan-ip>:8000
export LOCAL_CONF=/tmp/grinn-opkg-local.conf
export LOCAL_LISTS=/tmp/grinn-opkg-lists
mkdir -p "$LOCAL_LISTS"
Next, create the isolated opkg configuration. It reuses the target's installed package database and architecture definitions, but reads packages only from the development feed. The feed directory names are Grinn Genio BSP examples:
{
printf '%s\n' 'dest root /'
printf 'option lists_dir %s\n' "$LOCAL_LISTS"
printf '%s\n' 'option info_dir /var/lib/opkg/info'
printf '%s\n' 'option status_file /var/lib/opkg/status'
cat /etc/opkg/arch.conf
printf 'src/gz local-all %s/all\n' "$FEED_BASE_URL"
printf 'src/gz local-arm %s/armv8a\n' "$FEED_BASE_URL"
printf 'src/gz local-machine %s/grinn_genio_700_sbc\n' \
"$FEED_BASE_URL"
} >"$LOCAL_CONF"
Download the feed indexes and confirm that nano is available:
opkg -f "$LOCAL_CONF" update
opkg -f "$LOCAL_CONF" list | grep '^nano - '
Finally, install and verify the package:
opkg -f "$LOCAL_CONF" install nano
nano --version | sed -n '1p'
Create a temporary source list using each required DEB feed directory. Replace the placeholders with directories containing the target packages and dependencies:
deb [trusted=yes] http://<host-lan-ip>:8000/<feed-directory> ./
deb [trusted=yes] http://<host-lan-ip>:8000/<another-feed-directory> ./
Use only that source list and an isolated package-list directory for this exercise:
mkdir -p /tmp/grinn-apt-lists/partial
APT_LOCAL='-o Dir::Etc::sourcelist=/tmp/grinn-apt-local.list -o Dir::Etc::sourceparts=- -o Dir::State::lists=/tmp/grinn-apt-lists'
apt-get $APT_LOCAL update
apt-cache $APT_LOCAL search '^nano$'
apt-get $APT_LOCAL install --no-install-recommends -y nano
nano --version | sed -n '1p'
The package manager reads the indexes, selects the package for the target, and downloads compatible dependencies available in the configured feeds. The installation fails if a required dependency is absent from those feeds.
7. Clean Up
Stop the HTTP server with Ctrl+C. Then remove the package and temporary package-manager configuration from the target:
- IPK (opkg)
- DEB (apt)
opkg remove nano
rm -rf /tmp/grinn-opkg-lists
rm -f /tmp/grinn-opkg-local.conf
apt-get remove -y nano
rm -rf /tmp/grinn-apt-lists
rm -f /tmp/grinn-apt-local.list
Runtime installation is intended for development and testing. To include a package in every newly flashed image, see Add Packages to a Yocto Image.