Skip to content

Commit 937f5be

Browse files
committed
hal: Add halcompupdate to migrate .comp files to the new HAL API
Out-of-tree .comp components using the legacy HAL types (float, bit, s32, u32, s64, u64, signed, unsigned) and direct pin/param assignment stop working when the HAL API break is performed (#4099, #4247). halcompupdate rewrites them to the new API automatically: * declaration types are converted: float->real, bit->bool, s32->si32, u32->ui32, s64->sint, u64->uint, signed->si32, unsigned->ui32 ('port' is left alone, it has no new-style replacement yet) * writes to out/io pins and to params become <name>_set(...) calls, including compound assignments, ++/--, array pins, chained assignments, *<name>_ptr dereferences and writes inside #define macros (macro parameters shadow same-named pins) * legacy C types are modernized (double/real_t -> rtapi_real, hal_bit_t -> volatile rtapi_bool, ...) * reads are unchanged and pins are never renamed, so existing HAL configurations keep working Constructs that cannot be converted safely are left unchanged with a warning for manual conversion: taking the address of a pin/param, direct use of the legacy hal_pin_*_new/hal_param_*_new creation API, postfix ++/-- whose value is used, and array indices with side effects. In-place rewriting is atomic (temp file + rename) and keeps a .bak backup created with O_EXCL|O_NOFOLLOW. halcompile now warns once per deprecated type, pointing to halcompupdate(1), at the spot previously marked for this warning. Docs: migration section in comp.adoc, new halcompupdate(1) manpage, SEE ALSO in halcompile(1). Regression test in tests/halcompile/update-api. Validated by converting all in-tree components from master: 119/124 compile (the other 5 need in-tree headers and fail identically for the already-converted versions), and the output matches the hand conversions in #4247 functionally.
1 parent fedbb56 commit 937f5be

11 files changed

Lines changed: 1371 additions & 6 deletions

File tree

debian/linuxcnc-uspace-dev.install

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
usr/bin/halcompile
2+
usr/bin/halcompupdate
23
usr/bin/modcompile
34
usr/include/linuxcnc
45
usr/lib/liblinuxcnc.a
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
usr/share/man/man1/halcompile.1
2+
usr/share/man/man1/halcompupdate.1
23
usr/share/man/man3/*

docs/src/hal/comp.adoc

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,14 @@ In this case, r-strings are particularly useful, because the backslashes in an r
267267
r"\fIexample\fB"
268268
----
269269

270-
* 'TYPE' - One of the HAL types: 'bit', 's32', 'u32', 's64', 'u64' or 'float'.
271-
The names 'signed' and 'unsigned' may also be used for 's32' and 'u32' but 's32' and 'u32' are preferred.
270+
* 'TYPE' - One of the HAL types: 'real', 'bool', 'si32', 'ui32', 'sint' or 'uint'.
271+
'real' is a floating point value, 'bool' a boolean, 'si32' and 'ui32' are 32-bit signed and unsigned integers,
272+
and 'sint' and 'uint' are 64-bit signed and unsigned integers.
273+
The legacy types 'float' (for 'real'), 'bit' (for 'bool'), 's32' (for 'si32'), 'u32' (for 'ui32'),
274+
's64' (for 'sint') and 'u64' (for 'uint') are still accepted, as are the aliases 'signed' and 'unsigned'
275+
(for 'si32' and 'ui32'), but they are deprecated, 'halcompile' will warn about them,
276+
and they will be removed when the HAL API break is performed.
277+
See <<sub:hal-comp-migration,Migrating to the new HAL API>>.
272278
* 'PINDIRECTION' - One of the following: 'in', 'out', or 'io'.
273279
A component sets a value for an 'out' pin, it reads a value from an 'in' pin, and it may read or set the value of an 'io' pin.
274280
* 'PARAMDIRECTION' - One of the following: 'r' or 'rw'. A component sets a value for a 'r' parameter, and it may read or set the value of a 'rw' parameter.
@@ -458,6 +464,15 @@ The details of `struct __comp_state` and these macros may change from one versio
458464
+
459465
When the item is a conditional item, it is only legal to refer to it when its 'condition' evaluated to a nonzero value.
460466

467+
* `pin_name_set(`__value__`)` or `param_name_set(`__value__`)` - For each 'out' or 'io' pin and each parameter
468+
of a new-style type ('real', 'bool', 'si32', 'ui32', 'sint', 'uint'), there is a macro which sets the value of the pin or parameter.
469+
For arrays the form is 'pin_name_set(idx, value)'.
470+
With the new-style types, assigning to an 'out' or 'io' pin or to a parameter with plain C assignment is not possible;
471+
the '_set' macro must be used instead (reading stays transparent through the bare name).
472+
The '_set' macro evaluates to the value that was set, so chained use like 'a_set(b_set(x))' works.
473+
There is also a 'pin_name_ptr' macro, but with new-style types it evaluates to an opaque reference
474+
which can only be used with the 'hal_get_*' and 'hal_set_*' functions; it cannot be dereferenced.
475+
461476
* 'variable_name' - For each variable 'variable_name' there is a macro which allows the name to be used on its own to refer to the variable.
462477
When 'variable_name' is an array, the normal C-style subscript is used: 'variable_name[idx]'.
463478
* 'data' - If "option data" is specified, this macro allows access to the instance data.
@@ -466,6 +481,47 @@ When the item is a conditional item, it is only legal to refer to it when its 'c
466481
This macro iterates over all the defined instances.
467482
Inside the body of the loop, the 'pin_name', 'parameter_name', and 'data' macros work as they do in realtime functions.
468483

484+
[[sub:hal-comp-migration]]
485+
== Migrating to the new HAL API
486+
487+
HAL is moving from direct memory access of pin and parameter values to strongly typed getter/setter access.
488+
New-style declaration types replace the legacy types:
489+
490+
[cols="1,1,3",options="header"]
491+
|===
492+
| Legacy type | New type | Underlying C type
493+
| 'float' | 'real' | 'rtapi_real' (floating point)
494+
| 'bit' | 'bool' | 'rtapi_bool' (boolean)
495+
| 's32' | 'si32' | 'rtapi_s32' (32-bit signed)
496+
| 'u32' | 'ui32' | 'rtapi_u32' (32-bit unsigned)
497+
| 's64' | 'sint' | 'rtapi_sint' (64-bit signed)
498+
| 'u64' | 'uint' | 'rtapi_uint' (64-bit unsigned)
499+
| 'signed' | 'si32' | 'rtapi_s32' (32-bit signed)
500+
| 'unsigned' | 'ui32' | 'rtapi_u32' (32-bit unsigned)
501+
|===
502+
503+
The legacy types still work, but 'halcompile' warns about them and they will be removed when the HAL API break is performed.
504+
With the new-style types:
505+
506+
* reading a pin or parameter is unchanged (the bare name, or 'name(idx)' for arrays, evaluates to the value);
507+
* writing an 'out' or 'io' pin or a parameter requires the generated 'name_set(value)' macro
508+
(or 'name_set(idx, value)' for arrays) instead of plain assignment;
509+
* 'name_ptr' is an opaque reference for use with 'hal_get_*'/'hal_set_*' and can no longer be dereferenced.
510+
511+
Existing components can be migrated automatically with the 'halcompupdate' tool:
512+
513+
----
514+
halcompupdate mycomponent.comp # show a diff of the required changes
515+
halcompupdate -i mycomponent.comp # rewrite the file in place (keeps a .bak)
516+
----
517+
518+
The tool converts the declaration types and rewrites writes to pins and parameters
519+
(including compound assignments and dereferences of 'name_ptr') to the '_set' form.
520+
It deliberately does not rename pins or parameters, because their names are part of the HAL configuration interface.
521+
Components that use the legacy 'hal_pin_*_new'/'hal_param_*_new' creation functions or that pass
522+
the address of a pin ('&name') to helper functions cannot be converted automatically;
523+
'halcompupdate' prints a warning for those cases so they can be converted by hand.
524+
469525
== Components with one function
470526

471527
If a component has only one function and the string `"FUNCTION"` does not appear anywhere after `;;`,

docs/src/man/man1/halcompile.1.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ Extra arguments passed to the linker.
9999

100100
== SEE ALSO
101101

102+
* *halcompupdate*(1) to migrate existing *.comp* files to the new HAL
103+
pin/param API (new-style declaration types and *<name>_set()* accessors)
104+
102105
* _Halcompile_ / _HAL Component Generator_ in the LinuxCNC documentation for a
103106
full description of the *.comp* syntax, along with examples
104107

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
= halcompupdate(1)
2+
3+
== NAME
4+
5+
halcompupdate - Migrate HAL .comp components to the new HAL pin/param API
6+
7+
== SYNOPSIS
8+
9+
*halcompupdate* [--in-place] [--no-backup] [--check] [--no-c-types] [--quiet] compfile...
10+
11+
== DESCRIPTION
12+
13+
*halcompupdate* converts HAL components written for the legacy HAL API
14+
(pins and params declared with the types *float*, *bit*, *s32*, *u32*,
15+
*s64*, *u64*, *signed* or *unsigned* and written with plain C assignment)
16+
to the new HAL API, where pins and params are declared with the types
17+
*real*, *bool*, *si32*, *ui32*, *sint* and *uint* and written with the
18+
generated *<name>_set(value)* accessor.
19+
20+
The legacy types still work, but halcompile(1) warns about them and they
21+
will be removed when the HAL API break is performed.
22+
23+
The following transformations are applied:
24+
25+
* Declaration types are replaced: *float* -> *real*, *bit* -> *bool*,
26+
*s32* -> *si32*, *u32* -> *ui32*, *s64* -> *sint*, *u64* -> *uint*,
27+
*signed* -> *si32*, *unsigned* -> *ui32*. The type *port* is not
28+
converted yet.
29+
* Assignments to *out* and *io* pins and to parameters are rewritten to
30+
the *<name>_set(...)* form, including compound assignments
31+
(*name += x* becomes *name_set(name + (x))*), increments/decrements
32+
and array pins (*name(i) = x* becomes *name_set(i, x)*).
33+
* Dereferences of the old pin pointer macro are rewritten:
34+
***name_ptr*** reads become *(name)* and ***name_ptr = x*** writes
35+
become *name_set(x)*.
36+
* Legacy C types are modernized with their variable-use replacements
37+
(*double* -> *rtapi_real*, *hal_float_t* -> *rtapi_real*,
38+
*hal_bit_t* -> *rtapi_bool*, and so on). The *volatile* qualifier of
39+
the legacy types is dropped on purpose: it existed for direct access
40+
to HAL memory and was never right for variables. Pointers to the
41+
legacy types referenced HAL memory and become opaque references in the
42+
new API; those are warned about and left unchanged. Use
43+
*--no-c-types* to skip this conversion.
44+
45+
Reading pins and params is unchanged: the bare name (or *name(idx)* for
46+
arrays) evaluates to the value in both APIs.
47+
48+
Pin and parameter names are never changed, because they are part of the
49+
HAL configuration interface used by .hal files.
50+
51+
Components that use the legacy *hal_pin_*_new*/*hal_param_*_new* creation
52+
functions directly, or that pass the address of a pin (*&name*) to helper
53+
functions, cannot be converted automatically. *halcompupdate* prints a
54+
warning for those cases so they can be converted by hand.
55+
56+
== OPTIONS
57+
58+
*compfile...*::
59+
One or more .comp files to convert.
60+
Without other options, a unified diff of the required changes is printed.
61+
62+
*-i*, *--in-place*::
63+
Rewrite the files in place. A backup with the suffix *.bak* is kept
64+
unless *--no-backup* is given.
65+
66+
*--no-backup*::
67+
With *--in-place*, do not keep a *.bak* backup.
68+
69+
*--check*::
70+
Do not write anything; exit with status 1 if any file would be changed.
71+
Useful in build systems to verify that components are migrated.
72+
73+
*--no-c-types*::
74+
Only convert pin/param declarations and accesses; do not modernize
75+
C types in the component body.
76+
77+
*-q*, *--quiet*::
78+
Suppress warnings on stderr.
79+
80+
== EXAMPLES
81+
82+
Show what would change:
83+
84+
----
85+
halcompupdate mycomponent.comp
86+
----
87+
88+
Migrate in place:
89+
90+
----
91+
halcompupdate -i mycomponent.comp
92+
----
93+
94+
== SEE ALSO
95+
96+
*halcompile*(1), the _Halcompile_ / _HAL Component Generator_ section in
97+
the LinuxCNC documentation for a full description of the *.comp* syntax
98+
and the new HAL API.

src/hal/utils/Submakefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ endif
9696
$(ECHO) Copying python script $(notdir $@)
9797
$(Q)(echo '#!$(PYTHON)'; sed '1 { /^#!/d; }' $<) > $@.tmp && chmod +x $@.tmp && mv -f $@.tmp $@
9898

99+
../bin/halcompupdate: ../bin/%: hal/utils/%.py
100+
@$(ECHO) Syntax checking python script $(notdir $@)
101+
$(Q)$(PYTHON) -m py_compile $<
102+
$(ECHO) Copying python script $(notdir $@)
103+
$(Q)(echo '#!$(PYTHON)'; sed '1 { /^#!/d; }' $<) > $@.tmp && chmod +x $@.tmp && mv -f $@.tmp $@
104+
99105
../bin/modcompile: ../bin/%: hal/drivers/mesa-hostmot2/modbus/%.py
100106
@$(ECHO) Syntax checking python script $(notdir $@)
101107
$(Q)$(PYTHON) -m py_compile $<
@@ -111,7 +117,7 @@ endif
111117
$(ECHO) Copying python script $(notdir $@)
112118
$(Q)(echo '#!$(PYTHON)'; sed '1 { /^#!/d; }' $<) > $@.tmp && chmod +x $@.tmp && mv -f $@.tmp $@
113119

114-
TARGETS += ../bin/halcompile ../bin/elbpcom ../bin/modcompile ../share/linuxcnc/mesa_modbus.c.tmpl ../bin/mesambccc
120+
TARGETS += ../bin/halcompile ../bin/elbpcom ../bin/modcompile ../share/linuxcnc/mesa_modbus.c.tmpl ../bin/mesambccc ../bin/halcompupdate
115121
objects/%.py: %.g
116122
@mkdir -p $(dir $@)
117123
$(Q)$(YAPPS) $< $@

src/hal/utils/halcompile.g

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,11 @@ def parse(filename):
151151

152152
dirmap = {'r': 'HAL_RO', 'rw': 'HAL_RW', 'in': 'HAL_IN', 'out': 'HAL_OUT', 'io': 'HAL_IO' }
153153
typemap = {'signed': 's32', 'unsigned': 'u32'}
154-
deprmap = {'s32': 'signed', 'u32': 'unsigned'}
155-
deprecated = ['s32', 'u32']
156154
newtypes = ['bool', 'sint', 'uint', 'si32', 'ui32', 'real']
155+
# Old HAL declaration types and their new-style replacements. These types
156+
# will be removed when the HAL API break is performed.
157+
old2newtypes = {'float': 'real', 'bit': 'bool', 's32': 'si32', 'u32': 'ui32',
158+
's64': 'sint', 'u64': 'uint', 'signed': 'si32', 'unsigned': 'ui32'}
157159

158160
def initialize():
159161
global functions, params, pins, comp_name, names, docs, variables
@@ -162,6 +164,7 @@ def initialize():
162164
functions = []; params = []; pins = []; options = {}; variables = []
163165
modparams = []; docs = []; includes = [];
164166
comp_name = None
167+
deprecated_type_warnings.clear()
165168

166169
names = {}
167170

@@ -207,8 +210,14 @@ def see_also(doc):
207210
def notes(doc):
208211
docs.append(('notes', doc));
209212

213+
deprecated_type_warnings = set()
214+
210215
def type2type(type_):
211-
# When we start warning about s32/u32 this is where the warning goes
216+
if type_ in old2newtypes and type_ not in deprecated_type_warnings:
217+
deprecated_type_warnings.add(type_)
218+
Warn("HAL type '%s' is deprecated and will be removed at the HAL API "
219+
"break; use '%s' instead. Run halcompupdate(1) to migrate "
220+
"automatically." % (type_, old2newtypes[type_]))
212221
return typemap.get(type_, type_)
213222

214223
def checkarray(name, array):

0 commit comments

Comments
 (0)