Repository: mesonbuild/meson

Issue:
invalid compiler args for glbinding (cmake) dependency are set
**Describe the bug**
Meson generates invalid compiler args (a `'>'`) when configuring a project using glbinding as a cmake dependency. (it also adds `-std=c++11` as a compiler arg changing the c++ standard in use)
This causes g++ to fail:
```
ninja: Entering directory `/tmp/test/builddir'
[1/2] Compiling C++ object example.p/test.cpp.o
FAILED: example.p/test.cpp.o 
sccache c++ -Iexample.p -I. -I.. -I/usr/include -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++14 -O0 -g -DSYSTEM_LINUX -pthread -std=c++11 '>' -MD -MQ example.p/test.cpp.o -MF example.p/test.cpp.o.d -o example.p/test.cpp.o -c ../test.cpp
c++: warning: >: linker input file unused because linking not done
c++: error: >: linker input file not found: No such file or directory
ninja: build stopped: subcommand failed.
```

After doing a quick `git bisect` this issue seems to be introduced in 99aae9b4dfc7f1ab6469adee718d54d9afd45097.
Somehow this line in the glbinding cmake file (`/usr/share/glbinding/cmake/glbinding/glbinding-export.cmake`) is parsed wrong?
```cmake
  INTERFACE_COMPILE_OPTIONS "\$<\$<PLATFORM_ID:Darwin>:;-pthread;>;\$<\$<VERSION_LESS:3.14.4,3.1>:;-std=c++11;>"
```

**To Reproduce**
meson.build:
```meson
project('example', 'cpp',
  version : '0.1',
  default_options : ['warning_level=3', 'cpp_std=c++14'])

executable('example',
           'test.cpp',
           dependencies : [
              dependency('glbinding')],
           install : true)
```
test.cpp:
```c++
int main() { }
```

**Expected behavior**
The glbinding cmake file is parsed correctly

**system parameters**
* Is this a [cross build](https://mesonbuild.com/Cross-compilation.html) or just a plain native build (for the same computer)?
native build
* what operating system (e.g. MacOS Catalina, Windows 10, CentOS 8.0, Ubuntu 18.04, etc.)
Arch Linux
* what Python version are you using e.g. 3.8.0
Python 3.10.4
* what `meson --version`
0.62.0
* what `ninja --version` if it's a Ninja build
1.10.2

invalid compiler args for glbinding (cmake) dependency are set
**Describe the bug**
Meson generates invalid compiler args (a `'>'`) when configuring a project using glbinding as a cmake dependency. (it also adds `-std=c++11` as a compiler arg changing the c++ standard in use)
This causes g++ to fail:
```
ninja: Entering directory `/tmp/test/builddir'
[1/2] Compiling C++ object example.p/test.cpp.o
FAILED: example.p/test.cpp.o 
sccache c++ -Iexample.p -I. -I.. -I/usr/include -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++14 -O0 -g -DSYSTEM_LINUX -pthread -std=c++11 '>' -MD -MQ example.p/test.cpp.o -MF example.p/test.cpp.o.d -o example.p/test.cpp.o -c ../test.cpp
c++: warning: >: linker input file unused because linking not done
c++: error: >: linker input file not found: No such file or directory
ninja: build stopped: subcommand failed.
```

After doing a quick `git bisect` this issue seems to be introduced in 99aae9b4dfc7f1ab6469adee718d54d9afd45097.
Somehow this line in the glbinding cmake file (`/usr/share/glbinding/cmake/glbinding/glbinding-export.cmake`) is parsed wrong?
```cmake
  INTERFACE_COMPILE_OPTIONS "\$<\$<PLATFORM_ID:Darwin>:;-pthread;>;\$<\$<VERSION_LESS:3.14.4,3.1>:;-std=c++11;>"
```

**To Reproduce**
meson.build:
```meson
project('example', 'cpp',
  version : '0.1',
  default_options : ['warning_level=3', 'cpp_std=c++14'])

executable('example',
           'test.cpp',
           dependencies : [
              dependency('glbinding')],
           install : true)
```
test.cpp:
```c++
int main() { }
```

**Expected behavior**
The glbinding cmake file is parsed correctly

**system parameters**
* Is this a [cross build](https://mesonbuild.com/Cross-compilation.html) or just a plain native build (for the same computer)?
native build
* what operating system (e.g. MacOS Catalina, Windows 10, CentOS 8.0, Ubuntu 18.04, etc.)
Arch Linux
* what Python version are you using e.g. 3.8.0
Python 3.10.4
* what `meson --version`
0.62.0
* what `ninja --version` if it's a Ninja build
1.10.2



Discussion:
> Meson generates invalid compiler args (a `'>'`) when configuring a project using glbinding as a cmake dependency.

cmake generator expressions are madness. :(

> it also adds `-std=c++11` as a compiler arg changing the c++ standard in use

Unfortunately this seems to be the fault of the cmake definition...
`-std=c++11` isn't set as a compile arg before commit 99aae9b4dfc7f1ab6469adee718d54d9afd45097.
is setting `-std=c++11` the correct behavior for this cmake definition?

> Meson generates invalid compiler args (a `'>'`) when configuring a project using glbinding as a cmake dependency.

cmake generator expressions are madness. :(

> it also adds `-std=c++11` as a compiler arg changing the c++ standard in use

Unfortunately this seems to be the fault of the cmake definition...
`-std=c++11` isn't set as a compile arg before commit 99aae9b4dfc7f1ab6469adee718d54d9afd45097.
is setting `-std=c++11` the correct behavior for this cmake definition?


Resolving patch:
diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py
--- a/mesonbuild/cmake/traceparser.py
+++ b/mesonbuild/cmake/traceparser.py
@@ -89,6 +89,7 @@ class CMakeGeneratorTarget(CMakeTarget):
     def __init__(self, name: str) -> None:
         super().__init__(name, 'CUSTOM', {})
         self.outputs = []        # type: T.List[Path]
+        self._outputs_str = []   # type: T.List[str]
         self.command = []        # type: T.List[T.List[str]]
         self.working_dir = None  # type: T.Optional[Path]
 
@@ -202,8 +203,8 @@ def parse(self, trace: T.Optional[str] = None) -> None:
                 fn(l)
 
         # Evaluate generator expressions
-        strlist_gen:  T.Callable[[T.List[str]],  T.List[str]]  = lambda strlist: [parse_generator_expressions(x, self) for x in strlist]
-        pathlist_gen: T.Callable[[T.List[Path]], T.List[Path]] = lambda plist:   [Path(parse_generator_expressions(str(x), self)) for x in plist]
+        strlist_gen:  T.Callable[[T.List[str]], T.List[str]]  = lambda strlist: parse_generator_expressions(';'.join(strlist), self).split(';') if strlist else []
+        pathlist_gen: T.Callable[[T.List[str]], T.List[Path]] = lambda strlist: [Path(x) for x in parse_generator_expressions(';'.join(strlist), self).split(';')] if strlist else []
 
         self.vars = {k: strlist_gen(v) for k, v in self.vars.items()}
         self.vars_by_file = {
@@ -220,7 +221,7 @@ def parse(self, trace: T.Optional[str] = None) -> None:
         }
 
         for tgt in self.targets.values():
-            tgtlist_gen: T.Callable[[T.List[str], CMakeTarget],  T.List[str]] = lambda strlist, t: [parse_generator_expressions(x, self, context_tgt=t) for x in strlist]
+            tgtlist_gen: T.Callable[[T.List[str], CMakeTarget], T.List[str]] = lambda strlist, t: parse_generator_expressions(';'.join(strlist), self, context_tgt=t).split(';') if strlist else []
             tgt.name = parse_generator_expressions(tgt.name, self, context_tgt=tgt)
             tgt.type = parse_generator_expressions(tgt.type, self, context_tgt=tgt)
             tgt.properties = {
@@ -229,7 +230,7 @@ def parse(self, trace: T.Optional[str] = None) -> None:
             tgt.depends = tgtlist_gen(tgt.depends, tgt)
 
         for ctgt in self.custom_targets:
-            ctgt.outputs = pathlist_gen(ctgt.outputs)
+            ctgt.outputs = pathlist_gen(ctgt._outputs_str)
             ctgt.command = [strlist_gen(x) for x in ctgt.command]
             ctgt.working_dir = Path(parse_generator_expressions(str(ctgt.working_dir), self)) if ctgt.working_dir is not None else None
 
@@ -416,7 +417,7 @@ def _cmake_add_custom_command(self, tline: CMakeTraceLine, name: T.Optional[str]
         target = CMakeGeneratorTarget(name)
 
         def handle_output(key: str, target: CMakeGeneratorTarget) -> None:
-            target.outputs += [Path(key)]
+            target._outputs_str += [key]
 
         def handle_command(key: str, target: CMakeGeneratorTarget) -> None:
             if key == 'ARGS':
@@ -462,7 +463,7 @@ def handle_working_dir(key: str, target: CMakeGeneratorTarget) -> None:
         target.working_dir     = Path(working_dir) if working_dir else None
         target.current_bin_dir = Path(cbinary_dir) if cbinary_dir else None
         target.current_src_dir = Path(csource_dir) if csource_dir else None
-        target.outputs = [Path(x) for x in self._guess_files([str(y) for y in target.outputs])]
+        target._outputs_str = self._guess_files(target._outputs_str)
         target.depends = self._guess_files(target.depends)
         target.command = [self._guess_files(x) for x in target.command]
 


Test patch:
diff --git a/test cases/linuxlike/13 cmake dependency/cmake/FindImportedTarget.cmake b/test cases/linuxlike/13 cmake dependency/cmake/FindImportedTarget.cmake
--- a/test cases/linuxlike/13 cmake dependency/cmake/FindImportedTarget.cmake	
+++ b/test cases/linuxlike/13 cmake dependency/cmake/FindImportedTarget.cmake	
@@ -6,7 +6,7 @@ if(ZLIB_FOUND OR ZLIB_Found)
   set_property(TARGET mesonTestLibDefs PROPERTY IMPORTED_LOCATION ${ZLIB_LIBRARY})
   set_property(TARGET mesonTestLibDefs PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIR})
   set_property(TARGET mesonTestLibDefs APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS REQUIRED_MESON_FLAG1)
-  set_property(TARGET mesonTestLibDefs APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>) # Error empty string
+  set_property(TARGET mesonTestLibDefs APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:;QT_NO_DEBUG;>) # Error empty string
   set_property(TARGET mesonTestLibDefs APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS REQUIRED_MESON_FLAG2)
   set_target_properties(mesonTestLibDefs PROPERTIES IMPORTED_GLOBAL TRUE)
   add_library(MesonTest::TestLibDefs ALIAS mesonTestLibDefs)