contrib/python-zstandard/make_cffi.py
author Yuya Nishihara <yuya@tcha.org>
Sat, 15 Oct 2016 13:47:43 +0900
changeset 30506 d9d8d78e6bc9
parent 30435 b86a448a2965
child 30822 b54a2984cdd4
permissions -rw-r--r--
server: move cmdutil.service() to new module (API) And call it runservice() because I'll soon add createservice(). The main reason I'm going to introduce the 'server' module is to solve future dependency cycle between chgserver.py and commandserver.py. The 'server' module sits at the same layer as the cmdutil. I believe it's generally good to get rid of things from the big cmdutil module.

# Copyright (c) 2016-present, Gregory Szorc
# All rights reserved.
#
# This software may be modified and distributed under the terms
# of the BSD license. See the LICENSE file for details.

from __future__ import absolute_import

import cffi
import os


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

SOURCES = ['zstd/%s' % p for p in (
    'common/entropy_common.c',
    'common/error_private.c',
    'common/fse_decompress.c',
    'common/xxhash.c',
    'common/zstd_common.c',
    'compress/fse_compress.c',
    'compress/huf_compress.c',
    'compress/zbuff_compress.c',
    'compress/zstd_compress.c',
    'decompress/huf_decompress.c',
    'decompress/zbuff_decompress.c',
    'decompress/zstd_decompress.c',
    'dictBuilder/divsufsort.c',
    'dictBuilder/zdict.c',
)]

INCLUDE_DIRS = [os.path.join(HERE, d) for d in (
    'zstd',
    'zstd/common',
    'zstd/compress',
    'zstd/decompress',
    'zstd/dictBuilder',
)]

with open(os.path.join(HERE, 'zstd', 'zstd.h'), 'rb') as fh:
    zstd_h = fh.read()

ffi = cffi.FFI()
ffi.set_source('_zstd_cffi', '''
/* needed for typedefs like U32 references in zstd.h */
#include "mem.h"
#define ZSTD_STATIC_LINKING_ONLY
#include "zstd.h"
''',
    sources=SOURCES, include_dirs=INCLUDE_DIRS)

# Rather than define the API definitions from zstd.h inline, munge the
# source in a way that cdef() will accept.
lines = zstd_h.splitlines()
lines = [l.rstrip() for l in lines if l.strip()]

# Strip preprocessor directives - they aren't important for our needs.
lines = [l for l in lines
         if not l.startswith((b'#if', b'#else', b'#endif', b'#include'))]

# Remove extern C block
lines = [l for l in lines if l not in (b'extern "C" {', b'}')]

# The version #defines don't parse and aren't necessary. Strip them.
lines = [l for l in lines if not l.startswith((
    b'#define ZSTD_H_235446',
    b'#define ZSTD_LIB_VERSION',
    b'#define ZSTD_QUOTE',
    b'#define ZSTD_EXPAND_AND_QUOTE',
    b'#define ZSTD_VERSION_STRING',
    b'#define ZSTD_VERSION_NUMBER'))]

# The C parser also doesn't like some constant defines referencing
# other constants.
# TODO we pick the 64-bit constants here. We should assert somewhere
# we're compiling for 64-bit.
def fix_constants(l):
    if l.startswith(b'#define ZSTD_WINDOWLOG_MAX '):
        return b'#define ZSTD_WINDOWLOG_MAX 27'
    elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '):
        return b'#define ZSTD_CHAINLOG_MAX 28'
    elif l.startswith(b'#define ZSTD_HASHLOG_MAX '):
        return b'#define ZSTD_HASHLOG_MAX 27'
    elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '):
        return b'#define ZSTD_CHAINLOG_MAX 28'
    elif l.startswith(b'#define ZSTD_CHAINLOG_MIN '):
        return b'#define ZSTD_CHAINLOG_MIN 6'
    elif l.startswith(b'#define ZSTD_SEARCHLOG_MAX '):
        return b'#define ZSTD_SEARCHLOG_MAX 26'
    elif l.startswith(b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX '):
        return b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX 131072'
    else:
        return l
lines = map(fix_constants, lines)

# ZSTDLIB_API isn't handled correctly. Strip it.
lines = [l for l in lines if not l.startswith(b'#  define ZSTDLIB_API')]
def strip_api(l):
    if l.startswith(b'ZSTDLIB_API '):
        return l[len(b'ZSTDLIB_API '):]
    else:
        return l
lines = map(strip_api, lines)

source = b'\n'.join(lines)
ffi.cdef(source.decode('latin1'))


if __name__ == '__main__':
    ffi.compile()