This failure appears late—during packaging—but the mistake usually happened much earlier at the final linker command. That timing sends people into the recipe’s do_install() function even though copying the file is not what removed its GNU hash table.

What the error is saying

log.do_package_qatext
ERROR: example-1.0-r0 do_package_qa: QA Issue:
No GNU_HASH in the ELF binary:
'/usr/bin/example' [ldflags]
ERROR: QA run found fatal errors.

Read the bracketed check first

  • [ldflags] names the OpenEmbedded package QA test that failed.

  • The path is inside the package staging area, not necessarily the original build location.

  • The ELF may still run; the failure proves it did not follow the distribution’s expected link policy.

  • Changing FILES only moves ownership between packages and does not relink the binary.

Yocto build environmentbash
readelf -S path/to/example | grep -E '.(gnu.)?hash'
readelf -d path/to/example | grep -E 'GNU_HASH|HASH'
grep -n -- '--hash-style|LDFLAGS'   tmp/work/*/*/temp/log.do_compile
[ 5] .gnu.hash         GNU_HASH
 0x000000006ffffef5 (GNU_HASH)

Three pieces of evidence, not one guess

  • .gnu.hash and DT_GNU_HASH show that the GNU hash table reached the final ELF.

  • A .hash section or DT_HASH entry is the older System V hash and does not satisfy a GNU-hash expectation by itself.

  • log.do_compile reveals the command BitBake actually ran; exported variables are useless if the Makefile omits them.

  • Use the exact failing file from ${WORKDIR}/packages-split when confirming the packaged result.

Best fix: repair the build system

Makefilemakefile
example: main.o helper.o
	$(CC) $(CFLAGS) $(CPPFLAGS) main.o helper.o 		$(LDFLAGS) $(LDLIBS) -o $@
 
main.o: main.c
	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

Pass compiler flags while compiling and linker flags only on the final link.

Why placement matters

  • $(CC) is normally the correct driver for linking C objects because it supplies the target sysroot and runtime components.

  • LDFLAGS belongs on the link invocation; adding it only while compiling .c to .o cannot alter the final ELF.

  • LDLIBS carries libraries and generally follows the object files so link-order rules work.

  • Do not replace Yocto-provided flags with a private value; append project-specific options when necessary.

Recipe-level workaround for a stubborn Makefile

example_1.0.bbbitbake
EXTRA_OEMAKE += "CC='${CC}' CFLAGS='${CFLAGS}' LDFLAGS='${LDFLAGS}'"
 
# Documented fallback for build systems that use CC but discard LDFLAGS:
TARGET_CC_ARCH:append = " ${LDFLAGS}"

Prefer explicit variables; retain TARGET_CC_ARCH only for legacy build systems that ignore LDFLAGS.

Use the fallback with eyes open

  • EXTRA_OEMAKE passes the cross compiler and policy flags into oe_runmake.

  • Modern override syntax uses :append; older Yocto branches used _append.

  • Appending linker flags to TARGET_CC_ARCH works because that variable reaches compiler invocations, but it mixes two concepts and is a compatibility workaround.

  • A Makefile patch is clearer and remains correct outside one recipe.

Clean only enough to force relinking

Initialized BitBake environmentbash
bitbake -c clean example
bitbake example
bitbake -c package_qa -f example
NOTE: Tasks Summary: Attempted ... tasks ... all succeeded.

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

What this rebuild proves

  • clean removes recipe outputs so an old ELF cannot survive the Makefile change.

  • The normal build recreates and packages the artifact under the target toolchain.

  • Forcing package_qa reruns the relevant gate; inspect its log rather than trusting a successful compile alone.

  • This affects one recipe, unlike cleansstate, which also discards shared-state output and is usually unnecessary.

Prebuilt vendor binaries are a different case

A recipe cannot add a missing dynamic hash table by setting LDFLAGS after a binary has already been linked. Ask the vendor for a binary built with the target distribution’s toolchain and ABI. If replacement is impossible, test the binary on the exact image and document why accepting the exception is safer than pretending it was rebuilt.

vendor-tool_1.0.bbbitbake
# Vendor supplies this ELF without rebuildable source.
# Verified on MACHINE targets listed in the layer README.
INSANE_SKIP:${PN} += "ldflags"

A narrow last-resort exception for the runtime package.

An exception is not a repair

  • INSANE_SKIP disables only named checks for the selected output package.

  • ${PN} is the main package; use the actual package name when the file lands in a subpackage.

  • The older underscore form, INSANE_SKIP_${PN}, is for historical BitBake releases.

  • Never remove ldflags globally from ERROR_QA; that hides newly introduced build regressions across the image.

Why common attempts fail

  • Adding LDFLAGS only to the recipe: the upstream build can ignore the environment.

  • Editing do_install: installation copies the already-linked ELF.

  • Changing FILES: package assignment changes, binary contents do not.

  • Using HOST_LDFLAGS: host-tool flags are not target executable flags.

  • Skipping the wrong package: the QA message applies to the package that owns the file.

  • Keeping stale work output: the repaired link command never runs until the ELF is rebuilt.

References