From b62cf5044f13c30f1b0bf348cd2aa4ac42cf4ab4 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Wed, 15 Jul 2026 19:38:37 +0000 Subject: [PATCH] Filter non-BuildTarget paths from extra_paths In Postgres, we saw an issue[0] where translation targets (custom targets) parent directories were being added to PATH on Windows. Generally, this would not be a problem. However, Windows limits the length of environment variables. Given the amount of translation targets in Postgres, this led to PATH being longer than what Windows allows and tests would fail to run. By filtering non-BuildTarget dependencies, we can mitigate the problem. Windows searches for DLLs and executables on PATH, so because we can assume that non-BuildTarget dependencies are not going to be DLLs or executables, we can safely filter them out of the extra_paths list. Link: https://www.postgresql.org/message-id/CAD5tBcJXAX8bz5q9ngE4znvVLiXaPO89D0yTFhJgEPrPyT-Erw@mail.gmail.com [0] Signed-off-by: Tristan Partin --- mesonbuild/backend/backends.py | 2 +- .../test/meson.build | 10 +++++ unittests/windowstests.py | 39 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 21cc8bb0a65d..201edfe6d6d4 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1216,7 +1216,7 @@ def create_test_serialisation(self, tests: T.List['Test']) -> T.List[TestSeriali extra_bdeps: T.List[build.BuildTargetTypes] = [] if isinstance(exe, build.CustomTarget): extra_bdeps = list(exe.get_transitive_build_target_deps()) - extra_bdeps.extend(t.depends) + extra_bdeps.extend(d for d in t.depends if isinstance(d, build.BuildTarget)) extra_bdeps.extend(a for a in t.cmd_args if isinstance(a, build.BuildTarget)) extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) else: diff --git a/test cases/windows/13 test argument extra paths/test/meson.build b/test cases/windows/13 test argument extra paths/test/meson.build index 4daccaea669b..fa4ec5ed1b5b 100644 --- a/test cases/windows/13 test argument extra paths/test/meson.build +++ b/test cases/windows/13 test argument extra paths/test/meson.build @@ -1,3 +1,13 @@ python3 = find_program('python3') test('run_exe', python3, args: [files('test_run_exe.py')[0], barexe]) + +stamp = custom_target('stamp', + output: 'stamp.txt', + command: [python3, '-c', 'open("@OUTPUT@", "w").close()'], + build_by_default: true, +) + +test('run_exe_with_custom_depends', python3, + args: [files('test_run_exe.py')[0], barexe], + depends: stamp) diff --git a/unittests/windowstests.py b/unittests/windowstests.py index a6f9e264ffbb..fe3d91cdfff6 100644 --- a/unittests/windowstests.py +++ b/unittests/windowstests.py @@ -490,3 +490,42 @@ def test_vsenv_option(self): with mock.patch.object(self, 'install_command', self.meson_command + ['install']): out = self.install(override_envvars=env) self.assertIn('Activating VS', out) + + def test_custom_target_in_depends_no_extra_paths_bloat(self): + ''' + Test that when a test depends on a non-BuildTarget, the extra_paths does + not include parent directories from that non-BuildTarget. + + This is a regression test for: when t.depends contained non-BuildTarget + items (like CustomTarget), they were incorrectly added to extra_bdeps + and their parent directories could end up in the PATH, causing bloat. + + See: https://www.postgresql.org/message-id/CAD5tBcJXAX8bz5q9ngE4znvVLiXaPO89D0yTFhJgEPrPyT-Erw@mail.gmail.com + ''' + testdir = os.path.join(self.platform_test_dir, '13 test argument extra paths') + self.init(testdir) + + tests = self.introspect('--tests') + test_with_custom_depends = None + for t in tests: + if t['name'] == 'run_exe_with_custom_depends': + test_with_custom_depends = t + break + + self.assertIsNotNone(test_with_custom_depends, 'Test run_exe_with_custom_depends not found') + + extra_paths = test_with_custom_depends.get('extra_paths', []) + self.assertIsInstance(extra_paths, list) + + # The executable 'barexe' links against libfoo, so the lib directory + # should be in extra_paths (so the DLL can be found at runtime). + self.assertTrue(any('lib' in p for p in extra_paths) or len(extra_paths) == 0, + f'extra_paths should contain a lib directory or be empty: {extra_paths}') + + # The test depends on a CustomTarget in the test subdirectory. + # The CustomTarget's parent directory should NOT appear in extra_paths. + for path in extra_paths: + self.assertNotIn('test', path, + 'extra_paths should not include the test subdirectory. ' + 'This would indicate that non-BuildTarget dependencies are incorrectly ' + 'adding their parent directories to PATH.')