Skip to content

Commit c0ad989

Browse files
bmwiedemannindygreg
authored andcommitted
global: adapt to zstd 1.5.7
All our code changes required to support the upgrade from 1.5.6. * Rust zstd upgraded to 1.5.7 to match C version. * Test output changes. * `zstd_errors.h` inclusion via `zstd.h` caused problems. * MUSL 1.1 compatibility issues (see previous commit).
1 parent cb8fc35 commit c0ad989

13 files changed

Lines changed: 345 additions & 67 deletions

Cargo.lock

Lines changed: 295 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

c-ext/backend_c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void zstd_module_init(PyObject *m) {
152152
PyObject *features = NULL;
153153
PyObject *feature = NULL;
154154
unsigned zstd_ver_no = ZSTD_versionNumber();
155-
unsigned our_hardcoded_version = 10506;
155+
unsigned our_hardcoded_version = 10507;
156156
if (ZSTD_VERSION_NUMBER != our_hardcoded_version ||
157157
zstd_ver_no != our_hardcoded_version) {
158158
PyErr_Format(

make_cffi.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import tempfile
1515

1616
import cffi
17+
import packaging.tags
1718

1819
HERE = os.path.abspath(os.path.dirname(__file__))
1920

@@ -22,7 +23,7 @@
2223
]
2324

2425
# Headers whose preprocessed output will be fed into cdef().
25-
HEADERS = [os.path.join(HERE, "zstd", p) for p in ("zstd.h", "zdict.h")]
26+
HEADERS = [os.path.join(HERE, "zstd", p) for p in ("zstd_errors.h", "zstd.h", "zdict.h")]
2627

2728
INCLUDE_DIRS = [
2829
os.path.join(HERE, "zstd"),
@@ -76,8 +77,8 @@ def preprocess(path):
7677
# boilerplate. This can lead to duplicate declarations. So we strip
7778
# this include from the preprocessor invocation.
7879
#
79-
# The same things happens for including zstd.h, so give it the same
80-
# treatment.
80+
# The same things happens for including zstd.h and zstd_errors.h, so
81+
# give them the same treatment.
8182
#
8283
# We define ZSTD_STATIC_LINKING_ONLY, which is redundant with the inline
8384
# #define in zstdmt_compress.h and results in a compiler warning. So drop
@@ -86,11 +87,17 @@ def preprocess(path):
8687
(
8788
b"#include <stddef.h>",
8889
b'#include "zstd.h"',
90+
b'#include "zstd_errors.h"',
8991
b"#define ZSTD_STATIC_LINKING_ONLY",
9092
)
9193
):
9294
continue
9395

96+
# There's a naked `static` before the declaration of ZSTD_customMem that
97+
# confuses the cffi parser. Strip it.
98+
if line == b'static\n':
99+
continue
100+
94101
# The preprocessor environment on Windows doesn't define include
95102
# paths, so the #include of limits.h fails. We work around this
96103
# by removing that import and defining INT_MAX ourselves. This is
@@ -157,19 +164,25 @@ def normalize_output(output):
157164

158165
return b"\n".join(lines)
159166

167+
# musl 1.1 doesn't define qsort_r. We need to force using the C90
168+
# variant.
169+
musl_defines = ""
170+
for tag in packaging.tags.platform_tags():
171+
if tag.startswith("musllinux_1_1_"):
172+
musl_defines = "#define ZDICT_QSORT ZDICT_QSORT_C90"
173+
160174

161175
ffi = cffi.FFI()
162-
# zstd.h uses a possible undefined MIN(). Define it until
163-
# https://github.com/facebook/zstd/issues/976 is fixed.
164176
# *_DISABLE_DEPRECATE_WARNINGS prevents the compiler from emitting a warning
165177
# when cffi uses the function. Since we statically link against zstd, even
166178
# if we use the deprecated functions it shouldn't be a huge problem.
167179
ffi.set_source(
168180
"zstandard._cffi",
169-
"""
170-
#define MIN(a,b) ((a)<(b) ? (a) : (b))
181+
f"""
171182
#define ZSTD_STATIC_LINKING_ONLY
172183
#define ZSTD_DISABLE_DEPRECATE_WARNINGS
184+
{musl_defines}
185+
#include <zstd_errors.h>
173186
#include <zstd.h>
174187
#define ZDICT_STATIC_LINKING_ONLY
175188
#define ZDICT_DISABLE_DEPRECATE_WARNINGS
@@ -179,7 +192,7 @@ def normalize_output(output):
179192
include_dirs=INCLUDE_DIRS,
180193
)
181194

182-
DEFINE = re.compile(b"^\\#define ([a-zA-Z0-9_]+) ")
195+
DEFINE = re.compile(rb"^#define\s+([a-zA-Z0-9_]+)\s+(\S+)")
183196

184197
sources = []
185198

@@ -204,9 +217,14 @@ def normalize_output(output):
204217
if m.group(1) in (b"ZSTD_LIB_VERSION", b"ZSTD_VERSION_STRING"):
205218
continue
206219

220+
# These defines create aliases from old (camelCase) type names
221+
# to the new PascalCase names, which breaks CFFI.
222+
if m.group(1).lower() == m.group(2).lower():
223+
continue
224+
207225
# The ... is magic syntax by the cdef parser to resolve the
208226
# value at compile time.
209-
sources.append(m.group(0) + b" ...")
227+
sources.append(b"#define " + m.group(1) + b" ...")
210228

211229
cdeflines = b"\n".join(sources).splitlines()
212230
cdeflines = [line for line in cdeflines if line.strip()]

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Documentation = "https://python-zstandard.readthedocs.io/en/latest/"
2828
[build-system]
2929
requires = [
3030
"cffi>=1.17.0",
31+
"packaging",
3132
"setuptools",
3233
]
3334
# Need to use legacy backend because setup_zstd.py breaks build isolation.

rust-ext/src/decompressor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,11 @@ impl ZstdDecompressor {
256256
}
257257

258258
let chunk_buffer: PyBuffer<u8> = PyBuffer::get(&chunk.as_borrowed())?;
259-
let mut params = zstd_sys::ZSTD_frameHeader {
259+
let mut params = zstd_sys::ZSTD_FrameHeader {
260260
frameContentSize: 0,
261261
windowSize: 0,
262262
blockSizeMax: 0,
263-
frameType: zstd_sys::ZSTD_frameType_e::ZSTD_frame,
263+
frameType: zstd_sys::ZSTD_FrameType_e::ZSTD_frame,
264264
headerSize: 0,
265265
dictID: 0,
266266
checksumFlag: 0,

rust-ext/src/frame_parameters.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use {
1212

1313
#[pyclass(module = "zstandard.backend_rust")]
1414
struct FrameParameters {
15-
header: zstd_sys::ZSTD_frameHeader,
15+
header: zstd_sys::ZSTD_FrameHeader,
1616
}
1717

1818
unsafe impl Sync for FrameParameters {}
@@ -75,11 +75,11 @@ fn get_frame_parameters(py: Python, buffer: PyBuffer<u8>) -> PyResult<Py<FramePa
7575
std::slice::from_raw_parts::<u8>(buffer.buf_ptr() as *const _, buffer.len_bytes())
7676
};
7777

78-
let mut header = zstd_sys::ZSTD_frameHeader {
78+
let mut header = zstd_sys::ZSTD_FrameHeader {
7979
frameContentSize: 0,
8080
windowSize: 0,
8181
blockSizeMax: 0,
82-
frameType: zstd_sys::ZSTD_frameType_e::ZSTD_frame,
82+
frameType: zstd_sys::ZSTD_FrameType_e::ZSTD_frame,
8383
headerSize: 0,
8484
dictID: 0,
8585
checksumFlag: 0,

setup_zstd.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import subprocess
1515
import sys
1616

17+
import packaging.tags
18+
1719
ext_includes = [
1820
"c-ext",
1921
]
@@ -89,6 +91,13 @@ def get_c_extension(
8991
if not system_zstd and support_legacy:
9092
extra_args.append("-DZSTD_LEGACY_SUPPORT=1")
9193

94+
# musl 1.1 doesn't define qsort_r. We need to force using the C90
95+
# variant. ZDICT_QSORT officially introduced in 1.5.8. But our
96+
# vendored copy backported to 1.5.7.
97+
for tag in packaging.tags.platform_tags():
98+
if tag.startswith("musllinux_1_1_"):
99+
extra_args.append("-DZDICT_QSORT=ZDICT_QSORT_C90")
100+
92101
if warnings_as_errors:
93102
if compiler_type in ("unix", "mingw32"):
94103
extra_args.append("-Werror")

tests/test_compressor_compress.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_compress_large(self):
5252

5353
cctx = zstd.ZstdCompressor(level=3, write_content_size=False)
5454
result = cctx.compress(b"".join(chunks))
55-
self.assertEqual(len(result), 999)
55+
self.assertEqual(len(result), 1029)
5656
self.assertEqual(result[0:4], b"\x28\xb5\x2f\xfd")
5757

5858
# This matches the test for read_to_iter() below.

tests/test_compressor_compressobj.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_compressobj_large(self):
3939
cobj = cctx.compressobj()
4040

4141
result = cobj.compress(b"".join(chunks)) + cobj.flush()
42-
self.assertEqual(len(result), 999)
42+
self.assertEqual(len(result), 1029)
4343
self.assertEqual(result[0:4], b"\x28\xb5\x2f\xfd")
4444

4545
params = zstd.get_frame_parameters(result)

tests/test_compressor_copy_stream.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def test_large_data(self):
5050
r, w = cctx.copy_stream(source, dest)
5151

5252
self.assertEqual(r, 255 * 16384)
53-
self.assertEqual(w, 999)
53+
self.assertEqual(w, 1029)
5454

5555
params = zstd.get_frame_parameters(dest.getvalue())
5656
self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN)

0 commit comments

Comments
 (0)