Skip to content

Commit 696b55b

Browse files
authored
Merge pull request #25 from LinuxJedi/refactor-build
Refactor build to be more Python-like
2 parents 3c928b1 + 61d2f69 commit 696b55b

12 files changed

Lines changed: 233 additions & 264 deletions

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,7 @@ venv_*
6767

6868
# code editor preferences
6969
.vscode
70+
71+
# wolfSSL specific things
72+
wolfssl/_ffi*
73+
tmpdist/

setup.py

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,21 @@
2626
from setuptools import setup
2727
from setuptools.command.build_ext import build_ext
2828

29-
30-
import wolfssl
31-
from wolfssl._build_wolfssl import build_wolfssl
32-
from wolfssl._build_wolfssl import wolfssl_inc_path, wolfssl_lib_path
33-
29+
import re
30+
VERSIONFILE = "wolfssl/_version.py"
31+
verstrline = open(VERSIONFILE, "rt").read()
32+
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
33+
mo = re.search(VSRE, verstrline, re.M)
34+
if mo:
35+
verstr = mo.group(1)
36+
else:
37+
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
38+
VSRE = r"^__wolfssl_version__ = ['\"]([^'\"]*)['\"]"
39+
mo = re.search(VSRE, verstrline, re.M)
40+
if mo:
41+
wolfverstr = mo.group(1)
42+
else:
43+
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
3444

3545
# long_description
3646
with open("README.rst") as readme_file:
@@ -60,30 +70,16 @@ def verify_wolfssl_config():
6070
raise RuntimeError("wolfSSL needs to be compiled with "
6171
"--enable-opensslextra")
6272

63-
class cffiBuilder(build_ext, object):
64-
65-
def build_extension(self, ext):
66-
""" Compile manually the wolfssl-py extension, bypass setuptools
67-
"""
68-
69-
# if USE_LOCAL_WOLFSSL environment variable has been defined,
70-
# do not clone and compile wolfSSL from GitHub
71-
if os.environ.get("USE_LOCAL_WOLFSSL") is None:
72-
build_wolfssl(wolfssl.__wolfssl_version__)
73-
74-
verify_wolfssl_config()
75-
76-
super(cffiBuilder, self).build_extension(ext)
7773

7874
setup(
79-
name=wolfssl.__title__,
80-
version=wolfssl.__version__,
81-
description=wolfssl.__summary__,
75+
name="wolfssl",
76+
version=verstr,
77+
description="Python module that encapsulates wolfSSL's C SSL/TLS library.",
8278
long_description=long_description,
83-
author=wolfssl.__author__,
84-
author_email=wolfssl.__email__,
85-
url=wolfssl.__uri__,
86-
license=wolfssl.__license__,
79+
author="wolfSSL Inc.",
80+
author_email="info@wolfssl.com",
81+
url="https://github.com/wolfssl/wolfssl-py",
82+
license="GPLv2 or Commercial License",
8783

8884
packages=["wolfssl"],
8985

@@ -107,6 +103,5 @@ def build_extension(self, ext):
107103
setup_requires=["cffi"],
108104
install_requires=["cffi"],
109105
test_suite="tests",
110-
tests_require=["tox", "pytest"],
111-
cmdclass={"build_ext" : cffiBuilder}
106+
tests_require=["tox", "pytest"]
112107
)

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
envlist = py3
33

44
[testenv]
5+
wheel = true
56
setenv =
67
PYTHONPATH = {toxinidir}:{toxinidir}/wolfssl-py
78

wolfssl/__about__.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# __about__.py
44
#
5-
# Copyright (C) 2006-2020 wolfSSL Inc.
5+
# Copyright (C) 2006-2022 wolfSSL Inc.
66
#
77
# This file is part of wolfSSL. (formerly known as CyaSSL)
88
#
@@ -20,27 +20,17 @@
2020
# along with this program; if not, write to the Free Software
2121
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
2222

23+
from wolfssl._version import __version__, __wolfssl_version__
24+
2325
__title__ = "wolfssl"
2426
__summary__ = "Python module that encapsulates wolfSSL's C SSL/TLS library."
2527
__uri__ = "https://github.com/wolfssl/wolfssl-py"
2628

27-
# When bumping the C library version, reset the POST count to 0
28-
29-
__wolfssl_version__ = "v5.1.1-stable"
30-
31-
# We're using implicit post releases [PEP 440] to bump package version
32-
# while maintaining the C library version intact for better reference.
33-
# https://www.python.org/dev/peps/pep-0440/#implicit-post-releases
34-
#
35-
# MAJOR.MINOR.BUILD-POST
36-
37-
__version__ = __wolfssl_version__[1:].replace("stable", "0")
38-
3929
__author__ = "wolfSSL Inc."
4030
__email__ = "info@wolfssl.com"
4131

4232
__license__ = "GPLv2 or Commercial License"
43-
__copyright__ = "Copyright (C) 2006-2020 wolfSSL Inc"
33+
__copyright__ = "Copyright (C) 2006-2022 wolfSSL Inc"
4434

4535
__all__ = [
4636
"__title__", "__summary__", "__uri__", "__version__",

wolfssl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# __init__.py
44
#
5-
# Copyright (C) 2006-2020 wolfSSL Inc.
5+
# Copyright (C) 2006-2022 wolfSSL Inc.
66
#
77
# This file is part of wolfSSL. (formerly known as CyaSSL)
88
#

wolfssl/_build_ffi.py

Lines changed: 185 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# build_ffi.py
44
#
5-
# Copyright (C) 2006-2020 wolfSSL Inc.
5+
# Copyright (C) 2006-2022 wolfSSL Inc.
66
#
77
# This file is part of wolfSSL. (formerly known as CyaSSL)
88
#
@@ -22,10 +22,11 @@
2222

2323
# pylint: disable=missing-docstring, invalid-name
2424

25+
import argparse
26+
from contextlib import contextmanager
2527
from distutils.util import get_platform
2628
from cffi import FFI
27-
from wolfssl._build_wolfssl import wolfssl_inc_path, wolfssl_lib_path, ensure_wolfssl_src, make, make_flags, local_path
28-
from wolfssl.__about__ import __wolfssl_version__ as version
29+
from wolfssl._version import __wolfssl_version__ as version
2930
import wolfssl._openssl as openssl
3031
import subprocess
3132
import shlex
@@ -35,6 +36,180 @@
3536

3637
libwolfssl_path = ""
3738

39+
40+
def local_path(path):
41+
""" Return path relative to the root of this project
42+
"""
43+
current = os.path.abspath(os.getcwd())
44+
return os.path.abspath(os.path.join(current, path))
45+
46+
47+
WOLFSSL_SRC_PATH = local_path("lib/wolfssl")
48+
49+
50+
def wolfssl_inc_path():
51+
wolfssl_path = os.environ.get("USE_LOCAL_WOLFSSL")
52+
if wolfssl_path is None:
53+
return local_path("lib/wolfssl")
54+
else:
55+
if os.path.isdir(wolfssl_path) and os.path.exists(wolfssl_path):
56+
return wolfssl_path + "/include"
57+
else:
58+
return "/usr/local/include"
59+
60+
61+
def wolfssl_lib_path():
62+
wolfssl_path = os.environ.get("USE_LOCAL_WOLFSSL")
63+
if wolfssl_path is None:
64+
return local_path("lib/wolfssl/{}/{}/lib".format(
65+
get_platform(), version))
66+
else:
67+
if os.path.isdir(wolfssl_path) and os.path.exists(wolfssl_path):
68+
return wolfssl_path + "/lib"
69+
else:
70+
return "/usr/local/lib"
71+
72+
73+
def call(cmd):
74+
print("Calling: '{}' from working directory {}".format(cmd, os.getcwd()))
75+
76+
old_env = os.environ["PATH"]
77+
os.environ["PATH"] = "{}:{}".format(WOLFSSL_SRC_PATH, old_env)
78+
subprocess.check_call(cmd, shell=True, env=os.environ)
79+
os.environ["PATH"] = old_env
80+
81+
82+
@contextmanager
83+
def chdir(new_path, mkdir=False):
84+
old_path = os.getcwd()
85+
86+
if mkdir:
87+
try:
88+
os.mkdir(new_path)
89+
except OSError:
90+
pass
91+
92+
try:
93+
yield os.chdir(new_path)
94+
finally:
95+
os.chdir(old_path)
96+
97+
98+
def checkout_ref(ref):
99+
""" Ensure that we have the right version
100+
"""
101+
with chdir(WOLFSSL_SRC_PATH):
102+
current = ""
103+
try:
104+
current = subprocess.check_output(
105+
["git", "describe", "--all", "--exact-match"]
106+
).strip().decode().split('/')[-1]
107+
except:
108+
pass
109+
110+
if current != ref:
111+
tags = subprocess.check_output(
112+
["git", "tag"]
113+
).strip().decode().split("\n")
114+
115+
if ref != "master" and ref not in tags:
116+
call("git fetch --depth=1 origin tag {}".format(ref))
117+
118+
call("git checkout --force {}".format(ref))
119+
120+
return True # rebuild needed
121+
122+
return False
123+
124+
125+
def ensure_wolfssl_src(ref):
126+
""" Ensure that wolfssl sources are presents and up-to-date
127+
"""
128+
if not os.path.isdir("lib"):
129+
os.mkdir("lib")
130+
with chdir("lib"):
131+
subprocess.run(["git", "clone", "--depth=1", "https://github.com/wolfssl/wolfssl"])
132+
133+
if not os.path.isdir(os.path.join(WOLFSSL_SRC_PATH, "wolfssl")):
134+
subprocess.run(["git", "submodule", "update", "--init", "--depth=1"])
135+
136+
return checkout_ref(ref)
137+
138+
139+
def make_flags(prefix, debug):
140+
""" Returns compilation flags
141+
"""
142+
flags = []
143+
cflags = []
144+
145+
if get_platform() in ["linux-x86_64", "linux-i686"]:
146+
cflags.append("-fpic")
147+
148+
# install location
149+
flags.append("--prefix={}".format(prefix))
150+
151+
# lib only
152+
flags.append("--disable-shared")
153+
flags.append("--disable-examples")
154+
155+
# tls 1.3
156+
flags.append("--enable-tls13")
157+
flags.append("--enable-sslv3")
158+
159+
# for urllib3 - requires SNI (tlsx), options (openssl compat), peer cert
160+
flags.append("--enable-tlsx")
161+
flags.append("--enable-opensslextra")
162+
cflags.append("-DKEEP_PEER_CERT")
163+
164+
# for pyOpenSSL
165+
flags.append("--enable-secure-renegotiation")
166+
flags.append("--enable-opensslall")
167+
cflags.append("-DFP_MAX_BITS=8192")
168+
cflags.append("-DHAVE_EX_DATA")
169+
cflags.append("-DOPENSSL_COMPATIBLE_DEFAULTS")
170+
171+
if debug:
172+
flags.append("--enable-debug")
173+
174+
# Note: websocket-client test server (echo.websocket.org) only supports
175+
# TLS 1.2 with TLS_RSA_WITH_AES_128_CBC_SHA
176+
# If compiling for use with websocket-client, must enable static RSA suites.
177+
# cflags.append("-DWOLFSSL_STATIC_RSA")
178+
179+
joined_flags = " ".join(flags)
180+
joined_cflags = " ".join(cflags)
181+
182+
return joined_flags + " CFLAGS=\"" + joined_cflags + "\""
183+
184+
185+
def make(configure_flags):
186+
""" Create a release of wolfSSL C library
187+
"""
188+
with chdir(WOLFSSL_SRC_PATH):
189+
call("git clean -fdX")
190+
191+
try:
192+
call("./autogen.sh")
193+
except subprocess.CalledProcessError:
194+
call("libtoolize")
195+
call("./autogen.sh")
196+
197+
call("./configure {}".format(configure_flags))
198+
call("make")
199+
call("make install")
200+
201+
202+
def build_wolfssl(ref, debug=False):
203+
prefix = local_path("lib/wolfssl/{}/{}".format(
204+
get_platform(), ref))
205+
libfile = os.path.join(prefix, 'lib/libwolfssl.la')
206+
207+
rebuild = ensure_wolfssl_src(ref)
208+
209+
if rebuild or not os.path.isfile(libfile):
210+
make(make_flags(prefix, debug))
211+
212+
38213
def make_optional_func_list(libwolfssl_path, funcs):
39214
if libwolfssl_path.endswith(".so"):
40215
libwolfssl = cdll.LoadLibrary(libwolfssl_path)
@@ -55,6 +230,7 @@ def make_optional_func_list(libwolfssl_path, funcs):
55230

56231
return defined
57232

233+
58234
def get_libwolfssl():
59235
libwolfssl_path = os.path.join(wolfssl_lib_path(), "libwolfssl.a")
60236
if not os.path.exists(libwolfssl_path):
@@ -66,13 +242,16 @@ def get_libwolfssl():
66242
else:
67243
return 1
68244

245+
69246
def generate_libwolfssl():
70247
ensure_wolfssl_src(version)
71248
prefix = local_path("lib/wolfssl/{}/{}".format(
72249
get_platform(), version))
73250
make(make_flags(prefix, False))
74251

75-
if get_libwolfssl() == 0:
252+
253+
local_wolfssl = os.environ.get("USE_LOCAL_WOLFSSL")
254+
if local_wolfssl and get_libwolfssl() == 0:
76255
generate_libwolfssl()
77256
get_libwolfssl()
78257

@@ -294,4 +473,5 @@ def generate_libwolfssl():
294473
ffi_cdef = cdef + openssl.construct_cdef(optional_funcs)
295474
ffi.cdef(ffi_cdef)
296475

297-
ffi.compile(verbose=True)
476+
if __name__ == "__main__":
477+
ffi.compile(verbose=True)

0 commit comments

Comments
 (0)