One thing that annoys me about CMake is that there is a bunch of functionality in odd places. For example, list TRANSFORM only works for some string functions, or more recently with predicates as well. But the subset of string functions seems arbitrary.
I know there has been exploration of creating a descriptive language for CMake, like other build systems have (e.g. Visual Studio projects).
But has there been any exploration effort to take the sort of approach CPP2 takes to C++? Exploring breaking-changes for the sake of seeing what can be gotten away with to preserve compatibility, whilst considering getting rid of some legacy obstacles that might make a lot of other odd-tricks irrelevant. Not introducing more hacks to patch over old problems. Even if it is not CMake itself.
Some legacy annoyances I would have in mind:
Changing the functionality of the function if() (and related) to get rid of all the variable/expanded variable stuff. Consistent results without having to read through the documentation for each case.
More consistent use of predicates, and make them a more primary feature of the language (along with other special characters/character combinations, that are not interpreted as literal strings, such as ${}, $<>, $ABC:abc, [[…]]/[=…[…]=…]). Right now predicates are a bit cumbersome. You have to name each function, as CMake has no anonymous functions.
If there were anonymous functions, a lot of functions (string, list, cmake_path, file) could be simplified a lot?
Perhaps supporting some additional types, as others have asked for. Some perhaps straightforward ones would be tuples or dictionaries. As they currently already sort-of exist, such as CPACK_PACKAGE_EXECUTABLES being required to be a list of pairs.
There probably has been exploration of these sorts of features I expect. Something like generics would also be valuable I think. Function names is one place where CMake is very tolerant, but this functionality is actually never used in practice.
Just throwing ideas here. Maybe generic function syntax could be:
case() having a () would also allow for specifying comparison parameters such as STR_EQUAL to a case? Or as a second parameter in switch?
Would the nested switch and case be an example of an anonymous function? As case is an unnamed conditionally-executed scope within the switch scope.
I suppose even endswitch could be made a generic end:switch. Though maybe that is over-engineering something that would only confuse without providing any benefit.
Maybe an alternative anonymous function syntax would be:
function(my_function func)
#...
endfunction()
my_function($(a b c:message('something...'))) # : sort of like for generator expressions
my_function($(=( # No :, as no parameters in signature? Could still use ARGV?
#... Some multi-line function
)=)) # For a nested anonymous function, use equal signs maybe? The same as for [[]], so (=()=).
Another idea, introducing namespaces to functions? Something like cmake::set. Perhaps also a push_using(cmake) function (similar to cmake_push_check_state) for navigating symbol namespaces (not affecting target namespaces).
Not sure if there really is a functional impact of the : generic syntax. As it seems to be solely a special required parameter syntax reading left-to-right, nothing else.
Perhaps a benefit of a generic parameter could be that it won’t create an actual variable. Meaning that switch(type) above would not work. But if there is an operator, for example $:, for getting the value of a generic parameter inside of a scope that relies on variable nesting. Then switch($:type) would work. type won’t be visible in the inherited scope.