From e453be82f510303e41a24c0093bd03c7f8374f75 Mon Sep 17 00:00:00 2001
From: Joerg Bornemann <joerg.bornemann@qt.io>
Date: Tue, 25 Apr 2017 12:46:36 +0200
Subject: [PATCH] Make python2 usage more robust

After configuring Qt there will be an error message if a suitable python
version could not be found.

Add python2 configure test that
  - first looks for python2 in PATH
  - then looks for python in PATH
  - checks the Python version
  - stores the result in QMAKE_PYTHON2

Use $$QMAKE_PYTHON2 everywhere where we call python.

Pass $$QMAKE_PYTHON2 to gn for its exec_script feature.

Task-number: QTBUG-60164
Change-Id: I33de1273cbd20a787b3c8889d35280784dbcd5ae
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
---
 configure.json                             | 20 +++++++++++
 configure.pri                              | 41 ++++++++++++++++++++++
 src/buildtools/gn.pro                      |  2 +-
 src/buildtools/ninja.pro                   |  2 +-
 src/core/gn_run.pro                        |  3 +-
 src/webengine/webengine.pro                |  3 +-
 tools/qmake/mkspecs/features/functions.prf | 39 ++++++++++----------
 7 files changed, 86 insertions(+), 24 deletions(-)

diff --git a/configure.json b/configure.json
index 62b56bbb1..605807a36 100644
--- a/configure.json
+++ b/configure.json
@@ -58,6 +58,11 @@
     },
 
     "tests" : {
+        "python2": {
+            "label": "Python 2",
+            "type": "detectPython2",
+            "log": "location"
+        },
         "ninja": {
             "label": "system ninja",
             "type": "detectNinja"
@@ -73,6 +78,13 @@
     },
 
     "features": {
+        "python2": {
+            "label": "Python 2",
+            "condition": "tests.python2",
+            "output": [
+                { "type": "varAssign", "name": "QMAKE_PYTHON2", "value": "tests.python2.location" }
+            ]
+        },
         "embedded": {
             "label": "Embedded build",
             "condition": "config.unix",
@@ -157,6 +169,14 @@
         }
     },
 
+    "report": [
+        {
+            "type": "warning",
+            "condition": "!features.python2",
+            "message": "Python version 2 (2.7.5 or later) is required to build QtWebEngine."
+        }
+    ],
+
     "summary": [
         {
             "section": "Qt WebEngine",
diff --git a/configure.pri b/configure.pri
index 23f31686e..ce36642bb 100644
--- a/configure.pri
+++ b/configure.pri
@@ -1,5 +1,46 @@
 equals(QMAKE_HOST.os, Windows): EXE_SUFFIX = .exe
 
+defineTest(isPythonVersionSupported) {
+    python = $$system_quote($$system_path($$1))
+    python_version = $$system('$$python -c "import sys; print(sys.version_info[0:3])"')
+    python_version ~= s/[()]//g
+    python_version = $$split(python_version, ',')
+    python_major_version = $$first(python_version)
+    greaterThan(python_major_version, 2) {
+        qtLog("Python version 3 is not supported by Chromium.")
+        return(false)
+    }
+    python_minor_version = $$member(python_version, 1)
+    python_patch_version = $$member(python_version, 2)
+    greaterThan(python_major_version, 1): greaterThan(python_minor_version, 6): greaterThan(python_patch_version, 4): return(true)
+    qtLog("Unsupported python version: $${python_major_version}.$${python_minor_version}.$${python_patch_version}.")
+    return(false)
+}
+
+defineTest(qtConfTest_detectPython2) {
+    python = $$qtConfFindInPath("python2")
+    isEmpty(python) {
+        qtLog("'python2' not found in PATH. Checking for 'python'.")
+        python = $$qtConfFindInPath("python$$EXE_SUFFIX")
+    }
+    isEmpty(python) {
+        qtLog("'python$$EXE_SUFFIX' not found in PATH. Giving up.")
+        return(false)
+    }
+    !isPythonVersionSupported($$python) {
+        qtLog("A suitable Python 2 executable could not be located.")
+        return(false)
+    }
+
+    # Make tests.python2.location available in configure.json.
+    $${1}.location = $$clean_path($$python)
+    export($${1}.location)
+    $${1}.cache += location
+    export($${1}.cache)
+
+    return(true)
+}
+
 defineTest(qtConfTest_detectNinja) {
     ninja = $$qtConfFindInPath("ninja$$EXE_SUFFIX")
     !isEmpty(ninja) {
diff --git a/src/buildtools/gn.pro b/src/buildtools/gn.pro
index 092888e0e..f8f8b20da 100644
--- a/src/buildtools/gn.pro
+++ b/src/buildtools/gn.pro
@@ -14,7 +14,7 @@ defineReplace(buildGn) {
         gn_bootstrap = $$system_path($$absolute_path(chromium/tools/gn/bootstrap/bootstrap.py, $$src_3rd_party_dir))
         gn_args = $$system_quote($$gn_args)
         gn_configure = $$system_quote($$gn_bootstrap) --shadow --gn-gen-args=$$gn_args $$ninja_path
-        !system("cd $$system_quote($$system_path($$dirname(out))) && python $$gn_configure") {
+        !system("cd $$system_quote($$system_path($$dirname(out))) && $$pythonPathForSystem() $$gn_configure") {
             error("GN build error!")
         }
     }
diff --git a/src/buildtools/ninja.pro b/src/buildtools/ninja.pro
index c391d6e84..0a01f1f4e 100644
--- a/src/buildtools/ninja.pro
+++ b/src/buildtools/ninja.pro
@@ -8,7 +8,7 @@ defineReplace(buildNinja) {
        mkpath($$dirname(out))
        src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT")
        ninja_configure =  $$system_quote($$system_path($$absolute_path(ninja/configure.py, $$src_3rd_party_dir)))
-       !system("cd $$system_quote($$system_path($$dirname(out))) && python $$ninja_configure --bootstrap") {
+       !system("cd $$system_quote($$system_path($$dirname(out))) && $$pythonPathForSystem() $$ninja_configure --bootstrap") {
             error("NINJA build error!")
        }
    }
diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro
index 07635d04c..b6966a51d 100644
--- a/src/core/gn_run.pro
+++ b/src/core/gn_run.pro
@@ -51,7 +51,8 @@ build_pass|!debug_and_release {
     gn_args = $$shell_quote($$gn_args)
     gn_src_root = $$shell_quote($$shell_path($$QTWEBENGINE_ROOT/$$getChromiumSrcDir()))
     gn_build_root = $$shell_quote($$shell_path($$OUT_PWD/$$getConfigDir()))
-    $$runGn($$gn_binary gen $$gn_build_root --args=$$gn_args --root=$$gn_src_root)
+    gn_python = "--script-executable=$$pythonPathForSystem()"
+    $$runGn($$gn_binary gen $$gn_build_root $$gn_python --args=$$gn_args --root=$$gn_src_root)
 
     runninja.commands = $$NINJA \$\(NINJAFLAGS\) -C $$gn_build_root QtWebEngineCore
     QMAKE_EXTRA_TARGETS += runninja
diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro
index 27239225b..5ac93c9a7 100644
--- a/src/webengine/webengine.pro
+++ b/src/webengine/webengine.pro
@@ -71,9 +71,10 @@ use?(pdf) {
 }
 
 !build_pass {
+    python = $$pythonPathForShell()
     chromium_attributions.commands = \
         cd $$shell_quote($$shell_path($$PWD/../3rdparty)) && \
-        python chromium/tools/licenses.py \
+        $$python chromium/tools/licenses.py \
         --file-template ../../tools/about_credits.tmpl \
         --entry-template ../../tools/about_credits_entry.tmpl credits \
         > $$shell_quote($$shell_path($$OUT_PWD/chromium_attributions.qdoc))
diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf
index ed1133037..eb421f8b5 100644
--- a/tools/qmake/mkspecs/features/functions.prf
+++ b/tools/qmake/mkspecs/features/functions.prf
@@ -86,7 +86,6 @@ defineTest(isPlatformSupported) {
     skipBuild("Static builds of QtWebEngine aren't supported.")
     return(false)
   }
-  !isPythonVersionSupported(): return(false)
   !isArchSupported(): return(false)
   isSanitizerEnabled():!isSanitizerSupported():!forceSanitizerBuild(): return(false)
   return(true)
@@ -101,25 +100,6 @@ defineTest(isArchSupported) {
     return(false)
 }
 
-defineTest(isPythonVersionSupported) {
-    python_error_msg = "Python version 2 (2.7.5 or later) is required to build Qt WebEngine."
-    python_version = $$system('python -c "import sys; print(sys.version_info[0:3])"')
-    python_version ~= s/[()]//g
-    python_version = $$split(python_version, ',')
-    python_major_version = $$first(python_version)
-    greaterThan(python_major_version, 2) {
-        skipBuild("Python version 3 is not supported by Chromium.")
-        skipBuild($$python_error_msg)
-        return(false)
-    }
-    python_minor_version = $$member(python_version, 1)
-    python_patch_version = $$member(python_version, 2)
-    greaterThan(python_major_version, 1): greaterThan(python_minor_version, 6): greaterThan(python_patch_version, 4): return(true)
-    skipBuild("Using Python version $${python_major_version}.$${python_minor_version}.$${python_patch_version}.")
-    skipBuild($$python_error_msg)
-    return(false)
-}
-
 defineTest(isSanitizerEnabled) {
   sanitize_address|sanitize_memory|sanitize_undefined|sanitize_thread: return(true)
   return(false)
@@ -358,6 +338,25 @@ defineTest(use?) {
     return(false)
 }
 
+# Returns the unquoted path to the python executable.
+defineReplace(pythonPath) {
+    isEmpty(QMAKE_PYTHON2) {
+        # Fallback for building QtWebEngine with Qt < 5.8
+        QMAKE_PYTHON2 = python
+    }
+    return($$QMAKE_PYTHON2)
+}
+
+# Returns the python executable for use with shell / make targets.
+defineReplace(pythonPathForShell) {
+    return($$shell_quote($$shell_path($$pythonPath())))
+}
+
+# Returns the python executable for use with $$system()
+defineReplace(pythonPathForSystem) {
+    return($$system_quote($$system_path($$pythonPath())))
+}
+
 defineReplace(ninjaPath) {
     src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT")
     out = $$shadowed($$absolute_path(ninja/ninja, $$src_3rd_party_dir))
-- 
GitLab