File: build.py

package info (click to toggle)
python-xeddsa 0.4.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 884 kB
  • sloc: ansic: 5,442; python: 525; makefile: 5
file content (166 lines) | stat: -rw-r--r-- 5,095 bytes parent folder | download | duplicates (2)
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
from __future__ import absolute_import
from __future__ import print_function

import cffi
import os
import subprocess
import sys
import zipfile

try:
    # Python 3
    from urllib.request import urlopen
except:
    # Python 2
    from urllib2 import urlopen

ref10_dir  = os.path.abspath("ref10")
module_dir = os.path.join(ref10_dir, "crypto_sign")
bin_dir    = os.path.join(ref10_dir, "bin")
build_dir  = os.path.join(ref10_dir, "build")

library_header = os.path.join(module_dir, "module.h")

try:
    os.mkdir(build_dir)
except OSError:
    pass

libraries = [
    "crypto_sign_static",
    "crypto_hash_static",
    "crypto_hashblocks_static",
    "crypto_verify_static",
    "fastrandombytes_static",
    "kernelrandombytes_static",
    "crypto_rng_static",
    "crypto_stream_static",
    "crypto_core_static"
]

class UnknownSystemException(Exception):
    pass

def call_cmake(output):
    try:
        # Try to call CMake
        subprocess.check_call([ "cmake", "-G", output, ".." ], cwd = build_dir)
    except FileNotFoundError:
        # If that call fails, try to install CMake using the "cmake" package.

        # First, try to install it with --user
        try:
            subprocess.check_call([
                sys.executable,
                "-m",
                "pip",
                "install",
                "cmake",
                "--user"
            ])

            # Make sure the newly installed CMake executables can be found in the path
            os.path.append(os.path.expanduser("~/.local/bin"))
        except subprocess.CalledProcessError:
            # If installing with --user fails, try a global installation
            subprocess.check_call([
                sys.executable,
                "-m",
                "pip",
                "install",
                "cmake"
            ])

        # If either of the local or global installations worked, try again.
        subprocess.check_call([ "cmake", "-G", output, ".." ], cwd = build_dir)

if os.name == "posix":
    # On UNIX, we HAVE to make the ref10 libraries, because the kernelrandombytes module
    # can vary between different UNIX systems.
    print("Attempting to compile the ref10 library...")
    print("The compilation requires CMake and the \"make\" tool.")
    print("The \"cmake\" and \"make\" commands are used.")

    call_cmake("Unix Makefiles")
    subprocess.check_call([ "make" ], cwd = build_dir)

    print("Library built successfully!")
elif os.name == "nt":
    libraries += [ "ADVAPI32" ]

    # On Windows, there is only one possible version of the kernelrandombytes module:
    # rtlgenrandom. Thus, precompiled binaries can be used.
    print("Attempting to compile the ref10 library...")
    print("The compilation requires CMake and a MinGW environment.")
    print("The \"cmake\" and \"mingw32-make\" commands are used.")

    try:
        call_cmake("MinGW Makefiles")
        subprocess.check_call([ "mingw32-make" ], cwd = build_dir)

        print("Library built successfully!")
    except subprocess.CalledProcessError:
        print("Compiling the ref10 library failed.")
        print("Attempting to download precompiled binaries...")

        # The recommended way to detect 64-bit and 32-bit systems according to
        # https://docs.python.org/3/library/platform.html#cross-platform
        is_32bit = sys.maxsize == 2 ** 31 - 1
        is_64bit = sys.maxsize == 2 ** 63 - 1

        if not is_32bit and not is_64bit:
            raise UnknownSystemException(
                "This system was detected as neither 32-bit nor 64-bit."
            )

        precompiled_windows_32bit = (
            "https://github.com/Syndace/python-xeddsa/releases/download/v0.4.3-beta/" +
            "bin-windows-x86.zip"
        )

        precompiled_windows_64bit = (
            "https://github.com/Syndace/python-xeddsa/releases/download/v0.4.3-beta/" +
            "bin-windows-amd64.zip"
        )

        url = precompiled_windows_64bit if is_64bit else precompiled_windows_32bit

        zip_location = os.path.join(ref10_dir, "bin.zip")

        print("Downloading precompiled binaries...")
        print("Make sure the system can access https://github.com.")

        zip_memory = urlopen(url)
        with open(zip_location, "wb") as zip_file:
            zip_file.write(zip_memory.read())
        zip_memory.close()

        binaries_zipfile = zipfile.ZipFile(zip_location)
        binaries_zipfile.extractall(ref10_dir)
        binaries_zipfile.close()

        os.remove(zip_location)

        print("Precompiled binaries downloaded!")
else:
    raise UnknownSystemException(
        "Unsupported operating system (neither UNIX nor Windows)."
    )

ffibuilder = cffi.FFI()

# Load the header.
with open(library_header) as f:
    ffibuilder.cdef(f.read())

# Define how to compile the python module.
ffibuilder.set_source(
    "_crypto_sign",
    '#include "' + library_header + '"',
    library_dirs = [ bin_dir ],
    libraries    = libraries
)

if __name__ == "__main__":
    # Compile the code into a python module.
    ffibuilder.compile()