summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2024-11-16 16:05:05 +0100
committerDylan Baker <dylan@pnwbakers.com>2024-12-19 09:25:20 -0800
commit5768ccba6eb77167da96712c20a4e042efb31d03 (patch)
tree274bba153b1cdf9f5826d559681bd6be918b86b3
parent27c567de5d1807ac72708ea48018a21f0c6b8dd2 (diff)
downloadmeson-5768ccba6eb77167da96712c20a4e042efb31d03.tar.gz
ninjabackend: add support for "ninja clippy"
Add a target that builds all crates that could be extern to others, and then reruns clippy. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--docs/markdown/howtox.md20
-rw-r--r--docs/markdown/snippets/clippy.md5
-rw-r--r--docs/markdown/snippets/num-processes.md2
-rw-r--r--mesonbuild/backend/backends.py6
-rw-r--r--mesonbuild/backend/ninjabackend.py22
-rw-r--r--unittests/allplatformstests.py18
6 files changed, 71 insertions, 2 deletions
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index 4a57e8569..ba6a3b8f8 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -239,6 +239,26 @@ And then pass it through the variable (remember to use absolute path):
$ SCANBUILD=$(pwd)/my-scan-build.sh ninja -C builddir scan-build
```
+## Use clippy
+
+If your project includes Rust targets, you can invoke clippy like this:
+
+```console
+$ meson setup builddir
+$ ninja -C builddir clippy
+```
+
+Clippy will also obey the `werror` [builtin option](Builtin-options.md#core-options).
+
+By default Meson uses as many concurrent processes as there are cores
+on the test machine. You can override this with the environment
+variable `MESON_NUM_PROCESSES`.
+
+Meson will look for `clippy-driver` in the same directory as `rustc`,
+or try to invoke it using `rustup` if `rustc` points to a `rustup`
+binary. If `clippy-driver` is not detected properly, you can add it to
+a [machine file](Machine-files.md).
+
## Use profile guided optimization
Using profile guided optimization with GCC is a two phase
diff --git a/docs/markdown/snippets/clippy.md b/docs/markdown/snippets/clippy.md
new file mode 100644
index 000000000..14bcc7742
--- /dev/null
+++ b/docs/markdown/snippets/clippy.md
@@ -0,0 +1,5 @@
+## Meson can run "clippy" on Rust projects
+
+Meson now defines a `clippy` target if the project uses the Rust programming
+language. The target runs clippy on all Rust sources, using the `clippy-driver`
+program from the same Rust toolchain as the `rustc` compiler.
diff --git a/docs/markdown/snippets/num-processes.md b/docs/markdown/snippets/num-processes.md
index c484d930f..533637790 100644
--- a/docs/markdown/snippets/num-processes.md
+++ b/docs/markdown/snippets/num-processes.md
@@ -5,4 +5,4 @@ the amount of parallel jobs to run; this was useful when `meson test` is
invoked through `ninja test` for example. With this version, a new variable
`MESON_NUM_PROCESSES` is supported with a broader scope: in addition to
`meson test`, it is also used by the `external_project` module and by
-Ninja targets that invoke `clang-tidy` and `clang-format`.
+Ninja targets that invoke `clang-tidy`, `clang-format` and `clippy`.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index d2c6a4696..970fb82f2 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -2040,6 +2040,12 @@ class Backend:
commands += [input]
return commands
+ def have_language(self, langname: str) -> bool:
+ for for_machine in MachineChoice:
+ if langname in self.environment.coredata.compilers[for_machine]:
+ return True
+ return False
+
def compiler_to_generator(self, target: build.BuildTarget,
compiler: 'Compiler',
sources: _ALL_SOURCES_TYPE,
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 81b8bb51a..0c34e08de 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -463,6 +463,8 @@ class RustCrate:
display_name: str
root_module: str
+ crate_type: str
+ target_name: str
edition: RUST_EDITIONS
deps: T.List[RustDep]
cfg: T.List[str]
@@ -1878,6 +1880,7 @@ class NinjaBackend(backends.Backend):
return orderdeps, first_file
def _add_rust_project_entry(self, name: str, main_rust_file: str, args: CompilerArgs,
+ crate_type: str, target_name: str,
from_subproject: bool, proc_macro_dylib_path: T.Optional[str],
deps: T.List[RustDep]) -> None:
raw_edition: T.Optional[str] = mesonlib.first(reversed(args), lambda x: x.startswith('--edition'))
@@ -1895,6 +1898,8 @@ class NinjaBackend(backends.Backend):
len(self.rust_crates),
name,
main_rust_file,
+ crate_type,
+ target_name,
edition,
deps,
cfg,
@@ -2134,7 +2139,7 @@ class NinjaBackend(backends.Backend):
self._add_rust_project_entry(target.name,
os.path.abspath(os.path.join(self.environment.build_dir, main_rust_file)),
- args,
+ args, cratetype, target_name,
bool(target.subproject),
proc_macro_dylib_path,
project_deps)
@@ -3640,6 +3645,20 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
elem.add_item('pool', 'console')
self.add_build(elem)
+ def generate_clippy(self) -> None:
+ if 'clippy' in self.all_outputs or not self.have_language('rust'):
+ return
+
+ cmd = self.environment.get_build_command() + \
+ ['--internal', 'clippy', self.environment.build_dir]
+ elem = self.create_phony_target('clippy', 'CUSTOM_COMMAND', 'PHONY')
+ elem.add_item('COMMAND', cmd)
+ elem.add_item('pool', 'console')
+ for crate in self.rust_crates.values():
+ if crate.crate_type in {'rlib', 'dylib', 'proc-macro'}:
+ elem.add_dep(crate.target_name)
+ self.add_build(elem)
+
def generate_scanbuild(self) -> None:
if not environment.detect_scanbuild():
return
@@ -3707,6 +3726,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
self.generate_scanbuild()
self.generate_clangformat()
self.generate_clangtidy()
+ self.generate_clippy()
self.generate_tags('etags', 'TAGS')
self.generate_tags('ctags', 'ctags')
self.generate_tags('cscope', 'cscope')
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 1b1e16928..6544bcce1 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -4892,6 +4892,24 @@ class AllPlatformTests(BasePlatformTests):
# When 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)
+ self.build('clippy')
+
+ self.wipe()
+ self.init(testdir, extra_args=['--werror', '-Db_colorout=never'])
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ self.build('clippy')
+ self.assertTrue('error: use of a blacklisted/placeholder name `foo`' in cm.exception.stdout or
+ 'error: use of a disallowed/placeholder name `foo`' in cm.exception.stdout)
+
+ @skip_if_not_language('rust')
+ @unittest.skipIf(not shutil.which('clippy-driver'), 'Test requires clippy-driver')
+ def test_rust_clippy_as_rustc(self) -> None:
+ if self.backend is not Backend.ninja:
+ raise unittest.SkipTest('Rust is only supported with ninja currently')
+ # When 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()