Repository: mesonbuild/meson

Issue:
subproject() regression: cannot use subdirs any more
It was really handy to allow `/` in `subproject()` for git submodules containing several tiny projects with a common purpose but no inter-dependencies. That way, there was no need to handle options (that the user can touch, which means you have to check them manually or the build could fail because the user disabled something needed) and I could just use the part I wanted.
The fix for issue #2306 (6083eb29d0d5d81510a588dc64f5533ef58bb8e0) is quite overkill and prevents a really useful feature to me.
Could we have a trade-off here?


Discussion:
I actually agree, completely preventing `/` inside `subprojects` directories is the lazy solution to the problem of preventing a lot of edge-cases that can occur because of using `/`. As a first step, we need to list everything that can go wrong while doing that. I can think of:

1. `subproject()` on a directory inside another subproject
2. Breaks the assumption that a module is always `subprojdir/module-name`. What consequences does this have? Nothing on the Meson side, but build files may break because of this.

Anything else?
Probably a duplicate of https://github.com/mesonbuild/meson/issues/2719 - not ideal that 0.44 was released without this issue being addressed prior.
What layout do you have in your `subprojects` dir?
Not a duplicate. This one is about `subproject('project-name/subdir')` while #2719 is about `project(subproject_dir: 'something/subprojects')` (in the parent project).

I have [a project](https://github.com/sardemff7/libgwater) with several main loop integration sources. Each source has its own dependencies, they are not used in the same projects (though some are, based on enabled backends in the parent project).
@sardemff7 Ah, I didn't know you could do `subproject('project-name/subdir')` - makes sense then and clearly is a different issue.
I see that #2719 is fixed now, would it work to use the same fix for this regression too?
Hmm, I wonder how this relates to https://github.com/mesonbuild/meson/pull/2943 - @sardemff7 possibly... But the whole subprojects system seems really broken with the last release, me and others keep finding corner cases where subdirectories fail with subprojects in weird ways now.
> But the whole subprojects system seems really broken with the last release, me and others keep finding corner cases where subdirectories fail with subprojects in weird ways now.

I look at it as an opportunity to add more tests so we don't repeat the same mistakes. Changing code is the best way to uncover holes in our test coverage ;)

Also this is fixed since https://github.com/mesonbuild/meson/pull/2890.
This is not fixed at all. This issue is different from #2719 as I said already, and #2890 only fixes `subproject_dir`, not the `subproject()` call.
You can see in [current master](https://github.com/mesonbuild/meson/blob/15a1a317f4d8150dd9a1598f4f2f8bac6d092f66/mesonbuild/interpreter.py#L1726) that the code is still forbidding a `subproject()` call with a subdir.
Sorry, my bad.
Is it sufficient to allow subproject name to be of type `foo/bar` or do you need something more (specifically, `..` in any form)?
My use case is one git submodule (so one directory in `subprojects/`) containing several Meson projects in their own subdir. So the `foo/bar` solution would work.
A more "mesonific" way to set up your project would be to do roughly the following:

 - have a top level `meson.build` that recurses to each subdir
 - build each subproject if dependencies are met (or have an option or something)
 - have a `declare_dependency` for each dir, and if some target is not built, set it to a dummy not-found dependency
 - call `subproject` and extract the target you want with `get_variable`
 - check if the thing was found or not and build accordingly

You can even set the actual build targets as `build_by_default : false` so they will only get built only if someone actually uses them.
That would work, but it is far from perfect, because you cannot force a dependency then, and I need that (because packagers don’t like automagic dependencies, neither do I, as a packager and a dev). To do that, I would have to add options to the subproject, and I have that boilerplate for another project already. It requires to post-check that options were not changed by the user (because you cannot prevent the user to change subproject options, which is another subject, but makes the whole thing even more annoying).
Having the dependencies hard-checked is simpler, and using subdirs is not that uncommon. It helps organizing subprojects, keeping the tree tidy, and it’s not that hard to support in Meson.

Resolving patch:
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1735,8 +1735,16 @@ def func_subproject(self, nodes, args, kwargs):
         return self.do_subproject(dirname, kwargs)
 
     def do_subproject(self, dirname, kwargs):
-        if '/' in dirname or '\\' in dirname:
-            raise InterpreterException('Subproject name must not contain a path separator.')
+        if dirname == '':
+            raise InterpreterException('Subproject dir name must not be empty.')
+        if dirname[0] == '.':
+            raise InterpreterException('Subproject dir name must not start with a period.')
+        if '..' in dirname:
+            raise InterpreterException('Subproject name must not contain a ".." path segment.')
+        if os.path.isabs(dirname):
+            raise InterpreterException('Subproject name must not be an absolute path.')
+        if '\\' in dirname or '/' in dirname:
+            mlog.warning('Subproject name has a path separator. This may cause unexpected behaviour.')
         if dirname in self.subproject_stack:
             fullstack = self.subproject_stack + [dirname]
             incpath = ' => '.join(fullstack)


Test patch: