From a15cc895abfc9b426af75051d069fd625391b618 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 29 Nov 2023 10:30:21 -0800
Subject: [PATCH v1 2/2] meson: Add test checking if there are conflicting
 target names

Author:
Reviewed-by:
Discussion: https://postgr.es/m/703110e4-b495-e409-26a5-28e9fca8f3a5@dunslane.net
Backpatch:
---
 meson.build           |  8 ++++++
 src/tools/check_meson | 67 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100755 src/tools/check_meson

diff --git a/meson.build b/meson.build
index 0095fb183af..e0895f41f78 100644
--- a/meson.build
+++ b/meson.build
@@ -3320,6 +3320,14 @@ if meson.version().version_compare('>=0.57')
 endif
 
 
+# Tests verifing that source code follows certain rules
+test('meson-check',
+  files('src/tools/check_meson'),
+  args: ['--srcdir', meson.source_root(), '--builddir', meson.build_root()],
+  suite: 'source',
+  priority: 10)
+
+
 
 ###############################################################
 # Pseudo targets
diff --git a/src/tools/check_meson b/src/tools/check_meson
new file mode 100755
index 00000000000..060ccd269ff
--- /dev/null
+++ b/src/tools/check_meson
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+
+# Script to perform some consistency checks on the meson build.
+
+from collections import defaultdict
+import argparse
+import json
+import os
+import sys
+
+
+def check_target_names(args):
+    """
+    Check that the target names for run_target() and alias_target() do
+    not conflict with other target types like
+    custom_target(). alias_target()/run_target() targets are intended to
+    be invoked at the top-level, but "meson compile $target" complains
+    about conflicts if another name of the same target exists.
+    """
+    targets_info_path = os.path.join(
+        args.builddir, 'meson-info/intro-targets.json')
+    targets_info = json.load(open(targets_info_path))
+
+    targets_info_byname = defaultdict(list)
+
+    for r in targets_info:
+        targets_info_byname[r['name']].append(r)
+
+    have_conflicts = False
+
+    for name, v in targets_info_byname.items():
+        if len(targets_info_byname[name]) > 1:
+            dirs = set()
+            types = set()
+            have_target_conflict = False
+            for t in v:
+                dirs.add(t['defined_in'])
+                types.add(t['type'])
+            if len(dirs) < len(v) and ('alias' in types or 'run' in types):
+                have_target_conflict = True
+
+            if have_target_conflict:
+                have_conflicts = True
+                print(f'Global target "{name}" has conflicting target names:',
+                      file=sys.stderr)
+                for t in v:
+                    fname = os.path.relpath(t['defined_in'], args.srcdir)
+                    print(f'\t"{t["name"]}:{t["type"]}", defined in "{fname}"',
+                          file=sys.stderr)
+                print(file=sys.stderr)
+
+    if have_conflicts:
+        print("Please rename conflicting targets",
+              file=sys.stderr)
+        return False
+    return True
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--builddir', type=str, required=True)
+    parser.add_argument('--srcdir', type=str, required=True)
+    args = parser.parse_args()
+
+    all_ok = True
+    all_ok &= check_target_names(args)
+    sys.exit(not all_ok)
-- 
2.38.0

