-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
qt.py
97 lines (84 loc) · 3.2 KB
/
qt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# -----------------------------------------------------------------------------
# Copyright (c) 2024, PyInstaller Development Team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: Apache-2.0
# -----------------------------------------------------------------------------
import os
import importlib
import atexit
# Helper for relocating Qt prefix via embedded qt.conf file.
_QT_CONF_FILENAME = ":/qt/etc/qt.conf"
_QT_CONF_RESOURCE_NAME = (
# qt
b"\x00\x02"
b"\x00\x00\x07\x84"
b"\x00\x71"
b"\x00\x74"
# etc
b"\x00\x03"
b"\x00\x00\x6c\xa3"
b"\x00\x65"
b"\x00\x74\x00\x63"
# qt.conf
b"\x00\x07"
b"\x08\x74\xa6\xa6"
b"\x00\x71"
b"\x00\x74\x00\x2e\x00\x63\x00\x6f\x00\x6e\x00\x66"
)
_QT_CONF_RESOURCE_STRUCT = (
# :
b"\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01"
# :/qt
b"\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02"
# :/qt/etc
b"\x00\x00\x00\x0a\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03"
# :/qt/etc/qt.conf
b"\x00\x00\x00\x16\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
)
def create_embedded_qt_conf(qt_bindings, prefix_path):
QtCore = importlib.import_module(qt_bindings + ".QtCore")
# No-op if embedded qt.conf already exists
if QtCore.QFile.exists(_QT_CONF_FILENAME):
return
# Create qt.conf file that relocates Qt prefix.
# NOTE: paths should use POSIX-style forward slashes as separator, even on Windows.
if os.sep == '\\':
prefix_path = prefix_path.replace(os.sep, '/')
qt_conf = f"[Paths]\nPrefix = {prefix_path}\n"
if os.name == 'nt' and qt_bindings in {"PySide2", "PySide6"}:
# PySide PyPI wheels on Windows set LibraryExecutablesPath to PrefixPath
qt_conf += f"LibraryExecutables = {prefix_path}"
# Encode the contents; in Qt5, QSettings uses Latin1 encoding, in Qt6, it uses UTF8.
if qt_bindings in {"PySide2", "PyQt5"}:
qt_conf = qt_conf.encode("latin1")
else:
qt_conf = qt_conf.encode("utf-8")
# Prepend data size (32-bit integer, big endian)
qt_conf_size = len(qt_conf)
qt_resource_data = qt_conf_size.to_bytes(4, 'big') + qt_conf
# Register
succeeded = QtCore.qRegisterResourceData(
0x01,
_QT_CONF_RESOURCE_STRUCT,
_QT_CONF_RESOURCE_NAME,
qt_resource_data,
)
if not succeeded:
return # Tough luck
# Unregister the resource at exit, to ensure that the registered resource on Qt/C++ side does not outlive the
# `_qt_resource_data` python variable and its data buffer. This also adds a reference to the `_qt_resource_data`,
# which conveniently ensures that the data is not garbage collected before we perform the cleanup (otherwise garbage
# collector might kick in at any time after we exit this helper function, and `qRegisterResourceData` does not seem
# to make a copy of the data!).
atexit.register(
QtCore.qUnregisterResourceData,
0x01,
_QT_CONF_RESOURCE_STRUCT,
_QT_CONF_RESOURCE_NAME,
qt_resource_data,
)