Add cross-compilation support for `rustc`

This patch is largely modeled on the relatively-straightforward code
for Fortran cross-compilation, so there might be some intricacies
missing.
pull/2938/head
Adam C. Foltzer 6 years ago
parent 7eb6a29180
commit 1d81efb03d
  1. 1
      cross/ubuntu-armhf.txt
  2. 16
      docs/markdown/snippets/rust-cross.md
  3. 16
      mesonbuild/backend/ninjabackend.py
  4. 15
      mesonbuild/compilers/rust.py
  5. 29
      mesonbuild/environment.py
  6. 4
      mesonbuild/interpreter.py

@ -3,6 +3,7 @@
# when cross compiled binaries can't be run we don't do that
c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
cpp = '/usr/bin/arm-linux-gnueabihf-g++-7'
rust = ['rustc', '--target', 'arm-unknown-linux-gnueabihf', '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7']
ar = '/usr/arm-linux-gnueabihf/bin/ar'
strip = '/usr/arm-linux-gnueabihf/bin/strip'
pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'

@ -0,0 +1,16 @@
## Rust cross-compilation
Cross-compilation is now supported for Rust targets. Like other
cross-compilers, the Rust binary must be specified in your cross
file. It should specify a `--target` (as installed by `rustup target`)
and a custom linker pointing to your C cross-compiler. For example:
```
[binaries]
c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
rust = [
'rustc',
'--target', 'arm-unknown-linux-gnueabihf',
'-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7',
]
```

@ -1291,7 +1291,11 @@ int dummy;
# installations
for rpath_arg in rpath_args:
args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')]
element = NinjaBuildElement(self.all_outputs, target_name, 'rust_COMPILER', relsrc)
crstr = ''
if target.is_cross:
crstr = '_CROSS'
compiler_name = 'rust%s_COMPILER' % crstr
element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, relsrc)
if len(orderdeps) > 0:
element.add_orderdep(orderdeps)
element.add_item('ARGS', args)
@ -1579,8 +1583,11 @@ int dummy;
outfile.write(restat)
outfile.write('\n')
def generate_rust_compile_rules(self, compiler, outfile):
rule = 'rule %s_COMPILER\n' % compiler.get_language()
def generate_rust_compile_rules(self, compiler, outfile, is_cross):
crstr = ''
if is_cross:
crstr = '_CROSS'
rule = 'rule %s%s_COMPILER\n' % (compiler.get_language(), crstr)
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
command = ' command = %s $ARGS $in\n' % invoc
description = ' description = Compiling Rust source $in.\n'
@ -1671,8 +1678,7 @@ rule FORTRAN_DEP_HACK
self.generate_vala_compile_rules(compiler, outfile)
return
if langname == 'rust':
if not is_cross:
self.generate_rust_compile_rules(compiler, outfile)
self.generate_rust_compile_rules(compiler, outfile, is_cross)
return
if langname == 'swift':
if not is_cross:

@ -19,9 +19,11 @@ from ..mesonlib import EnvironmentException, Popen_safe
from .compilers import Compiler, rust_buildtype_args
class RustCompiler(Compiler):
def __init__(self, exelist, version):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
self.language = 'rust'
super().__init__(exelist, version)
self.is_cross = is_cross
self.exe_wrapper = exe_wrapper
self.id = 'rustc'
def needs_static_linker(self):
@ -41,7 +43,16 @@ class RustCompiler(Compiler):
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('Rust compiler %s can not compile programs.' % self.name_string())
if subprocess.call(output_name) != 0:
if self.is_cross:
if self.exe_wrapper is None:
# Can't check if the binaries run so we have to assume they do
return
cmdlist = self.exe_wrapper + [output_name]
else:
cmdlist = [output_name]
pe = subprocess.Popen(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
pe.wait()
if pe.returncode != 0:
raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string())
def get_dependency_gen_args(self, outfile):

@ -278,6 +278,7 @@ class Environment:
self.default_objc = ['cc']
self.default_objcpp = ['c++']
self.default_fortran = ['gfortran', 'g95', 'f95', 'f90', 'f77', 'ifort']
self.default_rust = ['rustc']
self.default_static_linker = ['ar']
self.vs_static_linker = ['lib']
self.gcc_static_linker = ['gcc-ar']
@ -688,16 +689,24 @@ class Environment:
return ValaCompiler(exelist, version)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_rust_compiler(self):
exelist = ['rustc']
try:
p, out = Popen_safe(exelist + ['--version'])[0:2]
except OSError:
raise EnvironmentException('Could not execute Rust compiler "%s"' % ' '.join(exelist))
version = search_version(out)
if 'rustc' in out:
return RustCompiler(exelist, version)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_rust_compiler(self, want_cross):
popen_exceptions = {}
compilers, ccache, is_cross, exe_wrap = self._get_compilers('rust', 'RUSTC', want_cross)
for compiler in compilers:
if isinstance(compiler, str):
compiler = [compiler]
try:
p, out = Popen_safe(compiler + ['--version'])[0:2]
except OSError as e:
popen_exceptions[compiler] = e
continue
version = search_version(out)
if 'rustc' in out:
return RustCompiler(compiler, version, is_cross, exe_wrap)
self._handle_exceptions(popen_exceptions, compilers)
def detect_d_compiler(self, want_cross):
is_cross = False

@ -1992,9 +1992,9 @@ to directly access options of other subprojects.''')
if need_cross_compiler:
cross_comp = self.environment.detect_d_compiler(True)
elif lang == 'rust':
comp = self.environment.detect_rust_compiler()
comp = self.environment.detect_rust_compiler(False)
if need_cross_compiler:
cross_comp = comp # FIXME, not correct.
cross_comp = self.environment.detect_rust_compiler(True)
elif lang == 'fortran':
comp = self.environment.detect_fortran_compiler(False)
if need_cross_compiler:

Loading…
Cancel
Save