| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Krzysztof Kosiński 2014 | ||
| # DragoonX6 2018 | ||
|
|
||
| """ | ||
| Detect the Clang C compiler | ||
| This version is an attempt at supporting the -target and -sysroot flag of Clang. | ||
| """ | ||
|
|
||
| from waflib.Tools import ccroot, ar, gcc | ||
| from waflib.Configure import conf | ||
| import waflib.Context | ||
| import waflib.extras.clang_cross_common | ||
|
|
||
| def options(opt): | ||
| """ | ||
| Target triplet for clang:: | ||
| $ waf configure --clang-target-triple=x86_64-pc-linux-gnu | ||
| """ | ||
| cc_compiler_opts = opt.add_option_group('Configuration options') | ||
| cc_compiler_opts.add_option('--clang-target-triple', default=None, | ||
| help='Target triple for clang', | ||
| dest='clang_target_triple') | ||
| cc_compiler_opts.add_option('--clang-sysroot', default=None, | ||
| help='Sysroot for clang', | ||
| dest='clang_sysroot') | ||
|
|
||
| @conf | ||
| def find_clang(conf): | ||
| """ | ||
| Finds the program clang and executes it to ensure it really is clang | ||
| """ | ||
|
|
||
| import os | ||
|
|
||
| cc = conf.find_program('clang', var='CC') | ||
|
|
||
| if conf.options.clang_target_triple != None: | ||
| conf.env.append_value('CC', ['-target', conf.options.clang_target_triple]) | ||
|
|
||
| if conf.options.clang_sysroot != None: | ||
| sysroot = str() | ||
|
|
||
| if os.path.isabs(conf.options.clang_sysroot): | ||
| sysroot = conf.options.clang_sysroot | ||
| else: | ||
| sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clang_sysroot)) | ||
|
|
||
| conf.env.append_value('CC', ['--sysroot', sysroot]) | ||
|
|
||
| conf.get_cc_version(cc, clang=True) | ||
| conf.env.CC_NAME = 'clang' | ||
|
|
||
| @conf | ||
| def clang_modifier_x86_64_w64_mingw32(conf): | ||
| conf.gcc_modifier_win32() | ||
|
|
||
| @conf | ||
| def clang_modifier_i386_w64_mingw32(conf): | ||
| conf.gcc_modifier_win32() | ||
|
|
||
| @conf | ||
| def clang_modifier_x86_64_windows_msvc(conf): | ||
| conf.clang_modifier_msvc() | ||
|
|
||
| # Allow the user to override any flags if they so desire. | ||
| clang_modifier_user_func = getattr(conf, 'clang_modifier_x86_64_windows_msvc_user', None) | ||
| if clang_modifier_user_func: | ||
| clang_modifier_user_func() | ||
|
|
||
| @conf | ||
| def clang_modifier_i386_windows_msvc(conf): | ||
| conf.clang_modifier_msvc() | ||
|
|
||
| # Allow the user to override any flags if they so desire. | ||
| clang_modifier_user_func = getattr(conf, 'clang_modifier_i386_windows_msvc_user', None) | ||
| if clang_modifier_user_func: | ||
| clang_modifier_user_func() | ||
|
|
||
| def configure(conf): | ||
| conf.find_clang() | ||
| conf.find_program(['llvm-ar', 'ar'], var='AR') | ||
| conf.find_ar() | ||
| conf.gcc_common_flags() | ||
| # Allow the user to provide flags for the target platform. | ||
| conf.gcc_modifier_platform() | ||
| # And allow more fine grained control based on the compiler's triplet. | ||
| conf.clang_modifier_target_triple() | ||
| conf.cc_load_tools() | ||
| conf.cc_add_flags() | ||
| conf.link_add_flags() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
| # DragoonX6 2018 | ||
|
|
||
| """ | ||
| Common routines for cross_clang.py and cross_clangxx.py | ||
| """ | ||
|
|
||
| from waflib.Configure import conf | ||
| import waflib.Context | ||
|
|
||
| def normalize_target_triple(target_triple): | ||
| target_triple = target_triple[:-1] | ||
| normalized_triple = target_triple.replace('--', '-unknown-') | ||
|
|
||
| if normalized_triple.startswith('-'): | ||
| normalized_triple = 'unknown' + normalized_triple | ||
|
|
||
| if normalized_triple.endswith('-'): | ||
| normalized_triple += 'unknown' | ||
|
|
||
| # Normalize MinGW builds to *arch*-w64-mingw32 | ||
| if normalized_triple.endswith('windows-gnu'): | ||
| normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-w64-mingw32' | ||
|
|
||
| # Strip the vendor when doing msvc builds, since it's unused anyway. | ||
| if normalized_triple.endswith('windows-msvc'): | ||
| normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-windows-msvc' | ||
|
|
||
| return normalized_triple.replace('-', '_') | ||
|
|
||
| @conf | ||
| def clang_modifier_msvc(conf): | ||
| import os | ||
|
|
||
| """ | ||
| Really basic setup to use clang in msvc mode. | ||
| We actually don't really want to do a lot, even though clang is msvc compatible | ||
| in this mode, that doesn't mean we're actually using msvc. | ||
| It's probably the best to leave it to the user, we can assume msvc mode if the user | ||
| uses the clang-cl frontend, but this module only concerns itself with the gcc-like frontend. | ||
| """ | ||
| v = conf.env | ||
| v.cprogram_PATTERN = '%s.exe' | ||
|
|
||
| v.cshlib_PATTERN = '%s.dll' | ||
| v.implib_PATTERN = '%s.lib' | ||
| v.IMPLIB_ST = '-Wl,-IMPLIB:%s' | ||
| v.SHLIB_MARKER = [] | ||
|
|
||
| v.CFLAGS_cshlib = [] | ||
| v.LINKFLAGS_cshlib = ['-Wl,-DLL'] | ||
| v.cstlib_PATTERN = '%s.lib' | ||
| v.STLIB_MARKER = [] | ||
|
|
||
| del(v.AR) | ||
| conf.find_program(['llvm-lib', 'lib'], var='AR') | ||
| v.ARFLAGS = ['-nologo'] | ||
| v.AR_TGT_F = ['-out:'] | ||
|
|
||
| # Default to the linker supplied with llvm instead of link.exe or ld | ||
| v.LINK_CC = v.CC + ['-fuse-ld=lld', '-nostdlib'] | ||
| v.CCLNK_TGT_F = ['-o'] | ||
| v.def_PATTERN = '-Wl,-def:%s' | ||
|
|
||
| v.LINKFLAGS = [] | ||
|
|
||
| v.LIB_ST = '-l%s' | ||
| v.LIBPATH_ST = '-Wl,-LIBPATH:%s' | ||
| v.STLIB_ST = '-l%s' | ||
| v.STLIBPATH_ST = '-Wl,-LIBPATH:%s' | ||
|
|
||
| CFLAGS_CRT_COMMON = [ | ||
| '-Xclang', '--dependent-lib=oldnames', | ||
| '-Xclang', '-fno-rtti-data', | ||
| '-D_MT' | ||
| ] | ||
|
|
||
| v.CFLAGS_CRT_MULTITHREADED = CFLAGS_CRT_COMMON + [ | ||
| '-Xclang', '-flto-visibility-public-std', | ||
| '-Xclang', '--dependent-lib=libcmt', | ||
| ] | ||
| v.CXXFLAGS_CRT_MULTITHREADED = v.CFLAGS_CRT_MULTITHREADED | ||
|
|
||
| v.CFLAGS_CRT_MULTITHREADED_DBG = CFLAGS_CRT_COMMON + [ | ||
| '-D_DEBUG', | ||
| '-Xclang', '-flto-visibility-public-std', | ||
| '-Xclang', '--dependent-lib=libcmtd', | ||
| ] | ||
| v.CXXFLAGS_CRT_MULTITHREADED_DBG = v.CFLAGS_CRT_MULTITHREADED_DBG | ||
|
|
||
| v.CFLAGS_CRT_MULTITHREADED_DLL = CFLAGS_CRT_COMMON + [ | ||
| '-D_DLL', | ||
| '-Xclang', '--dependent-lib=msvcrt' | ||
| ] | ||
| v.CXXFLAGS_CRT_MULTITHREADED_DLL = v.CFLAGS_CRT_MULTITHREADED_DLL | ||
|
|
||
| v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = CFLAGS_CRT_COMMON + [ | ||
| '-D_DLL', | ||
| '-D_DEBUG', | ||
| '-Xclang', '--dependent-lib=msvcrtd', | ||
| ] | ||
| v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CFLAGS_CRT_MULTITHREADED_DLL_DBG | ||
|
|
||
| @conf | ||
| def clang_modifier_target_triple(conf, cpp=False): | ||
| compiler = conf.env.CXX if cpp else conf.env.CC | ||
| output = conf.cmd_and_log(compiler + ['-dumpmachine'], output=waflib.Context.STDOUT) | ||
|
|
||
| modifier = ('clangxx' if cpp else 'clang') + '_modifier_' | ||
| clang_modifier_func = getattr(conf, modifier + normalize_target_triple(output), None) | ||
| if clang_modifier_func: | ||
| clang_modifier_func() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Thomas Nagy 2009-2018 (ita) | ||
| # DragoonX6 2018 | ||
|
|
||
| """ | ||
| Detect the Clang++ C++ compiler | ||
| This version is an attempt at supporting the -target and -sysroot flag of Clang++. | ||
| """ | ||
|
|
||
| from waflib.Tools import ccroot, ar, gxx | ||
| from waflib.Configure import conf | ||
| import waflib.extras.clang_cross_common | ||
|
|
||
| def options(opt): | ||
| """ | ||
| Target triplet for clang++:: | ||
| $ waf configure --clangxx-target-triple=x86_64-pc-linux-gnu | ||
| """ | ||
| cxx_compiler_opts = opt.add_option_group('Configuration options') | ||
| cxx_compiler_opts.add_option('--clangxx-target-triple', default=None, | ||
| help='Target triple for clang++', | ||
| dest='clangxx_target_triple') | ||
| cxx_compiler_opts.add_option('--clangxx-sysroot', default=None, | ||
| help='Sysroot for clang++', | ||
| dest='clangxx_sysroot') | ||
|
|
||
| @conf | ||
| def find_clangxx(conf): | ||
| """ | ||
| Finds the program clang++, and executes it to ensure it really is clang++ | ||
| """ | ||
|
|
||
| import os | ||
|
|
||
| cxx = conf.find_program('clang++', var='CXX') | ||
|
|
||
| if conf.options.clangxx_target_triple != None: | ||
| conf.env.append_value('CXX', ['-target', conf.options.clangxx_target_triple]) | ||
|
|
||
| if conf.options.clangxx_sysroot != None: | ||
| sysroot = str() | ||
|
|
||
| if os.path.isabs(conf.options.clangxx_sysroot): | ||
| sysroot = conf.options.clangxx_sysroot | ||
| else: | ||
| sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clangxx_sysroot)) | ||
|
|
||
| conf.env.append_value('CXX', ['--sysroot', sysroot]) | ||
|
|
||
| conf.get_cc_version(cxx, clang=True) | ||
| conf.env.CXX_NAME = 'clang' | ||
|
|
||
| @conf | ||
| def clangxx_modifier_x86_64_w64_mingw32(conf): | ||
| conf.gcc_modifier_win32() | ||
|
|
||
| @conf | ||
| def clangxx_modifier_i386_w64_mingw32(conf): | ||
| conf.gcc_modifier_win32() | ||
|
|
||
| @conf | ||
| def clangxx_modifier_msvc(conf): | ||
| v = conf.env | ||
| v.cxxprogram_PATTERN = v.cprogram_PATTERN | ||
| v.cxxshlib_PATTERN = v.cshlib_PATTERN | ||
|
|
||
| v.CXXFLAGS_cxxshlib = [] | ||
| v.LINKFLAGS_cxxshlib = v.LINKFLAGS_cshlib | ||
| v.cxxstlib_PATTERN = v.cstlib_PATTERN | ||
|
|
||
| v.LINK_CXX = v.CXX + ['-fuse-ld=lld', '-nostdlib'] | ||
| v.CXXLNK_TGT_F = v.CCLNK_TGT_F | ||
|
|
||
| @conf | ||
| def clangxx_modifier_x86_64_windows_msvc(conf): | ||
| conf.clang_modifier_msvc() | ||
| conf.clangxx_modifier_msvc() | ||
|
|
||
| # Allow the user to override any flags if they so desire. | ||
| clang_modifier_user_func = getattr(conf, 'clangxx_modifier_x86_64_windows_msvc_user', None) | ||
| if clang_modifier_user_func: | ||
| clang_modifier_user_func() | ||
|
|
||
| @conf | ||
| def clangxx_modifier_i386_windows_msvc(conf): | ||
| conf.clang_modifier_msvc() | ||
| conf.clangxx_modifier_msvc() | ||
|
|
||
| # Allow the user to override any flags if they so desire. | ||
| clang_modifier_user_func = getattr(conf, 'clangxx_modifier_i386_windows_msvc_user', None) | ||
| if clang_modifier_user_func: | ||
| clang_modifier_user_func() | ||
|
|
||
| def configure(conf): | ||
| conf.find_clangxx() | ||
| conf.find_program(['llvm-ar', 'ar'], var='AR') | ||
| conf.find_ar() | ||
| conf.gxx_common_flags() | ||
| # Allow the user to provide flags for the target platform. | ||
| conf.gxx_modifier_platform() | ||
| # And allow more fine grained control based on the compiler's triplet. | ||
| conf.clang_modifier_target_triple(cpp=True) | ||
| conf.cxx_load_tools() | ||
| conf.cxx_add_flags() | ||
| conf.link_add_flags() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Thomas Nagy, 2021 (ita) | ||
|
|
||
| from waflib import Utils, Runner | ||
|
|
||
| """ | ||
| Re-enable the classic threading system from waf 1.x | ||
| def configure(conf): | ||
| conf.load('classic_runner') | ||
| """ | ||
|
|
||
| class TaskConsumer(Utils.threading.Thread): | ||
| """ | ||
| Task consumers belong to a pool of workers | ||
| They wait for tasks in the queue and then use ``task.process(...)`` | ||
| """ | ||
| def __init__(self, spawner): | ||
| Utils.threading.Thread.__init__(self) | ||
| """ | ||
| Obtain :py:class:`waflib.Task.TaskBase` instances from this queue. | ||
| """ | ||
| self.spawner = spawner | ||
| self.daemon = True | ||
| self.start() | ||
|
|
||
| def run(self): | ||
| """ | ||
| Loop over the tasks to execute | ||
| """ | ||
| try: | ||
| self.loop() | ||
| except Exception: | ||
| pass | ||
|
|
||
| def loop(self): | ||
| """ | ||
| Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call | ||
| :py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it. | ||
| """ | ||
| master = self.spawner.master | ||
| while 1: | ||
| if not master.stop: | ||
| try: | ||
| tsk = master.ready.get() | ||
| if tsk: | ||
| tsk.log_display(tsk.generator.bld) | ||
| master.process_task(tsk) | ||
| else: | ||
| break | ||
| finally: | ||
| master.out.put(tsk) | ||
|
|
||
| class Spawner(object): | ||
| """ | ||
| Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and | ||
| spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each | ||
| :py:class:`waflib.Task.Task` instance. | ||
| """ | ||
| def __init__(self, master): | ||
| self.master = master | ||
| """:py:class:`waflib.Runner.Parallel` producer instance""" | ||
|
|
||
| self.pool = [TaskConsumer(self) for i in range(master.numjobs)] | ||
|
|
||
| Runner.Spawner = Spawner |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
|
|
||
| # Replaces the default formatter by one which understands MSVC output and colorizes it. | ||
| # Modified from color_gcc.py | ||
|
|
||
| __author__ = __maintainer__ = "Alibek Omarov <a1ba.omarov@gmail.com>" | ||
| __copyright__ = "Alibek Omarov, 2019" | ||
|
|
||
| import sys | ||
| from waflib import Logs | ||
|
|
||
| class ColorMSVCFormatter(Logs.formatter): | ||
| def __init__(self, colors): | ||
| self.colors = colors | ||
| Logs.formatter.__init__(self) | ||
|
|
||
| def parseMessage(self, line, color): | ||
| # Split messaage from 'disk:filepath: type: message' | ||
| arr = line.split(':', 3) | ||
| if len(arr) < 4: | ||
| return line | ||
|
|
||
| colored = self.colors.BOLD + arr[0] + ':' + arr[1] + ':' + self.colors.NORMAL | ||
| colored += color + arr[2] + ':' + self.colors.NORMAL | ||
| colored += arr[3] | ||
| return colored | ||
|
|
||
| def format(self, rec): | ||
| frame = sys._getframe() | ||
| while frame: | ||
| func = frame.f_code.co_name | ||
| if func == 'exec_command': | ||
| cmd = frame.f_locals.get('cmd') | ||
| if isinstance(cmd, list): | ||
| # Fix file case, it may be CL.EXE or cl.exe | ||
| argv0 = cmd[0].lower() | ||
| if 'cl.exe' in argv0: | ||
| lines = [] | ||
| # This will not work with "localized" versions | ||
| # of MSVC | ||
| for line in rec.msg.splitlines(): | ||
| if ': warning ' in line: | ||
| lines.append(self.parseMessage(line, self.colors.YELLOW)) | ||
| elif ': error ' in line: | ||
| lines.append(self.parseMessage(line, self.colors.RED)) | ||
| elif ': fatal error ' in line: | ||
| lines.append(self.parseMessage(line, self.colors.RED + self.colors.BOLD)) | ||
| elif ': note: ' in line: | ||
| lines.append(self.parseMessage(line, self.colors.CYAN)) | ||
| else: | ||
| lines.append(line) | ||
| rec.msg = "\n".join(lines) | ||
| frame = frame.f_back | ||
| return Logs.formatter.format(self, rec) | ||
|
|
||
| def options(opt): | ||
| Logs.log.handlers[0].setFormatter(ColorMSVCFormatter(Logs.colors)) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #! /usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Detection of the Fujitsu Fortran compiler for ARM64FX | ||
|
|
||
| import re | ||
| from waflib.Tools import fc,fc_config,fc_scan | ||
| from waflib.Configure import conf | ||
| from waflib.Tools.compiler_fc import fc_compiler | ||
| fc_compiler['linux'].append('fc_fujitsu') | ||
|
|
||
| @conf | ||
| def find_fujitsu(conf): | ||
| fc=conf.find_program(['frtpx'],var='FC') | ||
| conf.get_fujitsu_version(fc) | ||
| conf.env.FC_NAME='FUJITSU' | ||
| conf.env.FC_MOD_CAPITALIZATION='lower' | ||
|
|
||
| @conf | ||
| def fujitsu_flags(conf): | ||
| v=conf.env | ||
| v['_FCMODOUTFLAGS']=[] | ||
| v['FCFLAGS_DEBUG']=[] | ||
| v['FCFLAGS_fcshlib']=[] | ||
| v['LINKFLAGS_fcshlib']=[] | ||
| v['FCSTLIB_MARKER']='' | ||
| v['FCSHLIB_MARKER']='' | ||
|
|
||
| @conf | ||
| def get_fujitsu_version(conf,fc): | ||
| version_re=re.compile(r"frtpx\s*\(FRT\)\s*(?P<major>\d+)\.(?P<minor>\d+)\.",re.I).search | ||
| cmd=fc+['--version'] | ||
| out,err=fc_config.getoutput(conf,cmd,stdin=False) | ||
| if out: | ||
| match=version_re(out) | ||
| else: | ||
| match=version_re(err) | ||
| if not match: | ||
| return(False) | ||
| conf.fatal('Could not determine the Fujitsu FRT Fortran compiler version.') | ||
| else: | ||
| k=match.groupdict() | ||
| conf.env['FC_VERSION']=(k['major'],k['minor']) | ||
|
|
||
| def configure(conf): | ||
| conf.find_fujitsu() | ||
| conf.find_program('ar',var='AR') | ||
| conf.add_os_flags('ARFLAGS') | ||
| if not conf.env.ARFLAGS: | ||
| conf.env.ARFLAGS=['rcs'] | ||
| conf.fc_flags() | ||
| conf.fc_add_flags() | ||
| conf.fujitsu_flags() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #! /usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Detection of the NEC Fortran compiler for Aurora Tsubasa | ||
|
|
||
| import re | ||
| from waflib.Tools import fc,fc_config,fc_scan | ||
| from waflib.Configure import conf | ||
| from waflib.Tools.compiler_fc import fc_compiler | ||
| fc_compiler['linux'].append('fc_nfort') | ||
|
|
||
| @conf | ||
| def find_nfort(conf): | ||
| fc=conf.find_program(['nfort'],var='FC') | ||
| conf.get_nfort_version(fc) | ||
| conf.env.FC_NAME='NFORT' | ||
| conf.env.FC_MOD_CAPITALIZATION='lower' | ||
|
|
||
| @conf | ||
| def nfort_flags(conf): | ||
| v=conf.env | ||
| v['_FCMODOUTFLAGS']=[] | ||
| v['FCFLAGS_DEBUG']=[] | ||
| v['FCFLAGS_fcshlib']=[] | ||
| v['LINKFLAGS_fcshlib']=[] | ||
| v['FCSTLIB_MARKER']='' | ||
| v['FCSHLIB_MARKER']='' | ||
|
|
||
| @conf | ||
| def get_nfort_version(conf,fc): | ||
| version_re=re.compile(r"nfort\s*\(NFORT\)\s*(?P<major>\d+)\.(?P<minor>\d+)\.",re.I).search | ||
| cmd=fc+['--version'] | ||
| out,err=fc_config.getoutput(conf,cmd,stdin=False) | ||
| if out: | ||
| match=version_re(out) | ||
| else: | ||
| match=version_re(err) | ||
| if not match: | ||
| return(False) | ||
| conf.fatal('Could not determine the NEC NFORT Fortran compiler version.') | ||
| else: | ||
| k=match.groupdict() | ||
| conf.env['FC_VERSION']=(k['major'],k['minor']) | ||
|
|
||
| def configure(conf): | ||
| conf.find_nfort() | ||
| conf.find_program('nar',var='AR') | ||
| conf.add_os_flags('ARFLAGS') | ||
| if not conf.env.ARFLAGS: | ||
| conf.env.ARFLAGS=['rcs'] | ||
| conf.fc_flags() | ||
| conf.fc_add_flags() | ||
| conf.nfort_flags() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| import os | ||
| import pipes | ||
| import subprocess | ||
| import sys | ||
|
|
||
| from waflib import Logs, Task, Context | ||
| from waflib.Tools.c_preproc import scan as scan_impl | ||
| # ^-- Note: waflib.extras.gccdeps.scan does not work for us, | ||
| # due to its current implementation: | ||
| # The -MD flag is injected into the {C,CXX}FLAGS environment variable and | ||
| # dependencies are read out in a separate step after compiling by reading | ||
| # the .d file saved alongside the object file. | ||
| # As the genpybind task refers to a header file that is never compiled itself, | ||
| # gccdeps will not be able to extract the list of dependencies. | ||
|
|
||
| from waflib.TaskGen import feature, before_method | ||
|
|
||
|
|
||
| def join_args(args): | ||
| return " ".join(pipes.quote(arg) for arg in args) | ||
|
|
||
|
|
||
| def configure(cfg): | ||
| cfg.load("compiler_cxx") | ||
| cfg.load("python") | ||
| cfg.check_python_version(minver=(2, 7)) | ||
| if not cfg.env.LLVM_CONFIG: | ||
| cfg.find_program("llvm-config", var="LLVM_CONFIG") | ||
| if not cfg.env.GENPYBIND: | ||
| cfg.find_program("genpybind", var="GENPYBIND") | ||
|
|
||
| # find clang reasource dir for builtin headers | ||
| cfg.env.GENPYBIND_RESOURCE_DIR = os.path.join( | ||
| cfg.cmd_and_log(cfg.env.LLVM_CONFIG + ["--libdir"]).strip(), | ||
| "clang", | ||
| cfg.cmd_and_log(cfg.env.LLVM_CONFIG + ["--version"]).strip()) | ||
| if os.path.exists(cfg.env.GENPYBIND_RESOURCE_DIR): | ||
| cfg.msg("Checking clang resource dir", cfg.env.GENPYBIND_RESOURCE_DIR) | ||
| else: | ||
| cfg.fatal("Clang resource dir not found") | ||
|
|
||
|
|
||
| @feature("genpybind") | ||
| @before_method("process_source") | ||
| def generate_genpybind_source(self): | ||
| """ | ||
| Run genpybind on the headers provided in `source` and compile/link the | ||
| generated code instead. This works by generating the code on the fly and | ||
| swapping the source node before `process_source` is run. | ||
| """ | ||
| # name of module defaults to name of target | ||
| module = getattr(self, "module", self.target) | ||
|
|
||
| # create temporary source file in build directory to hold generated code | ||
| out = "genpybind-%s.%d.cpp" % (module, self.idx) | ||
| out = self.path.get_bld().find_or_declare(out) | ||
|
|
||
| task = self.create_task("genpybind", self.to_nodes(self.source), out) | ||
| # used to detect whether CFLAGS or CXXFLAGS should be passed to genpybind | ||
| task.features = self.features | ||
| task.module = module | ||
| # can be used to select definitions to include in the current module | ||
| # (when header files are shared by more than one module) | ||
| task.genpybind_tags = self.to_list(getattr(self, "genpybind_tags", [])) | ||
| # additional include directories | ||
| task.includes = self.to_list(getattr(self, "includes", [])) | ||
| task.genpybind = self.env.GENPYBIND | ||
|
|
||
| # Tell waf to compile/link the generated code instead of the headers | ||
| # originally passed-in via the `source` parameter. (see `process_source`) | ||
| self.source = [out] | ||
|
|
||
|
|
||
| class genpybind(Task.Task): # pylint: disable=invalid-name | ||
| """ | ||
| Runs genpybind on headers provided as input to this task. | ||
| Generated code will be written to the first (and only) output node. | ||
| """ | ||
| quiet = True | ||
| color = "PINK" | ||
| scan = scan_impl | ||
|
|
||
| @staticmethod | ||
| def keyword(): | ||
| return "Analyzing" | ||
|
|
||
| def run(self): | ||
| if not self.inputs: | ||
| return | ||
|
|
||
| args = self.find_genpybind() + self._arguments( | ||
| resource_dir=self.env.GENPYBIND_RESOURCE_DIR) | ||
|
|
||
| output = self.run_genpybind(args) | ||
|
|
||
| # For debugging / log output | ||
| pasteable_command = join_args(args) | ||
|
|
||
| # write generated code to file in build directory | ||
| # (will be compiled during process_source stage) | ||
| (output_node,) = self.outputs | ||
| output_node.write("// {}\n{}\n".format( | ||
| pasteable_command.replace("\n", "\n// "), output)) | ||
|
|
||
| def find_genpybind(self): | ||
| return self.genpybind | ||
|
|
||
| def run_genpybind(self, args): | ||
| bld = self.generator.bld | ||
|
|
||
| kwargs = dict(cwd=bld.variant_dir) | ||
| if hasattr(bld, "log_command"): | ||
| bld.log_command(args, kwargs) | ||
| else: | ||
| Logs.debug("runner: {!r}".format(args)) | ||
| proc = subprocess.Popen( | ||
| args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) | ||
| stdout, stderr = proc.communicate() | ||
|
|
||
| if not isinstance(stdout, str): | ||
| stdout = stdout.decode(sys.stdout.encoding, errors="replace") | ||
| if not isinstance(stderr, str): | ||
| stderr = stderr.decode(sys.stderr.encoding, errors="replace") | ||
|
|
||
| if proc.returncode != 0: | ||
| bld.fatal( | ||
| "genpybind returned {code} during the following call:" | ||
| "\n{command}\n\n{stdout}\n\n{stderr}".format( | ||
| code=proc.returncode, | ||
| command=join_args(args), | ||
| stdout=stdout, | ||
| stderr=stderr, | ||
| )) | ||
|
|
||
| if stderr.strip(): | ||
| Logs.debug("non-fatal warnings during genpybind run:\n{}".format(stderr)) | ||
|
|
||
| return stdout | ||
|
|
||
| def _include_paths(self): | ||
| return self.generator.to_incnodes(self.includes + self.env.INCLUDES) | ||
|
|
||
| def _inputs_as_relative_includes(self): | ||
| include_paths = self._include_paths() | ||
| relative_includes = [] | ||
| for node in self.inputs: | ||
| for inc in include_paths: | ||
| if node.is_child_of(inc): | ||
| relative_includes.append(node.path_from(inc)) | ||
| break | ||
| else: | ||
| self.generator.bld.fatal("could not resolve {}".format(node)) | ||
| return relative_includes | ||
|
|
||
| def _arguments(self, genpybind_parse=None, resource_dir=None): | ||
| args = [] | ||
| relative_includes = self._inputs_as_relative_includes() | ||
| is_cxx = "cxx" in self.features | ||
|
|
||
| # options for genpybind | ||
| args.extend(["--genpybind-module", self.module]) | ||
| if self.genpybind_tags: | ||
| args.extend(["--genpybind-tag"] + self.genpybind_tags) | ||
| if relative_includes: | ||
| args.extend(["--genpybind-include"] + relative_includes) | ||
| if genpybind_parse: | ||
| args.extend(["--genpybind-parse", genpybind_parse]) | ||
|
|
||
| args.append("--") | ||
|
|
||
| # headers to be processed by genpybind | ||
| args.extend(node.abspath() for node in self.inputs) | ||
|
|
||
| args.append("--") | ||
|
|
||
| # options for clang/genpybind-parse | ||
| args.append("-D__GENPYBIND__") | ||
| args.append("-xc++" if is_cxx else "-xc") | ||
| has_std_argument = False | ||
| for flag in self.env["CXXFLAGS" if is_cxx else "CFLAGS"]: | ||
| flag = flag.replace("-std=gnu", "-std=c") | ||
| if flag.startswith("-std=c"): | ||
| has_std_argument = True | ||
| args.append(flag) | ||
| if not has_std_argument: | ||
| args.append("-std=c++14") | ||
| args.extend("-I{}".format(n.abspath()) for n in self._include_paths()) | ||
| args.extend("-D{}".format(p) for p in self.env.DEFINES) | ||
|
|
||
| # point to clang resource dir, if specified | ||
| if resource_dir: | ||
| args.append("-resource-dir={}".format(resource_dir)) | ||
|
|
||
| return args |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| import re | ||
|
|
||
| from waflib import Utils, Task, Errors, Logs | ||
| from waflib.Configure import conf | ||
| from waflib.TaskGen import extension, taskgen_method | ||
|
|
||
| HAXE_COMPILERS = { | ||
| 'JS': {'tgt': '--js', 'ext_out': ['.js']}, | ||
| 'LUA': {'tgt': '--lua', 'ext_out': ['.lua']}, | ||
| 'SWF': {'tgt': '--swf', 'ext_out': ['.swf']}, | ||
| 'NEKO': {'tgt': '--neko', 'ext_out': ['.n']}, | ||
| 'PHP': {'tgt': '--php', 'ext_out': ['.php']}, | ||
| 'CPP': {'tgt': '--cpp', 'ext_out': ['.h', '.cpp']}, | ||
| 'CPPIA': {'tgt': '--cppia', 'ext_out': ['.cppia']}, | ||
| 'CS': {'tgt': '--cs', 'ext_out': ['.cs']}, | ||
| 'JAVA': {'tgt': '--java', 'ext_out': ['.java']}, | ||
| 'JVM': {'tgt': '--jvm', 'ext_out': ['.jar']}, | ||
| 'PYTHON': {'tgt': '--python', 'ext_out': ['.py']}, | ||
| 'HL': {'tgt': '--hl', 'ext_out': ['.hl']}, | ||
| 'HLC': {'tgt': '--hl', 'ext_out': ['.h', '.c']}, | ||
| } | ||
|
|
||
| @conf | ||
| def check_haxe_pkg(self, **kw): | ||
| self.find_program('haxelib') | ||
| libs = kw.get('libs') | ||
| if not libs or not (type(libs) == str or (type(libs) == list and all(isinstance(s, str) for s in libs))): | ||
| self.fatal('Specify correct libs value in ensure call') | ||
| return | ||
| fetch = kw.get('fetch') | ||
| if not fetch is None and not type(fetch) == bool: | ||
| self.fatal('Specify correct fetch value in ensure call') | ||
|
|
||
| libs = [libs] if type(libs) == str else libs | ||
| halt = False | ||
| for lib in libs: | ||
| try: | ||
| self.start_msg('Checking for library %s' % lib) | ||
| output = self.cmd_and_log(self.env.HAXELIB + ['list', lib]) | ||
| except Errors.WafError: | ||
| self.end_msg(False) | ||
| self.fatal('Can\'t run haxelib list, ensuring halted') | ||
| return | ||
|
|
||
| if lib in output: | ||
| self.end_msg(lib in output) | ||
| else: | ||
| if not fetch: | ||
| self.end_msg(False) | ||
| halt = True | ||
| continue | ||
| try: | ||
| status = self.exec_command(self.env.HAXELIB + ['install', lib]) | ||
| if status: | ||
| self.end_msg(False) | ||
| self.fatal('Can\'t get %s with haxelib, ensuring halted' % lib) | ||
| return | ||
| else: | ||
| self.end_msg('downloaded', color='YELLOW') | ||
| except Errors.WafError: | ||
| self.end_msg(False) | ||
| self.fatal('Can\'t run haxelib install, ensuring halted') | ||
| return | ||
| postfix = kw.get('uselib_store') or lib.upper() | ||
| self.env.append_unique('LIB_' + postfix, lib) | ||
|
|
||
| if halt: | ||
| self.fatal('Can\'t find libraries in haxelib list, ensuring halted') | ||
| return | ||
|
|
||
| class haxe(Task.Task): | ||
| vars = ['HAXE_VERSION', 'HAXE_FLAGS'] | ||
| ext_in = ['.hx'] | ||
|
|
||
| def run(self): | ||
| cmd = self.env.HAXE + self.env.HAXE_FLAGS_DEFAULT + self.env.HAXE_FLAGS | ||
| return self.exec_command(cmd) | ||
|
|
||
| for COMP in HAXE_COMPILERS: | ||
| # create runners for each compile target | ||
| type("haxe_" + COMP, (haxe,), {'ext_out': HAXE_COMPILERS[COMP]['ext_out']}) | ||
|
|
||
| @taskgen_method | ||
| def init_haxe(self): | ||
| errmsg = '%s not found, specify correct value' | ||
| try: | ||
| compiler = HAXE_COMPILERS[self.compiler] | ||
| comp_tgt = compiler['tgt'] | ||
| comp_mod = '/main.c' if self.compiler == 'HLC' else '' | ||
| except (AttributeError, KeyError): | ||
| self.bld.fatal(errmsg % 'COMPILER' + ': ' + ', '.join(HAXE_COMPILERS.keys())) | ||
| return | ||
|
|
||
| self.env.append_value( | ||
| 'HAXE_FLAGS', | ||
| [comp_tgt, self.path.get_bld().make_node(self.target + comp_mod).abspath()]) | ||
| if hasattr(self, 'use'): | ||
| if not (type(self.use) == str or type(self.use) == list): | ||
| self.bld.fatal(errmsg % 'USE') | ||
| return | ||
| self.use = [self.use] if type(self.use) == str else self.use | ||
|
|
||
| for dep in self.use: | ||
| if self.env['LIB_' + dep]: | ||
| for lib in self.env['LIB_' + dep]: | ||
| self.env.append_value('HAXE_FLAGS', ['-lib', lib]) | ||
|
|
||
| if hasattr(self, 'res'): | ||
| if not type(self.res) == str: | ||
| self.bld.fatal(errmsg % 'RES') | ||
| return | ||
| self.env.append_value('HAXE_FLAGS', ['-D', 'resourcesPath=%s' % self.res]) | ||
|
|
||
| @extension('.hx') | ||
| def haxe_hook(self, node): | ||
| if len(self.source) > 1: | ||
| self.bld.fatal('Use separate task generators for multiple files') | ||
| return | ||
|
|
||
| src = node | ||
| tgt = self.path.get_bld().find_or_declare(self.target) | ||
|
|
||
| self.init_haxe() | ||
| self.create_task('haxe_' + self.compiler, src, tgt) | ||
|
|
||
| @conf | ||
| def check_haxe(self, mini=None, maxi=None): | ||
| self.start_msg('Checking for haxe version') | ||
| try: | ||
| curr = re.search( | ||
| r'(\d+.?)+', | ||
| self.cmd_and_log(self.env.HAXE + ['-version'])).group() | ||
| except Errors.WafError: | ||
| self.end_msg(False) | ||
| self.fatal('Can\'t get haxe version') | ||
| return | ||
|
|
||
| if mini and Utils.num2ver(curr) < Utils.num2ver(mini): | ||
| self.end_msg('wrong', color='RED') | ||
| self.fatal('%s is too old, need >= %s' % (curr, mini)) | ||
| return | ||
| if maxi and Utils.num2ver(curr) > Utils.num2ver(maxi): | ||
| self.end_msg('wrong', color='RED') | ||
| self.fatal('%s is too new, need <= %s' % (curr, maxi)) | ||
| return | ||
| self.end_msg(curr, color='GREEN') | ||
| self.env.HAXE_VERSION = curr | ||
|
|
||
| def configure(self): | ||
| self.env.append_value( | ||
| 'HAXE_FLAGS_DEFAULT', | ||
| ['-D', 'no-compilation', '-cp', self.path.abspath()]) | ||
| Logs.warn('Default flags: %s' % ' '.join(self.env.HAXE_FLAGS_DEFAULT)) | ||
| self.find_program('haxe') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| #!/usr/bin/env python | ||
| # encoding: utf-8 | ||
| # Rafaël Kooi 2019 | ||
|
|
||
| from waflib import TaskGen | ||
|
|
||
| @TaskGen.feature('c', 'cxx', 'fc') | ||
| @TaskGen.after_method('propagate_uselib_vars') | ||
| def add_pdb_per_object(self): | ||
| """For msvc/fortran, specify a unique compile pdb per object, to work | ||
| around LNK4099. Flags are updated with a unique /Fd flag based on the | ||
| task output name. This is separate from the link pdb. | ||
| """ | ||
| if not hasattr(self, 'compiled_tasks'): | ||
| return | ||
|
|
||
| link_task = getattr(self, 'link_task', None) | ||
|
|
||
| for task in self.compiled_tasks: | ||
| if task.inputs and task.inputs[0].name.lower().endswith('.rc'): | ||
| continue | ||
|
|
||
| add_pdb = False | ||
| for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): | ||
| # several languages may be used at once | ||
| for flag in task.env[flagname]: | ||
| if flag[1:].lower() == 'zi': | ||
| add_pdb = True | ||
| break | ||
|
|
||
| if add_pdb: | ||
| node = task.outputs[0].change_ext('.pdb') | ||
| pdb_flag = '/Fd:' + node.abspath() | ||
|
|
||
| for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): | ||
| buf = [pdb_flag] | ||
| for flag in task.env[flagname]: | ||
| if flag[1:3] == 'Fd' or flag[1:].lower() == 'fs' or flag[1:].lower() == 'mp': | ||
| continue | ||
| buf.append(flag) | ||
| task.env[flagname] = buf | ||
|
|
||
| if link_task and not node in link_task.dep_nodes: | ||
| link_task.dep_nodes.append(node) | ||
| if not node in task.outputs: | ||
| task.outputs.append(node) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| """Support for Sphinx documentation | ||
| This is a wrapper for sphinx-build program. Please note that sphinx-build supports only | ||
| one output format at a time, but the tool can create multiple tasks to handle more. | ||
| The output formats can be passed via the sphinx_output_format, which is an array of | ||
| strings. For backwards compatibility if only one output is needed, it can be passed | ||
| as a single string. | ||
| The default output format is html. | ||
| Specific formats can be installed in different directories by specifying the | ||
| install_path_<FORMAT> attribute. If not defined, the standard install_path | ||
| will be used instead. | ||
| Example wscript: | ||
| def configure(cnf): | ||
| conf.load('sphinx') | ||
| def build(bld): | ||
| bld( | ||
| features='sphinx', | ||
| sphinx_source='sources', # path to source directory | ||
| sphinx_options='-a -v', # sphinx-build program additional options | ||
| sphinx_output_format=['html', 'man'], # output format of sphinx documentation | ||
| install_path_man='${DOCDIR}/man' # put man pages in a specific directory | ||
| ) | ||
| """ | ||
|
|
||
| from waflib.Node import Node | ||
| from waflib import Utils | ||
| from waflib import Task | ||
| from waflib.TaskGen import feature, after_method | ||
|
|
||
|
|
||
| def configure(cnf): | ||
| """Check if sphinx-build program is available and loads gnu_dirs tool.""" | ||
| cnf.find_program('sphinx-build', var='SPHINX_BUILD', mandatory=False) | ||
| cnf.load('gnu_dirs') | ||
|
|
||
|
|
||
| @feature('sphinx') | ||
| def build_sphinx(self): | ||
| """Builds sphinx sources. | ||
| """ | ||
| if not self.env.SPHINX_BUILD: | ||
| self.bld.fatal('Program SPHINX_BUILD not defined.') | ||
| if not getattr(self, 'sphinx_source', None): | ||
| self.bld.fatal('Attribute sphinx_source not defined.') | ||
| if not isinstance(self.sphinx_source, Node): | ||
| self.sphinx_source = self.path.find_node(self.sphinx_source) | ||
| if not self.sphinx_source: | ||
| self.bld.fatal('Can\'t find sphinx_source: %r' % self.sphinx_source) | ||
|
|
||
| # In the taskgen we have the complete list of formats | ||
| Utils.def_attrs(self, sphinx_output_format='html') | ||
| self.sphinx_output_format = Utils.to_list(self.sphinx_output_format) | ||
|
|
||
| self.env.SPHINX_OPTIONS = getattr(self, 'sphinx_options', []) | ||
|
|
||
| for source_file in self.sphinx_source.ant_glob('**/*'): | ||
| self.bld.add_manual_dependency(self.sphinx_source, source_file) | ||
|
|
||
| for cfmt in self.sphinx_output_format: | ||
| sphinx_build_task = self.create_task('SphinxBuildingTask') | ||
| sphinx_build_task.set_inputs(self.sphinx_source) | ||
| # In task we keep the specific format this task is generating | ||
| sphinx_build_task.env.SPHINX_OUTPUT_FORMAT = cfmt | ||
|
|
||
| # the sphinx-build results are in <build + output_format> directory | ||
| sphinx_build_task.sphinx_output_directory = self.path.get_bld().make_node(cfmt) | ||
| sphinx_build_task.set_outputs(sphinx_build_task.sphinx_output_directory) | ||
| sphinx_build_task.sphinx_output_directory.mkdir() | ||
|
|
||
| Utils.def_attrs(sphinx_build_task, install_path=getattr(self, 'install_path_' + cfmt, getattr(self, 'install_path', get_install_path(sphinx_build_task)))) | ||
|
|
||
|
|
||
| def get_install_path(object): | ||
| if object.env.SPHINX_OUTPUT_FORMAT == 'man': | ||
| return object.env.MANDIR | ||
| elif object.env.SPHINX_OUTPUT_FORMAT == 'info': | ||
| return object.env.INFODIR | ||
| else: | ||
| return object.env.DOCDIR | ||
|
|
||
|
|
||
| class SphinxBuildingTask(Task.Task): | ||
| color = 'BOLD' | ||
| run_str = '${SPHINX_BUILD} -M ${SPHINX_OUTPUT_FORMAT} ${SRC} ${TGT} -d ${TGT[0].bld_dir()}/doctrees-${SPHINX_OUTPUT_FORMAT} ${SPHINX_OPTIONS}' | ||
|
|
||
| def keyword(self): | ||
| return 'Compiling (%s)' % self.env.SPHINX_OUTPUT_FORMAT | ||
|
|
||
| def runnable_status(self): | ||
|
|
||
| for x in self.run_after: | ||
| if not x.hasrun: | ||
| return Task.ASK_LATER | ||
|
|
||
| self.signature() | ||
| ret = Task.Task.runnable_status(self) | ||
| if ret == Task.SKIP_ME: | ||
| # in case the files were removed | ||
| self.add_install() | ||
| return ret | ||
|
|
||
|
|
||
| def post_run(self): | ||
| self.add_install() | ||
| return Task.Task.post_run(self) | ||
|
|
||
|
|
||
| def add_install(self): | ||
| nodes = self.sphinx_output_directory.ant_glob('**/*', quiet=True) | ||
| self.outputs += nodes | ||
| self.generator.add_install_files(install_to=self.install_path, | ||
| install_from=nodes, | ||
| postpone=False, | ||
| cwd=self.sphinx_output_directory.make_node(self.env.SPHINX_OUTPUT_FORMAT), | ||
| relative_trick=True) |