comparison Configure.py @ 570:e15e86c47a27

ADD: Configure.py ind ninjy_syntax.py from py3-extension-tests
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 08 Jan 2022 17:57:36 +0100
parents
children
comparison
equal deleted inserted replaced
569:1bdf88437555 570:e15e86c47a27
1 #
2 #
3 # Important Triplets:
4 #
5 # clang-cl (clang-cl /clang:-dumpmachine)
6 #
7 # x86_64-pc-windows-msvc
8 # i386-pc-windows-msvc
9 #
10 # clang on FreeBSD (clang -dumpmachine):
11 #
12 # x86_64-unknown-freebsd12.2
13 # i386-unknown-freebsd12.2
14 #
15 # NOTE: gcc also known "-dumpmachine"
16 #
17 #
18
19 from __future__ import print_function, absolute_import
20
21 import argparse
22 import collections
23 import datetime
24 import copy
25 import getopt
26 import os
27 import sys
28
29 import ninja_syntax
30
31 tool = build = host = None
32
33 host = None
34
35
36 #
37 # Global build variables (ordered because they must be written ordered
38 # -- and with simple attribute access
39 #
40 class BuildVars(collections.OrderedDict):
41
42 def __getattr__(self, n):
43 try:
44 return self[n]
45 except KeyError:
46 raise AttributeError(n)
47
48 def __setattr__(self, n, v):
49 # private v
50 if n.startswith("_OrderedDict__"):
51 return super(BuildVars, self).__setattr__(n, v)
52 self[n] = v
53
54
55 def make_obj_name(name, newext):
56 bn = os.path.basename(name)
57 if not bn:
58 return bn
59 root, ext = os.path.splitext(bn)
60 return root + newext
61
62 options = argparse.Namespace(
63 user_includes = [],
64 sys_includes = [],
65 sys_libpath = [],
66 user_libpath = [],
67 link_with_python = None,
68 python_limited_api = None,
69 )
70
71 gbv = BuildVars()
72 gbv.intdir = "_builddir-test"
73 gbv.srcdir = "src"
74 gbv.builddir = "$intdir"
75 gbv.pxx3dir = "pxx3"
76
77 opts, args = getopt.getopt(
78 sys.argv[1:],
79 "B:H:t:I:L:",
80 ["build=",
81 "host=",
82 "tool=",
83 "include=",
84 "libpath=",
85 "sys-include=",
86 "sys-libpath=",
87 "CXX=",
88 "LINK=",
89 "intdir=", # intermediate files
90 "builddir=", # Ninja builddir
91 "link-with-python=", # link with libpython
92 "python-limited-api=", # Use Py_LIMITED_API
93 ])
94 for opt, val in opts:
95 if opt in ("-t", "--tool"):
96 if tool is None:
97 tool = argparse.Namespace(local=False, msvc=False, clang=False)
98 if val == "msvc":
99 tool.msvc = True
100 tool.compile_only = "/c"
101 tool.define_format = "/D {}"
102 tool.include_format = "/I {}"
103 tool.lib_format = "{}"
104 tool.libpath_format = "/libpath:{}"
105 tool.dependencies = "msvc"
106 elif val == "clang-cl":
107 tool.msvc = tool.clang = True
108 tool.compile_only = "/c"
109 tool.define_format = "/D {}"
110 tool.include_format = "/I {}"
111 tool.lib_format = "{}"
112 tool.libpath_format = "/libpath:{}"
113 tool.dependencies = "msvc"
114 elif val == "clang":
115 tool.clang = True
116 tool.compile_only = "-c"
117 tool.define_format = "-D{}"
118 tool.include_format = "-I{}"
119 tool.lib_format = "-l{}"
120 tool.libpath_format = "-L{}"
121 tool.dependencies = "gcc"
122 elif val in ("local", "posix"):
123 tool.local = True
124 tool.compile_only = "-c"
125 tool.define_format = "-D{}"
126 tool.include_format = "-I{}"
127 tool.lib_format = "-l{}"
128 tool.libpath_format = "-L{}"
129 tool.dependencies = "gcc"
130 else:
131 raise getopt.GetoptError("unknown tool value: {}".format(val), opt)
132 elif opt in ("-B", "--build"):
133 build = argparse.Namespace(type=None,
134 posix=False, windows=False,
135 pathmod=None)
136 if val == "windows":
137 # build on Windows with clang-cl
138 build.windows = True
139 build.type = "windows"
140 elif val == "posix":
141 build.posix = True
142 build.type = "posix"
143 else:
144 raise getopt.GetoptError("unknwon build value: {}".format(val),
145 opt)
146 elif opt in ("-H", "--host"):
147 if host is None:
148 host = argparse.Namespace(windows=False)
149 if val == "windows":
150 host.type = "windows"
151 host.windows = True
152 host.posix = False
153 host.objext = ".obj"
154 host.pydext = ".pyd"
155 elif val == "posix":
156 host.type = "posix"
157 host.windows = False
158 host.posix = True
159 host.objext = ".o"
160 host.pydext = ".so"
161 else:
162 raise getopt.GetoptError("unknown host value: {}".format(val),
163 opt)
164 elif opt in ("-I", "--include"):
165 options.user_includes.append(val)
166 elif opt in ("-L", "--libpath"):
167 options.user_libpath.append(val)
168 elif opt == "--sys-include":
169 options.sys_includes.append(val)
170 elif opt == "--sys-libpath":
171 options.sys_libpath.append(val)
172 elif opt == "--CXX":
173 gbv.cxx = val
174 elif opt == "--LINK":
175 gbv.link = val
176 elif opt == "--intdir":
177 gbv.intdir = val
178 elif opt == "--builddir":
179 gbv.builddir = val
180 elif opt == "--link-with-python":
181 options.link_with_python = val
182 elif opt == "--python-limited-api":
183 if val.lower().startswith("0x"):
184 options.python_limited_api = val
185 else:
186 options.python_limited_api = "0x03040000"
187 else:
188 raise getopt.GetoptError("Unhandled option `{}'".format(opt), opt)
189
190 if tool is None:
191 print("ERROR: no tool given", file=sys.stderr)
192 sys.exit(1)
193
194 if build.windows and host.posix:
195 print("ERROR: cross-compiling on Windows not supported", file=sys.stderr)
196 sys.exit(1)
197
198 if build.windows:
199 import ntpath as pathmod
200 else:
201 import posixpath as pathmod
202 build.pathmod = pathmod
203
204 if tool.msvc:
205 if tool.clang:
206 if not getattr(gbv, "cxx", None):
207 gbv.cxx = "clang-cl"
208 if not getattr(gbv, "link", None):
209 gbv.link = "lld-link"
210 else:
211 gbv.cxx = "cl"
212 gbv.link = "link"
213 elif tool.clang:
214 gbv.cxx = "clang++"
215 gbv.link = "clang++" # link C++ through the compiler
216 elif tool.local:
217 gbv.cxx = "c++"
218 gbv.link = "c++" # link through the compiler
219 else:
220 raise RuntimeError("tool condition is not handled")
221
222 ext1_sources = [
223 "$srcdir/ext1/testext1.cpp",
224 "$pxx3dir/shared/thread.cpp",
225 ]
226
227 ext2_sources = [
228 "$srcdir/ext2/testext2.cpp",
229 "$srcdir/ext2/hashes.cpp",
230 "$pxx3dir/shared/thread.cpp",
231 "$pxx3dir/shared/module.cpp",
232 "$pxx3dir/shared/xcept.cpp",
233 "$pxx3dir/shared/cfunctions.cpp",
234 "$pxx3dir/shared/misc.cpp",
235 "$pxx3dir/shared/exttype.cpp",
236 "$pxx3dir/shared/allocator.cpp",
237 ]
238
239 ccflags = []
240 cxxflags = []
241 ccwarnings = []
242 ldflags = []
243
244 defines = [
245 "PY_SSIZE_T_CLEAN",
246 "HAVE_THREADS",
247 ]
248 if options.python_limited_api:
249 defines.append("Py_LIMITED_API={}".format(options.python_limited_api))
250
251 # XXX TBD: handle debug/release build _DEBUG/NDEBUG
252
253 includes = []
254 includes.extend(options.sys_includes)
255 includes.extend(options.user_includes)
256
257 includes.append("$pxx3dir/include")
258
259 libpath = []
260 libpath.extend(options.sys_libpath)
261 libpath.extend(options.user_libpath)
262
263 libs = []
264 if host.windows:
265 if tool.msvc:
266 # automatically included via #pragma
267 # libs.append("python3.lib")
268 pass
269 else:
270 if options.link_with_python:
271 libs.append(options.link_with_python)
272
273 if host.windows:
274 defines.append("WIN32")
275 # XXX TBD Handle arch -> WIN64
276 defines.append("WIN64")
277 defines.append("_WINDOWS")
278 # for a user dll
279 defines.append("_USRDLL")
280 defines.append("_WINDLL")
281
282 defines.append("WIN32_LEAN_AND_MEAN")
283 defines.append("_WIN32_WINNT=0x0501") # WinXP
284
285 if tool.msvc:
286 # XXX TBD warnings
287
288 defines.append("_CRT_SECURE_NO_WARNINGS")
289
290 ccflags.append("/Zi")
291 ccflags.append("/MD") # link to dll runtime
292 ccflags.append("/EHsc")
293 ccflags.append("/Gy") # enable function level linking
294
295 cxxflags.append("/TP")
296 #cxxflags.append("/std:c++latest")
297
298 # XXX TBD machine
299 ccflags.append("-m64")
300
301 ldflags.append("/dll")
302 ldflags.append("/debug") # PDB output
303 # 32-bit: -> 5.01 64-bit: 5.02
304 ldflags.append("/subsystem:windows,5.02")
305 ldflags.append("/incremental:no")
306 #
307 ldflags.append("/manifest:NO")
308
309
310 if tool.clang:
311 ccflags.append("-fms-compatibility-version=16.00")
312
313 ccwarnings.append("-Wno-nonportable-include-path")
314 ccwarnings.append("-Wno-microsoft-template")
315 ccwarnings.append("-Wno-pragma-pack")
316 elif host.posix:
317 defines.append("PIC")
318
319 ccwarnings.extend(["-Wall", "-Wextra", "-pedantic"])
320
321 ccflags.append("-g")
322 ccflags.append("-fPIC")
323 ccflags.append("-fvisibility=hidden")
324 ccflags.append("-pthread")
325
326 if tool.clang: # || tool.gcc
327 ccflags.append("-ffunction-sections")
328 ccflags.append("-fdata-sections")
329
330 if tool.clang:
331 ccflags.append("-faddrsig") # use with --icf=all/safe when linking
332
333 ldflags.append("-shared")
334 ldflags.append("-Wl,-z,relro,-z,now")
335 ldflags.append("-Wl,--build-id=sha1")
336 # XXX TBD only when building in debug code
337 if options.link_with_python:
338 ldflags.append("-Wl,-z,defs")
339
340 if tool.clang: # || tool.gcc
341 ldflags.append("-Wl,--gc-sections")
342
343 if tool.clang:
344 ldflags.append("-Wl,--icf=safe")
345
346 gbv.cppdefines = [tool.define_format.format(d) for d in defines]
347 gbv.includes = [tool.include_format.format(pathmod.normpath(i))
348 for i in includes]
349 gbv.ccflags = ccflags
350 gbv.cxxflags = cxxflags
351 gbv.ccwarnings = ccwarnings
352 gbv.ldflags = ldflags
353 gbv.ldlibpath = [tool.libpath_format.format(pathmod.normpath(l))
354 for l in libpath]
355 gbv.ldlibs = [tool.lib_format.format(l) for l in libs]
356
357 n = ninja_syntax.Writer(sys.stdout)
358
359 n.comment('This file is used to build test Python extensions.')
360 n.comment(
361 'It is generated by {} at {}Z.'.format(
362 os.path.basename(__file__),
363 datetime.datetime.utcnow().isoformat()))
364 n.newline()
365 n.comment('Created using command: {!r}'.format(sys.argv))
366 n.newline()
367 for k, v in gbv.items():
368 n.variable(k, v)
369 n.newline()
370 if tool.msvc:
371 # Note: this includes clang-cl
372 n.rule("compile-pyextension-unit",
373 "$cxx /nologo /showIncludes /c $cppdefines $ccwarnings $includes $ccflags $cxxflags /Fd$intdir/$intsubdir/ /Fo$out $in",
374 deps=tool.dependencies)
375 else:
376 n.rule("compile-pyextension-unit",
377 "$cxx -MD -MF $intdir/_deps -MT $out $cppdefines $ccwarnings $includes $ccflags $cxxflags -c -o $out $in",
378 deps=tool.dependencies,
379 depfile="$intdir/_deps")
380 n.newline()
381 if tool.msvc:
382 # XXX TBD: in "release" builds use /pdbaltpath:$out.pdb
383 n.rule("link-pyextension", "$link /nologo $ldflags $ldlibpath /implib:$intdir/$out.lib /pdb:$intdir/$out.pdb /out:$out $in $ldlibs")
384 else:
385 n.rule("link-pyextension", "$link $cppdefines $ccwarnings $ccflags $cxxflags $ldflags -o $out $in $ldlibpath $ldlibs")
386 n.newline()
387
388 n.comment("testext1")
389 for f in ext1_sources:
390 n.build(pathmod.normpath("$intdir/$intsubdir/"+make_obj_name(f, host.objext)),
391 "compile-pyextension-unit",
392 inputs=pathmod.normpath(f),
393 variables={"intsubdir": "ext1"})
394 n.newline()
395 linkinputs = [pathmod.normpath("$intdir/ext1/"+make_obj_name(f, host.objext))
396 for f in ext1_sources]
397 if tool.msvc:
398 implicit_outputs = [
399 pathmod.normpath("$intdir/testext1"+host.pydext+".lib"),
400 pathmod.normpath("$intdir/testext1"+host.pydext+".pdb")]
401 if not tool.clang:
402 implicit_outputs.append(pathmod.normpath("$intdir/testext1"+host.pydext+".exp"))
403 else:
404 implicit_outputs = None
405 n.build("testext1"+host.pydext,
406 "link-pyextension",
407 inputs=linkinputs,
408 implicit_outputs=implicit_outputs)
409 n.newline()
410
411 n.comment("testext2")
412 for f in ext2_sources:
413 n.build(pathmod.normpath("$intdir/$intsubdir/"+make_obj_name(f, host.objext)),
414 "compile-pyextension-unit",
415 inputs=pathmod.normpath(f),
416 variables={"intsubdir": "ext2"})
417 n.newline()
418 linkinputs = [pathmod.normpath("$intdir/ext2/"+make_obj_name(f, host.objext))
419 for f in ext2_sources]
420 if tool.msvc:
421 implicit_outputs = [
422 pathmod.normpath("$intdir/testext2"+host.pydext+".lib"),
423 pathmod.normpath("$intdir/testext2"+host.pydext+".pdb")]
424 if not tool.clang:
425 implicit_outputs.append(pathmod.normpath("$intdir/testext2"+host.pydext+".exp"))
426 else:
427 implicit_outputs = None
428 n.build("testext2"+host.pydext,
429 "link-pyextension",
430 inputs=linkinputs,
431 implicit_outputs=implicit_outputs)