aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pylintrc1
-rw-r--r--ci/run.ps14
-rw-r--r--docs/markdown/snippets/rust-clippy-driver-support.md6
-rw-r--r--docs/markdown/snippets/rustc-improvements.md6
-rw-r--r--mesonbuild/backend/ninjabackend.py10
-rw-r--r--mesonbuild/compilers/__init__.py3
-rw-r--r--mesonbuild/compilers/detect.py27
-rw-r--r--mesonbuild/compilers/rust.py45
-rw-r--r--test cases/rust/1 basic/clippy.toml1
-rw-r--r--test cases/rust/1 basic/prog.rs3
-rw-r--r--unittests/allplatformstests.py13
-rw-r--r--unittests/baseplatformtests.py5
12 files changed, 102 insertions, 22 deletions
diff --git a/.pylintrc b/.pylintrc
index eae0667..983e836 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -16,6 +16,7 @@ enable=
consider-using-enumerate,
dangerous-default-value,
deprecated-lambda,
+ function-redefined,
len-as-condition,
literal-comparison,
missing-kwoa,
diff --git a/ci/run.ps1 b/ci/run.ps1
index 5f25685..d5bae10 100644
--- a/ci/run.ps1
+++ b/ci/run.ps1
@@ -13,6 +13,10 @@ if ($env:arch -eq 'x64') {
} elseif ($env:arch -eq 'x86') {
# Switch to the x86 Rust toolchain
rustup default stable-i686-pc-windows-msvc
+
+ # Also install clippy
+ rustup component add clippy
+
# Rust puts its shared stdlib in a secret place, but it is needed to run tests.
$env:Path += ";$HOME/.rustup/toolchains/stable-i686-pc-windows-msvc/bin"
# Need 32-bit Python for tests that need the Python dependency
diff --git a/docs/markdown/snippets/rust-clippy-driver-support.md b/docs/markdown/snippets/rust-clippy-driver-support.md
new file mode 100644
index 0000000..c486473
--- /dev/null
+++ b/docs/markdown/snippets/rust-clippy-driver-support.md
@@ -0,0 +1,6 @@
+## Support for clippy-driver as a rustc wrapper
+
+Clippy is a popular linting tool for Rust, and is invoked in place of rustc as a
+wrapper. Unfortunately it doesn't proxy rustc's output, so we need to have a
+small wrapper around it so that Meson can correctly detect the underlying rustc,
+but still display clippy
diff --git a/docs/markdown/snippets/rustc-improvements.md b/docs/markdown/snippets/rustc-improvements.md
new file mode 100644
index 0000000..869888c
--- /dev/null
+++ b/docs/markdown/snippets/rustc-improvements.md
@@ -0,0 +1,6 @@
+## Improvements for the Rustc compiler
+
+- Werror now works, this set's `-D warnings`, which will cause rustc to error
+ for every warning not explicitly disabled
+- warning levels have been implemented
+- support for meson's pic has been enabled
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 7c97ca3..5dbbf8b 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1691,20 +1691,12 @@ class NinjaBackend(backends.Backend):
if cratetype in {'bin', 'dylib'}:
args.extend(rustc.get_linker_always_args())
- opt_proxy = self.get_compiler_options_for_target(target)
-
+ args += self.generate_basic_compiler_args(target, rustc, False)
args += ['--crate-name', target.name]
- args += rustc.get_buildtype_args(self.get_option_for_target(OptionKey('buildtype'), target))
- args += rustc.get_debug_args(self.get_option_for_target(OptionKey('debug'), target))
- args += rustc.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target))
- args += rustc.get_option_compile_args(opt_proxy)
- args += self.build.get_global_args(rustc, target.for_machine)
- args += self.build.get_project_args(rustc, target.subproject, target.for_machine)
depfile = os.path.join(target.subdir, target.name + '.d')
args += ['--emit', f'dep-info={depfile}', '--emit', 'link']
args += target.get_extra_args('rust')
args += rustc.get_output_args(os.path.join(target.subdir, target.get_filename()))
- args += self.environment.coredata.get_external_args(target.for_machine, rustc.language)
linkdirs = mesonlib.OrderedSet()
external_deps = target.external_deps.copy()
for d in target.link_targets:
diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py
index 8c5275c..98b0b5f 100644
--- a/mesonbuild/compilers/__init__.py
+++ b/mesonbuild/compilers/__init__.py
@@ -112,6 +112,7 @@ __all__ = [
'PGICPPCompiler',
'PGIFortranCompiler',
'RustCompiler',
+ 'ClippyRustCompiler',
'CcrxCCompiler',
'CcrxCPPCompiler',
'Xc16CCompiler',
@@ -241,7 +242,7 @@ from .objcpp import (
ClangObjCPPCompiler,
GnuObjCPPCompiler,
)
-from .rust import RustCompiler
+from .rust import RustCompiler, ClippyRustCompiler
from .swift import SwiftCompiler
from .vala import ValaCompiler
from .mixins.visualstudio import VisualStudioLikeCompiler
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
index 59b425b..52ad7f3 100644
--- a/mesonbuild/compilers/detect.py
+++ b/mesonbuild/compilers/detect.py
@@ -124,7 +124,7 @@ from .objcpp import (
GnuObjCPPCompiler,
)
from .cython import CythonCompiler
-from .rust import RustCompiler
+from .rust import RustCompiler, ClippyRustCompiler
from .swift import SwiftCompiler
from .vala import ValaCompiler
from .mixins.visualstudio import VisualStudioLikeCompiler
@@ -952,6 +952,13 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
continue
version = search_version(out)
+ cls: T.Type[RustCompiler] = RustCompiler
+
+ # Clippy is a wrapper around rustc, but it doesn't have rustc in it's
+ # output. We can otherwise treat it as rustc.
+ if 'clippy' in out:
+ out = 'rustc'
+ cls = ClippyRustCompiler
if 'rustc' in out:
# On Linux and mac rustc will invoke gcc (clang for mac
@@ -970,19 +977,21 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
'or use the RUST_LD environment variable, otherwise meson '
'will override your selection.')
+ compiler = compiler.copy() # avoid mutating the original list
+
if override is None:
extra_args: T.Dict[str, T.Union[str, bool]] = {}
always_args: T.List[str] = []
if is_link_exe:
- compiler.extend(RustCompiler.use_linker_args(cc.linker.exelist[0]))
+ compiler.extend(cls.use_linker_args(cc.linker.exelist[0]))
extra_args['direct'] = True
extra_args['machine'] = cc.linker.machine
else:
- exelist = cc.linker.exelist.copy()
+ exelist = cc.linker.exelist + cc.linker.get_always_args()
if 'ccache' in exelist[0]:
del exelist[0]
c = exelist.pop(0)
- compiler.extend(RustCompiler.use_linker_args(c))
+ compiler.extend(cls.use_linker_args(c))
# Also ensure that we pass any extra arguments to the linker
for l in exelist:
@@ -1000,12 +1009,12 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
**extra_args) # type: ignore
elif 'link' in override[0]:
linker = guess_win_linker(env,
- override, RustCompiler, for_machine, use_linker_prefix=False)
+ override, cls, for_machine, use_linker_prefix=False)
# rustc takes linker arguments without a prefix, and
# inserts the correct prefix itself.
assert isinstance(linker, VisualStudioLikeLinkerMixin)
linker.direct = True
- compiler.extend(RustCompiler.use_linker_args(linker.exelist[0]))
+ compiler.extend(cls.use_linker_args(linker.exelist[0]))
else:
# On linux and macos rust will invoke the c compiler for
# linking, on windows it will use lld-link or link.exe.
@@ -1017,10 +1026,10 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
# Of course, we're not going to use any of that, we just
# need it to get the proper arguments to pass to rustc
c = linker.exelist[1] if linker.exelist[0].endswith('ccache') else linker.exelist[0]
- compiler.extend(RustCompiler.use_linker_args(c))
+ compiler.extend(cls.use_linker_args(c))
- env.coredata.add_lang_args(RustCompiler.language, RustCompiler, for_machine, env)
- return RustCompiler(
+ env.coredata.add_lang_args(cls.language, cls, for_machine, env)
+ return cls(
compiler, version, for_machine, is_cross, info, exe_wrap,
linker=linker)
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index 2b566c8..9423b2d 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -45,6 +45,13 @@ class RustCompiler(Compiler):
# rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX
language = 'rust'
+ _WARNING_LEVELS: T.Dict[str, T.List[str]] = {
+ '0': ['-A', 'warnings'],
+ '1': [],
+ '2': [],
+ '3': ['-W', 'warnings'],
+ }
+
def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
@@ -168,3 +175,41 @@ class RustCompiler(Compiler):
for a in super().get_linker_always_args():
args.extend(['-C', f'link-arg={a}'])
return args
+
+ def get_werror_args(self) -> T.List[str]:
+ # Use -D warnings, which makes every warning not explicitly allowed an
+ # error
+ return ['-D', 'warnings']
+
+ def get_warn_args(self, level: str) -> T.List[str]:
+ # TODO: I'm not really sure what to put here, Rustc doesn't have warning
+ return self._WARNING_LEVELS[level]
+
+ def get_no_warn_args(self) -> T.List[str]:
+ return self._WARNING_LEVELS["0"]
+
+ def get_pic_args(self) -> T.List[str]:
+ # This defaults to
+ return ['-C', 'relocation-model=pic']
+
+ def get_pie_args(self) -> T.List[str]:
+ # Rustc currently has no way to toggle this, it's controlled by whether
+ # pic is on by rustc
+ return []
+
+
+class ClippyRustCompiler(RustCompiler):
+
+ """Clippy is a linter that wraps Rustc.
+
+ This just provides us a different id
+ """
+
+ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
+ is_cross: bool, info: 'MachineInfo',
+ exe_wrapper: T.Optional['ExternalProgram'] = None,
+ full_version: T.Optional[str] = None,
+ linker: T.Optional['DynamicLinker'] = None):
+ super().__init__(exelist, version, for_machine, is_cross, info,
+ exe_wrapper, full_version, linker)
+ self.id = 'clippy-driver rustc'
diff --git a/test cases/rust/1 basic/clippy.toml b/test cases/rust/1 basic/clippy.toml
new file mode 100644
index 0000000..e9ac31b
--- /dev/null
+++ b/test cases/rust/1 basic/clippy.toml
@@ -0,0 +1 @@
+blacklisted-names = ["foo"]
diff --git a/test cases/rust/1 basic/prog.rs b/test cases/rust/1 basic/prog.rs
index b171a80..f1b3d30 100644
--- a/test cases/rust/1 basic/prog.rs
+++ b/test cases/rust/1 basic/prog.rs
@@ -1,3 +1,4 @@
fn main() {
- println!("rust compiler is working");
+ let foo = "rust compiler is working";
+ println!("{}", foo);
}
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 7afa989..93a2e49 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -4034,3 +4034,16 @@ class AllPlatformTests(BasePlatformTests):
for file, details in files.items():
with self.subTest(key='{}.{}'.format(data_type, file)):
self.assertEqual(res[data_type][file], details)
+
+ @skip_if_not_language('rust')
+ @unittest.skipIf(not shutil.which('clippy-driver'), 'Test requires clippy-driver')
+ def test_rust_clippy(self) -> None:
+ if self.backend is not Backend.ninja:
+ raise unittest.SkipTest('Rust is only supported with ninja currently')
+ # Wehn clippy is used, we should get an exception since a variable named
+ # "foo" is used, but is on our denylist
+ testdir = os.path.join(self.rust_test_dir, '1 basic')
+ self.init(testdir, extra_args=['--werror'], override_envvars={'RUSTC': 'clippy-driver'})
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ self.build()
+ self.assertIn('error: use of a blacklisted/placeholder name `foo`', cm.exception.stdout)
diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py
index 3492785..9371395 100644
--- a/unittests/baseplatformtests.py
+++ b/unittests/baseplatformtests.py
@@ -69,6 +69,7 @@ class BasePlatformTests(TestCase):
self.uninstall_command = get_backend_commands(self.backend)
# Test directories
self.common_test_dir = os.path.join(src_root, 'test cases/common')
+ self.rust_test_dir = os.path.join(src_root, 'test cases/rust')
self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
@@ -135,7 +136,7 @@ class BasePlatformTests(TestCase):
os.environ.update(self.orig_env)
super().tearDown()
- def _run(self, command, *, workdir=None, override_envvars=None):
+ def _run(self, command, *, workdir=None, override_envvars: T.Optional[T.Mapping[str, str]] = None):
'''
Run a command while printing the stdout and stderr to stdout,
and also return a copy of it
@@ -164,7 +165,7 @@ class BasePlatformTests(TestCase):
extra_args=None,
default_args=True,
inprocess=False,
- override_envvars=None,
+ override_envvars: T.Optional[T.Mapping[str, str]] = None,
workdir=None,
allow_fail: bool = False) -> str:
"""Call `meson setup`