The name "cmake_command" is overloaded

It just occurred to me that we already have a variable called CMAKE_COMMAND, so I’m wondering if there might be any places where the new cmake_command() command being added for CMake 3.18 might cause a name clash. In particular, since commands are not case-sensitive, if there are any places where a variable name and a command name are both valid, it would seem to be a potential issue. I can’t think of any such places at the moment - the if() command comes close, but I think the existing expressions are such that we don’t (currently) hit problems there. Anyone think of other potential cases?

@brad.king @cristianadam @marc.chevrier

I pointed out the name clash at https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4286#note_694851

It was not deemed as a problem.

I don’t think there is any potential problem because there is no syntax expression where a variable and a command are both valid.
For if() none valid expression includes a command.

Note that we have to consider not just current functionality. By using the same name, we are effectively committing to never having the choice of being able to use a command or variable name in the same context in the future. I don’t have any use cases in mind, but the reach of this decision is further than just right now.

You are right but even in this situation it will be possible to distinguish variable from command by the difference in syntax: command has form <name> '(' [ args ] ')' and variable is just <name> or '${' <name> '}'.

For example, if hypothetically commands can return a value we will have:

set (item "data")
function (item)
...
return ("data")  # tentative syntax :)
endfunction()

`if (item() AND item)
  ...
endif()

Part of my point is that we don’t actually have to place this restriction on ourselves. If we can find an equally suitable name for the command, we haven’t reduced our future options. I’m mindful that this feature has been there for a little while on master now, but not in the last release. It isn’t too late to consider a different name if we wanted to (cmake_code() anyone?).

I missed the whole development and review of this feature due to other commitments, so I’m only just catching up now. I understand if people consider it too late to revisit.

I don’t think it is too late but cmake_code is a bit disappointing in the following form cmake_code(EVAL CODE ...). One can wonder why to re-specify CODE?

Just $0.02 from an ordinary user, but how about cmake_exec? exec and eval are both terms commonly used for such “dynamic code” functionality.

Just to fuel the discussion: cmake_call()? Dunno if I like it myself though.

I’d like to stick with cmake_command(). It is the clearest of the proposed names for its role. I think that is more important than the tiny risk of future conflicts with the CMAKE_COMMAND variable.

1 Like

Ok. Would the name duplication be a problem for any syntax highlighting scenarios? Maybe we should update the vim syntax highlighter as some sort of verification?

Except in arguments to invocations of cmake_command() itself, the command name is always followed by ( and the variable name is not.

CMake’s command parser and variable parsers are two completely separate things. The first is an unnecessarily complicated lax/yacc generated thing that does balanced parentheses, comment, and quote/square brackets computations to find the last parenthesis. This returns a command name and a string to split into arguments cmMakefile::ExpandVariableInString then takes the argument list and expands arguments where some other routine then picks up and splits it into actual arguments (with quoting information). This proposed syntax would need to merge these somehow which seems…unlikely. Given CMake’s wonky argument semantics, is this allowed?

function (thought_experiment)
  return (somevar STREQUAL)
endfunction ()

if (though_experiment() "a string")
  message("hmm")
else ()
  message(
    "functions can't return lists? "
    "returned lists are not expanded at their use site? "
    "what is the exception here? "
    "is this just another `if` special case? why?")
endif ()

So I think any such real-world collision has far more problems than the name collision to consider. The syntax parser would hopefully have which is which be 100% unambiguous anyways (if is a bit special here, but any other variable naming occurs within a $key{ style expansion, so that should be unambiguous. You probably lose on ${thought_experiment()}, but even that may be an acceptable future since () are invalid characters in literal variable names today anyways:

set("thought_experiment()" value)
set(varname "thought_experiment()")
set(expanded "${varname}") # expands to "value"

But explaining the difference between the above and ${though_experiment()} is going to be tricky, so probably not the best idea.

In addition if cares about the quoting used in the argument list. With list expansion, you probably can only get unquoted arguments, so there’s no way to use this mechanism to make the "a string" part of the example without looking up the a string variable.

Not quite:

if(COMMAND CMAKE_COMMAND)
if(DEFINED CMAKE_COMMAND)

My experiences with my book and the CMake syntax highlighting coming from things like pygments, rouge, code ray, etc. has taught me that highlighters sometimes try to highlight all the way into command arguments, with varying degrees of success. I am not super familiar with their parsing rules, but the above is one example for which I’m wondering how they would go. The context makes it clear what type of name is expected, but I don’t know if the highlighters are that smart.

Or another example (does this even work?):

cmake_command(INVOKE cmake_command message hello)

And that last comment of mine nicely demonstrates what I mean: the CMake highlighting of my code example has indeed reached into the command arguments and identified message as a command. Let me try another one:

cmake_command(INVOKE CMAKE_COMMAND MESSAGE hello)

When the highlighter for this forum is updated to learn about the cmake_command() command, what should it do with CMAKE_COMMAND? Treat it as a variable or as a command?

I think these are fine. The first only takes names of commands and the second only takes names of variables. Given a variable named /usr, is this also ambiguous?

if (EXISTS "/usr")
if (IS_ABSOLUTE "/usr")
if (DEFINED "/usr")

The former 2 take paths, the last is a variable name. If syntax highlighters want to try and interpret CMake argument lists as the corresponding command actually does, I wish them the best of luck.

I’d say variable is safer since ScreamMake is “over” is the better option, but it is fundamentally undecidable without the syntax highlighter knowing what cmake_command does (other than that it is a token on the left side of a top-level ( character). Highlighters for CMake are always going to be disadvantaged. I get keywords to ExternalProject_add highlighted as “keywords” no matter what function they’re used in making some functions look pretty odd if they share some keywords with other CMake APIs.

For highlighting, I’ve learned to live with the mistakes and corner cases you get, but I’m also much more familiar with EVIS than most to know that emulating CMake parsing is…hard.

cmake_command() operates on cmake commands. The name is consistent with the terminology used in the cmake-language(7) manual. I don’t think any other command name will be as clear. We should not sacrifice that clarity just because the CMAKE_COMMAND variable exists already. I don’t think it will cause confusion in practice.

I’m not concerned about syntax highlighting of raw mentions of CMAKE_COMMAND. Syntax highlighting of variables outside ${} is ad-hoc anyway.

Actually, my line of thinking here has only been in the context of cmake_command(INVOKE ...) which was originally the only signature. The cmake_command(EVAL CODE ...) signature does not operate just on cmake commands but also on arbitrary cmake language code.

How about the name cmake_lang()?

  • cmake_lang(CALL <command> <args>...)
  • cmake_lang(EVAL CODE <code>...)