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>)
43 static string const python23(string const & binary, bool verbose = false)
45 const string version_info = " -c 'from __future__ import print_function;import sys; print(sys.version_info[:2], end=\"\")'";
46 static regex const python_reg("\\((\\d*), (\\d*)\\)");
48 lyxerr << "Examining " << binary << "\n";
50 // Check whether this is a python 2 or 3 binary.
51 cmd_ret const out = runCommand(binary + version_info);
54 if (out.first < 0 || !regex_match(out.second, sm, python_reg))
57 int major = convert<int>(sm.str(1));
58 int minor = convert<int>(sm.str(2));
59 if((major == 2 and minor < 7) or (major == 3 and minor < 4))
63 lyxerr << "Found Python " << out.second << "\n";
74 string const python(bool reset)
76 // Check whether python3 in PATH is the right one.
77 static string command = python23("python3");
80 command = python23("python3");
83 // python3 does not exists, let us try python3.x
84 if (command.empty()) {
85 // It was not, so check whether we can find it elsewhere in
86 // PATH, maybe with some suffix appended.
87 vector<string> const path = getEnvPath("PATH");
88 lyxerr << "Looking for python 3.x ...\n";
89 for (auto bin: path) {
90 QString const dir = toqstr(bin);
91 string const localdir = dir.toLocal8Bit().constData();
93 qdir.setFilter(QDir::Files | QDir::Executable);
94 QStringList list = qdir.entryList(QStringList("python3*"));
95 for (int i = 0; i < list.size() && command.empty(); ++i) {
96 string const binary = addName(localdir,
97 list.at(i).toLocal8Bit().constData());
98 command = python23(binary, true);
103 // python 3 not found let us look for python 2
105 command = python23("python2");
107 // python2 does not exists, let us try python2.x
108 if (command.empty()) {
109 // It was not, so check whether we can find it elsewhere in
110 // PATH, maybe with some suffix appended.
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("python2*"));
119 for (int i = 0; i < list.size() && command.empty(); ++i) {
120 string const binary = addName(localdir,
121 list.at(i).toLocal8Bit().constData());
122 command = python23(binary, true);
128 // Default to "python" if no usable binary was found.
129 // If this happens all hope is lost that there is a sane system
130 if (command.empty()) {
131 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
135 // Add the -tt switch so that mixed tab/whitespace
136 // indentation is an error
142 } // namespace support