Replace run_linter.sh with check_linter ninja target.

This allows for potentially better performance, as it shares the build
flags, and thus can share some of the cache with the `cargo build`
targets.

Change-Id: Ie817610a73554b0e46615ba328db92406a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/25041
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/build/gen.py b/build/gen.py
index 969cccd..fd4475d 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -499,7 +499,14 @@
               args='--diff',
               env=f'NOBUILD=1 NINJA_OUT_DIR={os.path.relpath(build_dir, REPO_ROOT)}',
           ),
-      ],
+      ] + [
+          ninja.CargoClippyTarget(
+              'check_linter',
+              cargo_flags='--workspace --all-targets',
+              clippy_flags='-D warnings',
+              **starlark_common_args,
+          ),
+      ] if options.starlark else [],
   )
 
   with open(path, 'w') as f:
diff --git a/build/ninja_file.py b/build/ninja_file.py
index 8c6672d..a5120ad 100644
--- a/build/ninja_file.py
+++ b/build/ninja_file.py
@@ -160,6 +160,21 @@
         pool='cargo_pool',
     )
 
+    self.CargoClippy = Rule(
+        name='cargo_clippy',
+        ninja_file=self,
+        command=python(
+            run_cargo_rel_path,
+            '$target_type $out $cargo_out_dir $cxx "$cxxflags" "$ldflags" $target_triple $ld'
+            ' cargo clippy --color=always --target=$target_triple'
+            ' --manifest-path=$manifest_path $cargo_target_dir $cargo_flags'
+            + ('' if self.debug else ' --release')
+            + ' -- $clippy_flags',
+        ),
+        description='CARGO clippy $out',
+        inputs=[run_cargo_script],
+    )
+
   def chain(self, *commands):
     joined = ' && '.join(commands)
     if self.platform.is_windows():
@@ -203,6 +218,21 @@
         **kwargs,
     )
 
+  def CargoClippyTarget(self, name, *, crate_dir, target_dir, cargo_flags='', clippy_flags='', **kwargs):
+    target_triple = self.platform.rust_triple()
+    return self.CargoClippy(
+        name,
+        inputs=self.directory(crate_dir, ['target']),
+        manifest_path=crate_dir / 'Cargo.toml',
+        cargo_target_dir=f'--target-dir={target_dir}',
+        cargo_flags=cargo_flags,
+        clippy_flags=clippy_flags,
+        target_type='clippy',
+        target_triple=target_triple,
+        cargo_out_dir=f'{target_dir}/{target_triple}/{self.rust_profile}',
+        **kwargs,
+    )
+
   def directory(self, dir_path, exclude_dirs):
     # Join out_dir with dir_path (which is relative to out_dir) to get absolute path for filesystem walk
     full_dir_path = (self.out_dir / dir_path).resolve()
diff --git a/build/run_cargo.py b/build/run_cargo.py
index 2faadff..9a2d499 100755
--- a/build/run_cargo.py
+++ b/build/run_cargo.py
@@ -286,7 +286,11 @@
 
   # Cargo build doesn't output files in a format ninja can use. So we now
   # need to convert them.
-  if target_type == 'lib':
+  if target_type == 'clippy':
+    out_path.parent.mkdir(parents=True, exist_ok=True)
+    out_path.touch()
+    sys.exit(0)
+  elif target_type == 'lib':
     src_depfiles = process_lib_target(out_path, cargo_out_dir)
   elif target_type == 'test':
     src_depfiles = process_test_target(out_path, cargo_out_dir)
diff --git a/tools/run_linter.sh b/tools/run_linter.sh
deleted file mode 100755
index 5042f27..0000000
--- a/tools/run_linter.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash -eu
-# Copyright 2026 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Resolve root directory
-cd "$(dirname "$(dirname "$0")")"
-
-if command -v cargo >/dev/null 2>&1; then
-  (cd src/gn/starlark && cargo clippy --workspace --all-targets --all-features -- -D warnings)
-else
-  echo "cargo is not installed, skipping Rust linting."
-fi