|
1 # Copyright (c) 2016-present, Gregory Szorc |
|
2 # All rights reserved. |
|
3 # |
|
4 # This software may be modified and distributed under the terms |
|
5 # of the BSD license. See the LICENSE file for details. |
|
6 |
|
7 from __future__ import absolute_import |
|
8 |
|
9 import cffi |
|
10 import os |
|
11 |
|
12 |
|
13 HERE = os.path.abspath(os.path.dirname(__file__)) |
|
14 |
|
15 SOURCES = ['zstd/%s' % p for p in ( |
|
16 'common/entropy_common.c', |
|
17 'common/error_private.c', |
|
18 'common/fse_decompress.c', |
|
19 'common/xxhash.c', |
|
20 'common/zstd_common.c', |
|
21 'compress/fse_compress.c', |
|
22 'compress/huf_compress.c', |
|
23 'compress/zbuff_compress.c', |
|
24 'compress/zstd_compress.c', |
|
25 'decompress/huf_decompress.c', |
|
26 'decompress/zbuff_decompress.c', |
|
27 'decompress/zstd_decompress.c', |
|
28 'dictBuilder/divsufsort.c', |
|
29 'dictBuilder/zdict.c', |
|
30 )] |
|
31 |
|
32 INCLUDE_DIRS = [os.path.join(HERE, d) for d in ( |
|
33 'zstd', |
|
34 'zstd/common', |
|
35 'zstd/compress', |
|
36 'zstd/decompress', |
|
37 'zstd/dictBuilder', |
|
38 )] |
|
39 |
|
40 with open(os.path.join(HERE, 'zstd', 'zstd.h'), 'rb') as fh: |
|
41 zstd_h = fh.read() |
|
42 |
|
43 ffi = cffi.FFI() |
|
44 ffi.set_source('_zstd_cffi', ''' |
|
45 /* needed for typedefs like U32 references in zstd.h */ |
|
46 #include "mem.h" |
|
47 #define ZSTD_STATIC_LINKING_ONLY |
|
48 #include "zstd.h" |
|
49 ''', |
|
50 sources=SOURCES, include_dirs=INCLUDE_DIRS) |
|
51 |
|
52 # Rather than define the API definitions from zstd.h inline, munge the |
|
53 # source in a way that cdef() will accept. |
|
54 lines = zstd_h.splitlines() |
|
55 lines = [l.rstrip() for l in lines if l.strip()] |
|
56 |
|
57 # Strip preprocessor directives - they aren't important for our needs. |
|
58 lines = [l for l in lines |
|
59 if not l.startswith((b'#if', b'#else', b'#endif', b'#include'))] |
|
60 |
|
61 # Remove extern C block |
|
62 lines = [l for l in lines if l not in (b'extern "C" {', b'}')] |
|
63 |
|
64 # The version #defines don't parse and aren't necessary. Strip them. |
|
65 lines = [l for l in lines if not l.startswith(( |
|
66 b'#define ZSTD_H_235446', |
|
67 b'#define ZSTD_LIB_VERSION', |
|
68 b'#define ZSTD_QUOTE', |
|
69 b'#define ZSTD_EXPAND_AND_QUOTE', |
|
70 b'#define ZSTD_VERSION_STRING', |
|
71 b'#define ZSTD_VERSION_NUMBER'))] |
|
72 |
|
73 # The C parser also doesn't like some constant defines referencing |
|
74 # other constants. |
|
75 # TODO we pick the 64-bit constants here. We should assert somewhere |
|
76 # we're compiling for 64-bit. |
|
77 def fix_constants(l): |
|
78 if l.startswith(b'#define ZSTD_WINDOWLOG_MAX '): |
|
79 return b'#define ZSTD_WINDOWLOG_MAX 27' |
|
80 elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '): |
|
81 return b'#define ZSTD_CHAINLOG_MAX 28' |
|
82 elif l.startswith(b'#define ZSTD_HASHLOG_MAX '): |
|
83 return b'#define ZSTD_HASHLOG_MAX 27' |
|
84 elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '): |
|
85 return b'#define ZSTD_CHAINLOG_MAX 28' |
|
86 elif l.startswith(b'#define ZSTD_CHAINLOG_MIN '): |
|
87 return b'#define ZSTD_CHAINLOG_MIN 6' |
|
88 elif l.startswith(b'#define ZSTD_SEARCHLOG_MAX '): |
|
89 return b'#define ZSTD_SEARCHLOG_MAX 26' |
|
90 elif l.startswith(b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX '): |
|
91 return b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX 131072' |
|
92 else: |
|
93 return l |
|
94 lines = map(fix_constants, lines) |
|
95 |
|
96 # ZSTDLIB_API isn't handled correctly. Strip it. |
|
97 lines = [l for l in lines if not l.startswith(b'# define ZSTDLIB_API')] |
|
98 def strip_api(l): |
|
99 if l.startswith(b'ZSTDLIB_API '): |
|
100 return l[len(b'ZSTDLIB_API '):] |
|
101 else: |
|
102 return l |
|
103 lines = map(strip_api, lines) |
|
104 |
|
105 source = b'\n'.join(lines) |
|
106 ffi.cdef(source.decode('latin1')) |
|
107 |
|
108 |
|
109 if __name__ == '__main__': |
|
110 ffi.compile() |