diff --git a/environment.py b/environment.py index 6f89b4736..255784ee5 100755 --- a/environment.py +++ b/environment.py @@ -17,6 +17,7 @@ import subprocess, os.path, platform import coredata from glob import glob +import tempfile build_filename = 'meson.build' @@ -33,6 +34,7 @@ class CCompiler(): else: raise TypeError('Unknown argument to CCompiler') self.language = 'c' + self.default_suffix = 'c' def get_dependency_gen_flags(self, outtarget, outfile): return ['-MMD', '-MT', outtarget, '-MF', outfile] @@ -44,10 +46,10 @@ class CCompiler(): return self.language def get_exelist(self): - return self.exelist + return self.exelist[:] def get_linker_exelist(self): - return self.exelist + return self.exelist[:] def get_compile_only_flags(self): return ['-c'] @@ -102,6 +104,28 @@ class CCompiler(): pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by C compiler %s are not runnable.' % self.name_string()) + + def compiles(self, code): + suflen = len(self.default_suffix) + (fd, srcname) = tempfile.mkstemp(suffix='.'+self.default_suffix) + open(srcname, 'w').write(code) + commands = self.get_exelist() + commands += self.get_compile_only_flags() + commands.append(srcname) + p = subprocess.Popen(commands, cwd=os.path.split(srcname)[0], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + p.communicate() + os.close(fd) + os.remove(srcname) + try: + trial = srcname[:-suflen] + 'o' + os.remove(trial) + except FileNotFoundError: + pass + try: + os.remove(srcname[:-suflen] + 'obj') + except FileNotFoundError: + pass + return p.returncode == 0 cxx_suffixes = ['cc', 'cpp', 'cxx', 'hh', 'hpp', 'hxx'] @@ -109,6 +133,7 @@ class CXXCompiler(CCompiler): def __init__(self, exelist): CCompiler.__init__(self, exelist) self.language = 'cxx' + self.default_suffix = 'cpp' def can_compile(self, filename): suffix = filename.split('.')[-1] @@ -135,7 +160,8 @@ class ObjCCompiler(CCompiler): def __init__(self, exelist): CCompiler.__init__(self, exelist) self.language = 'objc' - + self.default_suffix = 'm' + def can_compile(self, filename): suffix = filename.split('.')[-1] if suffix == 'm' or suffix == 'h': @@ -146,6 +172,7 @@ class ObjCXXCompiler(CXXCompiler): def __init__(self, exelist): CXXCompiler.__init__(self, exelist) self.language = 'objcxx' + self.default_suffix = 'mm' def can_compile(self, filename): suffix = filename.split('.')[-1] @@ -228,6 +255,8 @@ class VisualStudioCCompiler(CCompiler): class VisualStudioCXXCompiler(VisualStudioCCompiler): def __init__(self, exelist): VisualStudioCCompiler.__init__(self, exelist) + self.language = 'cxx' + self.default_suffix = 'cpp' def can_compile(self, filename): suffix = filename.split('.')[-1] diff --git a/interpreter.py b/interpreter.py index 22dee9d31..e788c98f3 100755 --- a/interpreter.py +++ b/interpreter.py @@ -496,6 +496,38 @@ class Test(InterpreterObject): def get_name(self): return self.name +class CompilerHolder(InterpreterObject): + def __init__(self, compiler): + InterpreterObject.__init__(self) + self.compiler = compiler + self.methods.update({'compiles': self.compiles_method}) + + def compiles_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('compiles method takes exactly one argument.') + string = args[0] + if isinstance(string, nodes.StringStatement): + string = string.value + if not isinstance(string, str): + raise InterpreterException('Argument to compiles() must be a string') + return self.compiler.compiles(string) + +class MesonMain(InterpreterObject): + def __init__(self, build): + InterpreterObject.__init__(self) + self.build = build + self.methods.update({'get_compiler': self.get_compiler_method}) + + def get_compiler_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('get_compiler_method must have one and only one argument.') + cname = args[0] + for c in self.build.compilers: + if c.get_language() == cname: + return CompilerHolder(c) + raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) + + class Interpreter(): def __init__(self, build): @@ -510,12 +542,13 @@ class Interpreter(): self.variables = {} self.builtin = {} self.builtin['host'] = Host() + self.builtin['meson'] = MesonMain(build) self.environment = build.environment self.build_func_dict() self.build_def_files = [environment.build_filename] + self.coredata = self.environment.get_coredata() self.subdir = '' self.generators = [] - self.coredata = self.environment.get_coredata() self.visited_subdirs = {} def build_func_dict(self): diff --git a/test cases/common/33 try compile/meson.build b/test cases/common/33 try compile/meson.build new file mode 100644 index 000000000..da3978439 --- /dev/null +++ b/test cases/common/33 try compile/meson.build @@ -0,0 +1,18 @@ +project('try compile', 'c') + +code = '''#include +void func() { printf("Something.\n"); } +''' + +breakcode = '''#include +void func() { printf("This won't work.\n"); } +''' + +compiler = meson.get_compiler('c') +if compiler.compiles(code) == false + error('Compiler is fail.') +endif + +if compiler.compiles(breakcode) + error('Compiler returned true on broken code.') +endif