ci: Drop CentOS 8 Stream and switch F38 to 40, Ubuntu 20.04 to 22.04
[libvirt-python.git] / setup.py
blobb1c87e80f22a33f494d065dd77e1da7f78d992c5
1 #!/usr/bin/env python3
3 import sys
4 import re
5 import shutil
6 import subprocess
7 import time
9 from pathlib import Path
10 from setuptools import setup, Extension
11 from setuptools.command.build_ext import build_ext
12 from setuptools.command.build_py import build_py
13 from setuptools.command.sdist import sdist
16 def getVersion():
17 with open("VERSION") as f:
18 return f.read().strip()
21 def check_pkgcfg():
22 try:
23 proc = subprocess.run(["pkg-config", "--version"],
24 stdout=subprocess.DEVNULL,
25 stderr=subprocess.DEVNULL)
26 if proc.returncode != 0:
27 print("pkg-config binary does not appear to be functional")
28 sys.exit(1)
29 except FileNotFoundError:
30 print("pkg-config binary is required to compile libvirt-python")
31 sys.exit(1)
34 def check_minimum_libvirt_version():
35 subprocess.check_call(["pkg-config",
36 "--print-errors",
37 f"--atleast-version={MIN_LIBVIRT}",
38 "libvirt"])
41 def have_libvirt_lxc():
42 proc = subprocess.run(["pkg-config",
43 f"--atleast-version={MIN_LIBVIRT_LXC}",
44 "libvirt"])
45 if proc.returncode == 0:
46 return True
47 return False
50 def get_pkgconfig_data(args, mod, required=True):
51 """Run pkg-config to and return content associated with it"""
53 cmd = ["pkg-config"] + args + [mod]
54 output = subprocess.check_output(cmd, universal_newlines=True)
55 for line in output.splitlines():
56 if line == "":
57 if required:
58 args_str = " ".join(args)
59 raise Exception(f"Cannot determine '{args_str}' from "
60 "libvirt pkg-config file")
61 line = ""
62 return line.strip()
65 def get_api_xml_files():
66 """Check with pkg-config that libvirt is present and extract
67 the API XML file paths we need from it"""
69 libvirt_api = get_pkgconfig_data(["--variable", "libvirt_api"], "libvirt")
71 offset = libvirt_api.index("-api.xml")
72 libvirt_qemu_api = libvirt_api[0:offset] + "-qemu-api.xml"
74 offset = libvirt_api.index("-api.xml")
75 libvirt_lxc_api = libvirt_api[0:offset] + "-lxc-api.xml"
77 return (libvirt_api, libvirt_qemu_api, libvirt_lxc_api)
80 def get_module_lists():
81 """
82 Determine which modules we are actually building, and all their
83 required config
84 """
85 c_modules = []
86 py_modules = []
87 ldflags = get_pkgconfig_data(["--libs-only-L"], "libvirt", False).split()
88 cflags = get_pkgconfig_data(["--cflags"], "libvirt", False).split()
90 cflags += ["-Ibuild"]
91 cflags += ["-Wp,-DPy_LIMITED_API=0x03060000"]
93 module = Extension("libvirtmod",
94 sources=[
95 "libvirt-override.c",
96 "build/libvirt.c",
97 "typewrappers.c",
98 "libvirt-utils.c"
100 libraries=["virt"],
101 include_dirs=["."])
102 module.extra_compile_args.extend(cflags)
103 module.extra_link_args.extend(ldflags)
105 c_modules.append(module)
106 py_modules.append("libvirt")
108 moduleqemu = Extension("libvirtmod_qemu",
109 sources=[
110 "libvirt-qemu-override.c",
111 "build/libvirt-qemu.c",
112 "typewrappers.c",
113 "libvirt-utils.c"
115 libraries=["virt-qemu", "virt"],
116 include_dirs=["."])
117 moduleqemu.extra_compile_args.extend(cflags)
118 moduleqemu.extra_link_args.extend(ldflags)
120 c_modules.append(moduleqemu)
121 py_modules.append("libvirt_qemu")
123 if have_libvirt_lxc():
124 modulelxc = Extension("libvirtmod_lxc",
125 sources=[
126 "libvirt-lxc-override.c",
127 "build/libvirt-lxc.c",
128 "typewrappers.c",
129 "libvirt-utils.c"
131 libraries=["virt-lxc", "virt"],
132 include_dirs=["."])
133 modulelxc.extra_compile_args.extend(cflags)
134 modulelxc.extra_link_args.extend(ldflags)
136 c_modules.append(modulelxc)
137 py_modules.append("libvirt_lxc")
139 py_modules.append("libvirtaio")
141 return c_modules, py_modules
144 ###################
145 # Custom commands #
146 ###################
148 class my_build_ext(build_ext):
150 def run(self):
151 check_minimum_libvirt_version()
152 apis = get_api_xml_files()
154 subprocess.check_call([sys.executable, "generator.py", "libvirt", apis[0], "c"])
155 subprocess.check_call([sys.executable, "generator.py", "libvirt-qemu", apis[1], "c"])
156 if have_libvirt_lxc():
157 subprocess.check_call([sys.executable, "generator.py", "libvirt-lxc", apis[2], "c"])
159 build_ext.run(self)
162 class my_build_py(build_py):
164 def run(self):
165 check_minimum_libvirt_version()
166 apis = get_api_xml_files()
168 subprocess.check_call([sys.executable, "generator.py", "libvirt", apis[0], "py"])
169 subprocess.check_call([sys.executable, "generator.py", "libvirt-qemu", apis[1], "py"])
170 if have_libvirt_lxc():
171 subprocess.check_call([sys.executable, "generator.py", "libvirt-lxc", apis[2], "py"])
172 shutil.copy("libvirtaio.py", "build")
174 build_py.run(self)
177 class my_sdist(sdist):
178 user_options = sdist.user_options
180 description = "Update libvirt-python.spec; build sdist-tarball."
182 def initialize_options(self):
183 self.snapshot = None
184 sdist.initialize_options(self)
186 def finalize_options(self):
187 if self.snapshot is not None:
188 self.snapshot = 1
189 sdist.finalize_options(self)
191 @staticmethod
192 def _gen_from_in(file_in, file_out, replace_pattern, replace):
193 with open(file_in) as f_in, open(file_out, "w") as f_out:
194 for line in f_in:
195 f_out.write(line.replace(replace_pattern, replace))
197 def gen_rpm_spec(self):
198 return self._gen_from_in("libvirt-python.spec.in",
199 "libvirt-python.spec",
200 "@VERSION@",
201 getVersion())
203 def gen_authors(self):
205 cmd = ["git", "log", "--pretty=format:%aN <%aE>"]
206 output = subprocess.check_output(cmd, universal_newlines=True)
207 git_authors = {line.strip() for line in output.splitlines()}
208 authors = sorted(git_authors, key=str.lower)
209 authors = [" " + author for author in authors]
210 self._gen_from_in("AUTHORS.in",
211 "AUTHORS",
212 "@AUTHORS@",
213 "\n".join(authors))
215 def gen_changelog(self):
216 cmd = ["git", "log", "--pretty=format:%H:%ct %an <%ae>%n%n%s%n%b%n"]
217 with open("ChangeLog", "w") as f_out:
218 output = subprocess.check_output(cmd, universal_newlines=True)
219 for line in output.splitlines():
220 m = re.match(r"([a-f0-9]+):(\d+)\s(.*)", line)
221 if m:
222 t = time.gmtime(int(m.group(2)))
223 fmt = "{: 04d}-{: 02d}-{: 02d} {}\n"
224 f_out.write(fmt.format(t.tm_year, t.tm_mon, t.tm_mday, m.group(3)))
225 else:
226 if re.match(r"Signed-off-by", line):
227 continue
228 f_out.write(" " + line.strip() + "\n")
230 def run(self):
231 if Path(".git").exists():
232 try:
233 self.gen_rpm_spec()
234 self.gen_authors()
235 self.gen_changelog()
237 sdist.run(self)
239 finally:
240 files = [
241 "libvirt-python.spec",
242 "AUTHORS",
243 "ChangeLog"
245 for f in files:
246 try:
247 Path(f).unlink()
248 except FileNotFoundError:
249 pass
250 else:
251 sdist.run(self)
254 ##################
255 # Invoke setup() #
256 ##################
258 if sys.version_info < (3, 6):
259 print("libvirt-python requires Python >= 3.6 to build")
260 sys.exit(1)
262 MIN_LIBVIRT = "0.9.11"
263 MIN_LIBVIRT_LXC = "1.0.2"
265 # Hack to stop "pip install" failing with error
266 # about missing "build" dir.
267 Path("build").mkdir(exist_ok=True)
269 check_pkgcfg()
271 _c_modules, _py_modules = get_module_lists()
273 setup(
274 ext_modules=_c_modules,
275 py_modules=_py_modules,
276 package_dir={
277 '': 'build'
279 cmdclass={
280 "build_ext": my_build_ext,
281 "build_py": my_build_py,
282 "sdist": my_sdist,