# BST-TIMEOUT: 180 . "$BST_LIB" # ade 0.1.2 (meta-oe recipes-support/opencv, git SRCREV 1e02d748 = upstream tag # v0.1.2) -- the OpenCV project's directed-graph framework, the computation-graph # engine behind G-API and a dependency-free DAG container on its own. Static # library: the port ships libade.a, 51 headers under /usr/include/ade, and the # find_package(ade) cmake package. No shared object, no CLI, no pkg-config file -- # cmake is the only integration surface upstream provides. # # WHAT THIS SUITE IS REALLY PINNING DOWN, and it is not "the files arrived". ade # is a graph ENGINE, and the only property that separates a working one from a # present one is that it REFUSES the graphs it must refuse. A topological sort # that returns some order for every input, cycles included, passes every payload # assertion in section 1 and every ordering assertion in section 4. Section 5 is # the case that catches it. # # THE EXCEPTIONS ARM IS UPSTREAM'S OWN HERE, which is why this port needed no # argument where libcereal's and libtinyxml2's did. ade routes every error # through one function -- ade::throw_error() in util/assert.hpp -- written as # # #if defined(__EXCEPTIONS) || defined(_CPPUNWIND) # throw std::forward(e); # #else # ::ade::details::dev_exception_abort(e.what()); # #endif # # There is exactly one `throw` in the whole tree and it is that line; there is no # try/catch anywhere. So on this image's exceptions-off arm ade takes a branch # upstream wrote and maintains, not a branch we forced it onto. Measured on # x86-64 with clang 18.1.3 at this SRCREV: the same probe built -fno-exceptions # and -fexceptions produced 32 report lines that were identical except for the # line saying which arm it was. The arm changes what a REFUSAL looks like and # nothing else about what ade computes. # # A REFUSAL IS THEREFORE A PROCESS-LEVEL EVENT, and that is why section 5 runs # the probe a second time instead of adding a case to section 4: # dev_exception_abort() prints to stderr and abort()s, so the cycle case ends the # process by design and cannot report through a P- line. The .test supplies the # process isolation the library cannot. # # Style follows 81-libcereal and 74-libtinyxml2: the archive is flattened to # printable text once and interrogated with grep, because GNU grep suppresses # matches inside binary data. inc=/usr/include/ade cm=/usr/share/ade lib=/usr/lib/libade.a PT=/usr/libexec/ade-tests # --------------------------------------------------------------------------- # 1. The payload. check ade/inc-dir test -d "$inc" check ade/lib-present test -f "$lib" check ade/lib-nonempty test -s "$lib" check ade/cmake-dir test -d "$cm" for h in graph.hpp node.hpp edge.hpp handle.hpp typed_graph.hpp \ typed_metadata.hpp passmanager.hpp graph_listener.hpp; do check "ade/header-$h" test -f "$inc/$h" done for d in communication execution_engine helpers memory metatypes passes util; do check "ade/dir-$d" test -d "$inc/$d" done # Header counts, per directory as well as in total. A truncated install is the # failure this catches, and a single total would hide one directory arriving # empty while another grew. Dated snapshot at SRCREV 1e02d748, not a target. check_eq ade/header-count "51" "$(find "$inc" -name '*.hpp' 2>/dev/null | grep -c .)" check_eq ade/header-count-top "8" "$(ls "$inc"/*.hpp 2>/dev/null | grep -c .)" check_eq ade/header-count-util "23" "$(ls "$inc/util" 2>/dev/null | grep -c .)" check_eq ade/header-count-mem "7" "$(ls "$inc/memory" 2>/dev/null | grep -c .)" check_eq ade/header-count-pass "4" "$(ls "$inc/passes" 2>/dev/null | grep -c .)" check_eq ade/header-count-comm "3" "$(ls "$inc/communication" 2>/dev/null | grep -c .)" check_eq ade/header-count-exec "3" "$(ls "$inc/execution_engine" 2>/dev/null | grep -c .)" check_eq ade/header-count-help "2" "$(ls "$inc/helpers" 2>/dev/null | grep -c .)" check_eq ade/header-count-meta "1" "$(ls "$inc/metatypes" 2>/dev/null | grep -c .)" # The tree's own #include "..." graph must close inside the installed payload: a # header that resolves at build time and not on target is a port that only looks # complete. ade writes its internal references root-relative ("ade/util/assert.hpp") # rather than sibling-relative, so they resolve against /usr/include, not against # the ade/ directory -- resolving them the other way scores 20 of 114 and reads as # a catastrophically broken install rather than as a wrong base. root=/usr/include incs=$(grep -rn -e '#include[[:space:]]*"[^"]*"' "$inc" --include='*.hpp' 2>/dev/null | sed "s|^$inc/||") nrefs=0; nres=0; miss= oIFS=$IFS; IFS=' ' for line in $incs; do src=${line%%:*} rest=${line#*\"}; tgt=${rest%%\"*} case "$tgt" in '') continue;; esac nrefs=$((nrefs + 1)) dir=${src%/*} case "$dir" in "$src") dir="";; esac if [ -n "$dir" ] && [ -f "$inc/$dir/$tgt" ]; then nres=$((nres + 1)) elif [ -f "$root/$tgt" ]; then nres=$((nres + 1)) elif [ -f "$inc/$tgt" ]; then nres=$((nres + 1)) else miss="$miss $src->$tgt"; fi done IFS=$oIFS check_eq ade/include-refs "114" "$nrefs" # 113 of the 114 close inside the payload. The one that does not is upstream's, # and it is pinned as itself rather than smoothed into the count: passes/ # topological_sort.hpp says `#include "utility"` -- a QUOTED include of a C++ # standard header, which compiles only because quoted lookup falls back to the # include path. Counting it as a miss would leave a permanent red; excluding it # silently would hide the day upstream fixes it or adds a second one. check_eq ade/includes-close "113" "$nres" case "$miss" in " passes/topological_sort.hpp->utility") bst_ok ade/quoted-system-header;; *) bst_notok ade/quoted-system-header "unexpected unresolved includes:$(_bst_1line "$miss")";; esac # --------------------------------------------------------------------------- # 2. The archive -- and the evidence that a C++ front end produced it. # # There is no C++ compiler on this image, so the archive cannot be linked # against here. What CAN be asserted is that the bytes are a real C++ compile: # Itanium-mangled names encoding namespace, class, method and full parameter # types, and the vtable/typeinfo/typename records, which no C compile can emit. check_out ade/lib-archive "!" head -c 8 "$lib" # THE SUBSHELL IS LOAD-BEARING AND IS NOT STYLE, and it is the layer's form # rather than this suite's invention -- 74-pugixml.test carries the identical # line and the packager README states the rule ("Do not redirect stdin from the # rootfs"). Written bare, a top-level `prog < ` makes # dup2(2) return 513, the kernel's -ERESTARTNOINTR park sentinel reaching # userspace through glibc's errno return path, and ash treats a failed top-level # redirect as fatal: THE SUITE'S SHELL EXITS and every case below is silently # never reached, while the runner reports the ones it did see as a complete # all-green suite. Re-measured here on 2026-08-21 before the form was adopted -- # the first run of this suite reported pass=32 fail=0 against 139 declared, dying # exactly at this line, with `glibc-wasm32: RESTART-SENTINEL-LEAK val=513 nr=33 # site=error_label` on the console. Forking before the redirect is what makes it # safe. # # The sweep of the suites still carrying the bare form is BRINTOS-1151; # 74-libtinyxml2.test is one of them and loses 41 of its own 139 cases to it. # BRINTOS-WORKAROUND: brintos/linux#73 remove -- drop the subshell when the # restart sentinel no longer reaches userspace on a top-level redirect. flat=${TMPDIR:-/tmp}/bst-ade.$$ ( tr -c '\40-\176\n' ' ' < "$lib" > "$flat" ) 2>/dev/null # One object per upstream .cpp. The .cpp.o suffix is itself the finding: a C # compile of this recipe would have produced no object at all. for o in graph node edge topological_sort check_cycles search subgraphs \ metadata metatypes execution_engine memory_accessor \ memory_descriptor memory_descriptor_ref memory_descriptor_view \ alloc assert communications; do check "ade/member-$o" grep -q "$o\.cpp\.o" "$flat" done # The graph API, mangled. Every symbol below takes only ade types or primitives # in its signature, deliberately: anything naming std::string would mangle # differently under libc++ than under the libstdc++ these were first read from, # and the suite would then be asserting the standard library rather than ade. for s in _ZN3ade5GraphC1Ev \ _ZN3ade5GraphD1Ev \ _ZN3ade5Graph10createNodeEv \ _ZN3ade5Graph4linkERKNS_6HandleINS_4NodeEEES5_ \ _ZN3ade5Graph4linkERKNS_6HandleINS_4EdgeEEERKNS1_INS_4NodeEEE \ _ZN3ade5Graph4linkERKNS_6HandleINS_4NodeEEERKNS1_INS_4EdgeEEE \ _ZN3ade5Graph5eraseERKNS_6HandleINS_4NodeEEE \ _ZN3ade5Graph5eraseERKNS_6HandleINS_4EdgeEEE \ _ZN3ade5Graph6unlinkERKNS_6HandleINS_4NodeEEE \ _ZN3ade5Graph5nodesEv \ _ZN3ade5Graph11setListenerEPNS_14IGraphListenerE \ _ZN3ade4Node7inEdgesEv \ _ZN3ade4Node8outEdgesEv \ _ZN3ade4Node7inNodesEv \ _ZN3ade4Node8outNodesEv \ _ZN3ade4Node6unlinkEv \ _ZNK3ade4Edge7srcNodeEv \ _ZNK3ade4Edge7dstNodeEv; do check "ade/sym-$s" grep -q "$s" "$flat" done # The two passes this port is really about, and the pass-manager machinery. for s in _ZNK3ade6passes11CheckCyclesclERKNS0_11PassContextE \ _ZNK3ade6passes15TopologicalSortclENS0_16TypedPassContextIJNS0_19TopologicalSortDataEEEE \ _ZN3ade6passes15TopologicalSort4nameEv \ _ZN3ade6passes19TopologicalSortData4nameEv \ _ZNK3ade6passes10CycleFound4whatEv \ _ZN3ade6passes26LazyTopologicalSortChecker11edgeCreatedERKNS_5GraphERKNS_6HandleINS_4EdgeEEE; do check "ade/sym-$s" grep -q "$s" "$flat" done # THE EXCEPTIONS-OFF BRIDGE, in the archive, by name. ade::throw_error's #else # branch calls ade::details::dev_exception_abort, and that symbol being present # is the compile-time half of what section 5 demonstrates at run time. If the # exceptions arm ever lands (brintos/hwjs-cc#10) this stays -- the function is # compiled either way -- so read a red here as a missing object, not as the arm # having moved; the arm is what section 4's probe-exceptions case reports. for s in _ZN3ade7details19dev_exception_abortEPKc \ _ZN3ade7details16dev_assert_abortEPKciS2_S2_ \ _ZN3ade11throw_errorINS_6passes10CycleFoundEEEvOT_; do check "ade/sym-$s" grep -q "$s" "$flat" done # Vtable, typeinfo and typename records. These exist only because a C++ front # end emitted them, and CycleFound -- ade's one exception type, derived from # std::exception with a virtual what() -- is the polymorphic type the whole # refusal path runs through. for s in _ZTVN3ade6passes10CycleFoundE \ _ZTIN3ade6passes10CycleFoundE \ _ZTSN3ade6passes10CycleFoundE; do check "ade/rtti-$s" grep -q "$s" "$flat" done # The rest of ade's polymorphic surface: the listener and executable interfaces # and the metadata holder the typed-graph machinery instantiates. for s in _ZTIN3ade14IGraphListenerE \ _ZTIN3ade10ExecutableE \ _ZTIN3ade14ExecutableImplE \ _ZTVN3ade14ExecutableImplE \ _ZTIN3ade17BackendExecutableE \ _ZTVN3ade17BackendExecutableE \ _ZTIN3ade7details8Metadata18MetadataHolderBaseE; do check "ade/rtti-$s" grep -q "$s" "$flat" done rm -f "$flat" # Static-only distro. ade declares add_library(... STATIC ...) unconditionally, # so a shared object here would mean something in this layer overrode upstream # rather than that a default drifted. ade ships no pkg-config file at all -- # asserted rather than assumed, so a future recipe that starts generating one # is noticed rather than silently depended on. check ade/no-shared sh -c 'set -- /usr/lib/libade.so*; [ ! -e "$1" ]' check ade/no-libtool sh -c 'set -- /usr/lib/libade.la; [ ! -e "$1" ]' check ade/no-pkgconfig sh -c 'set -- /usr/lib/pkgconfig/ade.pc; [ ! -e "$1" ]' # --------------------------------------------------------------------------- # 3. The cmake package -- the only integration surface upstream provides, and # the one place this port carries an upstream wart worth pinning. # # sources/ade/manifest.cmake still says 0.1.0 at tag v0.1.2 and always has, so # write_basic_package_version_file() stamps 0.1.0 -- while upstream also asks # for COMPATIBILITY ExactVersion. Measured against the installed package on # x86-64: find_package(ade) and find_package(ade 0.1.0) resolve, # find_package(ade 0.1.2) does NOT. This is upstream's and is left alone; # it is asserted here so the next reader finds it stated rather than trips on it. check ade/cmake-config test -f "$cm/adeConfig.cmake" check ade/cmake-version test -f "$cm/adeConfigVersion.cmake" check ade/cmake-targets test -f "$cm/adeTargets.cmake" cv=$(cat "$cm/adeConfigVersion.cmake" 2>/dev/null) case "$cv" in *'set(PACKAGE_VERSION "0.1.0")'*) bst_ok ade/cmake-declares-0-1-0;; *) bst_notok ade/cmake-declares-0-1-0 "upstream manifest version moved -- re-measure find_package";; esac case "$cv" in *PACKAGE_VERSION_EXACT*) bst_ok ade/cmake-exact-version;; *) bst_notok ade/cmake-exact-version "no ExactVersion arm in the version file";; esac cc=$(cat "$cm/adeConfig.cmake" 2>/dev/null) case "$cc" in *adeTargets.cmake*) bst_ok ade/cmake-config-includes-targets;; *) bst_notok ade/cmake-config-includes-targets "config does not include adeTargets.cmake";; esac # The imported target must name the archive this image actually ships, and must # name it as a static library: a consumer's link line is generated from here. tg=$(cat "$cm"/adeTargets*.cmake 2>/dev/null) case "$tg" in *'add_library(ade STATIC IMPORTED)'*) bst_ok ade/cmake-target-static;; *) bst_notok ade/cmake-target-static "imported ade target is not STATIC";; esac case "$tg" in *libade.a*) bst_ok ade/cmake-target-archive;; *) bst_notok ade/cmake-target-archive "imported target does not name libade.a";; esac case "$tg" in *INTERFACE_INCLUDE_DIRECTORIES*) bst_ok ade/cmake-include-dirs;; *) bst_notok ade/cmake-include-dirs "no INTERFACE_INCLUDE_DIRECTORIES";; esac # --------------------------------------------------------------------------- # 4. The probe -- the engine itself, on this arm. # # data-free: the probe is a real program in its own package, cross-linked at # port time against the very libade.a above, so do_compile is the port's first # consumer and this run is its second. require "$PT/ade-probe" ade/probe-present out=$("$PT/ade-probe" 2>&1); prc=$? bst_ok ade/probe-ran pv() { printf '%s\n' "$out" | grep "^P-$1 " | head -1 | cut -d' ' -f2- ; } check_eq ade/probe-rc "0" "$prc" check_eq ade/probe-result "OK" "$(pv RESULT)" check_eq ade/probe-failures "0" "$(pv FAILURES)" # The arm's configuration, asserted rather than assumed: everything this suite # says about refusals is a statement about the exceptions-off arm, so a probe # built with them on would be evidence for a different claim. A red here is # GOOD NEWS (brintos/hwjs-cc#10 landed) and means section 5 must be re-measured, # not that ade regressed. check_eq ade/probe-exceptions-off "0" "$(pv EXCEPTIONS)" # Construction, and the two views of adjacency a consumer walks. check_eq ade/nodes "6" "$(pv NODES)" check_eq ade/edge-src "0" "$(pv SRC-OF-E01)" check_eq ade/edge-dst "1" "$(pv DST-OF-E01)" check_eq ade/out-degree "2" "$(pv OUT-DEGREE-0)" check_eq ade/in-degree "2" "$(pv IN-DEGREE-5)" check_eq ade/in-degree-root "0" "$(pv IN-DEGREE-0)" check_eq ade/out-nodes "1,2" "$(pv OUT-NODES-0)" # The sort, on a diamond. TOPO-VALID is the real assertion -- every edge's # source precedes its destination -- because a diamond has several valid orders # and pinning one permutation would pin an implementation detail. check_eq ade/topo-count "6" "$(pv TOPO-COUNT)" check_eq ade/topo-valid "1" "$(pv TOPO-VALID)" check_eq ade/topo-first "0" "$(pv TOPO-FIRST)" check_eq ade/topo-last "5" "$(pv TOPO-LAST)" # CheckCycles must ACCEPT an acyclic graph and an empty one. Reaching the line # after the call is the result: a refusal on this arm would have aborted. check_eq ade/checkcycles-dag "1" "$(pv CHECKCYCLES-DAG)" check_eq ade/checkcycles-empty "1" "$(pv CHECKCYCLES-EMPTY)" # Mutation. Each is read back through the graph rather than through the handle # that made it, and the handle-nulling cases are ade's documented contract: # erase() nulls every handle pointing at what it removed. check_eq ade/erase-edge-nulls-handle "1" "$(pv ERASED-EDGE-NULL)" check_eq ade/erase-edge-out-degree "1" "$(pv OUT-DEGREE-0-AFTER-ERASE)" check_eq ade/erase-edge-in-degree "0" "$(pv IN-DEGREE-2-AFTER-ERASE)" check_eq ade/relink-dst "4" "$(pv RELINK-DST)" check_eq ade/relink-src-unchanged "1" "$(pv RELINK-SRC-UNCHANGED)" check_eq ade/relink-old-dst-degree "0" "$(pv IN-DEGREE-3-AFTER-RELINK)" check_eq ade/unlink-drops-edges "0" "$(pv IN-DEGREE-5-AFTER-UNLINK)" check_eq ade/unlink-keeps-node "6" "$(pv NODES-AFTER-UNLINK)" check_eq ade/unlink-nulls-e35 "1" "$(pv ERASED-E35-NULL)" check_eq ade/unlink-nulls-e45 "1" "$(pv ERASED-E45-NULL)" check_eq ade/erase-node-count "5" "$(pv NODES-AFTER-ERASE)" check_eq ade/erase-node-nulls-handle "1" "$(pv ERASED-NODE-NULL)" # A 512-node chain: exactly one valid order, so a width or ordering slip that a # six-node graph cannot separate from luck shows up as a nonzero CHAIN-BAD. check_eq ade/chain-count "512" "$(pv CHAIN-COUNT)" check_eq ade/chain-bad "0" "$(pv CHAIN-BAD)" check_eq ade/chain-stable "1" "$(pv CHAIN-STABLE)" # No edges at all: every node is a root, and the sort must return all of them # rather than none -- the degenerate input a filter-based implementation drops. check_eq ade/isolated-count "4" "$(pv ISOLATED-COUNT)" # The probe emitted the whole of its report rather than dying part way: a # truncated run would pass every case above that it happened to reach. check_eq ade/probe-line-count "32" "$(printf '%s\n' "$out" | grep -c '^P-')" # --------------------------------------------------------------------------- # 5. The refusal -- the case that catches a graph engine which accepts anything. # # A second process, because on this arm the refusal ends the one it happens in. # `ade-probe cycle` builds a two-node cycle, prints P-CYCLE-ENTER, and calls # CheckCycles; upstream's exceptions-off branch then prints to stderr and # abort()s, so P-CYCLE-ACCEPTED is unreachable unless ade accepted the cycle. # # The exit STATUS is asserted as nonzero rather than as a specific number: what # a guest reports for a SIGABRT is the kernel's business, not ade's, and pinning # 134 here would buy a red the day that changes for an unrelated reason. The # stderr text is the assertion that says WHICH refusal happened. cout=$("$PT/ade-probe" cycle 2>&1); crc=$? case "$cout" in *P-CYCLE-ENTER*) bst_ok ade/cycle-reached;; *) bst_notok ade/cycle-reached "probe did not reach the cycle check: $(_bst_1line "$cout")";; esac case "$cout" in *P-CYCLE-ACCEPTED*) bst_notok ade/cycle-refused "ade ACCEPTED a cyclic graph -- CheckCycles returned normally";; *) bst_ok ade/cycle-refused;; esac if [ "$crc" -ne 0 ]; then bst_ok ade/cycle-nonzero-exit else bst_notok ade/cycle-nonzero-exit "cycle probe exited 0"; fi case "$cout" in *"An exception thrown!"*) bst_ok ade/cycle-abort-diagnosed;; *) bst_notok ade/cycle-abort-diagnosed "no dev_exception_abort diagnostic: $(_bst_1line "$cout")";; esac case "$cout" in *"Cycle was detected in graph"*) bst_ok ade/cycle-message;; *) bst_notok ade/cycle-message "wrong diagnostic: $(_bst_1line "$cout")";; esac bst_ok ade/suite-complete