BitBake Class Functions: Preserve the Original Implementation with EXPORT_FUNCTIONS

A recipe replaces a class-provided function but still needs the class's implementation on one branch of its logic. Calling the public function name from inside that replacement calls the replacement again. Copying the original body into the recipe avoids recursion today but creates a second implementation to maintain.

EXPORT_FUNCTIONS provides a deliberate interface for this situation. The class retains a separately named implementation, while the public function becomes a default entry point that a recipe can replace.

Give the implementation a class-qualified name

The flexible class-function inheritance guide requires the implementation name to combine the class name and exported function name. For an illustrative reportstage.bbclass, define reportstage_do_report, then declare EXPORT_FUNCTIONS do_report.

A recipe inheriting reportstage can define its own do_report and call reportstage_do_report when it wants the class behavior. The two names are intentional: one is the replaceable entry point; the other is the class implementation.

If the class defines only do_report and the recipe replaces it, the original body has not automatically acquired a callable class-qualified alias. Adding a call to a name that was never defined cannot restore it. Establish the interface in the class first.

Inspect the generated wrapper rather than assuming inheritance

The examined export-function AST code constructs a wrapper that calls the class-qualified implementation. It distinguishes shell and BitBake-style Python functions when generating that call.

It also preserves an existing non-generated public implementation instead of blindly replacing it. Thus, inheriting another class does not prove that its exported wrapper became the active public function. Inspect the final function body and its assignment history when multiple classes or recipe definitions are involved.

This is a real metadata pattern, not a special convention for this example: the examined OpenEmbedded base class exports functions including do_fetch, do_unpack and do_compile through its base-qualified implementations.

Diagram showing a class-qualified function, the default exported wrapper, a recipe replacement and verification of its explicit helper call.
Original function-interface diagram. The illustrative class and task were not executed.

Call the implementation with the right execution model

For a shell replacement, invoke the shell helper by its qualified name, such as reportstage_do_report. Do not invoke do_report from its own replacement body as a substitute for a parent call.

For a BitBake-style Python implementation, use bb.build.exec_func("reportstage_do_report", d) from Python. This is different from calling a regular Python utility defined with def. Keep the function's language and invocation mechanism aligned rather than moving code between shell and Python based only on a matching name.

The export declaration does not itself make an arbitrary function a scheduled task. If do_report is meant to be independently runnable, its task registration and dependencies still need to exist. Likewise, calling the class helper within a task is not a request to schedule a second independent recipe task.

Choose replacement only when the control flow needs it

If the desired change simply runs before or after all of the original behavior, extending the public function can be clearer. A replacement with an explicit class call is useful when the recipe must choose a branch, pass through only selected behavior, or wrap the implementation with specific logic.

Do not call the class helper twice accidentally: once from a replacement and again from an appended fragment written under the assumption that the default wrapper remained. Inspect the fully assembled public body, not only the newest bbappend.

The examined implementation rejects a dash in a class name when exporting a shell function because the generated shell helper name would be invalid. Use a shell-safe class basename for this interface instead of renaming only the call site.

Verify both paths with an observable, harmless function

For a small test recipe, make the class helper and recipe branch emit different diagnostic messages. Inspect both definitions with bitbake -e, then exercise the registered task's class-call and alternative branches separately. Check ordering and the number of helper invocations.

Once that minimal interface behaves as intended, apply the same naming and control-flow review to the real task. The key result is one explicit public implementation and an intentional call to preserved class behavior, without recursion or a copied body that silently diverges from the class.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *