Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CPython] Include TCL/TK for Windows binding #1535

Open
HannesWell opened this issue Aug 27, 2024 · 3 comments
Open

[CPython] Include TCL/TK for Windows binding #1535

HannesWell opened this issue Aug 27, 2024 · 3 comments

Comments

@HannesWell
Copy link
Contributor

When using Python's tkinter directly or indirectly a local installation of tcl and tk is necessary.
And while JavaCPP's cPypthon includes the tkinter module it doesn't contain tcl/tk.

Installing tcl/tk via PIP or alike is not possible. On Windows the CPython can install tcl/tk as part of the python installation and on Linux it can be installed via apt-get and is often already available:
https://stackoverflow.com/questions/69603788/how-to-pip-install-tkinter

Therefore I would like to suggest to include tcl/tk into JavaCPP's cpython-preset for Windows.
Without that the following Python program cannot be executed using javacpp-embedded-python:

        Pip.install("matplotlib"); // "numpy"

        StringJoiner lines = new StringJoiner("\n");
        lines.add("import matplotlib.pyplot as plt");
        lines.add("import numpy as np");
        lines.add("x = np.linspace(0, 2 * np.pi, 200)");
        lines.add("y = np.sin(x)");
        lines.add("fig, ax = plt.subplots()");
        lines.add("ax.plot(x, y)");
        lines.add("fig.savefig('plot.png')");

        Python.eval(lines.toString());
org.bytedeco.embeddedpython.PythonException: Failed to execute:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
fig.savefig('plot.png')
Traceback (most recent call last):
  File "<string>", line 6, in <module>
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\pyplot.py",
line 1759, in subplots
    fig = figure(**fig_kw)
          ^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\pyplot.py",
line 1027, in figure
    manager = new_figure_manager(
              ^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\pyplot.py",
line 550, in new_figure_manager
    return _get_backend_mod().new_figure_manager(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\backend_bases.py",
line 3507, in new_figure_manager
    return cls.new_figure_manager_given_figure(num, fig)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\backend_bases.py",
line 3512, in new_figure_manager_given_figure
    return cls.FigureCanvas.new_manager(figure, num)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\backend_bases.py",
line 1797, in new_manager
    return cls.manager_class.create_with_canvas(cls, figure, num)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\site-packages\matplotlib\backends\_backend_tk.py",
line 483, in create_with_canvas
    window = tk.Tk(className="matplotlib")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "~\.javacpp\cache\cpython-3.12.1-1.5.10-windows-x86_64.jar\org\bytedeco\cpython\windows-x86_64\lib\tkinter\__init__.py",
line 2340, in __init__
    self.tk = _tkinter.create(screenName, baseName, className,
interactive, wantobjects, useTk, sync, use)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: Can't find a usable init.tcl in the following
directories:
    ~/.javacpp/cache/cpython-3.12.1-1.5.10-windows-x86_64.jar/org/bytedeco/cpython/windows-x86_64/lib/tcl8.6

This probably means that Tcl wasn't installed properly.

A workaround is to wrap the tcl folder of a 'classic' Cpython installation and distribute and cache it along with javacpp-cpython and run the following as first steps after the initialization of python (e.g. via Py_Initialize()):

File tclFolder = Loader.cacheResource("/foo/bar/tcl/" + Loader.getPlatform());
Path tclLibrary = tclFolder.toPath().resolve("tcl8.6");
Path tkLibrary = tclFolder.toPath().resolve("tk8.6");
Path tixLibrary = tclFolder.toPath().resolve("tix8.4.3");
PyRun_SimpleStringFlags(String.format("""
	import os
	os.environ['TCL_LIBRARY'] = r'%1$s'
	os.environ['TK_LIBRARY'] = r'%2$s'
	os.environ['TIX_LIBRARY'] = r'%3$s'
""", tclLibrary, tkLibrary, tixLibrary));

That's possible, but cumbersome and not easy to get to if one is not deeply familiar with the topic.

Unfortunately I cannot tell yet how including tcl/tk could be achieved, since I haven't fully understood yet how the CPython installer bundle tcl/tk.

@saudet
Copy link
Member

saudet commented Aug 28, 2024

Looks like we can use PCbuild/prepare_tcltk.bat for that on Windows:
https://github.com/python/cpython/blob/main/PCbuild/readme.txt

@HannesWell
Copy link
Contributor Author

HannesWell commented Aug 29, 2024

Thanks for the pointer. This looks promising. I'll look into it.
Do you have any immediate hints where this could maybe applied in the cpython preset?

@saudet
Copy link
Member

saudet commented Aug 29, 2024

I'm guessing somewhere before calling build.bat here:
https://github.com/bytedeco/javacpp-presets/blob/master/cpython/cppbuild.sh#L189

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants