diff mbox series

meson: move sparse detection to Meson and rewrite check_sparse.py

Message ID 20201001155313.18364-1-pbonzini@redhat.com
State New
Headers show
Series meson: move sparse detection to Meson and rewrite check_sparse.py | expand

Commit Message

Paolo Bonzini Oct. 1, 2020, 3:53 p.m. UTC
Pass the path to the program to scripts/check_sparse.py, which
previously was not included in config-host.mak.  Change
scripts/check_sparse.py to work with cgcc, which seems to
work better with sparse 0.6.x.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 configure               | 24 +++---------------
 meson.build             | 10 +++++---
 meson_options.txt       |  2 ++
 scripts/check_sparse.py | 56 +++++++++++++++++++++++++++++++++--------
 4 files changed, 57 insertions(+), 35 deletions(-)
diff mbox series

Patch

diff --git a/configure b/configure
index 73e3b14749..02a091dafb 100755
--- a/configure
+++ b/configure
@@ -303,7 +303,7 @@  sdl_image="auto"
 virtfs=""
 mpath="auto"
 vnc="enabled"
-sparse="no"
+sparse="auto"
 vde=""
 vnc_sasl="auto"
 vnc_jpeg="auto"
@@ -1040,9 +1040,9 @@  for opt do
   ;;
   --disable-tsan) tsan="no"
   ;;
-  --enable-sparse) sparse="yes"
+  --enable-sparse) sparse="enabled"
   ;;
-  --disable-sparse) sparse="no"
+  --disable-sparse) sparse="disabled"
   ;;
   --disable-strip) strip_opt="no"
   ;;
@@ -2875,19 +2875,6 @@  if test "$gettext" != "false" ; then
   fi
 fi
 
-##########################################
-# Sparse probe
-if test "$sparse" != "no" ; then
-  if has sparse; then
-    sparse=yes
-  else
-    if test "$sparse" = "yes" ; then
-      feature_not_found "sparse" "Install sparse binary"
-    fi
-    sparse=no
-  fi
-fi
-
 ##########################################
 # X11 probe
 if $pkg_config --exists "x11"; then
@@ -7127,9 +7114,6 @@  echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
 echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
 echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
 echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
-if test "$sparse" = "yes" ; then
-  echo "SPARSE_CFLAGS = -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
-fi
 echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
 echo "LDFLAGS_NOPIE=$LDFLAGS_NOPIE" >> $config_host_mak
 echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak
@@ -7383,7 +7367,7 @@  NINJA=${ninja:-$PWD/ninjatool} $meson setup \
         -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \
         -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \
         -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \
-	-Dmalloc=$malloc -Dmalloc_trim=$malloc_trim \
+	-Dmalloc=$malloc -Dmalloc_trim=$malloc_trim -Dsparse=$sparse \
 	-Dkvm=$kvm -Dhax=$hax -Dwhpx=$whpx -Dhvf=$hvf \
 	-Dxen=$xen -Dxen_pci_passthrough=$xen_pci_passthrough -Dtcg=$tcg \
 	-Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \
diff --git a/meson.build b/meson.build
index baaeab459d..40af93fa53 100644
--- a/meson.build
+++ b/meson.build
@@ -102,11 +102,13 @@  if host_machine.system() == 'darwin'
   add_languages('objc', required: false, native: false)
 endif
 
-if 'SPARSE_CFLAGS' in config_host
+sparse = find_program('cgcc', required: get_option('sparse'))
+if sparse.found()
   run_target('sparse',
              command: [find_program('scripts/check_sparse.py'),
-                       config_host['SPARSE_CFLAGS'].split(),
-                       'compile_commands.json'])
+                       'compile_commands.json', sparse.full_path(), '-Wbitwise',
+                       '-Wno-transparent-union', '-Wno-old-initializer',
+                       '-Wno-non-pointer-null'])
 endif
 
 ###########################################
@@ -1556,7 +1558,7 @@  summary_info += {'host CPU':          cpu}
 summary_info += {'host endianness':   build_machine.endian()}
 summary_info += {'target list':       ' '.join(target_dirs)}
 summary_info += {'gprof enabled':     config_host.has_key('CONFIG_GPROF')}
-summary_info += {'sparse enabled':    meson.get_compiler('c').cmd_array().contains('cgcc')}
+summary_info += {'sparse enabled':    sparse.found()}
 summary_info += {'strip binaries':    get_option('strip')}
 summary_info += {'profiler':          config_host.has_key('CONFIG_PROFILER')}
 summary_info += {'static build':      config_host.has_key('CONFIG_STATIC')}
diff --git a/meson_options.txt b/meson_options.txt
index 05adc7a179..bc5c674642 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -5,6 +5,8 @@  option('docdir', type : 'string', value : 'doc',
 
 option('gettext', type : 'boolean', value : true,
        description: 'Localization of the GTK+ user interface')
+option('sparse', type : 'feature', value : 'auto',
+       description: 'sparse checker')
 
 option('malloc_trim', type : 'feature', value : 'auto',
        description: 'enable libc malloc_trim() for memory optimization')
diff --git a/scripts/check_sparse.py b/scripts/check_sparse.py
index 0de7aa55d9..2956124442 100644
--- a/scripts/check_sparse.py
+++ b/scripts/check_sparse.py
@@ -1,25 +1,59 @@ 
 #! /usr/bin/env python3
 
-# Invoke sparse based on the contents of compile_commands.json
+# Invoke sparse based on the contents of compile_commands.json,
+# also working around several deficiencies in cgcc's command line
+# parsing
 
 import json
 import subprocess
+import os
 import sys
 import shlex
 
-def extract_cflags(shcmd):
-    cflags = shlex.split(shcmd)
-    return [x for x in cflags
-            if x.startswith('-D') or x.startswith('-I') or x.startswith('-W')
-               or x.startswith('-std=')]
+def cmdline_for_sparse(sparse, cmdline):
+    # Do not include the C compiler executable
+    skip = True
+    arg = False
+    out = sparse + ['-no-compile']
+    for x in cmdline:
+        if arg:
+            out.append(x)
+            arg = False
+            continue
+        if skip:
+            skip = False
+            continue
+        # prevent sparse from treating output files as inputs
+        if x == '-MF' or x == '-MQ' or x == '-o':
+            skip = True
+            continue
+        # cgcc ignores -no-compile if it sees -M or -MM?
+        if x.startswith('-M'):
+            continue
+        # sparse does not understand these!
+        if x == '-iquote' or x == '-isystem':
+            x = '-I'
+        if x == '-I':
+            arg = True
+        out.append(x)
+    return out
 
-cflags = sys.argv[1:-1]
-with open(sys.argv[-1], 'r') as fd:
+root_path = os.getenv('MESON_BUILD_ROOT')
+def build_path(s):
+    return s if not root_path else os.path.join(root_path, s)
+
+ccjson_path = build_path(sys.argv[1])
+with open(ccjson_path, 'r') as fd:
     compile_commands = json.load(fd)
 
+sparse = sys.argv[2:]
+sparse_env = os.environ.copy()
 for cmd in compile_commands:
-    cmd = ['sparse'] + cflags + extract_cflags(cmd['command']) + [cmd['file']]
-    print(' '.join((shlex.quote(x) for x in cmd)))
-    r = subprocess.run(cmd)
+    cmdline = shlex.split(cmd['command'])
+    cmd = cmdline_for_sparse(sparse, cmdline)
+    print('REAL_CC=%s' % shlex.quote(cmdline[0]),
+          ' '.join((shlex.quote(x) for x in cmd)))
+    sparse_env['REAL_CC'] = cmdline[0]
+    r = subprocess.run(cmd, env=sparse_env, cwd=root_path)
     if r.returncode != 0:
         sys.exit(r.returncode)