aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-11-23 21:35:52 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-12-11 14:54:30 +0530
commit04c1909a4dcc4f92c845eabab5515419f0881dc5 (patch)
tree8c2bdf0a54e644a1982bf1354895e51e67493e7f
parent38f6fee86defebc6ccbc68c21ff857f6111ed874 (diff)
downloadmeson-04c1909a4dcc4f92c845eabab5515419f0881dc5.zip
meson-04c1909a4dcc4f92c845eabab5515419f0881dc5.tar.gz
meson-04c1909a4dcc4f92c845eabab5515419f0881dc5.tar.bz2
compilers: Implement support for LLVM IR compilation
Also C++ compilers can build .S assembly files. This wasn't noticed earlier because most people were also using C compilers in their C++ projects and we would fall back to using the C compiler for building the assembly files. Now we have a test for this. This was trivial to add; except that we needed a new LLVM IR rule because the compiler emits warnings if you pass any special arguments to it such as include arguments or dependency arguments. Closes #1089
-rw-r--r--mesonbuild/backend/ninjabackend.py80
-rw-r--r--mesonbuild/compilers.py13
-rw-r--r--mesonbuild/environment.py3
3 files changed, 84 insertions, 12 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index c95ee18..188823a 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -374,6 +374,9 @@ int dummy;
# because we need `header_deps` to be fully generated in the above loop.
for src in generated_source_files:
src_list.append(src)
+ if self.environment.is_llvm_ir(src):
+ obj_list.append(self.generate_llvm_ir_compile(target, outfile, src))
+ continue
obj_list.append(self.generate_single_compile(target, outfile, src, True,
header_deps=header_deps))
@@ -409,7 +412,9 @@ int dummy;
for f, src in target_sources.items():
if not self.environment.is_header(src):
src_list.append(src)
- if is_unity and self.get_target_source_can_unity(target, src):
+ if self.environment.is_llvm_ir(src):
+ obj_list.append(self.generate_llvm_ir_compile(target, outfile, src))
+ elif is_unity and self.get_target_source_can_unity(target, src):
abs_src = os.path.join(self.environment.get_build_dir(),
src.rel_to_builddir(self.build_to_src))
unity_src.append(abs_src)
@@ -1365,6 +1370,36 @@ rule FORTRAN_DEP_HACK
'''
outfile.write(template % cmd)
+ def generate_llvm_ir_compile_rule(self, compiler, is_cross, outfile):
+ if getattr(self, 'created_llvm_ir_rule', False):
+ return
+ rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '')
+ args = [' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
+ ' '.join(self.get_cross_info_lang_args(compiler, is_cross)),
+ ' '.join(compiler.get_output_args('$out')),
+ ' '.join(compiler.get_compile_only_args())]
+ if mesonlib.is_windows():
+ command_template = ' command = {} @$out.rsp\n' \
+ ' rspfile = $out.rsp\n' \
+ ' rspfile_content = {} $ARGS {} {} $in\n'
+ else:
+ command_template = ' command = {} {} $ARGS {} {} $in\n'
+ command = command_template.format(*args)
+ description = ' description = Compiling LLVM IR object $in.\n'
+ outfile.write(rule)
+ outfile.write(command)
+ outfile.write(description)
+ outfile.write('\n')
+ self.created_llvm_ir_rule = True
+
+ def get_cross_info_lang_args(self, lang, is_cross):
+ if is_cross:
+ try:
+ return self.environment.cross_info.config['properties'][lang + '_args']
+ except KeyError:
+ pass
+ return []
+
def generate_compile_rule_for(self, langname, compiler, qstr, is_cross, outfile):
if langname == 'java':
if not is_cross:
@@ -1399,12 +1434,7 @@ rule FORTRAN_DEP_HACK
if d != '$out' and d != '$in':
d = qstr % d
quoted_depargs.append(d)
- cross_args = []
- if is_cross:
- try:
- cross_args = self.environment.cross_info.config['properties'][langname + '_args']
- except KeyError:
- pass
+ cross_args = self.get_cross_info_lang_args(langname, is_cross)
if mesonlib.is_windows():
command_template = ''' command = %s @$out.rsp
rspfile = $out.rsp
@@ -1477,6 +1507,8 @@ rule FORTRAN_DEP_HACK
qstr = quote_char + "%s" + quote_char
for compiler in self.build.compilers:
langname = compiler.get_language()
+ if compiler.get_id() == 'clang':
+ self.generate_llvm_ir_compile_rule(compiler, False, outfile)
self.generate_compile_rule_for(langname, compiler, qstr, False, outfile)
self.generate_pch_rule_for(langname, compiler, qstr, False, outfile)
if self.environment.is_cross_build():
@@ -1488,6 +1520,8 @@ rule FORTRAN_DEP_HACK
cclist = self.build.compilers
for compiler in cclist:
langname = compiler.get_language()
+ if compiler.get_id() == 'clang':
+ self.generate_llvm_ir_compile_rule(compiler, True, outfile)
self.generate_compile_rule_for(langname, compiler, qstr, True, outfile)
self.generate_pch_rule_for(langname, compiler, qstr, True, outfile)
outfile.write('\n')
@@ -1680,9 +1714,39 @@ rule FORTRAN_DEP_HACK
def get_link_debugfile_args(self, linker, target, outname):
return linker.get_link_debugfile_args(outname)
+ def generate_llvm_ir_compile(self, target, outfile, src):
+ compiler = get_compiler_for_source(target.compilers.values(), src)
+ commands = []
+ # Compiler args for compiling this target
+ commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
+ compiler)
+ if isinstance(src, (RawFilename, File)):
+ src_filename = src.fname
+ elif os.path.isabs(src):
+ src_filename = os.path.basename(src)
+ else:
+ src_filename = src
+ obj_basename = src_filename.replace('/', '_').replace('\\', '_')
+ rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
+ rel_obj += '.' + self.environment.get_object_suffix()
+ commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
+ if isinstance(src, RawFilename):
+ rel_src = src.fname
+ elif isinstance(src, File):
+ rel_src = src.rel_to_builddir(self.build_to_src)
+ else:
+ raise InvalidArguments('Invalid source type: {!r}'.format(src))
+ # Write the Ninja build command
+ compiler_name = 'llvm_ir{}_COMPILER'.format('_CROSS' if target.is_cross else '')
+ element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
+ commands = self.dedup_arguments(commands)
+ element.add_item('ARGS', commands)
+ element.write(outfile)
+ return rel_obj
+
def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]):
"""
- Compiles C/C++, ObjC/ObjC++, and D sources
+ Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
"""
if isinstance(src, str) and src.endswith('.h'):
raise AssertionError('BUG: sources should not contain headers')
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 2ee4aac..08ebbfb 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -59,6 +59,11 @@ def is_source(fname):
suffix = fname.split('.')[-1]
return suffix in clike_suffixes
+def is_llvm_ir(fname):
+ if hasattr(fname, 'fname'):
+ fname = fname.fname
+ return fname.split('.')[-1] == 'll'
+
def is_object(fname):
if hasattr(fname, 'fname'):
fname = fname.fname
@@ -2018,6 +2023,8 @@ class GnuCompiler:
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
self.base_options.append('b_asneeded')
+ # All GCC backends can do assembly
+ self.can_compile_suffixes.add('s')
def get_colorout_args(self, colortype):
if mesonlib.version_compare(self.version, '>=4.9.0'):
@@ -2071,8 +2078,6 @@ class GnuCCompiler(GnuCompiler, CCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
GnuCompiler.__init__(self, gcc_type, defines)
- # Gcc can do asm, too.
- self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
@@ -2185,6 +2190,8 @@ class ClangCompiler():
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
self.base_options.append('b_asneeded')
+ # All Clang backends can do assembly and LLVM IR
+ self.can_compile_suffixes.update(['ll', 's'])
def get_pic_args(self):
if self.clang_type in (CLANG_WIN, CLANG_OSX):
@@ -2240,8 +2247,6 @@ class ClangCCompiler(ClangCompiler, CCompiler):
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
ClangCompiler.__init__(self, clang_type)
- # Clang can do asm, too.
- self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index e673d50..0e8364c 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -271,6 +271,9 @@ class Environment():
def is_source(self, fname):
return is_source(fname)
+ def is_llvm_ir(self, fname):
+ return is_llvm_ir(fname)
+
def is_object(self, fname):
return is_object(fname)