Mercurial > hgrepos > Python > libs > ConfigMix
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) |
