diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md index a0a054476..0ed731e51 100644 --- a/docs/markdown/FAQ.md +++ b/docs/markdown/FAQ.md @@ -551,4 +551,81 @@ libA = library('libA', 'fileA.cpp', link_with : []) This means that you HAVE to write your `library(...)` calls in the order that the dependencies flow. While ideas to make arbitrary orders possible exist, they were rejected because reordering the `library(...)` calls was considered the "proper" -way. See [here](https://github.com/mesonbuild/meson/issues/8178) for the discussion. \ No newline at end of file +way. See [here](https://github.com/mesonbuild/meson/issues/8178) for the discussion. + +## Why doesn't meson have user defined functions/macros? + +The tl;dr answer to this is that meson's design is focused on solving specific +problems rather than providing a general purpose language to write complex +code solutions in build files. Build systems should be quick to write and +quick to understand, functions muddle this simplicity. + +The long answer is twofold: + +First, Meson aims to provide a rich set of tools that solve specific problems +simply out of the box. This is similar to the "batteries included" mentality of +Python. By providing tools that solve common problems in the simplest way +possible *in* Meson we are solving that problem for everyone instead of forcing +everyone to solve that problem for themselves over and over again, often +badly. One example of this are Meson's dependency wrappers around various +config-tool executables (sdl-config, llvm-config, etc). In other build +systems each user of that dependency writes a wrapper and deals with the +corner cases (or doesn't, as is often the case), in Meson we handle them +internally, everyone gets fixes and the corner cases are ironed out for +*everyone*. Providing user defined functions or macros goes directly against +this design goal. + +Second, functions and macros makes the build system more difficult to reason +about. When you encounter some function call, you can refer to the reference +manual to see that function and its signature. Instead of spending +frustrating hours trying to interpret some bit of m4 or follow long include +paths to figure out what `function1` (which calls `function2`, which calls +`function3`, ad infinitum), you know what the build system is doing. Unless +you're actively developing Meson itself, it's just a tool to orchestrate +building the thing you actually care about. We want you to spend as little +time worrying about build systems as possible so you can spend more time on +*your code*. + +Many times user defined functions are used due to a lack of loops or +because loops are tedious to use in the language. Meson has both arrays/lists +and hashes/dicts natively. Compare the following pseudo code: + +```meson +func(name, sources, extra_args) + executable( + name, + sources, + c_args : extra_args + ) +endfunc + +func(exe1, ['1.c', 'common.c'], []) +func(exe2, ['2.c', 'common.c'], []) +func(exe2_a, ['2.c', 'common.c'], ['-arg']) +``` + +```meson +foreach e : [['1', '1.c', []], + ['2', '2.c', []], + ['2', '2.c', ['-arg']]] + executable( + 'exe' + e[0], + e[1], + c_args : e[2], + ) +endforeach +``` + +The loop is both less code and is much easier to reason about than the function +version is, especially if the function were to live in a separate file, as is +common in other popular build systems. + +Build system DSLs also tend to be badly thought out as generic programming +languages, Meson tries to make it easy to use external scripts or programs +for handling complex problems. While one can't always convert build logic +into a scripting language (or compiled language), when it can be done this is +often a better solution. External languages tend to be well-thought-out and +tested, generally don't regress, and users are more likely to have domain +knowledge about them. They also tend to have better tooling (such as +autocompletion, linting, testing solutions), which make them a lower +maintenance burden over time.