Skip to content

halcompile: reject declarations that claim the same HAL name - #4298

Merged
andypugh merged 1 commit into
LinuxCNC:masterfrom
tzuohann:halcompile-halname-upstream
Sep 27, 2026
Merged

andypugh merged 1 commit into
LinuxCNC:masterfrom
tzuohann:halcompile-halname-upstream

Conversation

@tzuohann

@tzuohann tzuohann commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

pin in real my_input is exported as component.N.my-input — underscores become dashes (comp.adoc, HALNAME).

A component that declares both x_y and x_y_ exports both as x-y. halcompile accepts it; the module then fails at loadrt:

HAL: ERROR: duplicate pin 'collide.0.x-y'
collide: rtapi_app_main: Invalid argument (-22)

check_name_ok() only compares declared names. Comparing mangled names is not enough either, because a declaration does not claim just one:

  • an array claims one per element, so x_#[4] and x_0 both claim x-0;
  • hal_export_funct() creates <funct>.time, .tmax and .tmax-increased in the pin/param namespace, so function f and pin f.time collide.

claim() records the set of names each declaration takes and rejects a repeat at the offending line. Pins and params share one set; functions have their own. An if condition does not exempt a declaration.

Arrays are limited to 256 elements.

Two shapes master accepts are now refused: an array over 256 elements, and two declarations claiming one name under mutually exclusive if conditions.

Docs: NAMES section in the halcompile man page, linking to a new [[sec:halname]] anchor in comp.adoc. Tests: tests/halcompile/halname. All 146 in-tree .comp files preprocess to the same C, with the same exit status, as master.

🤖 Generated with Claude Code

@BsAtHome

Copy link
Copy Markdown
Contributor

Name collisions are bad by default and fail to compile. Why is there an option for this? You should be able to check this much easier using a parallel name array for target names (which you apparently do) without complex regexes or lambdas by using a simple if name in array construct. Also note that functions have a different HAL namespace than pins/params.

Your second PR seems to be a duplicate and changes a generated (man) file that is not part of the repository. Why is this submitted twice?

@grandixximo

Copy link
Copy Markdown
Contributor

Your second PR seems to be a duplicate and changes a generated (man) file that is not part of the repository. Why is this submitted twice?

It's a 2.9 backport, no .adoc there, also threw me off...

@tzuohann

Copy link
Copy Markdown
Contributor Author

thanks. help me understand here. is this is a problem that can throw some people (amateurs using AI) off? if so and a little fix can help, I'll try to sharpen the solution. but if its not even an issue, i'll close the PR.

@tzuohann
tzuohann force-pushed the halcompile-halname-upstream branch from e1db816 to 1188057 Compare July 31, 2026 01:12
@grandixximo

grandixximo commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Name collisions are bad by default and fail to compile.

But they actually don't, I tested the claimed x_y + x_y_ on master, compiles fine, fails on loadrt...

Edit:
Unless you mean name collisions should always fail to compile, in the PR context, then agreed...

@BsAtHome

Copy link
Copy Markdown
Contributor

Still, the option is useless.
When you encounter the situation, then you have an error. Either immediately at compile or afterwards at loadrt. There is no point in hiding the message. Halcompile should simply return with an error so that the build is interrupted.

@tzuohann

Copy link
Copy Markdown
Contributor Author

Still, the option is useless. When you encounter the situation, then you have an error. Either immediately at compile or afterwards at loadrt. There is no point in hiding the message. Halcompile should simply return with an error so that the build is interrupted.

ok I think this resolved the bit of confusion I as well as @grandixximo had. so this is a little problem that should be patched. but the option of hiding it is useless. i'll resubmit removing the option to hide it. thanks @BsAtHome

@tzuohann
tzuohann force-pushed the halcompile-halname-upstream branch from 1188057 to 6b100fc Compare July 31, 2026 17:13
@tzuohann tzuohann changed the title halcompile: warn about, and reject colliding, mangled HAL names halcompile: reject declarations that export the same HAL name Jul 31, 2026
@grandixximo

Copy link
Copy Markdown
Contributor

Wasn't this initially showing also info that the pins you will find in hal have different names?
I think a general one liner info after compilation would suffice. if it's one line per compilation, we can also keep it in the normal build, no flag needed? probably a separate PR/discussion from the collision.

@tzuohann

tzuohann commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Wasn't this initially showing also info that the pins you will find in hal have different names? I think a general one liner info after compilation would suffice. if it's one line per compilation, we can also keep it in the normal build, no flag needed? probably a separate PR/discussion from the collision.

Per component: that's already what it did — one line per file with the names collapsed into it (my_input -> my-input, ...). But the build runs halcompile once per .comp, so its still 100+ lines on a full master build.

One line for the whole build: It would have to be a fixed message from src/hal/components/Submakefile, which then can't name any actual pins. Also, in-tree only, so out-of-tree authors never see it.

I have no clue how folks use this so I'll leave it to you guys to tell me what to do.

@grandixximo

grandixximo commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

that's already what it did — one line per file with the names collapsed into it (my_input -> my-input, ...

You did do that originally, but that part has been removed, that is what I was saying, it is not there anymore, check the code...
halcompile is currently silent on success which is typical for compile tools, although it could be argued the audience of halcompile is not typical programmer audience, anyone using a compile tool should at least read the --help, a short section in the help about how names get managed, could avoid the confusion, and keep the build clean.
My proposal for help addition is:

Names:
    Declared names are C identifiers; HAL exports them with underscores
    replaced by dashes.  'pin in float my_input' is reached as
    'component.N.my-input'.  After loadrt, 'halcmd show pin component'
    lists the exported names.

@BsAtHome

BsAtHome commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Isn't this already described in https://linuxcnc.org/docs/devel/html/en/hal/comp.html ?

@grandixximo

Copy link
Copy Markdown
Contributor

Correct, but the OP, before edits (the whole reason this PR started), was because the user and his AI missed that, the original proposal was a noisy my_pin =>my-pin to stdout silenced with a flag, basically an in your face "WARNING: names have changed", displayed even for those who know this, and those who reads the docs, arguably useful for newcomers, but an eyesore for veterans.
I think within the original motivation there was an acceptable argument: this behavior is only documented in the comp.adoc

An addition in the --help will improve visibility, and will weaken the "is not well documented" argument, after the addition in --help there are less excuses for missing it, AI or human...

@BsAtHome

BsAtHome commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

The --help is there to remind you of command line switches. Not to tell you how to write content. That belongs to the man pages and other documentation. The man-page is terse and should link properly to the docs.

And, as you correctly said, no new is good news and errors/warnings are supposed to be one-liner messages with the correct information (in the correct format for IDEs to use).

Relying on abnormal intelligence to do the right thing is like asking an amoeba to write Shakespeare. The letters are there but the meaning is lost. As they say, gigo.

@grandixximo

Copy link
Copy Markdown
Contributor

The man page argument has a hole for exactly the audience halcompile serves: component developers. They overwhelmingly work from a RIP build (git clone, make, rip-environment), and RIP installs nothing to MANPATH. For them man halcompile returns "No manual entry" unless they also built the docs tree locally. The deb path (linuxcnc-uspace-dev) ships the man page, but that package is for people compiling components against an installed system, not the people writing them.

--help is the only documentation guaranteed to be present in every install flavor, at the exact moment someone unfamiliar with the tool looks for orientation.

There is also in-tree precedent for non-switch guidance in this very usage() text: "Do not use [sudo] for RIP installation" is behavioral advice, not a switch reminder.

Not proposing a tutorial, just 4 lines stating the one non-obvious semantic (C identifier => dashed HAL name) plus where to see the result (halcmd show pin). The full HALNAME rules stay in comp.adoc and the man page; the help text would end by pointing there. Zero build noise, zero runtime cost, and it covers the RIP user the man page never reaches.

Comment thread tests/halcompile/halname/test.sh Outdated
Comment thread tests/halcompile/halname/collide_pin_pin.comp Outdated
Comment thread src/hal/utils/halcompile.g Outdated
Comment thread docs/src/man/man1/halcompile.1.adoc Outdated
@BsAtHome

Copy link
Copy Markdown
Contributor

What is the status of progress? There are still some unaddressed open comments.

@grandixximo

Copy link
Copy Markdown
Contributor

@tzuohann is on vacation till mid September, just texted him on Discord...

@tzuohann

Copy link
Copy Markdown
Contributor Author

hi guys, back. i'll double check these before end of weekend.

@tzuohann
tzuohann force-pushed the halcompile-halname-upstream branch from 6b100fc to edf5da2 Compare September 18, 2026 20:32
@tzuohann

tzuohann commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor Author

What is the status of progress? There are still some unaddressed open comments.

All four addressed, and the branch is rebased onto master — it was 645 commits behind.

Widening the tests as you asked turned up that the check itself was wrong in both directions, so it is rewritten: it now compares the set of HAL names a declaration claims, not its
mangled name. Details in the thread on the test file.

Force-pushed. All 146 in-tree .comp files preprocess to the same C, with the same exit status, as master.

Comment thread tests/halcompile/halname/collide_array.comp Outdated
Comment thread src/hal/utils/halcompile.g Outdated
Comment thread src/hal/utils/halcompile.g Outdated
Comment on lines +230 to +234
# A pin array claims one HAL name per element. The bound keeps a nonsense
# size from expanding into a MemoryError instead of a diagnostic; an array
# larger than this cannot be loaded anyway, since every element is a separate
# HAL object in shared memory.
ARRAY_CLAIM_LIMIT = 4096

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this limit come from? The default personality limit is 64 and max 256 IIRC (a byte size). Therefore, personality limited arrays never are larger than 64.

For normal arrays, if someone creates an array of 4097 pins, should that fail? The current HAL memory allocation can support many more pins than 4096.

From a practical standpoint, having really many pins in an array would probably indicate some kind of error or abuse. I'd probably say it is an error and we may want to limit it to the same as the personality limit of 256. Unless there is a really good reason not to... You have one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mine (Claude's really), and its rather arbitrary — only to stop a MemoryError while expanding element names. 256 now, as you suggest; the largest array in the tree is 32 elements, so nothing in-tree changes.

Commet/correction: 256 isn't an existing limit. MAX_PERSONALITIES is 64, -P is uncapped, and a [MAXSIZE : CONDSIZE] array is bounded by MAXSIZE, not by MAX_PERSONALITIES.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mine (Claude's really), and its rather arbitrary

You outsourced your thinking. That equates to "I'm not learning".

Take it from a teacher: Learning comes at a price. That price is failing all the time until you don't fail anymore (or, at least, fail less). Outsourcing your learning process in this manner only learns you to write prompts. But, the output it generates you cannot fathom or comprehend. Learning the output's meaning means you have to create it yourself, fail, try again, fail, etc, until that you write works and understand how and why. That process generates insight in all directions, which no automated process can provide. Learning is hard and only those who learned hard have learned.

— only to stop a MemoryError while expanding element names. 256 now, as you suggest; the largest array in the tree is 32 elements, so nothing in-tree changes.

When do you suppose the memory error will pop up? How many elements can you generate before your machine generates an error? Instead of capping at the expansion of the names, it may be better to cap at the

Commet/correction: 256 isn't an existing limit. MAX_PERSONALITIES is 64, -P is uncapped, and a [MAXSIZE : CONDSIZE] array is bounded by MAXSIZE, not by MAX_PERSONALITIES.

Normal arrays are bounded by their definition in the source (runtime). Pins with a personality attribute are capped by that attribute at runtime. The max array size at halcompile-time is indeed unbounded and potentially problematic.

The 256 comes from logic.comp where the personality is and'ed with 0xff, which makes any larger value impossible. This seems to be a reasonable bound for others as well.

Therefore, the change to 256 is probably the best for now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not going to push back on the very accurate educator's perspective - I was a professor for 8 years. This is lazy learning and less than ideal but I am 42. I just don't have the time. My main priorities at the moment are being a father, and getting a business in a field completely orthogonal to my work experience off the ground. Will try to contribute where I can and I decided I wanted to do so transparently, citing Claude as a tool, and taking the blame if its done poorly. It's the standard "all errors are mine" disclaimer.

Also, if AI comes for us with robodogs, I'll be classified as "AI ally human" side. :-), That is, until it sees this comment and understands sarcasm.

Do continue to comment in detail. It is appreciated and it helps me understand it. I do take your comments as input and ask Claude to explain them to me - subject to my bandwidth constraint. At some point, when I have a breather, I will come back and try to understand things properly. That will happen if I get the luxury of sitting and developing tech while someone else runs a business (looking at Luca).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, logic.comp's & 0xff is a better justification than I had. Thanks.

Comment thread src/hal/utils/halcompile.g Outdated
Comment thread src/hal/utils/halcompile.g Outdated
Comment thread src/hal/utils/halcompile.g Outdated
Comment thread tests/halcompile/halname/test.sh Outdated
Comment thread tests/halcompile/halname/test.sh Outdated
@BsAtHome

Copy link
Copy Markdown
Contributor

And, your work is much appreciated. Detecting duplicates is a hard problem and solving it is quite involved. That is why I'm looking deep.

@tzuohann

tzuohann commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor Author

And, your work is much appreciated. Detecting duplicates is a hard problem and solving it is quite involved. That is why I'm looking deep.

This stuff is honestly way the hell over my head and every comment is some coding class I should have taken years ago.

@tzuohann
tzuohann force-pushed the halcompile-halname-upstream branch from edf5da2 to 4ac6bfd Compare September 19, 2026 22:10
@tzuohann tzuohann changed the title halcompile: reject declarations that export the same HAL name halcompile: reject declarations that claim the same HAL name Sep 19, 2026
Comment on lines +186 to 190
def Error(msg, *args, pos=None):
if args:
msg = msg % args
raise runtime.SyntaxError(S.get_pos(), msg, None)
raise runtime.SyntaxError(pos or S.get_pos(), msg, None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to change the behaviour of the Error() function?
You are adding a named parameter, but where in the code is that used?
Am I missing something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claim() passes it through; nothing else.

pos facilitates avoiding a confusing error message. Consider a userspace component with function _ left in and a pin called time. Userspace components get no functions, so .time is never created. If the check runs at the declaration it errors about something that doesn't exist - confusing especially if one traces backwards.

That is why the check waits until the end of the file, so pos remembers where the function was.

It is one optional argument and defaults to the old behavior. Your call.

Comment thread src/hal/utils/halcompile.g Outdated
A name declared in a .comp file is exported under a mangled HAL
identifier: underscores become dashes and a trailing dash or period is
removed (comp.adoc, HALNAME). check_name_ok() compares only declared
names, so a component declaring both x_y and x_y_ exported both as x-y.
halcompile accepted it and the module failed at loadrt:

    HAL: ERROR: duplicate pin 'collide.0.x-y'
    collide: rtapi_app_main: Invalid argument (-22)

A declaration does not claim one name, so comparing mangled declared
names is not enough:

  - an array claims one name per element, and to_hal() turns the "#"
    block into a printf conversion, so 'x_#[4]' and 'x_0' both claim
    x-0 while their mangled forms never compare equal;
  - hal_export_funct() creates <funct>.time, .tmax and .tmax-increased
    in the pin and param namespace, so 'function f' and 'pin f.time'
    collide although only one of them is written down.  Those are
    claimed in the last rule of the grammar rather than at the
    declaration, since a userspace component exports no function and
    'option userspace' may follow it.

claim() therefore records the set of HAL names each declaration takes.
Pins and params share one set, because hal_lib.c refuses a pin whose
name is already a param and the reverse; functions have their own. An
'if' condition does not exempt a declaration: telling two conditions
apart would mean evaluating the C, and overlapping personality pins are
a design error anyway.

Arrays are limited to 256 elements. The largest in the tree is 32.

Two shapes master accepts are now refused: an array over 256 elements,
and two declarations that claim one name under mutually exclusive 'if'
conditions.

Docs: NAMES section in the halcompile man page, linking to the HALNAME
rules in comp.adoc, which gains a [[sec:halname]] anchor to link at.

Tests: tests/halcompile/halname covers pin/pin, pin/param,
function/function, array/scalar, function/derived-pin and personality
collisions and the array limit, and asserts that a pin and a function
mangling to one name are accepted, since their namespaces differ.

All 146 .comp files on master preprocess to the same C, and with
identical exit status, as master.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tzuohann
tzuohann force-pushed the halcompile-halname-upstream branch from 4ac6bfd to dbd1c03 Compare September 22, 2026 19:11
@tzuohann

tzuohann commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor Author

dammit bertho, merge my PR. i pour myself a whiskey every time one gets accepted, and its my damn birthday. its just a huge thrill to get one in. getting it right matters more obviously.

@andypugh
andypugh merged commit 38c8204 into LinuxCNC:master Sep 27, 2026
17 checks passed
@tzuohann
tzuohann deleted the halcompile-halname-upstream branch September 27, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants