def check_cpp_default(cnf:Context, name:str, version:Optional[str]): u"Adds a requirement checker" if name.startswith('boost'): return if name.startswith('python_'): _check_cpp_python(cnf, name, version) else: cnf.check_cfg(package = name, uselib_store = name, args = '--cflags --libs', atleast_version = version)
def configure(cls, cnf:Context): u"setup configure" cnf.env.append_value('SYS_INCS', 'BOOST') libs, vers = cls.getlibs() if not len(libs): return if not cnf.options.boost_includes and not cnf.options.boost_libs: cls.__getboostfromconda(cnf) cnf.check_boost(lib = ' '.join(libs-set(cls._H_ONLY)), mandatory = True) if 'LIB_BOOST' not in cnf.env: cnf.env['LIB_BOOST']= [] elif sys.platform.startswith("win32"): cnf.env['LIB_BOOST']= [i.replace("-sgd-", "-gd-") for i in cnf.env["LIB_BOOST"]] else: path = Path(cnf.env["LIBPATH_BOOST"][0]) good = [] for i in cnf.env["LIB_BOOST"]: if i.endswith('.so') and (path/f"lib{i}").exists(): good.append(i) elif (path/f"lib{i[:i.find('.so')+3]}").exists(): good.append(i[:i.find('.so')]) else: raise KeyError(f"missing $path/lib$i") cnf.env["LIB_BOOST"] = good cnf.env['DEFINES_BOOST']= ['HAVE_BOOST=1'] if LooseVersion(cnf.env.BOOST_VERSION.replace('_', '.')) < vers: cnf.fatal('Boost version is too old: %s < %s' % (str(vers), str(cnf.env.BOOST_VERSION)))
def build_python_version_file(bld: Context): "creates a version.py file" bld(features='subst', source=bld.srcnode.find_resource( __package__.replace(".", "/") + '/_version.template'), target="version.py", name=str(bld.path) + ":version", version=_version(), lasthash=lasthash(), lastdate=lastdate(), isdirty=isdirty(), timestamp=lasttimestamp(), cpp_compiler_name=bld.cpp_compiler_name(), **bld.installcodepath())
def check_cpp_compiler(cnf:Context, name:str, version:Optional[str]): u"checks the compiler version" if cnf.env['COMPILER_CXX'] != name: return curr = cnf.env['CC_VERSION'] if _ismsvc(cnf): curr = cnf.env['MSVC_VERSION'] if isinstance(curr, float): curr = str(curr) elif isinstance(curr, tuple): curr = '.'.join(curr) if LooseVersion(curr) < version: cnf.fatal(cnf.env['COMPILER_CXX'] +' version '+curr +' should be greater than '+version)
def options(opt: Context): "add options" return (opt.add_option_group("Python Options").add_option( "--nolinting", help="Discard linting jobs", default=True, dest="DO_PY_LINTING", action="store_false", ))
def __make_deps(cls, bld: Context, name: str, items: Sequence) -> List: if cls.INCLUDE_PYEXTS: pyext = set(bld.env.pyextmodules) if any(i.get_name() == name + ':pyext' for i in bld.get_all_task_gen()): pyext.add(name) return list(pymoduledependencies(items, name) & pyext) return []
def __getboostfromconda(cnf:Context): rem = 'PYTHON' not in cnf.env if rem: cnf.find_program("python", var="PYTHON", mandatory=False) if 'PYTHON' in cnf.env: path = Path(cnf.env["PYTHON"][0]).parent if sys.platform.startswith("win32"): path /= "Library" for _ in range(3): if (path/"include"/"boost").exists() and (path/"lib").exists(): cnf.options.boost_includes = str(path/"include") cnf.options.boost_libs = str(path/"lib") break path = path.parent if rem: del cnf.env['PYTHON']
def _check_cpp_python(cnf:Context, name:str, version:Optional[str]): base = name[len('python_'):] cond = 'ver >= num('+str(version).replace('.',',')+')' cnf.check_python_module(base, condition = cond) paths = get_python_paths(cnf, name, version) lib, inc = paths['lib'], paths['inc'] line = f' -I{inc} -I{Path(inc).parent} -L{lib}' iswin = sys.platform.startswith('win') if not iswin: line += ' -lm' if base.endswith("-c"): base = base[:-2] bases = set(PYTHON_MODULE_LIBS.get(base, (base,))) fullname = "--dummy--" for basename in set(bases): for fullname in ( pre+basename+suf for pre in ('', 'lib') for suf in ('.so', '.dll', '.lib') ): if (Path(lib) / fullname).exists(): if sys.platform.startswith('win') and fullname.startswith('lib'): line += f' -llib{basename}' else: line += f' -l{basename}' bases -= {basename} break for basename in bases: for lib in (pre+basename+'.a' for pre in ('', 'lib')): if (Path(lib) / fullname).exists(): if '-Wl,-Bstatic' not in line: line += f' -Wl,-Bstatic -L{lib}' line += f' l{basename}' break cnf.parse_flags(line, uselib_store = base) for suf in ('', '.exe', '.bat', '.sh'): test = (paths['bin']/base).with_suffix(suf) if test.exists(): setattr(cnf.env, f"BIN_{base}", [str(test)]) cnf.env.append_value(f'DEFINES_{base}', f'BIN_{base}="{test}"')
def get_python_paths(cnf:Context, name:str, version: Optional[str]) -> Dict[str, Path]: "get the python path" rem = not getattr(cnf.env, 'PYTHON') if rem: cnf.find_program("python", var="PYTHON", mandatory=False) if not getattr(cnf.env, 'PYTHON'): check_cpp_default(cnf, name, version) root = Path(cnf.env["PYTHON"][0]).parent if rem: del cnf.env['PYTHON'] path = root/'Library' if sys.platform.startswith('win') else root.parent return dict( root = root.resolve(), inc = (path/'include').resolve(), lib = (path/'lib').resolve(), bin = (path/'bin').resolve() )
def copyfiles(bld: Context, arg, items: Sequence, install=False): "copy py modules to build root path" if len(items) == 0: return if bld.cmd != "build" and install: bld.install_files(bld.installcodepath(arg, direct=True), items, cwd=bld.path, relative_trick=True) return def _kword(_): return 'Copying' if arg != '': copyroot(bld, arg).mkdir() for src, tgt in copytargets(bld, arg, items): bld(rule=copytask, name=str(src) + ':' + _kword(None).lower(), source=[src], target=[tgt], cls_keyword=_kword)
def configure(cls, cnf:Context): u"setup configure" if not _isrequired() or cls._DONE: return cls._DONE = True name = cnf.env['COMPILER_CXX'] cxx = cnf.options.cxxflaglist links = cnf.options.linkflaglist # add options for i, j in OPTIONS.items(): if i not in cxx and getattr(cnf.options, i[1:]+'flags'): cxx += ' ' + i if i in cxx and name in j: cxx = cxx.replace(i, j[name].get('cxx', '')) links = links.strip()+" "+j[name].get('links', '') # add default flags if cxx[0] == "+": cxx = cls.defaultcxx(cnf).strip()+" "+cxx[1:] # add warnings cxx += ' ' + ' '.join(WARNINGS.get(name, WARNINGS[...])) cxx = cls.convertFlags(cnf, cxx) links = cls.convertFlags(cnf, links) cnf.check(features = 'cxx cxxprogram', cxxflags = cxx, linkflags = links, mandatory = True) cnf.env.append_unique('CXXFLAGS', Utils.to_list(cxx)) cnf.env.append_unique('LINKFLAGS', Utils.to_list(links)) cnf.env.append_unique('INCLUDES', ['../'])
def buildpyext(bld : Context, name : str, version : str, pysrc : Sequence, csrc : List, **kwargs): "builds a python extension" if len(csrc) == 0: return if name not in bld.env.pyextmodules and not haspyext(csrc): return mod = '_core' if len(pysrc) else name parent = copyroot(bld, name if len(pysrc) else None) target = parent.path_from(bld.bldnode.make_node(bld.path.relpath()))+"/"+mod node = bld(features = 'subst', source = bld.srcnode.find_resource(__package__.replace('.', '/') +'/_module.template'), target = name+"module.cpp", name = str(bld.path)+":pybind11", nsname = name, module = mod, version = version) csrc.append(node.target) args = copyargs(kwargs) args.setdefault('source', csrc) args.setdefault('target', target) args.setdefault('features', []).append('pyext') args.setdefault('name', name+":pyext") args.update(**bld.installcodepath(name if pysrc else "")) bld.shlib(**args)
def options(opt: Context): "defines options for conda setup" from ..shellvars import ENV_DEFAULT grp = opt.add_option_group('Condasetup Options') grp.add_option( '-e', '--envname', dest='condaenv', action='store', default=ENV_DEFAULT[0], help=("conda environment name: one can use 'branch'" + " to automatically use the current git branch name")) grp.add_option('--suggested', dest='suggested', action='store_true', default=False, help="install suggested modules as well") grp.add_option('--pinned', dest='pinned', action='store', default='', help="packages with pinned versions") grp.add_option('-m', '--min-version', dest='minversion', action='store_true', default=False, help="install requirement minimum versions by default") grp.add_option('-r', '--runtime-only', dest='runtimeonly', action='store_true', default=False, help="install only runtime modules") grp.add_option('-p', '--packages', dest='packages', action='store', default='', help="consider only these packages")
def programversion(cnf: Context, name: str, minver: LooseVersion, reg=None, mandatory=True) -> bool: "check version of a program" if reg is None: areg = name else: areg = reg try: cnf.find_program(name, var=name.upper()) except: # pylint: disable=bare-except if mandatory: raise else: return False cmd = [getattr(cnf.env, name.upper())[0], "--version"] found = cnf.cmd_and_log(cmd).split('\n') found = [line for line in found if len(line)] found = next((line for line in found if areg in line), found[-1]).split()[-1] found = found[found.rfind(' ') + 1:].replace(',', '').strip() if found.startswith('v'): found = found[1:] if LooseVersion(found) < minver: if not mandatory: return False if reg is None: cnf.fatal('The %s version is too old, expecting %r' % (name, minver)) else: cnf.fatal('The %s (%s) version is too old, expecting %r' % (name, str(reg), minver)) return True
def store(cnf: Context, flg: str): "store more python flags" if hascompiler(cnf): for item in 'PYEXT', 'PYEMBED': cnf.parse_flags(flg, uselib_store=item)
def load(opt: Context): "applies load from all basic items" outp = glob.get('toload', lambda _: None)(opt) if len(outp): opt.load(outp)
def configure(cnf: Context): "get conda script" cnf.env.CONDA_DEFAULT_ENV = os.environ['CONDA_DEFAULT_ENV'] cnf.find_program("conda", var="CONDA", mandatory=True)
def check_cpp_gtest(cnf:Context, name:str, version:Optional[str]): "check for gtest" path = get_python_paths(cnf, name, version)['lib'] vers = libmain = lib = inc = None for i in range(3): inc = path/"include"/"gtest" if sys.platform.startswith('win'): libmain = path/"lib"/f"{name}_main-md.lib" lib = path/"lib"/f"{name}-md.lib" else: libmain = path/"lib"/f"lib{name}_main.a" lib = path/"lib"/f"lib{name}.a" if inc.exists() and lib.exists(): break path = path.parent else: cnf.start_msg(f"Checking for conda module {name} (>= {version})") cnf.end_msg(False) cnf.fatal('Could not find the conda module ' +name) return setattr(cnf.env, f"INCLUDES_{name}", [str(inc.parent)]) setattr(cnf.env, f"STLIBPATH_{name}", [str(lib.parent)]) setattr(cnf.env, f"STLIB_{name}", [i.stem.replace('lib', '') for i in (lib, libmain)]) if sys.platform.startswith('win'): setattr(cnf.env, f"DEFINES_{name}", ['GTEST_LANG_CX11=1', '_HAS_TR1_NAMESPACE=1']) else: setattr(cnf.env, f"LIB_{name}", ['pthread']) if version is None: cnf.start_msg(f"Checking for conda module {name} (>= {version})") cnf.end_msg(True) return cond = 'ver >= num('+str(version).replace('.',',')+')' cnf.check_python_module(name, condition = cond)
def options(opt:Context): u"add options" if _isrequired(): opt.add_option_group(CXX_OPTION_GROUP)