Skip to content

Commit 8bd6f61

Browse files
committed
Added setup.py and related config files
1 parent 0bfa19d commit 8bd6f61

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
global-exclude *.dll* *.dylib* *.so*

pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build-system]
2+
requires = ["GitPython", "cmake>=3.14", "setuptools>=30.3.0", "wheel>=0.25"]

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cffi>=1.10

setup.cfg

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[metadata]
2+
name = atomics
3+
version = 0.1.0b0
4+
description = Atomic lock-free primitives
5+
long_description = file: README.md
6+
long_description_content_type = text/markdown
7+
keywords = atomic, atomics, lock-free, lock free
8+
url = https://github.com/doodspav/atomics
9+
author = doodspav
10+
author_email = [email protected]
11+
license_file = LICENSE.txt
12+
platforms = any
13+
classifiers =
14+
Development Status :: 4 - Beta
15+
Intended Audience :: Developers
16+
Topic :: System :: Hardware :: Symmetric Multi-processing
17+
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
18+
Operating System :: OS Independent
19+
Programming Language :: C
20+
Programming Language :: Python :: 3
21+
Programming Language :: Python :: 3 :: Only
22+
Programming Language :: Python :: 3.6
23+
Programming Language :: Python :: 3.7
24+
Programming Language :: Python :: 3.8
25+
Programming Language :: Python :: 3.9
26+
Programming Language :: Python :: 3.10
27+
Programming Language :: Python :: 3.11
28+
Programming Language :: Python :: Implementation :: CPython
29+
Programming Language :: Python :: Implementation :: PyPy
30+
download_url = https://github.com/doodspav/atomics
31+
project_urls =
32+
patomic-source=https://github.com/doodspav/patomic
33+
atomics-source=https://github.com/doodspav/atomics
34+
35+
[options]
36+
python_requires = >=3.6, <4

setup.py

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
from distutils.cmd import Command
2+
from setuptools import setup, find_packages
3+
from setuptools.command import build_py
4+
from wheel.bdist_wheel import bdist_wheel
5+
6+
import git
7+
import os
8+
import pathlib
9+
import subprocess
10+
import sys
11+
import tempfile
12+
13+
14+
here = pathlib.Path(__file__).parent.resolve()
15+
16+
17+
class BdistWheelCommand(bdist_wheel):
18+
19+
def finalize_options(self):
20+
super().finalize_options()
21+
self.root_is_pure = False
22+
23+
def get_tag(self):
24+
python, abi, plat = super().get_tag()
25+
return python, "none", plat
26+
27+
28+
class BuildPatomicCommand(Command):
29+
30+
description = "Build patomic shared library"
31+
user_options = [
32+
("git-url=", 'u', "[str] URL to patomic git repo"),
33+
("git-tag=", 't', "[str] Tag of commit to use from git repo"),
34+
("dst-dir=", 'd', "[str] Directory to place patomic shared library"),
35+
("build-type=", 'b', "[str] CMake build type to use when building patomic"),
36+
("force-replace=", 'f', "[bool] Whether to replace existing patomic shared library file(s)"),
37+
("verbose-cmake=", None, "[bool] Whether to print CMake output to stdout"),
38+
("c-compiler=", 'c', "[str] C compiler executable"),
39+
("c-standard=", 's', "[int] ISO C Standard to pass to the compiler")
40+
]
41+
42+
def initialize_options(self) -> None:
43+
self.git_url = "https://github.com/doodspav/patomic"
44+
self.git_tag = None
45+
self.dst_dir = here / "src" / "atomics" / "_clib"
46+
self.build_type = "Release"
47+
self.force_replace = False
48+
self.verbose_cmake = False
49+
self.c_compiler = None
50+
self.c_standard = 11
51+
52+
def finalize_options(self) -> None:
53+
if type(self.dst_dir) is not pathlib.Path:
54+
self.dst_dir = pathlib.Path(self.dst_dir).resolve()
55+
if self.c_compiler in [89, 95]:
56+
self.c_compiler = 90
57+
if self.git_tag is not None:
58+
raise RuntimeError(f"Option 'git-tag' (set to: {self.git_tag}) not supported.")
59+
60+
@staticmethod
61+
def get_patomic_libs(dir_path: pathlib.Path) -> [pathlib.Path]:
62+
"""Returns a list of patomic shared library files found in dir_path"""
63+
assert dir_path.is_dir()
64+
exts = [".dll", ".dylib", ".so"]
65+
files = [p for p in dir_path.iterdir() if p.is_file()]
66+
libs = [f for f in files if any(map(str(f).__contains__, exts))]
67+
patomic_libs = [f for f in libs if "patomic" in str(f)]
68+
return patomic_libs
69+
70+
def clone_patomic(self, clone_to: pathlib.Path) -> None:
71+
"""Clones self.git_url into clone_to directory path"""
72+
assert clone_to.is_dir()
73+
# clone default branch
74+
repo = git.Repo.clone_from(url=self.git_url, to_path=str(clone_to))
75+
# switch to devel branch if main isn't populated
76+
if not (clone_to / "src").is_dir():
77+
repo.git.checkout("devel")
78+
79+
def build_patomic(self, repo_dir: pathlib.Path) -> pathlib.Path:
80+
"""Builds patomic shared library in repo_dir and returns library file path"""
81+
assert repo_dir.is_dir()
82+
use_shell = (os.name == "nt")
83+
fd_out = sys.stdout if self.verbose_cmake else subprocess.DEVNULL
84+
# configure build directory
85+
os.mkdir(str(repo_dir / "build"))
86+
cmd_config = [
87+
"cmake", "-S", repo_dir, "-B", repo_dir / "build",
88+
f"-DCMAKE_BUILD_TYPE={self.build_type}",
89+
f"-DCMAKE_C_STANDARD={self.c_standard}",
90+
"-DBUILD_SHARED_LIBS=ON"
91+
]
92+
if self.c_compiler:
93+
cmd_config.append(f"-DCMAKE_C_COMPILER={self.c_compiler}")
94+
subprocess.check_call(cmd_config, stdout=fd_out, shell=use_shell)
95+
# build
96+
out_path = repo_dir / "build"
97+
cmd_build = ["cmake", "--build", out_path, "--config", self.build_type]
98+
subprocess.check_call(cmd_build, stdout=fd_out, shell=use_shell)
99+
# check if using multi-config generator
100+
if (out_path / self.build_type).is_dir():
101+
out_path /= self.build_type
102+
lib_paths = self.get_patomic_libs(out_path)
103+
lib_paths.sort(reverse=True)
104+
assert lib_paths, "Should not be empty of CMake succeeds"
105+
return lib_paths[0]
106+
107+
def run(self):
108+
dst_dir = pathlib.Path(self.dst_dir).resolve()
109+
existing_libs = self.get_patomic_libs(dst_dir)
110+
# check whether we replace any existing files
111+
if existing_libs and not self.force_replace:
112+
print("[build_patomic] skipping; library already built")
113+
return
114+
# create shared library and copy over
115+
with tempfile.TemporaryDirectory() as temp_dir:
116+
repo_path = pathlib.Path(temp_dir)
117+
print("[build_patomic] cloning repo")
118+
self.clone_patomic(repo_path)
119+
print("[build_patomic] building shared library")
120+
lib_path = self.build_patomic(repo_path)
121+
if self.force_replace and existing_libs:
122+
print("[build_patomic] removing existing shared library file(s)")
123+
for el in existing_libs:
124+
el.unlink(missing_ok=True)
125+
print("[build_patomic] copying over shared library")
126+
os.rename(str(lib_path), str(self.dst_dir / lib_path.name))
127+
128+
129+
class BuildPyCommand(build_py.build_py):
130+
131+
def run(self):
132+
self.run_command("build_patomic")
133+
build_py.build_py.run(self)
134+
135+
136+
setup(
137+
packages=find_packages(where="src"),
138+
package_dir={"": "src"},
139+
package_data={"atomics": ["_clib/*"]},
140+
cmdclass={
141+
"bdist_wheel": BdistWheelCommand,
142+
"build_patomic": BuildPatomicCommand,
143+
"build_py": BuildPyCommand,
144+
}
145+
)

0 commit comments

Comments
 (0)