hal: C++ API (hal.hh) and pybind11 bindings on the new HAL API#4251
hal: C++ API (hal.hh) and pybind11 bindings on the new HAL API#4251grandixximo wants to merge 1 commit into
Conversation
|
This seems to be working, but I am not sure if it is the right shape we want, these are the direction I took on the issue raised in the meeting, subject to revision.
@BsAtHome A bare hal_sint_t is width-blind, and wrapping foreign raw handles across widths is unsafe in the interim. But the C++ layer never selects from the handle alone. Component-created pins carry the type at construction via traits (int32_t vs int64_t are distinct C++ types, compile-time selection), and the runtime path uses q->pp.type from your query API to pick the variant alternative, the stored-type-tag multiplex you described in #4099. The only unsafe path is explicitly reinterpreting a raw handle, which can be guarded with a query lookup. So the layer works transitionally, it just gets simpler after the break. |
|
oh, that was quick. I think this should be separate from the other big PR, as this can go in master fairly quickly. the only reason I stopped was that buster had no pybind11 package. this should also replace the current pyhal/halmodule instead of adding a third module. and, the same cpp api should be used in xhc, task and other places which are implemented in cpp. |
|
Buster is basically not supported anymore with master, I will fix the review points tomorrow, thank you both |
a8c2a71 to
87ff92b
Compare
|
There is another issue. The new hal_lib uses a reference counted init/exit and has separated out Calling The python class must initialize using hal_lib_init() and terminate by calling hal_lib_exit(). If the user has not called hal_exit() on any created components, you will now get a proper error message (because the user forgot to terminate correctly). |
|
can you rename the module to halmodule, so that the UIs and the tests that are already in place use the new bindings, and remove the old ones? |
Replacing halmodule is the goal, agreed, but renaming now would break things for two separate reasons. First, a hard technical one: on master the new bindings cannot cover the existing Python surface. Second, the compatibility tail: So the proposal stands as: land this additive now (hal.hh + halpp alongside, nothing replaced), and do the rename + replacement as a follow-up once #4247 is in. Your old branch's consumer sweep (hal_glib, qtvcp core, raster, tests) is the starting checklist for that PR. Is this acceptable? Open for discussion... |
|
I see that #4231 changes halmodule.cc, we should also add those functions via c++/pybind11 |
No, all of this should be in halquery. |
What is halquery? |
That is the new interface to all of HAL's internals nicely wrapped up from the hal query interface without someone needing to dig into HAL's internals. Hal_lib's internals are fully isolated in #4247 and nobody should be writing code that circumvents that. Inclusion of hal_priv.h is strictly forbidden in any code that is not part of hal_lib. |
|
ah, found it. I would much prefer if it would be a c++ api, which can be used to automatically generate the python bindings. |
|
It is a pure C version, so it does not have the same problems as C++ interfacing C-based Python ;-) |
|
This is exactly the split #4251 (this PR) implements: the query API stays pure C in the library (Bertho's layer, no bypass possible), and the C++ API sits on top of it (hal.hh), which is where Python bindings get generated (halpybind) , no hand-written CPython code. halquery.c proves the query API is sufficient; the same functions can be exposed as pybind wrappers over |
|
Fine by me to get it C++ wrapped. It does not yet have priority one. There is one thing that should be fixed in both halmodule and halquery: use IntEnum types for both type and direction. It may be necessary to have a |
|
A shared pure-Python |
That would be the simple way. If it works, then it should be nice. The real benefit is in halquery to have the iteration result show the right name instead of a number. There it is big value. Probably also need to add the same for other constants.
Global namespace naming and fixing hierarchy is a problem we need to fix in a later version. This would be a version 3.0 thing, I guess ;-)
Ha, and so much for "C++ is easy to maintain" ;-) |
Reintroduce a C++ interface for HAL, built strictly on the public C API and the user-land query API: no hal_priv.h, no direct shared memory access, no re-implemented library internals. - hal.hh: type-safe, header-only C++ layer in linuxcnc::hal. Typed pin/param handles via traits<T> over the rtapi_ types (compile-time accessor selection), runtime-typed pin_t variant and anypin for name-based access, component class with add_pin for the struct-member idiom, and ULAPI by-name query/set functions when the query API is present. Handles re-read the shmem slot on every access so hal_link() slot rewrites stay visible (C pointer-variable semantics). Handles are move-only; HAL objects are unique. Query callback paths are exception-free; errors are reported after the library releases the HAL mutex. - halpybind.cc: pybind11 module (halpp.so) exposing component, Pin, enums and the by-name functions. Built alongside _hal/hal.py, replacing nothing. Library init/exit at import; string set values delegate to setps_common_cb for halcmd-consistent parsing. - taskclass converted to the new API (it was the only hal.hh user). - HAL_PORT intentionally exempted until the API break: the port handle type and creation semantics are still in flux. - tests/halpp: Python and native C++ smoke suites. Based on the pybind11 branch by rene-dev, re-based on the new HAL API.
202386a to
6925b79
Compare
@rene-dev @BsAtHome - this is the unification pass we discussed in the #4099 meeting: Rene's C++/pybind11 interface rebuilt on Bertho's getter/setter API, satisfying both constraints (no HAL internals access; simple, low-maintenance, self-documenting C++ surface).
Based on master, fully additive:
_hal/hal.pyare untouched and nothing is replaced. The by-name query functions and HAL_PORT creation are compiled out when the query API header is absent and activate automatically when #4247 lands.What this adds
src/hal/hal.hh- type-safe C++ layer, header-only, innamespace linuxcnc::hal:hal::pin<T>typed handles viatraits<T>over the rtapi_ types:rtapi_s32/rtapi_sintare distinct C++ types, so 32/64 accessor selection happens at compile time with zero cost. Handles re-read the shmem slot per access, sohal_link()rewrites stay visible (same semantics as C pin pointers). Handles are move-only; HAL objects are unique.hal::pin_tvariant +hal::anypin: runtime-typed access multiplexes on the variant tag (the stored-type pattern required for name-keyed collections), with the tag supplied by the query API.hal::component: pins + params,newpin/newparam(typed and runtime-typed),add_pinfor the struct-member idiom, item access, prefix handling.get_value,set_value,set_signal,component_exists,pin_has_writer, signal management) implemented entirely onhal_get_p/hal_set_p/hal_get_s/hal_set_s/hal_comp_by_name. Nohal_priv.h, no direct shmem access, no re-implemented parsers.src/hal/halpybind.cc- pybind11 module (halpp.so), adapted from @rene-dev's bindings, extended with params and error paths. Built alongside_hal/hal.py; module replacement is a separate (3.0) discussion.src/emc/task/taskclass.cc- converted to the new API (it was the only hal.hh consumer).tests/halpp/- Python and native C++ smoke suites (both green), pluspython3-pybind11build dep.Safety properties worth noting
Relationship to the original pybind11 branch
Kept: the variant/map/PyPin structure and the binding shape.
Dropped: the private
set_commonstring parser (superseded byhal_set_p),hal_mutex_guard, theget_info_signalsstub,waitWritable(was non-functional).Compatibility aliases (
hal_comp,hal_pin<T>,hal_dir,PyPin) are provided so existing consumers of the old hal.hh keep working.Test evidence
Full tree builds;
tests/halmodule.0/.1pass; new smoke suites cover component lifecycle, typed pins/params (incl. negative S32 and 64-bit values), signals, linking, by-name get/set with coercion, port pins, and error paths. The suites auto-skip query-API checks when built without the query API, so they run on both master and the #4247 tree.