@@ -17,13 +17,13 @@ integrates much better with the operating system if the application is delivered
17
17
as a native Windows executable. However, Python is not a natively compiled
18
18
language, and so does not create executables by default.
19
19
20
- The normal way around this issue is to make your Python code into a library, and
21
- declare one or more " script entry points" for the library. When the library is
22
- installed, the installer will generate a native executable which invokes the
23
- Python interpreter, calling your entry point function. This is a very effective
24
- solution, and is used by many Python applications. It is supported by utilities
25
- such as ``pipx `` and ``uv tool ``, which make managing such entry points (and the
26
- virtual environments needed to support them) easy.
20
+ One way around this issue is to make your Python code into a library, and
21
+ declare one or more :ref: ` script entry points < script-entry-points >` for the
22
+ library. When the library is installed, the installer will provide an executable
23
+ which invokes the Python interpreter, calling your entry point function. This is
24
+ a very effective solution, and is used by many Python applications. It is
25
+ supported by utilities such as ``pipx `` and ``uv tool ``, which make managing
26
+ such entry points (and the virtual environments needed to support them) easy.
27
27
28
28
There are, however, some downsides to this approach. The entry point wrapper
29
29
results in a chain of processes being created - the wrapper itself, the virtual
@@ -90,10 +90,27 @@ need to do is make a small modification to the wrapper code.
90
90
Your code can use 3rd party dependencies freely. These will be installed along
91
91
with your application.
92
92
93
- When you are ready to build your application, you can install the Python code
94
- using::
93
+ You can create your application code in whatever way you prefer - there is no
94
+ particular need to make it buildable as a wheel. For the purposes of this
95
+ discussion, we will assume one of two project layouts:
95
96
96
- pip install --target "<Application directory>\lib" MyAwesomePythonApp
97
+ 1. A project which can be installed via ``pip install ``, with all of its
98
+ dependencies listed in the ``pyproject.toml `` file, as normal.
99
+ 2. A Python application stored in a local directory. In this case, third party
100
+ dependencies are listed in a ``requirements.txt `` file.
101
+
102
+ When you are ready to build your application, you need to copy all of the
103
+ required code and dependencies into the ``lib `` directory of the application.
104
+ For case (1), this can be done using::
105
+
106
+ pip install --target "<Application directory>\lib" .
107
+
108
+ For case (2), you should copy your application code into the ``lib `` directory
109
+ and then run::
110
+
111
+ pip install --target "<Application directory>\lib" -r requirements.txt
112
+
113
+ to install the 3rd party dependencies.
97
114
98
115
You can then run your application as follows::
99
116
@@ -154,6 +171,10 @@ application code should look like the following::
154
171
/* Include the Python headers */
155
172
#include <Python.h>
156
173
174
+ #define PYTHON_LOCATION L"interp"
175
+ #define APP_MODULE "MyAwesomePythonApp"
176
+ #define APP_FUNCTION "main"
177
+
157
178
/* Finding the Python interpreter */
158
179
#include <windows.h>
159
180
#include <pathcch.h>
@@ -188,7 +209,7 @@ application code should look like the following::
188
209
* This MUST be called before any functions from the Python
189
210
* runtime are called.
190
211
*/
191
- if (!dll_dir(L"interp" ))
212
+ if (!dll_dir(PYTHON_LOCATION ))
192
213
return -1;
193
214
194
215
/* Initialise the Python configuration */
@@ -214,10 +235,10 @@ application code should look like the following::
214
235
*/
215
236
216
237
int exitCode = -1;
217
- PyObject *module = PyImport_ImportModule("MyAwesomePythonApp" );
238
+ PyObject *module = PyImport_ImportModule(APP_MODULE );
218
239
if (module) {
219
240
// Pass any more arguments here
220
- PyObject *result = PyObject_CallMethod(module, "main" , NULL);
241
+ PyObject *result = PyObject_CallMethod(module, APP_FUNCTION , NULL);
221
242
if (result) {
222
243
exitCode = 0;
223
244
Py_DECREF(result);
@@ -342,8 +363,16 @@ needs a GUI, the simplest option is likely to be to use one of the other GUI
342
363
frameworks available from PyPI, such as PyQt or wxPython.
343
364
344
365
If your only option is tkinter, you will need to add a copy to the embedded
345
- distribution, or use a different distribution. Both of these options are outside
346
- the scope of this guide, however.
366
+ distribution. You can get the relevant files from a full Python installation
367
+ (which must be the same version as you're using for your application). The
368
+ files you need are:
369
+
370
+ * ``_tkinter.pyd ``, ``tcl*.dll ``, ``tk*.dll `` and ``zlib1.dll `` from
371
+ ``{sys.prefix}\DLLs ``
372
+ * The ``tcl `` directory from ``{sys.prefix} ``
373
+ * The ``tkinter `` directory from ``{sys.prefix}\Lib ``
374
+
375
+ You should copy all of these into your embedded interpreter directory.
347
376
348
377
Subprocesses and ``sys.executable ``
349
378
-----------------------------------
@@ -373,7 +402,7 @@ positive side, though, operating systems other than Windows have less need for
373
402
this, as support for interpreted code as applications is generally better. In
374
403
particular, on Unix a Python file with a "shebang" line is treated as a
375
404
first-class application, and there is no benefit to making a native
376
- appliocation .
405
+ application .
377
406
378
407
So while this discussion is specific to Windows, the problem it is solving is
379
408
*also * unique to Windows.
0 commit comments