. "$BST_LIB" # nanopb 0.4.8 runtime -- Petteri Aimonen's Protocol Buffers implementation for # constrained targets, as meta-oe ships it from # dynamic-layers/meta-python/recipes-devtools/nanopb. The RUNTIME half only: # pb_common.c, pb_encode.c, pb_decode.c and four headers. The generator # (nanopb-generator) is a separate recipe that needs protobuf-native and # python3-protobuf and is NOT in this image. # # --------------------------------------------------------------------------- # WHY THIS SUITE CAN BE UNUSUALLY STRICT # # THE PROTOBUF WIRE FORMAT IS FULLY SPECIFIED AND ARCHITECTURE-INDEPENDENT. # Every byte this suite compares is required by the spec to be identical on # x86_64 and on wasm32 -- varints are base-128 little-endian with a continuation # bit, fixed32/fixed64 go out least-significant byte first whatever the host # does, and floats are IEEE754 bit patterns. So unlike a suite that has to reason # about what a platform might legitimately do differently, here a single byte of # disagreement with the native control IS a defect, in the runtime or in the # toolchain. There is no tolerance band anywhere in this file. # # That is what makes data/nanopb-native.txt a real oracle rather than a # convenience: it is the verbatim output of the SAME probe source, compiled # against the SAME nanopb 0.4.8 sources, run on x86_64. The probe prints only hex # byte strings, small integers and nanopb's own fixed error strings -- never a # pointer, a size_t or a sizeof -- so there is nothing in its output that is # allowed to differ between the two machines. # # WHAT IS ACTUALLY BEING MEASURED. nanopb-runtime installs no executable, so # without a cross-linked consumer this suite could only assert that an archive # and four headers exist -- which would pass just as happily if every function in # the archive trapped on first call. data/nanopb-probe is that consumer: the # probe source cross-linked against the very archive this port installs, reached # through the same /usr/include compat symlinks a real consumer would use. Its # message descriptors were produced by NANOPB'S OWN GENERATOR from a .proto, so # what runs on target is the code a real user of this package would compile. # # THE THREE CASES THAT MATTER MOST are the bounds checks, because nanopb's whole # premise is static allocation with no malloc anywhere: a string longer than the # generated max_size and a repeated field with more elements than max_count must # be REFUSED (C10/C12), not truncated into the fixed buffer. Their absence would # be a buffer overflow in every consumer on the image rather than a wrong answer. # --------------------------------------------------------------------------- # A root prefix, empty on the target and set only when this suite is validated # NATIVELY under dash before it ships -- which is how the expectations here were # checked in the first place. Writing /usr/lib and /usr/include needs real root, # so a native run stages them under a temporary tree and points this at it. The # runner never sets it, so on the image these are exactly the absolute paths. R="${BST_NANOPB_ROOT:-}" ARCHIVE=$R/usr/lib/libprotobuf-nanopb.a INCDIR=$R/usr/include/nanopb CMAKEDIR=$R/usr/lib/cmake/nanopb PROBE=$BST_DATA/nanopb-probe NATIVE=$BST_DATA/nanopb-native.txt if [ ! -f "$ARCHIVE" ]; then bst_skip nanopb/present "nanopb-runtime not installed on this image" exit 0 fi bst_ok nanopb/present # --- the package is whole ---------------------------------------------------- check nanopb/hdr-pb test -f "$INCDIR/pb.h" check nanopb/hdr-common test -f "$INCDIR/pb_common.h" check nanopb/hdr-encode test -f "$INCDIR/pb_encode.h" check nanopb/hdr-decode test -f "$INCDIR/pb_decode.h" check nanopb/staticlib test -f "$ARCHIVE" # The recipe's do_install:append symlinks each header into ${includedir} for # consumers written before nanopb moved them under nanopb/. The probe is compiled # through those symlinks (#include ), so if they were ever dropped this # port would silently stop being usable the documented way. check nanopb/compat-pb test -L "$R/usr/include/pb.h" check nanopb/compat-common test -L "$R/usr/include/pb_common.h" check nanopb/compat-encode test -L "$R/usr/include/pb_encode.h" check nanopb/compat-decode test -L "$R/usr/include/pb_decode.h" # ${PN} is empty by design: upstream's only non-archive library output is a # shared object, and this arm refuses the -shared side-module link outright # (wasmld FATAL). A .so appearing here would mean the bbappend's # BUILD_SHARED_LIBS=OFF stopped taking effect. if [ -e "$R/usr/lib/libprotobuf-nanopb.so" ] || [ -e "$R/usr/lib/libprotobuf-nanopb.so.0" ]; then bst_notok nanopb/no-shared "a shared libprotobuf-nanopb is installed on a static-only distro" else bst_ok nanopb/no-shared fi # The cmake package config, which is how a consumer recipe finds this library. check nanopb/cmake-config test -f "$CMAKEDIR/nanopb-config.cmake" check nanopb/cmake-targets test -f "$CMAKEDIR/nanopb-targets.cmake" # The archive carries the API. grep rather than nm: the image ships no binutils # nm, and an ar symbol index holds the names as plain bytes, so this works on # busybox grep with no toolchain present. for sym in pb_encode pb_decode pb_encode_varint pb_decode_varint pb_get_encoded_size; do if grep -q "$sym" "$ARCHIVE" 2>/dev/null; then bst_ok "nanopb/sym-$sym" else bst_notok "nanopb/sym-$sym" "$sym absent from $ARCHIVE" fi done # --- the probe --------------------------------------------------------------- for f in "$PROBE" "$NATIVE"; do if [ ! -f "$f" ]; then bst_skip nanopb/probe-runs "$(basename "$f") absent from the image" exit 0 fi done # data/* installs 0644, so stage a copy and make it executable. pout=${TMPDIR:-/tmp}/bst-nanopb-out.$$ _p=${TMPDIR:-/tmp}/bst-nanopb-$$.bin cp "$PROBE" "$_p" 2>/dev/null && chmod 0755 "$_p" 2>/dev/null if [ ! -x "$_p" ]; then bst_notok nanopb/probe-runs "could not stage an executable copy of the probe" rm -f "$_p" "$pout" exit 0 fi "$_p" > "$pout" 2>&1 prc=$? rm -f "$_p" if [ "$prc" -eq 0 ]; then bst_ok nanopb/probe-runs else bst_notok nanopb/probe-runs "probe exited $prc" fi # The probe prints a terminator, so a run that DIED PARTWAY is distinguishable # from one that merely disagreed. That distinction is what stopped this suite # from turning a single trap into ninety-seven indistinguishable reds -- the # per-case loop below reports a missing value as "probe stopped before this # case", which localises the death to one case id instead of smearing it. if grep -q '^PROBE-END$' "$pout" 2>/dev/null; then bst_ok nanopb/probe-complete else bst_notok nanopb/probe-complete "probe output has no PROBE-END terminator (died at $(awk 'END{print $1}' "$pout" 2>/dev/null))" fi # --- every probe case, against the native x86_64 control --------------------- # One BST case per probe case, so a disagreement names the exact construct that # differs rather than reporting "the probe output changed". The expectation is # read from the control file, never written here: nothing in this suite encodes # what a value "should" be, which is what keeps the oracle honest. while read -r id want; do [ -n "$id" ] || continue case "$id" in PROBE-END) continue ;; esac got=$(awk -v k="$id" '$1==k{ $1=""; sub(/^ /,""); print; exit }' "$pout") if [ -z "$got" ]; then bst_notok "nanopb/$id" "no value on target (probe stopped before this case); native='$want'" else check_eq "nanopb/$id" "$want" "$got" fi done < "$NATIVE" rm -f "$pout"