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.
14 #include "support/convert.h"
15 #include "support/debug.h"
16 #include "support/filetools.h"
17 #include "support/qstring_helpers.h"
18 #include "support/regex.h"
22 #if defined(__CYGWIN__)
23 #include "support/os_cygwin.cpp"
25 #include "support/os_win32.cpp"
27 #include "support/os_unix.cpp"
30 // Static assert to break compilation on platforms where
31 // int/unsigned int is not 4 bytes. Added to make sure that
32 // e.g., the author hash is always 32-bit.
33 template<bool Condition> struct static_assert_helper;
34 template <> struct static_assert_helper<true> {};
36 dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
49 static string const python23_call(string const & binary, bool verbose = false)
51 const string version_info = " -c 'from __future__ import print_function;import sys; print(sys.version_info[:2], end=\"\")'";
52 // Default to "python" if no binary is given.
57 lyxerr << "Examining " << binary << "\n";
58 // Check whether this is a python 2 or 3 binary.
59 cmd_ret const out = runCommand(binary + version_info);
63 static regex const python_reg("\\((\\d*), (\\d*)\\)");
64 if (out.first < 0 || !regex_match(out.second, sm, python_reg))
66 } catch(regex_error const & /*e*/) {
67 LYXERR0("Regex error! This should not happen.");
71 int major = convert<int>(sm.str(1));
72 int minor = convert<int>(sm.str(2));
73 if((major == 2 && minor < 7) || (major == 3 && minor < 5))
77 lyxerr << "Found Python " << out.second << "\n";
78 // Add the -tt switch so that mixed tab/whitespace
79 // indentation is an error
80 return binary + " -tt";
84 static string const find_python_binary()
86 // This function takes inspiration from PEP 394 and PEP 397
87 // PEP 394 -- The "python" Command on Unix-Like Systems
88 // https://www.python.org/dev/peps/pep-0394/
89 // PEP 397 -- Python launcher for Windows
90 // https://www.python.org/dev/peps/pep-0397/
92 // Check whether python3 in PATH is the right one.
93 string command = python23_call("python3");
97 // python3 does not exists, let us try to find python3.x in PATH
98 // the search is probably broader than required
99 // but we are trying hard to find a valid python binary
100 vector<string> const path = getEnvPath("PATH");
101 lyxerr << "Looking for python 3.x ...\n";
102 for (auto bin : path) {
103 QString const dir = toqstr(bin);
104 string const localdir = dir.toLocal8Bit().constData();
106 qdir.setFilter(QDir::Files | QDir::Executable);
107 QStringList list = qdir.entryList(QStringList("python3*"));
108 for (auto bin2 : list) {
109 string const binary = addName(localdir,
110 bin2.toLocal8Bit().constData());
111 command = python23_call(binary, true);
112 if (!command.empty())
117 // python 3 was not found let us look for python 2
118 command = python23_call("python2");
119 if (!command.empty())
122 // python2 does not exists, let us try to find python2.x in PATH
123 // the search is probably broader than required
124 // but we are trying hard to find a valid python binary
125 lyxerr << "Looking for python 2.x ...\n";
126 for (auto bin : path) {
127 QString const dir = toqstr(bin);
128 string const localdir = dir.toLocal8Bit().constData();
130 qdir.setFilter(QDir::Files | QDir::Executable);
131 QStringList list = qdir.entryList(QStringList("python2*"));
132 for (auto bin2 : list) {
133 string const binary = addName(localdir,
134 bin2.toLocal8Bit().constData());
135 command = python23_call(binary, true);
136 if (!command.empty())
141 // If this happens all hope is lost that this is a sane system
142 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
143 return python23_call("");
147 string const python(bool reset)
149 static string command = find_python_binary();
152 command = find_python_binary();
158 } // namespace support