Repository: mesonbuild/meson

Issue:
[Bug] meson failed to compile with ubuntu 18.04 on launchpad build
**Describe the bug**

I was trying to build meson with ubuntu 18.04 on launchpad . But it is continuously failing to  build. Always test error. For more details see the [launchpad build log](https://launchpad.net/~pipewire-debian/+archive/ubuntu/bionic-qt5125/+build/22357414/+files/buildlog_ubuntu-bionic-amd64.meson_0.60.0.r15.gc9e6afc-1~ubuntu18.04_BUILDING.txt.gz)

I'd tried to build from release and from the latest branch 0.60 both are failing. I can successfully build the same with ubuntu >= 20.04


**Expected behavior**

Test is failing. I think you can understand seeing the above mentioned launchpad build log properly.

**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.) ubuntu 18.04
* what Python version are you using e.g. 3.6.9
* what `meson --version` 0.58
* what `ninja --version` if it's a Ninja build 1.10.2



Discussion:
> Test is failing. I think you can understand seeing the above mentioned launchpad build log properly.

Can you not assume that and just report the part of that log that is failing? There are 85k lines there and I can't even grep for the word "failed" because that appears over a hundred times and none of the succeeding tests are collapsing/hiding their logs.


Sorry for that.  [This log](https://launchpadlibrarian.net/566488331/buildlog_ubuntu-bionic-amd64.meson_0.60.0.r15.gc9e6afc-6~ubuntu18.04_BUILDING.txt.gz) is more cleaner and shorter version of build log. I think you can understand. There are lots of error. I don't understand which one should i mention Can you please try to reproduce the same for ubuntu 18.04 ?. You can also see the [launchpad ubuntu daily build of meson](https://launchpad.net/~ubuntu-support-team/+archive/ubuntu/meson/+packages) also can't build and so that they didn't published.
I don't use operating systems that are produced by the company known as Canonical. However, meson's own CI runners test every commit on Ubuntu Bionic, Ubuntu Latest, Fedora, openSUSE, and Arch Linux. The tests pass. So your test failures are more specific than just "can you try to run the tests on Ubuntu 18.04 and see if they fail" -- maybe a question of the tools you have installed, maybe a question of your unique environment, I don't know.

I will try to look at your log later today. But really, it would be very helpful if you followed standard bug reporting procedures and distilled relevant details, then posted relevant excerpts, directly to the ticket you are reporting -- this both ensures that transient attachments from third-party hosting don't disappear from the record, and allows the project maintainers to get a much more focused look at what your problem is.
> I don't use operating systems that are produced by the company known as Canonical

me too. :wink:  using arch personally. making packages for ubuntu thats another story and out of context. In short you know ubuntu family are very slow in updating packages and thats why I am trying to fill the gap since last april. My only focus on "PipeWire for ubuntu" thats it.

At the time of reporting there  few depencies were missing and providing them still its failed actually I take the official recipie from [daily build of meson on launchpad](https://launchpad.net/~ubuntu-support-team/+archive/ubuntu/meson/+packages) and was trying to build on ubuntu 18.04. So if CI is not failing then I should look at [bionic CI](https://github.com/mesonbuild/meson/blob/master/ci/ciimage/bionic/install.sh) this may fix the problem. OKK I will report you back  if thing goes well. 

Still sorry for everything and Its my utmost respect to devs to build this all. Thank you.

 Edit : If you are talking about env its not very flexible. You can't use internet there. Thats why you can't use PIP, You can use only official builds or the launchpad ppa builds. So if PIP install the latest python package, you can't install there If that particular package version not available same as the pip.
Alright, thanks. The new build log (only 8k lines) is a lot clearer. The relevant bits look like this:

```
/usr/bin/python3 /<<PKGBUILDDIR>>/meson.py --internal coverage '/<<PKGBUILDDIR>>/test cases/common/105 generatorcustom' '/<<PKGBUILDDIR>>/test cases/common/105 generatorcustom/subprojects' /<<PKGBUILDDIR>>/tmpomhzrkbl /<<PKGBUILDDIR>>/tmpomhzrkbl/meson-logs
LLVM (http://llvm.org/):
  LLVM version 6.0.0
  
  Optimized build.
  Default target: x86_64-pc-linux-gnu
  Host CPU: bdver1
lcov: LCOV version 1.13
genhtml: LCOV version 1.13
Usage: gcovr [options]

gcovr: error: no such option: --sonarqube
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/meson.py", line 29, in <module>
    sys.exit(mesonmain.main())
  File "/<<PKGBUILDDIR>>/mesonbuild/mesonmain.py", line 235, in main
    return run(sys.argv[1:], launcher)
  File "/<<PKGBUILDDIR>>/mesonbuild/mesonmain.py", line 224, in run
    return run_script_command(args[1], args[2:])
  File "/<<PKGBUILDDIR>>/mesonbuild/mesonmain.py", line 172, in run_script_command
    return module.run(script_args)
  File "/<<PKGBUILDDIR>>/mesonbuild/scripts/coverage.py", line 184, in run
    options.log_dir, options.use_llvm_cov)
  File "/<<PKGBUILDDIR>>/mesonbuild/scripts/coverage.py", line 55, in coverage
    ] + gcov_exe_args)
  File "/usr/lib/python3.6/subprocess.py", line 311, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['gcovr', '-r', '/<<PKGBUILDDIR>>/tmpomhzrkbl', '--sonarqube', '-o', '/<<PKGBUILDDIR>>/tmpomhzrkbl/meson-logs/sonarqube.xml', '-e', '\\/build\\/meson\\-isi7wc\\/meson\\-0\\.60\\.0\\.r15\\.gc9e6afc\\/test\\ cases\\/common\\/105\\ generatorcustom\\/subprojects']' returned non-zero exit status 2.
ninja: build stopped: subcommand failed.
```

The version of `gcovr` installed in this build VM does not support --sonarqube, added in https://github.com/gcovr/gcovr/commit/702aa38edb52d7f03d1063db3b0de003af741e83 back in mid-2019 in gcovr 4.2 and added to meson 0.60 in commit 2e30b5a1e2ca21555bb3aa50f91e87f4d2821bb6.

The funny thing is that the tool claims it will only attempt to generate coverage reports for output formats which your gcovr version supports. However, this is FALSE. It unconditionally adds all of them, and the only version check is to find out whether it needs syntax changes to point to the builddir.

That's definitely a bug, albeit one which could be solved by upgrading gcovr.

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -559,8 +559,14 @@ def generate(self):
             key = OptionKey('b_coverage')
             if (key in self.environment.coredata.options and
                     self.environment.coredata.options[key].value):
-                self.add_build_comment(NinjaComment('Coverage rules'))
-                self.generate_coverage_rules()
+                gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, _ = environment.find_coverage_tools()
+                if gcovr_exe or (lcov_exe and genhtml_exe):
+                    self.add_build_comment(NinjaComment('Coverage rules'))
+                    self.generate_coverage_rules(gcovr_exe, gcovr_version)
+                else:
+                    # FIXME: since we explicitly opted in, should this be an error?
+                    # The docs just say these targets will be created "if possible".
+                    mlog.warning('Need gcovr or lcov/genhtml to generate any coverage reports')
             self.add_build_comment(NinjaComment('Suffix'))
             self.generate_utils()
             self.generate_ending()
@@ -1070,37 +1076,16 @@ def generate_coverage_command(self, elem, outputs):
                        self.environment.get_log_dir()] +
                       (['--use_llvm_cov'] if use_llvm_cov else []))
 
-    def generate_coverage_rules(self):
+    def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]):
         e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY')
         self.generate_coverage_command(e, [])
         e.add_item('description', 'Generates coverage reports')
         self.add_build(e)
         # Alias that runs the target defined above
         self.create_target_alias('meson-coverage')
-        self.generate_coverage_legacy_rules()
-
-    def generate_coverage_legacy_rules(self):
-        e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY')
-        self.generate_coverage_command(e, ['--xml'])
-        e.add_item('description', 'Generates XML coverage report')
-        self.add_build(e)
-        # Alias that runs the target defined above
-        self.create_target_alias('meson-coverage-xml')
-
-        e = NinjaBuildElement(self.all_outputs, 'meson-coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY')
-        self.generate_coverage_command(e, ['--sonarqube'])
-        e.add_item('description', 'Generates Sonarqube XML coverage report')
-        self.add_build(e)
-        # Alias that runs the target defined above
-        self.create_target_alias('meson-coverage-sonarqube')
-
-        e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY')
-        self.generate_coverage_command(e, ['--text'])
-        e.add_item('description', 'Generates text coverage report')
-        self.add_build(e)
-        # Alias that runs the target defined above
-        self.create_target_alias('meson-coverage-text')
+        self.generate_coverage_legacy_rules(gcovr_exe, gcovr_version)
 
+    def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]):
         e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY')
         self.generate_coverage_command(e, ['--html'])
         e.add_item('description', 'Generates HTML coverage report')
@@ -1108,6 +1093,29 @@ def generate_coverage_legacy_rules(self):
         # Alias that runs the target defined above
         self.create_target_alias('meson-coverage-html')
 
+        if gcovr_exe:
+            e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY')
+            self.generate_coverage_command(e, ['--xml'])
+            e.add_item('description', 'Generates XML coverage report')
+            self.add_build(e)
+            # Alias that runs the target defined above
+            self.create_target_alias('meson-coverage-xml')
+
+            e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY')
+            self.generate_coverage_command(e, ['--text'])
+            e.add_item('description', 'Generates text coverage report')
+            self.add_build(e)
+            # Alias that runs the target defined above
+            self.create_target_alias('meson-coverage-text')
+
+            if mesonlib.version_compare(gcovr_version, '>=4.2'):
+                e = NinjaBuildElement(self.all_outputs, 'meson-coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY')
+                self.generate_coverage_command(e, ['--sonarqube'])
+                e.add_item('description', 'Generates Sonarqube XML coverage report')
+                self.add_build(e)
+                # Alias that runs the target defined above
+                self.create_target_alias('meson-coverage-sonarqube')
+
     def generate_install(self):
         self.create_install_data_files()
         elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY')
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -84,7 +84,7 @@ def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T
     return value
 
 
-def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
+def detect_gcovr(min_version='3.3', log=False):
     gcovr_exe = 'gcovr'
     try:
         p, found = Popen_safe([gcovr_exe, '--version'])[0:2]
@@ -95,7 +95,7 @@ def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
     if p.returncode == 0 and mesonlib.version_compare(found, '>=' + min_version):
         if log:
             mlog.log('Found gcovr-{} at {}'.format(found, quote_arg(shutil.which(gcovr_exe))))
-        return gcovr_exe, mesonlib.version_compare(found, '>=' + new_rootdir_version)
+        return gcovr_exe, found
     return None, None
 
 def detect_llvm_cov():
@@ -106,7 +106,7 @@ def detect_llvm_cov():
     return None
 
 def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
-    gcovr_exe, gcovr_new_rootdir = detect_gcovr()
+    gcovr_exe, gcovr_version = detect_gcovr()
 
     llvm_cov_exe = detect_llvm_cov()
 
@@ -118,7 +118,7 @@ def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optiona
     if not mesonlib.exe_exists([genhtml_exe, '--version']):
         genhtml_exe = None
 
-    return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe
+    return gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe
 
 def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.List[str]:
     r = detect_ninja_command_and_version(version, log)
diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py
--- a/mesonbuild/scripts/coverage.py
+++ b/mesonbuild/scripts/coverage.py
@@ -21,10 +21,10 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
     outfiles = []
     exitcode = 0
 
-    (gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
+    (gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
 
     # gcovr >= 4.2 requires a different syntax for out of source builds
-    if gcovr_new_rootdir:
+    if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
         gcovr_base_cmd = [gcovr_exe, '-r', source_root, build_root]
     else:
         gcovr_base_cmd = [gcovr_exe, '-r', build_root]
@@ -35,7 +35,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
         gcov_exe_args = []
 
     if not outputs or 'xml' in outputs:
-        if gcovr_exe:
+        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
             subprocess.check_call(gcovr_base_cmd +
                                   ['-x',
                                    '-e', re.escape(subproject_root),
@@ -47,7 +47,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
             exitcode = 1
 
     if not outputs or 'sonarqube' in outputs:
-        if gcovr_exe:
+        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
             subprocess.check_call(gcovr_base_cmd +
                                   ['--sonarqube',
                                    '-o', os.path.join(log_dir, 'sonarqube.xml'),
@@ -59,7 +59,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
             exitcode = 1
 
     if not outputs or 'text' in outputs:
-        if gcovr_exe:
+        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
             subprocess.check_call(gcovr_base_cmd +
                                   ['-e', re.escape(subproject_root),
                                    '-o', os.path.join(log_dir, 'coverage.txt')
@@ -132,7 +132,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
                                    '--branch-coverage',
                                    covinfo])
             outfiles.append(('Html', pathlib.Path(htmloutdir, 'index.html')))
-        elif gcovr_exe:
+        elif gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
             htmloutdir = os.path.join(log_dir, 'coveragereport')
             if not os.path.isdir(htmloutdir):
                 os.mkdir(htmloutdir)


Test patch: