3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Ruurd A. Reitsma
7 * \author Enrico Forestieri
9 * Full author contact details are available in file CREDITS.
15 # define _WIN32_WINNT 0x0600
18 #include "support/convert.h"
19 #include "support/debug.h"
20 #include "support/filetools.h"
21 #include "support/qstring_helpers.h"
22 #include "support/regex.h"
26 #if defined(__CYGWIN__)
27 #include "support/os_cygwin.cpp"
29 #include "support/os_win32.cpp"
31 #include "support/os_unix.cpp"
34 // Static assert to break compilation on platforms where
35 // int/unsigned int is not 4 bytes. Added to make sure that
36 // e.g., the author hash is always 32-bit.
37 template<bool Condition> struct static_assert_helper;
38 template <> struct static_assert_helper<true> {};
40 dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
53 static string const python23_call(string const & binary, bool verbose = false)
55 const string version_info = " -c \"from __future__ import print_function;import sys; print(sys.version_info[:2], end=\\\"\\\")\"";
56 // Default to "python" if no binary is given.
61 lyxerr << "Examining " << binary << "\n";
62 // Check whether this is a python 2 or 3 binary.
63 cmd_ret const out = runCommand(binary + version_info);
67 static regex const python_reg("\\((\\d*), (\\d*)\\)");
68 if (out.first < 0 || !regex_match(out.second, sm, python_reg))
70 } catch(regex_error const & /*e*/) {
71 LYXERR0("Regex error! This should not happen.");
75 int major = convert<int>(sm.str(1));
76 int minor = convert<int>(sm.str(2));
77 if((major == 2 && minor < 7) || (major == 3 && minor < 5))
81 lyxerr << "Found Python " << out.second << "\n";
82 // Add the -tt switch so that mixed tab/whitespace
83 // indentation is an error
84 return binary + " -tt";
88 static string const find_python_binary()
90 // This function takes inspiration from PEP 394 and PEP 397
91 // PEP 394 -- The "python" Command on Unix-Like Systems
92 // https://www.python.org/dev/peps/pep-0394/
93 // PEP 397 -- Python launcher for Windows
94 // https://www.python.org/dev/peps/pep-0397/
97 // Check through python launcher whether python 3 is
98 // installed on computer.
99 string command = python23_call("py -3");
101 // Check whether python3 in PATH is the right one.
102 string command = python23_call("python3");
104 if (!command.empty())
108 // python3 does not exists, let us try to find python3.x in PATH
109 // the search is probably broader than required
110 // but we are trying hard to find a valid python binary
111 vector<string> const path = getEnvPath("PATH");
112 lyxerr << "Looking for python 3.x ...\n";
113 for (auto bin : path) {
114 QString const dir = toqstr(bin);
115 string const localdir = dir.toLocal8Bit().constData();
117 qdir.setFilter(QDir::Files | QDir::Executable);
118 QStringList list = qdir.entryList(QStringList("python3*"));
119 for (auto bin2 : list) {
120 string const binary = "\"" + addName(localdir,
121 bin2.toLocal8Bit().constData()) + "\"";
122 command = python23_call(binary, true);
123 if (!command.empty())
129 // python 3 was not found let us look for python 2
131 command = python23_call("py -2");
133 command = python23_call("python2");
135 if (!command.empty())
139 // python launcher is not installed, let cmd auto check
140 // PATH for a python.exe
141 command = python23_call("python");
142 if (!command.empty())
145 //failed, prepare to search PATH manually
146 vector<string> const path = getEnvPath("PATH");
147 lyxerr << "Manually looking for python in PATH ...\n";
148 QString const exeName = "python*";
150 // python2 does not exists, let us try to find python2.x in PATH
151 // the search is probably broader than required
152 // but we are trying hard to find a valid python binary
153 lyxerr << "Looking for python 2.x ...\n";
154 QString const exeName = "python2*";
157 for (auto bin : path) {
158 QString const dir = toqstr(bin);
159 string const localdir = dir.toLocal8Bit().constData();
161 qdir.setFilter(QDir::Files | QDir::Executable);
162 QStringList list = qdir.entryList(QStringList(exeName));
163 for (auto bin2 : list) {
164 string const binary = "\"" + addName(localdir,
165 bin2.toLocal8Bit().constData()) + "\"";
166 command = python23_call(binary, true);
167 if (!command.empty())
172 // If this happens all hope is lost that this is a sane system
173 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
174 return python23_call("");
178 string const python(bool reset)
180 static string command = find_python_binary();
183 command = find_python_binary();
189 } // namespace support