The first time an SDK installer appears in tmp/deploy/sdk, it feels like the hard part is over. It is not quite: the real success criterion is that another developer can install it, source one environment file, compile against the same headers and libraries as the target image, and produce a binary for the intended machine. This workflow builds that reproducible handoff.

What the SDK contains

  • A host-side cross compiler, assembler, linker, debugger, and related tools.

  • A target sysroot containing headers and libraries selected for the image.

  • A native sysroot containing tools that run on the SDK workstation.

  • An environment-setup-* script that exports PATH, compiler variables, sysroot flags, and build-tool configuration.

  • Configuration, version, site, and relocation data needed to use the installation away from the original build tree.

Standard SDK or extensible SDK?

  • Choose the standard SDK for C/C++ application builds with Make, Autotools, CMake, Meson, or another external build system.

  • Choose the extensible SDK when developers need devtool, recipe-aware workflows, workspace changes, or SDK updates.

  • Both should be generated from the image/configuration they target.

  • An SDK is not a replacement for the complete product build when kernel, bootloader, image composition, or distribution policy changes.

  • Agree on Yocto release, distro, machine, image, host architecture, and expected developer workflow before publishing an installer.

Start from one coherent Yocto release

workspacebash
git clone -b scarthgap https://git.yoctoproject.org/poky
cd poky
source oe-init-build-env build
You had no conf/local.conf file. This configuration file has therefore been created for you.
...
### Shell environment set up for builds. ###

Why this is different from the old recipe

  • poky already contains the OpenEmbedded-Core metadata, BitBake, and Poky distribution metadata; do not add a second overlapping OE-Core checkout.

  • scarthgap is shown as a named release branch; select a currently supported branch compatible with every vendor layer.

  • All layers must use compatible release branches—mixing branch generations causes parsing and API failures.

  • oe-init-build-env build creates or enters the build directory and exports the BitBake environment in the current shell.

  • Use the host packages, supported Linux distributions, disk space, and locale documented for your selected Yocto release.

Configure the target before building

build/conf/local.conftext
MACHINE = "qemux86-64"
SDKMACHINE = "x86_64"
 
# Keep downloads and shared state outside disposable build output.
DL_DIR = "/srv/yocto/downloads"
SSTATE_DIR = "/srv/yocto/sstate-cache"

These values define two different machines

  • MACHINE selects the target board/emulator and its tuning, providers, and machine features.

  • SDKMACHINE selects the workstation architecture on which the generated SDK tools will run; x86_64 is the usual default.

  • The SDK target sysroot follows the image, distro, machine, tune, and package configuration in this build.

  • Shared downloads and sstate can reduce rebuild time, but access control, cleanup, mirrors, and reproducibility policy still matter.

  • Put organization settings in versioned distro, machine, or layer configuration rather than relying on an undocumented local.conf.

Confirm layers and effective configuration

poky/buildbash
bitbake-layers show-layers
bitbake-getvar MACHINE
bitbake-getvar DISTRO
bitbake-getvar SDKMACHINE
... layer paths, priorities, and branches ...
MACHINE="qemux86-64"
DISTRO="poky"
SDKMACHINE="x86_64"

A configuration check saves hours

  • bitbake-layers show-layers proves which metadata is active; merely cloning a layer does not enable it.

  • bitbake-getvar reports parsed values and is clearer than guessing from the last assignment found by grep.

  • Vendor BSPs may require their own setup script and machine; follow that release’s documentation.

  • Record layer revisions in a manifest or lockable repository setup for repeatable SDK releases.

  • Never copy an old bblayers.conf with another developer’s absolute paths.

Build an image-matched standard SDK

poky/buildbash
bitbake core-image-minimal -c populate_sdk
...
NOTE: Tasks Summary: Attempted ... tasks of which ... succeeded.

What populate_sdk does

  • The task constructs a relocatable SDK installer for the selected image.

  • Its target sysroot is populated from packages appropriate to that image, avoiding a compiler-only handoff with missing headers.

  • BitBake reuses compatible sstate artifacts and builds missing native, cross, target, packaging, and SDK components.

  • CPU, memory, disk I/O, network mirrors, and parallelism affect build time; preserve the task log when it fails.

  • Do not run multiple uncontrolled builds against the same build directory.

Build an extensible SDK when recipe work is required

poky/buildbash
bitbake core-image-minimal -c populate_sdk_ext
...
NOTE: Tasks Summary: Attempted ... tasks of which ... succeeded.

The eSDK has a broader job

  • populate_sdk_ext produces an environment with OpenEmbedded build support and devtool.

  • It is larger and has different update, artifact, and workspace behavior from a standard SDK.

  • Use it for recipe-aware modification and packaging, not merely because it sounds more complete.

  • SDK providers must plan sstate/source availability and update publishing if developers will install additional components.

  • Test the exact installer on a clean supported host before distributing it.

Find and checksum the installer

poky/buildbash
find tmp/deploy/sdk -maxdepth 1 -type f -name "*.sh" -print
sha256sum tmp/deploy/sdk/*.sh
tmp/deploy/sdk/poky-glibc-x86_64-core-image-minimal-core2-64-toolchain-....sh
<sha256>  tmp/deploy/sdk/poky-glibc-...-toolchain-....sh

Treat the installer as a release artifact

  • The filename encodes distro/libc, SDK host, image, target tune, and version details; exact names vary.

  • Publish a SHA-256 checksum through a trusted channel and ideally sign the release manifest.

  • Archive layer revisions, build configuration, license manifest, build history, and release notes alongside it.

  • Do not use ls | head to choose an installer automatically when old artifacts share the directory.

  • Restrict publishing credentials and scan the artifact according to supply-chain policy.

Install without root into a versioned directory

poky/buildbash
chmod +x tmp/deploy/sdk/poky-glibc-*-core-image-minimal-*-toolchain-*.sh
./tmp/deploy/sdk/poky-glibc-*-core-image-minimal-*-toolchain-*.sh -d "$PWD/sdk/core-image-minimal" -y
Extracting SDK...done
Setting it up...done
SDK has been successfully set up and is ready to be used.

Risk level: caution. Review the command before running it.

Know what the installer changes

  • -d chooses an explicit destination and -y accepts installation without the interactive prompt; verify options with the installer’s --help because release behavior can differ.

  • A user-owned versioned path avoids casual sudo, makes cleanup clear, and permits side-by-side SDKs.

  • The glob must match exactly one reviewed artifact; production automation should use the exact filename.

  • Installing executes the generated shell program and writes many files, so verify its checksum and destination first.

  • Do not install over an active SDK; create a new directory and switch consumers deliberately.

Enter the SDK environment

application source treebash
source /absolute/path/to/sdk/core-image-minimal/environment-setup-*
printf "CC=%s\nSDKTARGETSYSROOT=%s\n" "$CC" "$SDKTARGETSYSROOT"
"${CC%% *}" --version
CC=x86_64-poky-linux-gcc ... --sysroot=/.../sysroots/core2-64-poky-linux
SDKTARGETSYSROOT=/.../sysroots/core2-64-poky-linux
... gcc version ...

Source it in each clean shell

  • source modifies the current shell; executing the file as a child process cannot export variables back to its parent.

  • The setup script defines compiler commands with target flags and --sysroot, plus pkg-config and build-tool variables.

  • The wildcard should resolve to one target setup file; use its exact name in automation.

  • Start a fresh shell when switching SDKs to avoid mixed PATH, compiler, and sysroot state.

  • Do not strip flags from $CC; it may contain required target and sysroot arguments rather than a bare executable path.

Compile a proof program

hello.cc
#include <stdio.h>
 
int main(void)
{
    puts("hello from the Yocto SDK");
    return 0;
}

The source is deliberately boring

  • stdio.h proves the compiler sees headers in the SDK target sysroot.

  • puts creates a libc dependency representative of an ordinary dynamically linked target program.

  • A zero return value reports success to the target shell.

  • Keep the smoke test small so architecture, interpreter, and library problems are easy to isolate.

application source tree with SDK sourcedbash
$CC $CFLAGS $LDFLAGS hello.c -o hello
file hello
readelf -h hello | grep -E "Class:|Data:|Machine:"
readelf -l hello | grep "Requesting program interpreter"
hello: ELF 64-bit LSB pie executable, x86-64, ...
  Class: ELF64
  Data: 2's complement, little endian
  Machine: Advanced Micro Devices X86-64
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

Inspect before you copy

  • $CC retains the toolchain’s target options; $CFLAGS and $LDFLAGS carry build policy exported by the SDK.

  • file and readelf inspect architecture, byte order, ABI, and dynamic loader without executing the target binary.

  • Expected output depends on MACHINE, tune, libc, and linkage; compare it with the actual device.

  • A valid ELF can still fail if its interpreter or shared-library versions are absent on the target.

  • Deploy through the product’s supported package/image workflow when possible, then run on hardware or a matching emulator.

Add libraries to the SDK intentionally

conf/local.conf or distro configurationbitbake
TOOLCHAIN_TARGET_TASK:append = " zlib-dev"
# Example for static libc development files when genuinely required:
# TOOLCHAIN_TARGET_TASK:append = " libc-staticdev"

Packages, recipes, and images are different names

  • TOOLCHAIN_TARGET_TASK contains target package names included in the SDK sysroot, not arbitrary recipe names.

  • Development packages normally provide headers, unversioned linker symlinks, and pkg-config metadata.

  • Static libraries are not included by default in the documented standard SDK workflow; add only what the product permits.

  • Prefer putting stable SDK policy in version-controlled distro/image metadata over a workstation’s local.conf.

  • Rebuild, reinstall to a clean directory, and compile a consumer to prove each addition.

Why meta-toolchain appears in older tutorials

  • The original article used Yocto 2.6 Thud, a historical branch that should not be presented as current.

  • Do not mix current syntax such as override colons with old releases that require underscore override syntax.

  • Do not upgrade a production BSP merely by changing branch names; validate vendor support, migration notes, recipes, patches, and output.

  • Keep a legacy SDK reproducible for maintenance while planning migration to a supported Yocto release.

Common failures and their real causes

  • “Nothing PROVIDES” → wrong recipe/package name, missing layer, incompatible branch, or disabled feature.

  • Header not found → development package absent from the SDK sysroot or the external build ignores exported sysroot flags.

  • Library not found at link time → target development package absent, wrong library name/order, or build system bypasses $LDFLAGS/pkg-config.

  • Exec format error on the workstation → you tried to run a target binary locally, or SDKMACHINE produced host tools for another architecture.

  • No such file or directory on the target despite the file existing → missing ELF interpreter or incompatible ABI is often the cause.

  • CMake finds host libraries → source the SDK and use its exported toolchain settings; clear the project’s old CMake cache.

  • Installer relocation failure → unsupported path/content mutation, incomplete extraction, permissions, or host incompatibility.

A release-ready verification checklist

  • Rebuild from pinned layer revisions and documented configuration.

  • Install the artifact on a clean supported workstation outside the Yocto build tree.

  • Source exactly one environment setup script and record compiler/sysroot variables.

  • Compile, inspect, deploy, and run a representative application.

  • Verify required headers, shared libraries, licenses, debug symbols, and static policy.

  • Publish checksum/signature, manifest, supported host/target, image identity, installation instructions, and known limitations.

  • Keep old SDK releases immutable; issue a new version instead of silently replacing an installer.

Primary references

  • The current Yocto Project SDK manual explains standard and extensible SDK development models.

  • The official obtaining an SDK page documents populate_sdk, populate_sdk_ext, SDKMACHINE, installer output, and installation.

  • The standard SDK chapter describes its toolchain, sysroots, and image-aligned purpose.

  • Use the exact manual for your selected release and BSP vendor; variable syntax and supported hosts change between release generations.