Bug 1259960 - Make check_prog more flexible about the list of programs it will check. r=chmanchester
authorMike Hommey <mh+mozilla@glandium.org>
Sat, 26 Mar 2016 10:11:29 +0900
changeset 314700 7c01ff2b685af859ce62233984a6b4b65cb418d9
parent 314699 58ea10aa8c8975d72b5a931d76077f74212d2746
child 314701 bd956b7718c96998ed80143b0f77a7f0a1f87281
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschmanchester
bugs1259960
milestone48.0a1
Bug 1259960 - Make check_prog more flexible about the list of programs it will check. r=chmanchester
build/moz.configure/checks.configure
python/mozbuild/mozbuild/test/configure/test_checks_configure.py
--- a/build/moz.configure/checks.configure
+++ b/build/moz.configure/checks.configure
@@ -67,16 +67,18 @@ def checking(what, callback=None):
         return wrapped
     return decorator
 
 
 # Template to check for programs in $PATH.
 # - `var` is the name of the variable that will be set with `set_config` when
 #   the program is found.
 # - `progs` is a list (or tuple) of program names that will be searched for.
+#   It can also be a reference to a @depends function that returns such a
+#   list. If the list is empty and there is no input, the check is skipped.
 # - `what` is a human readable description of what is being looked for. It
 #   defaults to the lowercase version of `var`.
 # - `input` is a string reference to an existing option or a reference to a
 #   @depends function resolving to explicit input for the program check.
 #   The default is to create an option for the environment variable `var`.
 #   This argument allows to use a different kind of option (possibly using a
 #   configure flag), or doing some pre-processing with a @depends function.
 # - `allow_missing` indicates whether not finding the program is an error.
@@ -85,16 +87,17 @@ def checking(what, callback=None):
 #   check_prog('PROG', ('a', 'b'))
 # This will look for 'a' or 'b' in $PATH, and set_config PROG to the one
 # it can find. If PROG is already set from the environment or command line,
 # use that value instead.
 @template
 @advanced
 def check_prog(var, progs, what=None, input=None, allow_missing=False):
     from mozbuild.shellutil import quote
+    from mozbuild.configure import DependsFunction
 
     if input:
         # Wrap input with type checking and normalization.
         @depends(input)
         def input(value):
             if not value:
                 return
             if isinstance(value, str):
@@ -104,33 +107,37 @@ def check_prog(var, progs, what=None, in
             configure_error('input must resolve to a tuple or a list with a '
                             'single element, or a string')
     else:
         option(env=var, nargs=1,
                help='Path to %s' % (what or 'the %s program' % var.lower()))
         input = var
     what = what or var.lower()
 
-    if not isinstance(progs, (tuple, list)):
-        configure_error('progs should be a list or tuple!')
-    progs = list(progs)
+    if not isinstance(progs, DependsFunction):
+        # Trick to make a @depends function out of an immediate value.
+        progs = depends('--help')(lambda h: progs)
 
-    @depends(input)
+    @depends_if(input, progs)
     @checking('for %s' % what, lambda x: quote(x) if x else 'not found')
-    def check(value):
-        if value:
-            progs[:] = value
-        for prog in progs:
+    def check(value, progs):
+        if progs is None:
+            progs = ()
+
+        if not isinstance(progs, (tuple, list)):
+            configure_error('progs must resolve to a list or tuple!')
+
+        for prog in value or progs:
             log.debug('%s: Trying %s', var.lower(), quote(prog))
             result = find_program(prog)
             if result:
                 return result
 
         if not allow_missing or value:
             raise FatalCheckError('Cannot find %s' % what)
 
-    @depends(check)
-    def normalized_for_config(value):
+    @depends_if(check, progs)
+    def normalized_for_config(value, progs):
         return ':' if value is None else value
 
     set_config(var, normalized_for_config)
 
     return check
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -196,22 +196,87 @@ class TestChecksConfigure(unittest.TestC
         self.assertEqual(config, {'CC': '/usr/local/bin/known-b'})
         self.assertEqual(out, 'checking for cc... /usr/local/bin/known-b\n')
 
         config, out, status = self.get_result(script, ['CC=known-b -m32'])
         self.assertEqual(status, 0)
         self.assertEqual(config, {'CC': '/usr/local/bin/known-b'})
         self.assertEqual(out, 'checking for cc... /usr/local/bin/known-b\n')
 
+    def test_check_prog_progs(self):
+        config, out, status = self.get_result(
+            'check_prog("FOO", ())')
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {})
+        self.assertEqual(out, '')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ())', ['FOO=known-a'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for foo... /usr/bin/known-a\n')
+
+        script = (
+            'option(env="TARGET", nargs=1, default="linux", help="target")\n'
+            '@depends("TARGET")\n'
+            'def compiler(value):\n'
+            '    if value:\n'
+            '        if value[0] == "linux":\n'
+            '            return ("gcc", "clang")\n'
+            '        if value[0] == "winnt":\n'
+            '            return ("cl", "clang-cl")\n'
+            'check_prog("CC", compiler)'
+        )
+        config, out, status = self.get_result(script)
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for cc... not found\n'
+                              'DEBUG: cc: Trying gcc\n'
+                              'DEBUG: cc: Trying clang\n'
+                              'ERROR: Cannot find cc\n')
+
+        config, out, status = self.get_result(script, ['TARGET=linux'])
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for cc... not found\n'
+                              'DEBUG: cc: Trying gcc\n'
+                              'DEBUG: cc: Trying clang\n'
+                              'ERROR: Cannot find cc\n')
+
+        config, out, status = self.get_result(script, ['TARGET=winnt'])
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for cc... not found\n'
+                              'DEBUG: cc: Trying cl\n'
+                              'DEBUG: cc: Trying clang-cl\n'
+                              'ERROR: Cannot find cc\n')
+
+        config, out, status = self.get_result(script, ['TARGET=none'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {})
+        self.assertEqual(out, '')
+
+        config, out, status = self.get_result(script, ['TARGET=winnt',
+                                                       'CC=known-a'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'CC': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for cc... /usr/bin/known-a\n')
+
+        config, out, status = self.get_result(script, ['TARGET=none',
+                                                       'CC=known-a'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'CC': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for cc... /usr/bin/known-a\n')
+
     def test_check_prog_configure_error(self):
         with self.assertRaises(ConfigureError) as e:
             self.get_result('check_prog("FOO", "foo")')
 
         self.assertEqual(e.exception.message,
-                         'progs should be a list or tuple!')
+                         'progs must resolve to a list or tuple!')
 
         with self.assertRaises(ConfigureError) as e:
             self.get_result(
                 'foo = depends("--help")(lambda h: ("a", "b"))\n'
                 'check_prog("FOO", ("known-a",), input=foo)'
             )
 
         self.assertEqual(e.exception.message,