Mercurial > hgrepos > Python > libs > ConfigMix
diff windows-dev/Configure.py @ 571:aa240af27589
Move Configure.py and ninja_syntax.py to windows-dev
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 08 Jan 2022 18:35:01 +0100 |
| parents | Configure.py@e15e86c47a27 |
| children | 65a52a3f3575 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windows-dev/Configure.py Sat Jan 08 18:35:01 2022 +0100 @@ -0,0 +1,431 @@ +# +# +# Important Triplets: +# +# clang-cl (clang-cl /clang:-dumpmachine) +# +# x86_64-pc-windows-msvc +# i386-pc-windows-msvc +# +# clang on FreeBSD (clang -dumpmachine): +# +# x86_64-unknown-freebsd12.2 +# i386-unknown-freebsd12.2 +# +# NOTE: gcc also known "-dumpmachine" +# +# + +from __future__ import print_function, absolute_import + +import argparse +import collections +import datetime +import copy +import getopt +import os +import sys + +import ninja_syntax + +tool = build = host = None + +host = None + + +# +# Global build variables (ordered because they must be written ordered +# -- and with simple attribute access +# +class BuildVars(collections.OrderedDict): + + def __getattr__(self, n): + try: + return self[n] + except KeyError: + raise AttributeError(n) + + def __setattr__(self, n, v): + # private v + if n.startswith("_OrderedDict__"): + return super(BuildVars, self).__setattr__(n, v) + self[n] = v + + +def make_obj_name(name, newext): + bn = os.path.basename(name) + if not bn: + return bn + root, ext = os.path.splitext(bn) + return root + newext + +options = argparse.Namespace( + user_includes = [], + sys_includes = [], + sys_libpath = [], + user_libpath = [], + link_with_python = None, + python_limited_api = None, +) + +gbv = BuildVars() +gbv.intdir = "_builddir-test" +gbv.srcdir = "src" +gbv.builddir = "$intdir" +gbv.pxx3dir = "pxx3" + +opts, args = getopt.getopt( + sys.argv[1:], + "B:H:t:I:L:", + ["build=", + "host=", + "tool=", + "include=", + "libpath=", + "sys-include=", + "sys-libpath=", + "CXX=", + "LINK=", + "intdir=", # intermediate files + "builddir=", # Ninja builddir + "link-with-python=", # link with libpython + "python-limited-api=", # Use Py_LIMITED_API + ]) +for opt, val in opts: + if opt in ("-t", "--tool"): + if tool is None: + tool = argparse.Namespace(local=False, msvc=False, clang=False) + if val == "msvc": + tool.msvc = True + tool.compile_only = "/c" + tool.define_format = "/D {}" + tool.include_format = "/I {}" + tool.lib_format = "{}" + tool.libpath_format = "/libpath:{}" + tool.dependencies = "msvc" + elif val == "clang-cl": + tool.msvc = tool.clang = True + tool.compile_only = "/c" + tool.define_format = "/D {}" + tool.include_format = "/I {}" + tool.lib_format = "{}" + tool.libpath_format = "/libpath:{}" + tool.dependencies = "msvc" + elif val == "clang": + tool.clang = True + tool.compile_only = "-c" + tool.define_format = "-D{}" + tool.include_format = "-I{}" + tool.lib_format = "-l{}" + tool.libpath_format = "-L{}" + tool.dependencies = "gcc" + elif val in ("local", "posix"): + tool.local = True + tool.compile_only = "-c" + tool.define_format = "-D{}" + tool.include_format = "-I{}" + tool.lib_format = "-l{}" + tool.libpath_format = "-L{}" + tool.dependencies = "gcc" + else: + raise getopt.GetoptError("unknown tool value: {}".format(val), opt) + elif opt in ("-B", "--build"): + build = argparse.Namespace(type=None, + posix=False, windows=False, + pathmod=None) + if val == "windows": + # build on Windows with clang-cl + build.windows = True + build.type = "windows" + elif val == "posix": + build.posix = True + build.type = "posix" + else: + raise getopt.GetoptError("unknwon build value: {}".format(val), + opt) + elif opt in ("-H", "--host"): + if host is None: + host = argparse.Namespace(windows=False) + if val == "windows": + host.type = "windows" + host.windows = True + host.posix = False + host.objext = ".obj" + host.pydext = ".pyd" + elif val == "posix": + host.type = "posix" + host.windows = False + host.posix = True + host.objext = ".o" + host.pydext = ".so" + else: + raise getopt.GetoptError("unknown host value: {}".format(val), + opt) + elif opt in ("-I", "--include"): + options.user_includes.append(val) + elif opt in ("-L", "--libpath"): + options.user_libpath.append(val) + elif opt == "--sys-include": + options.sys_includes.append(val) + elif opt == "--sys-libpath": + options.sys_libpath.append(val) + elif opt == "--CXX": + gbv.cxx = val + elif opt == "--LINK": + gbv.link = val + elif opt == "--intdir": + gbv.intdir = val + elif opt == "--builddir": + gbv.builddir = val + elif opt == "--link-with-python": + options.link_with_python = val + elif opt == "--python-limited-api": + if val.lower().startswith("0x"): + options.python_limited_api = val + else: + options.python_limited_api = "0x03040000" + else: + raise getopt.GetoptError("Unhandled option `{}'".format(opt), opt) + +if tool is None: + print("ERROR: no tool given", file=sys.stderr) + sys.exit(1) + +if build.windows and host.posix: + print("ERROR: cross-compiling on Windows not supported", file=sys.stderr) + sys.exit(1) + +if build.windows: + import ntpath as pathmod +else: + import posixpath as pathmod +build.pathmod = pathmod + +if tool.msvc: + if tool.clang: + if not getattr(gbv, "cxx", None): + gbv.cxx = "clang-cl" + if not getattr(gbv, "link", None): + gbv.link = "lld-link" + else: + gbv.cxx = "cl" + gbv.link = "link" +elif tool.clang: + gbv.cxx = "clang++" + gbv.link = "clang++" # link C++ through the compiler +elif tool.local: + gbv.cxx = "c++" + gbv.link = "c++" # link through the compiler +else: + raise RuntimeError("tool condition is not handled") + +ext1_sources = [ + "$srcdir/ext1/testext1.cpp", + "$pxx3dir/shared/thread.cpp", +] + +ext2_sources = [ + "$srcdir/ext2/testext2.cpp", + "$srcdir/ext2/hashes.cpp", + "$pxx3dir/shared/thread.cpp", + "$pxx3dir/shared/module.cpp", + "$pxx3dir/shared/xcept.cpp", + "$pxx3dir/shared/cfunctions.cpp", + "$pxx3dir/shared/misc.cpp", + "$pxx3dir/shared/exttype.cpp", + "$pxx3dir/shared/allocator.cpp", +] + +ccflags = [] +cxxflags = [] +ccwarnings = [] +ldflags = [] + +defines = [ + "PY_SSIZE_T_CLEAN", + "HAVE_THREADS", +] +if options.python_limited_api: + defines.append("Py_LIMITED_API={}".format(options.python_limited_api)) + +# XXX TBD: handle debug/release build _DEBUG/NDEBUG + +includes = [] +includes.extend(options.sys_includes) +includes.extend(options.user_includes) + +includes.append("$pxx3dir/include") + +libpath = [] +libpath.extend(options.sys_libpath) +libpath.extend(options.user_libpath) + +libs = [] +if host.windows: + if tool.msvc: + # automatically included via #pragma + # libs.append("python3.lib") + pass +else: + if options.link_with_python: + libs.append(options.link_with_python) + +if host.windows: + defines.append("WIN32") + # XXX TBD Handle arch -> WIN64 + defines.append("WIN64") + defines.append("_WINDOWS") + # for a user dll + defines.append("_USRDLL") + defines.append("_WINDLL") + + defines.append("WIN32_LEAN_AND_MEAN") + defines.append("_WIN32_WINNT=0x0501") # WinXP + + if tool.msvc: + # XXX TBD warnings + + defines.append("_CRT_SECURE_NO_WARNINGS") + + ccflags.append("/Zi") + ccflags.append("/MD") # link to dll runtime + ccflags.append("/EHsc") + ccflags.append("/Gy") # enable function level linking + + cxxflags.append("/TP") + #cxxflags.append("/std:c++latest") + + # XXX TBD machine + ccflags.append("-m64") + + ldflags.append("/dll") + ldflags.append("/debug") # PDB output + # 32-bit: -> 5.01 64-bit: 5.02 + ldflags.append("/subsystem:windows,5.02") + ldflags.append("/incremental:no") + # + ldflags.append("/manifest:NO") + + + if tool.clang: + ccflags.append("-fms-compatibility-version=16.00") + + ccwarnings.append("-Wno-nonportable-include-path") + ccwarnings.append("-Wno-microsoft-template") + ccwarnings.append("-Wno-pragma-pack") +elif host.posix: + defines.append("PIC") + + ccwarnings.extend(["-Wall", "-Wextra", "-pedantic"]) + + ccflags.append("-g") + ccflags.append("-fPIC") + ccflags.append("-fvisibility=hidden") + ccflags.append("-pthread") + + if tool.clang: # || tool.gcc + ccflags.append("-ffunction-sections") + ccflags.append("-fdata-sections") + + if tool.clang: + ccflags.append("-faddrsig") # use with --icf=all/safe when linking + + ldflags.append("-shared") + ldflags.append("-Wl,-z,relro,-z,now") + ldflags.append("-Wl,--build-id=sha1") + # XXX TBD only when building in debug code + if options.link_with_python: + ldflags.append("-Wl,-z,defs") + + if tool.clang: # || tool.gcc + ldflags.append("-Wl,--gc-sections") + + if tool.clang: + ldflags.append("-Wl,--icf=safe") + +gbv.cppdefines = [tool.define_format.format(d) for d in defines] +gbv.includes = [tool.include_format.format(pathmod.normpath(i)) + for i in includes] +gbv.ccflags = ccflags +gbv.cxxflags = cxxflags +gbv.ccwarnings = ccwarnings +gbv.ldflags = ldflags +gbv.ldlibpath = [tool.libpath_format.format(pathmod.normpath(l)) + for l in libpath] +gbv.ldlibs = [tool.lib_format.format(l) for l in libs] + +n = ninja_syntax.Writer(sys.stdout) + +n.comment('This file is used to build test Python extensions.') +n.comment( + 'It is generated by {} at {}Z.'.format( + os.path.basename(__file__), + datetime.datetime.utcnow().isoformat())) +n.newline() +n.comment('Created using command: {!r}'.format(sys.argv)) +n.newline() +for k, v in gbv.items(): + n.variable(k, v) +n.newline() +if tool.msvc: + # Note: this includes clang-cl + n.rule("compile-pyextension-unit", + "$cxx /nologo /showIncludes /c $cppdefines $ccwarnings $includes $ccflags $cxxflags /Fd$intdir/$intsubdir/ /Fo$out $in", + deps=tool.dependencies) +else: + n.rule("compile-pyextension-unit", + "$cxx -MD -MF $intdir/_deps -MT $out $cppdefines $ccwarnings $includes $ccflags $cxxflags -c -o $out $in", + deps=tool.dependencies, + depfile="$intdir/_deps") +n.newline() +if tool.msvc: + # XXX TBD: in "release" builds use /pdbaltpath:$out.pdb + n.rule("link-pyextension", "$link /nologo $ldflags $ldlibpath /implib:$intdir/$out.lib /pdb:$intdir/$out.pdb /out:$out $in $ldlibs") +else: + n.rule("link-pyextension", "$link $cppdefines $ccwarnings $ccflags $cxxflags $ldflags -o $out $in $ldlibpath $ldlibs") +n.newline() + +n.comment("testext1") +for f in ext1_sources: + n.build(pathmod.normpath("$intdir/$intsubdir/"+make_obj_name(f, host.objext)), + "compile-pyextension-unit", + inputs=pathmod.normpath(f), + variables={"intsubdir": "ext1"}) +n.newline() +linkinputs = [pathmod.normpath("$intdir/ext1/"+make_obj_name(f, host.objext)) + for f in ext1_sources] +if tool.msvc: + implicit_outputs = [ + pathmod.normpath("$intdir/testext1"+host.pydext+".lib"), + pathmod.normpath("$intdir/testext1"+host.pydext+".pdb")] + if not tool.clang: + implicit_outputs.append(pathmod.normpath("$intdir/testext1"+host.pydext+".exp")) +else: + implicit_outputs = None +n.build("testext1"+host.pydext, + "link-pyextension", + inputs=linkinputs, + implicit_outputs=implicit_outputs) +n.newline() + +n.comment("testext2") +for f in ext2_sources: + n.build(pathmod.normpath("$intdir/$intsubdir/"+make_obj_name(f, host.objext)), + "compile-pyextension-unit", + inputs=pathmod.normpath(f), + variables={"intsubdir": "ext2"}) +n.newline() +linkinputs = [pathmod.normpath("$intdir/ext2/"+make_obj_name(f, host.objext)) + for f in ext2_sources] +if tool.msvc: + implicit_outputs = [ + pathmod.normpath("$intdir/testext2"+host.pydext+".lib"), + pathmod.normpath("$intdir/testext2"+host.pydext+".pdb")] + if not tool.clang: + implicit_outputs.append(pathmod.normpath("$intdir/testext2"+host.pydext+".exp")) +else: + implicit_outputs = None +n.build("testext2"+host.pydext, + "link-pyextension", + inputs=linkinputs, + implicit_outputs=implicit_outputs)
