Merge pull request #1922 from acfoltzer/rust-improvements

Enhance Rust support
pull/1884/merge
Jussi Pakkanen 8 years ago committed by GitHub
commit 65d5ec5f18
  1. 5
      docs/markdown/Reference-manual.md
  2. 36
      mesonbuild/backend/ninjabackend.py
  3. 43
      mesonbuild/build.py
  4. 12
      mesonbuild/compilers.py
  5. 0
      test cases/failing/55 wrong shared crate type/foo.rs
  6. 3
      test cases/failing/55 wrong shared crate type/meson.build
  7. 0
      test cases/failing/56 wrong static crate type/foo.rs
  8. 3
      test cases/failing/56 wrong static crate type/meson.build
  9. 2
      test cases/rust/2 sharedlib/installed_files.txt
  10. 2
      test cases/rust/4 polyglot/installed_files.txt
  11. 5
      test cases/rust/4 polyglot/meson.build
  12. 8
      test cases/rust/4 polyglot/prog.c
  13. 6
      test cases/rust/4 polyglot/stuff.rs
  14. 2
      test cases/rust/5 polyglot static/installed_files.txt
  15. 10
      test cases/rust/5 polyglot static/meson.build
  16. 8
      test cases/rust/5 polyglot static/prog.c
  17. 6
      test cases/rust/5 polyglot static/stuff.rs

@ -510,11 +510,12 @@ Joins the given strings into a file system path segment. For example `join_paths
Builds a library that is either static or shared depending on the value of `default_library` user option. You should use this instead of [`shared_library`](#shared_library) or [`static_library`](#static_library) most of the time. This allows you to toggle your entire project (including subprojects) from shared to static with only one option. Builds a library that is either static or shared depending on the value of `default_library` user option. You should use this instead of [`shared_library`](#shared_library) or [`static_library`](#static_library) most of the time. This allows you to toggle your entire project (including subprojects) from shared to static with only one option.
The keyword arguments for this are the same as for [`executable`](#executable) with the following addition: The keyword arguments for this are the same as for [`executable`](#executable) with the following additions:
- `name_prefix` the string that will be used as the suffix for the target by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers except with MSVC where it is omitted. - `name_prefix` the string that will be used as the suffix for the target by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers except with MSVC where it is omitted.
- `rust_crate_type` specifies the crate type for Rust libraries. Defaults to `dylib` for shared libraries and `rlib` for static libraries.
`static_library` and `shared_library` also accept this keyword argument. `static_library` and `shared_library` also accept these keyword arguments.
### message() ### message()

@ -1165,8 +1165,10 @@ int dummy;
args = ['--crate-type'] args = ['--crate-type']
if isinstance(target, build.Executable): if isinstance(target, build.Executable):
cratetype = 'bin' cratetype = 'bin'
elif hasattr(target, 'rust_crate_type'):
cratetype = target.rust_crate_type
elif isinstance(target, build.SharedLibrary): elif isinstance(target, build.SharedLibrary):
cratetype = 'rlib' cratetype = 'dylib'
elif isinstance(target, build.StaticLibrary): elif isinstance(target, build.StaticLibrary):
cratetype = 'rlib' cratetype = 'rlib'
else: else:
@ -1185,6 +1187,36 @@ int dummy;
if d == '': if d == '':
d = '.' d = '.'
args += ['-L', d] args += ['-L', d]
has_shared_deps = False
for dep in target.get_dependencies():
if isinstance(dep, build.SharedLibrary):
has_shared_deps = True
if isinstance(target, build.SharedLibrary) or has_shared_deps:
# add prefer-dynamic if any of the Rust libraries we link
# against are dynamic, otherwise we'll end up with
# multiple implementations of crates
args += ['-C', 'prefer-dynamic']
# build the usual rpath arguments as well...
# Set runtime-paths so we can run executables without needing to set
# LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
if '/' in target.name or '\\' in target.name:
# Target names really should not have slashes in them, but
# unfortunately we did not check for that and some downstream projects
# now have them. Once slashes are forbidden, remove this bit.
target_slashname_workaround_dir = os.path.join(os.path.split(target.name)[0],
self.get_target_dir(target))
else:
target_slashname_workaround_dir = self.get_target_dir(target)
rpath_args = rustc.build_rpath_args(self.environment.get_build_dir(),
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.install_rpath)
# ... but then add rustc's sysroot to account for rustup
# 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) element = NinjaBuildElement(self.all_outputs, target_name, 'rust_COMPILER', relsrc)
if len(orderdeps) > 0: if len(orderdeps) > 0:
element.add_orderdep(orderdeps) element.add_orderdep(orderdeps)
@ -1192,6 +1224,8 @@ int dummy;
element.add_item('targetdep', depfile) element.add_item('targetdep', depfile)
element.add_item('cratetype', cratetype) element.add_item('cratetype', cratetype)
element.write(outfile) element.write(outfile)
if isinstance(target, build.SharedLibrary):
self.generate_shsym(outfile, target)
def swift_module_file_name(self, target): def swift_module_file_name(self, target):
return os.path.join(self.get_target_private_dir(target), return os.path.join(self.get_target_private_dir(target),

@ -71,6 +71,7 @@ known_lib_kwargs.update({'version': True, # Only for shared libs
'vala_vapi': True, 'vala_vapi': True,
'vala_gir': True, 'vala_gir': True,
'pic': True, # Only for static libs 'pic': True, # Only for static libs
'rust_crate_type': True, # Only for Rust libs
}) })
@ -1123,6 +1124,14 @@ class StaticLibrary(BuildTarget):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
if 'cs' in self.compilers: if 'cs' in self.compilers:
raise InvalidArguments('Static libraries not supported for C#.') raise InvalidArguments('Static libraries not supported for C#.')
if 'rust' in self.compilers:
# If no crate type is specified, or it's the generic lib type, use rlib
if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib':
mlog.debug('Defaulting Rust static library target crate type to rlib')
self.rust_crate_type = 'rlib'
# Don't let configuration proceed with a non-static crate type
elif self.rust_crate_type not in ['rlib', 'staticlib']:
raise InvalidArguments('Crate type "{0}" invalid for static libraries; must be "rlib" or "staticlib"'.format(self.rust_crate_type))
# By default a static library is named libfoo.a even on Windows because # By default a static library is named libfoo.a even on Windows because
# MSVC does not have a consistent convention for what static libraries # MSVC does not have a consistent convention for what static libraries
# are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses # are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses
@ -1133,9 +1142,12 @@ class StaticLibrary(BuildTarget):
if not hasattr(self, 'prefix'): if not hasattr(self, 'prefix'):
self.prefix = 'lib' self.prefix = 'lib'
if not hasattr(self, 'suffix'): if not hasattr(self, 'suffix'):
# Rust static library crates have .rlib suffix
if 'rust' in self.compilers: if 'rust' in self.compilers:
if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'rlib':
# default Rust static library suffix
self.suffix = 'rlib' self.suffix = 'rlib'
elif self.rust_crate_type == 'staticlib':
self.suffix = 'a'
else: else:
self.suffix = 'a' self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix self.filename = self.prefix + self.name + '.' + self.suffix
@ -1147,6 +1159,15 @@ class StaticLibrary(BuildTarget):
def check_unknown_kwargs(self, kwargs): def check_unknown_kwargs(self, kwargs):
self.check_unknown_kwargs_int(kwargs, known_lib_kwargs) self.check_unknown_kwargs_int(kwargs, known_lib_kwargs)
def process_kwargs(self, kwargs, environment):
super().process_kwargs(kwargs, environment)
if 'rust_crate_type' in kwargs:
rust_crate_type = kwargs['rust_crate_type']
if isinstance(rust_crate_type, str):
self.rust_crate_type = rust_crate_type
else:
raise InvalidArguments('Invalid rust_crate_type "{0}": must be a string.'.format(rust_crate_type))
class SharedLibrary(BuildTarget): class SharedLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
self.soversion = None self.soversion = None
@ -1159,6 +1180,14 @@ class SharedLibrary(BuildTarget):
# The import library that GCC would generate (and prefer) # The import library that GCC would generate (and prefer)
self.gcc_import_filename = None self.gcc_import_filename = None
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
if 'rust' in self.compilers:
# If no crate type is specified, or it's the generic lib type, use dylib
if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib':
mlog.debug('Defaulting Rust dynamic library target crate type to "dylib"')
self.rust_crate_type = 'dylib'
# Don't let configuration proceed with a non-dynamic crate type
elif self.rust_crate_type not in ['dylib', 'cdylib']:
raise InvalidArguments('Crate type "{0}" invalid for dynamic libraries; must be "dylib" or "cdylib"'.format(self.rust_crate_type))
if not hasattr(self, 'prefix'): if not hasattr(self, 'prefix'):
self.prefix = None self.prefix = None
if not hasattr(self, 'suffix'): if not hasattr(self, 'suffix'):
@ -1200,12 +1229,6 @@ class SharedLibrary(BuildTarget):
prefix = '' prefix = ''
suffix = 'dll' suffix = 'dll'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
# Rust
elif 'rust' in self.compilers:
# Currently, we always build --crate-type=rlib
prefix = 'lib'
suffix = 'rlib'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
# C, C++, Swift, Vala # C, C++, Swift, Vala
# Only Windows uses a separate import library for linking # Only Windows uses a separate import library for linking
# For all other targets/platforms import_filename stays None # For all other targets/platforms import_filename stays None
@ -1315,6 +1338,12 @@ class SharedLibrary(BuildTarget):
raise InvalidArguments( raise InvalidArguments(
'Shared library vs_module_defs must be either a string, ' 'Shared library vs_module_defs must be either a string, '
'a file object or a Custom Target') 'a file object or a Custom Target')
if 'rust_crate_type' in kwargs:
rust_crate_type = kwargs['rust_crate_type']
if isinstance(rust_crate_type, str):
self.rust_crate_type = rust_crate_type
else:
raise InvalidArguments('Invalid rust_crate_type "{0}": must be a string.'.format(rust_crate_type))
def check_unknown_kwargs(self, kwargs): def check_unknown_kwargs(self, kwargs):
self.check_unknown_kwargs_int(kwargs, known_lib_kwargs) self.check_unknown_kwargs_int(kwargs, known_lib_kwargs)

@ -1570,7 +1570,7 @@ class MonoCompiler(Compiler):
def split_shlib_to_parts(self, fname): def split_shlib_to_parts(self, fname):
return None, fname return None, fname
def build_rpath_args(self, build_dir, rpath_paths, install_rpath): def build_rpath_args(self, build_dir, from_dir, rpath_paths, install_rpath):
return [] return []
def get_dependency_gen_args(self, outtarget, outfile): def get_dependency_gen_args(self, outtarget, outfile):
@ -1651,7 +1651,7 @@ class JavaCompiler(Compiler):
def split_shlib_to_parts(self, fname): def split_shlib_to_parts(self, fname):
return None, fname return None, fname
def build_rpath_args(self, build_dir, rpath_paths, install_rpath): def build_rpath_args(self, build_dir, from_dir, rpath_paths, install_rpath):
return [] return []
def get_dependency_gen_args(self, outtarget, outfile): def get_dependency_gen_args(self, outtarget, outfile):
@ -1833,6 +1833,14 @@ class RustCompiler(Compiler):
def get_buildtype_args(self, buildtype): def get_buildtype_args(self, buildtype):
return rust_buildtype_args[buildtype] return rust_buildtype_args[buildtype]
def build_rpath_args(self, build_dir, from_dir, rpath_paths, install_rpath):
return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, install_rpath)
def get_sysroot(self):
cmd = self.exelist + ['--print', 'sysroot']
p, stdo, stde = Popen_safe(cmd)
return stdo.split('\n')[0]
class SwiftCompiler(Compiler): class SwiftCompiler(Compiler):
def __init__(self, exelist, version): def __init__(self, exelist, version):
self.language = 'swift' self.language = 'swift'

@ -0,0 +1,3 @@
project('test', 'rust')
shared_library('test', 'foo.rs', rust_crate_type : 'staticlib')

@ -0,0 +1,3 @@
project('test', 'rust')
static_library('test', 'foo.rs', rust_crate_type : 'cdylib')

@ -1,2 +1,2 @@
usr/bin/prog?exe usr/bin/prog?exe
usr/lib/libstuff.rlib usr/lib/libstuff.so

@ -0,0 +1,2 @@
usr/bin/prog?exe
usr/lib/libstuff.so

@ -0,0 +1,5 @@
project('rust and c polyglot executable', 'c', 'rust')
l = library('stuff', 'stuff.rs', install : true)
e = executable('prog', 'prog.c', link_with : l, install : true)
test('polyglottest', e)

@ -0,0 +1,8 @@
#include <stdio.h>
void f();
int main() {
printf("Hello from C!\n");
f();
}

@ -0,0 +1,6 @@
#![crate_name = "stuff"]
#[no_mangle]
pub extern fn f() {
println!("Hello from Rust!");
}

@ -0,0 +1,2 @@
usr/bin/prog?exe
usr/lib/libstuff.a

@ -0,0 +1,10 @@
project('static rust and c polyglot executable', 'c', 'rust')
deps = [
meson.get_compiler('c').find_library('dl'),
dependency('threads'),
]
l = static_library('stuff', 'stuff.rs', rust_crate_type : 'staticlib', install : true)
e = executable('prog', 'prog.c', dependencies: deps, link_with : l, install : true)
test('polyglottest', e)

@ -0,0 +1,8 @@
#include <stdio.h>
void f();
int main() {
printf("Hello from C!\n");
f();
}

@ -0,0 +1,6 @@
#![crate_name = "stuff"]
#[no_mangle]
pub extern fn f() {
println!("Hello from Rust!");
}
Loading…
Cancel
Save