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.
Other odd rules in CMake that could be addressed, might be:
Mandating namespaces. Also to assure that things like ${CMAKE_FIND_PACKAGE_NAME} aren’t ever required “to avoid capitalization inconsistencies”.
More intuitive property organisation, using structured types. E.g. not CMAKE_CXX_SOME_PROPERTY, but something like CMAKE_CXX.SOME_PROPERTY.
Getting rid of some of the many partially-working (and inconsistently named) modules CMake provides. Perhaps in favor of merging some of them into modules that are on their way out but not yet deprecated.
I would really like to see the string-based variables of CMake persist. As a type system makes a build system really hard to use, as it creates distance between the build system, and terminals and file systems.
I don’t think there’s much interest in improving CMakeLang as a language, or the “standard library” which ships as the CMake modules.
Most improvements today are moving CMakeLang towards being entirely declarative within its interpreted environment. File sets and the ever expanding march of generator expressions are examples of this.
The long-horizon efforts are towards making CMakeLang a legacy technology, replaced entirely with declarative structures.
The growing feeling is that if you do need to do some programming, some real imperative work, as part of your project description it belongs in any tool other than the build system itself. You do the work in Python, or JS, or C++, and you hand the build system a declarative set of results from that work.
Build system developers are not language designers, and are clearly not good at it.
I disagree. Emphasis on that I disagree with “clearly not good at”. CMake, and Unix/GNU Make before it, are nice because it allows people to define their own pipelines without any restrictions that comes with bloated frameworks, regardless of what formats they have. Declarative build pipelines don’t allow for that. You may disagree, but that just means we differ on opinion about that. There is more than practicality in programming. There is joy. Programming languages are psychological support systems for developers. Without psychology factored in, just bits would suffice for all programs. With some (non formalized/arbitrary) patterns sure. CMake to me embraces that aiding a developer rather than imposing something on them. It creates a kind of community to empower developers rather than just “put them to work” with technology that makes developers feel invisible, and therefore demotivated, and in the end creating a worse environment and thus worse products. Miserable people make miserable produce.
To me CMake is quite beautiful in how it creates interfaces for many things a declarative format COULD do. But it instead gives those choices to developers. A declarative only build pipeline is to me “enshittification”, to use a term of a younger than me generation.
Using CMake is like working on a project. Using a declarative language is like reading through a thick old book that was written as part of some mindless production process with no significant attention for end users on reading it.