Skip to content

Commit 42865d6

Browse files
committed
Use meson to build C extensions
1 parent 7f6d069 commit 42865d6

File tree

5 files changed

+92
-78
lines changed

5 files changed

+92
-78
lines changed

build.py

Lines changed: 17 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,32 @@
1-
import os
2-
import shutil
3-
import sys
1+
import subprocess
42

5-
from distutils.command.build_ext import build_ext
6-
from distutils.core import Distribution
7-
from distutils.core import Extension
8-
from distutils.errors import CCompilerError
9-
from distutils.errors import DistutilsExecError
10-
from distutils.errors import DistutilsPlatformError
3+
from pathlib import Path
114

125

13-
# C Extensions
14-
with_extensions = os.getenv("PENDULUM_EXTENSIONS", None)
6+
def meson(*args):
7+
subprocess.call(["meson"] + list(args))
158

16-
if with_extensions == "1" or with_extensions is None:
17-
with_extensions = True
189

19-
if with_extensions == "0" or hasattr(sys, "pypy_version_info"):
20-
with_extensions = False
10+
def _build():
11+
build_dir = Path(__file__).parent.joinpath("build")
12+
build_dir.mkdir(parents=True, exist_ok=True)
2113

22-
extensions = []
23-
if with_extensions:
24-
extensions = [
25-
Extension("pendulum._extensions._helpers", ["pendulum/_extensions/_helpers.c"]),
26-
Extension("pendulum.parsing._iso8601", ["pendulum/parsing/_iso8601.c"]),
27-
]
28-
29-
30-
class BuildFailed(Exception):
31-
32-
pass
33-
34-
35-
class ExtBuilder(build_ext):
36-
# This class allows C extension building to fail.
37-
38-
built_extensions = []
39-
40-
def run(self):
41-
try:
42-
build_ext.run(self)
43-
except (DistutilsPlatformError, FileNotFoundError):
44-
print(
45-
" Unable to build the C extensions, "
46-
"Pendulum will use the pure python code instead."
47-
)
48-
49-
def build_extension(self, ext):
50-
try:
51-
build_ext.build_extension(self, ext)
52-
except (CCompilerError, DistutilsExecError, DistutilsPlatformError, ValueError):
53-
print(
54-
f' Unable to build the "{ext.name}" C extension, '
55-
"Pendulum will use the pure python version of the extension."
56-
)
14+
meson("setup", build_dir.as_posix())
15+
meson("compile", "-C", build_dir.as_posix())
16+
meson("install", "-C", build_dir.as_posix())
5717

5818

5919
def build(setup_kwargs):
6020
"""
6121
This function is mandatory in order to build the extensions.
6222
"""
63-
distribution = Distribution({"name": "pendulum", "ext_modules": extensions})
64-
distribution.package_dir = "pendulum"
65-
66-
cmd = ExtBuilder(distribution)
67-
cmd.ensure_finalized()
68-
cmd.run()
69-
70-
# Copy built extensions back to the project
71-
for output in cmd.get_outputs():
72-
relative_extension = os.path.relpath(output, cmd.build_lib)
73-
if not os.path.exists(output):
74-
continue
75-
76-
shutil.copyfile(output, relative_extension)
77-
mode = os.stat(relative_extension).st_mode
78-
mode |= (mode & 0o444) >> 2
79-
os.chmod(relative_extension, mode)
80-
81-
return setup_kwargs
23+
try:
24+
_build()
25+
except Exception:
26+
print(
27+
" Unable to build C extensions, "
28+
"Pendulum will use the pure python version of the extensions."
29+
)
8230

8331

8432
if __name__ == "__main__":

meson.build

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
project('pendulum C extensions', 'c')
2+
3+
py_mod = import('python')
4+
py = py_mod.find_installation()
5+
py_dep = py.dependency()
6+
7+
extensions = [
8+
['_helpers', 'pendulum/_extensions/_helpers.c', meson.source_root() / 'pendulum/_extensions/'],
9+
['_iso8601', 'pendulum/parsing/_iso8601.c', meson.source_root() / 'pendulum/parsing/'],
10+
]
11+
12+
foreach extension : extensions
13+
py.extension_module(
14+
extension[0],
15+
extension[1],
16+
dependencies : py_dep,
17+
install : true,
18+
install_dir: extension[2]
19+
)
20+
endforeach

pendulum/parsing/_iso8601.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
522522
int leap = 0;
523523
int separators = 0;
524524
int time = 0;
525-
int has_hour = 0;
526525
int i;
527526
int j;
528527

@@ -773,7 +772,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
773772
}
774773

775774
parsed->hour = time;
776-
has_hour = 1;
777775
break;
778776
case 4:
779777
// Hours and minutes
@@ -786,7 +784,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
786784

787785
parsed->hour = time / 100;
788786
parsed->minute = time % 100;
789-
has_hour = 1;
790787
break;
791788
case 6:
792789
// Hours, minutes and seconds
@@ -800,7 +797,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
800797
parsed->hour = time / 10000;
801798
parsed->minute = time / 100 % 100;
802799
parsed->second = time % 100;
803-
has_hour = 1;
804800
break;
805801
default:
806802
// Any other case is wrong
@@ -942,7 +938,6 @@ Parsed* _parse_iso8601_duration(char *str, Parsed *parsed) {
942938
int fraction = 0;
943939
int has_ymd = 0;
944940
int has_week = 0;
945-
int has_year = 0;
946941
int has_month = 0;
947942
int has_day = 0;
948943
int has_hour = 0;
@@ -979,7 +974,6 @@ Parsed* _parse_iso8601_duration(char *str, Parsed *parsed) {
979974
fraction = 0;
980975
in_fraction = 0;
981976
has_ymd = 1;
982-
has_year = 1;
983977

984978
break;
985979
case 'M':

poetry.lock

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

pyproject.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ keywords = ['datetime', 'date', 'time']
1212

1313
packages = [
1414
{ include = "pendulum" },
15-
#{include = "tests", format = "sdist"},
15+
{ include = "tests", format = "sdist" },
1616
]
1717
include = [
18+
{ path = "meson.build", format = "sdist" },
1819
{ path = "pendulum/py.typed" },
1920
# C extensions must be included in the wheel distributions
2021
{ path = "pendulum/_extensions/*.so", format = "wheel" },
@@ -56,6 +57,13 @@ babel = "^2.10.3"
5657
cleo = "^1.0.0a5"
5758
tox = "^3.25.1"
5859

60+
[tool.poetry.group.build]
61+
optional = true
62+
63+
[tool.poetry.group.build.dependencies]
64+
meson = "^0.63.2"
65+
ninja = "^1.10.2.3"
66+
5967
[tool.poetry.build]
6068
generate-setup-file = false
6169
script = "build.py"
@@ -171,5 +179,5 @@ omit = [
171179
]
172180

173181
[build-system]
174-
requires = ["poetry-core>=1.1.0a6"]
182+
requires = ["poetry-core>=1.1.0a6", "meson", "ninja"]
175183
build-backend = "poetry.core.masonry.api"

0 commit comments

Comments
 (0)