An example: the main software I work on, along with a few other software I know, has to generate a SDK as part of its build so that people can build plug-ins for it. How often do you have to do this in java or JS ? almost never. But this requirement implies having a build system powerful enough to do that.
Another example: another software I work on must produce a Max/MSP package ; this implies:
- working with multiple versions of the Max SDK which changed their structure on disk
- setting different build options such as file naming depending on the target architecture: .dll on win32, .dll64 on win64
- generating a relatively complex tree structure which combines a Windows and a macOS build together because people don't want the hassle of having two different download options
- generating some stub C file that will declare a function to be exported
- generating some .json file with various build information, build date, etc
- generating a symbols.txt file which contains all the symbols that are known to be explicitly exported to minimize binary size ; the build system has to: list the symbols (one per plug-in we build), write them to a symbols.txt file, pass that file to Apple's dyld like this:
set_property(TARGET ossia-max APPEND PROPERTY
LINK_FLAGS
"-s -exported_symbols_list '${CMAKE_CURRENT_BINARY_DIR}/symbols.txt'"
)
etc etc.these are the requirements we have. can you solve these requirements with just Java's XML ?
Yes, actually. They don’t come up very often, but maven in particular has the ability to do everything you’ve mentioned. Most of them built right into the standard plugin set, like setting various compiler options, adding build information, or even platform specific build shenanigans (usually when dealing with javafx).
Maven also has a rarely used escape hatch plugin (ant run) which allows you to run custom scripts if you really need to.
The canonical way to do such a thing is through the java annotation processing api [1] and using a tool like java poet [2]. Before you did that, you'd probably decide if you wanted to instead use bytecode generation with a library like bytebuddy [3]
But, assuming for some reason, you wanted to torture yourself and actually consume a java.in file and apply a regex, then you'd probably pull out the "maven-replacer-plugin" [4] and configure that for the task at hand. (or use your favorite templating language plugin. There's a million of them).
Though, to be fair, this really isn't something that comes up in regular java programming due to the nature of the ecosystem. Anything you'd want to codegen likely already has a library and anything you didn't would receive (legitimate) push back.
> And could you really say that this would be cleaner than the same thing done with cmake?
Probably not. But not really the main point. cmake becomes a problem when you want to do anything more complex than string replacement. Imagine, for example, if you did want to use a code generation library within a project. The strength of maven is a new team dev only needs maven. Further, if they need to update that library they only need to change that maven file.
What happens with cmake if you wanted to update a minimum dependency?
[1] https://www.baeldung.com/java-annotation-processing-builder
Rust tries to avoid that by hard-coding availability into the libraries themselves, but the result is less reliable. For example I cannot use `libc::mkostemp` on macOS because Rust has (incorrectly) hard-coded that it is not available on that platform.
CMake is able to detect it, but we pay a cost in build system complexity. I wish instead this detection could be done at runtime.
But that was too boring, so people turned to gradle and we're back at ad-hoc scripting in a bizarre Turing-complete language. Believe me, I've hated maven with a passion (and still do) but this episode taught me build systems are nothing but a zero-sum game and typical junior-grade pastime.
Update: the story with Node.js is a bit different, but package.json was soon augmented by package-lock.json and yarn at about the same time Webpack and similar became kitchen sinks requiring config-generator tools such as create-react-app. The morale is, the grass is always greener on the other side I guess. Though tbh, cmake always was absolute garbage making autotools look sane in comparison. Now I hear there's legacy/unmaintained and new cmake syntax; what were people thinking?
Just because it accepts XML doesn't mean your build system is meaningfully declarative.
Never needed 18 programming languages to build. I actually don't think CMake is harder than Gradle or SwiftPM. Most people I see complaining about CMake actually write bad CMakeLists, so the way I see it is that they don't want to learn the basics. And that's maybe why e.g. gradle works better: for many projects, the IDE is probably able to automatically handle an imperfect and not-so-readable gradle configuration, so people don't need to learn gradle.
But the result is the same: they don't really master their build tool.
But your C++ project never needed 18 languages.
If you feel it does, you need to take a step back and take a serious look at the mess you're making because you're making at least 17 mistakes.
Tell me, what exactly does your build need that is not met with the following:
project(foo LANGUAGES CXX)
add_executable(foo_exec ${SOURCE_FILES} )
target_link_libraries(foo_exec ${MY_TARGETS} )
But there is a philosophical question here: I think that developers should master their basic tools to the point where they don't make a mess writing a CMakeLists.txt or a build.gradle.
It feels like many devs think that a tool is too complex if you need to learn it.