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"
27 #if defined(__CYGWIN__)
28 #include "support/os_cygwin.cpp"
30 #include "support/os_win32.cpp"
32 #include "support/os_unix.cpp"
35 // Static assert to break compilation on platforms where
36 // int/unsigned int is not 4 bytes. Added to make sure that
37 // e.g., the author hash is always 32-bit.
38 template<bool Condition> struct static_assert_helper;
39 template <> struct static_assert_helper<true> {};
41 dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
54 static string const python23_call(string const & binary, bool verbose = false)
56 const string version_info = " -c \"from __future__ import print_function;import sys; print(sys.version_info[:2], end=\\\"\\\")\"";
57 // Default to "python" if no binary is given.
62 lyxerr << "Examining " << binary << "\n";
63 // Check whether this is a python 2 or 3 binary.
64 cmd_ret const out = runCommand(binary + version_info);
68 static regex const python_reg("\\((\\d*), (\\d*)\\)");
69 if (!out.valid || !regex_match(out.result, sm, python_reg))
71 } catch(regex_error const & /*e*/) {
72 LYXERR0("Regex error! This should not happen.");
76 int major = convert<int>(sm.str(1));
77 int minor = convert<int>(sm.str(2));
78 if((major == 2 && minor < 7) || (major == 3 && minor < 5))
82 lyxerr << "Found Python " << out.result << "\n";
83 // Add the -tt switch so that mixed tab/whitespace
84 // indentation is an error
85 return binary + " -tt";
89 static string const find_python_binary()
91 // This function takes inspiration from PEP 394 and PEP 397
92 // PEP 394 -- The "python" Command on Unix-Like Systems
93 // https://www.python.org/dev/peps/pep-0394/
94 // PEP 397 -- Python launcher for Windows
95 // https://www.python.org/dev/peps/pep-0397/
98 // Check through python launcher whether python 3 is
99 // installed on computer.
100 string command = python23_call("py -3");
102 // Check whether python3 in PATH is the right one.
103 string command = python23_call("python3");
105 if (!command.empty())
109 // python3 does not exists, let us try to find python3.x in PATH
110 // the search is probably broader than required
111 // but we are trying hard to find a valid python binary
112 vector<string> const path = getEnvPath("PATH");
113 lyxerr << "Looking for python 3.x ...\n";
114 for (auto bin : path) {
115 QString const dir = toqstr(bin);
116 string const localdir = dir.toLocal8Bit().constData();
118 qdir.setFilter(QDir::Files | QDir::Executable);
119 QStringList list = qdir.entryList(QStringList("python3*"));
120 for (auto bin2 : list) {
121 string const binary = "\"" + addName(localdir,
122 bin2.toLocal8Bit().constData()) + "\"";
123 command = python23_call(binary, true);
124 if (!command.empty())
130 // python 3 was not found let us look for python 2
132 command = python23_call("py -2");
134 command = python23_call("python2");
136 if (!command.empty())
140 // python launcher is not installed, let cmd auto check
141 // PATH for a python.exe
142 command = python23_call("python");
143 if (!command.empty())
146 //failed, prepare to search PATH manually
147 vector<string> const path = getEnvPath("PATH");
148 lyxerr << "Manually looking for python in PATH ...\n";
149 QString const exeName = "python*";
151 // python2 does not exists, let us try to find python2.x in PATH
152 // the search is probably broader than required
153 // but we are trying hard to find a valid python binary
154 lyxerr << "Looking for python 2.x ...\n";
155 QString const exeName = "python2*";
158 for (auto bin : path) {
159 QString const dir = toqstr(bin);
160 string const localdir = dir.toLocal8Bit().constData();
162 qdir.setFilter(QDir::Files | QDir::Executable);
163 QStringList list = qdir.entryList(QStringList(exeName));
164 for (auto bin2 : list) {
165 string const binary = "\"" + addName(localdir,
166 bin2.toLocal8Bit().constData()) + "\"";
167 command = python23_call(binary, true);
168 if (!command.empty())
173 // If this happens all hope is lost that this is a sane system
174 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
175 return python23_call("");
179 string const python(bool reset)
181 static string command = find_python_binary();
184 command = find_python_binary();
190 } // namespace support