summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam James <sam@gentoo.org>2025-11-22 19:06:22 +0000
committerJussi Pakkanen <jussi.pakkanen@mailbox.org>2025-11-23 17:01:13 +0200
commit9104bb616766bd9a05f0b2f280359463d32e227d (patch)
treeb575d6f9cf74c13848e026a9d42267c973543ed7
parent06242bc6f47b25c19f91c76897ada39cd425015f (diff)
downloadmeson-9104bb616766bd9a05f0b2f280359463d32e227d.tar.gz
templates: respect parameters
Respect collected sources for `meson init` as well as --executable. This regressed in 9f0ac314ba0c54cc18c2499845324efc14c1849e (part of https://github.com/mesonbuild/meson/pull/14086, it's easier to see how with the whole PR). Also, add subtests (distinguishing between empty directories and those with some file(s) within). We already had some of these but they weren't marked as such. Test `meson init` with a broken source file in the source directory as we should fail with that, not ignore the file. It's easier to test with a broken file than a working one as we can assert the build should fail, it'll pass with just the 1 example file we generate. Closes: https://github.com/mesonbuild/meson/issues/15286
-rw-r--r--mesonbuild/templates/cpptemplates.py11
-rw-r--r--mesonbuild/templates/ctemplates.py10
-rw-r--r--mesonbuild/templates/dlangtemplates.py11
-rw-r--r--mesonbuild/templates/javatemplates.py12
-rw-r--r--mesonbuild/templates/sampleimpl.py55
-rw-r--r--unittests/allplatformstests.py51
6 files changed, 112 insertions, 38 deletions
diff --git a/mesonbuild/templates/cpptemplates.py b/mesonbuild/templates/cpptemplates.py
index cdfbbf8c0..1c742cfaa 100644
--- a/mesonbuild/templates/cpptemplates.py
+++ b/mesonbuild/templates/cpptemplates.py
@@ -35,9 +35,12 @@ hello_cpp_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+]
+
exe = executable(
'{exe_name}',
- '{source_name}',
+ [sources],
install : true,
dependencies : dependencies,
)
@@ -121,9 +124,13 @@ dependencies = [{dependencies}
# not the executables that use the library.
lib_args = ['-DBUILDING_{utoken}']
+sources = [{source_files}
+
+]
+
lib = library(
'{lib_name}',
- '{source_file}',
+ [sources],
install : true,
cpp_shared_args : lib_args,
gnu_symbol_visibility : 'hidden',
diff --git a/mesonbuild/templates/ctemplates.py b/mesonbuild/templates/ctemplates.py
index 559cef91b..c2db1e5e2 100644
--- a/mesonbuild/templates/ctemplates.py
+++ b/mesonbuild/templates/ctemplates.py
@@ -71,9 +71,12 @@ lib_args = ['-DBUILDING_{utoken}']
dependencies = [{dependencies}
]
+sources = [{source_files}
+]
+
lib = library(
'{lib_name}',
- '{source_file}',
+ [sources],
install : true,
c_shared_args : lib_args,
gnu_symbol_visibility : 'hidden',
@@ -133,9 +136,12 @@ hello_c_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+]
+
exe = executable(
'{exe_name}',
- '{source_name}',
+ [sources],
dependencies : dependencies,
install : true,
)
diff --git a/mesonbuild/templates/dlangtemplates.py b/mesonbuild/templates/dlangtemplates.py
index db3bdbf16..4ca91a69b 100644
--- a/mesonbuild/templates/dlangtemplates.py
+++ b/mesonbuild/templates/dlangtemplates.py
@@ -35,9 +35,13 @@ hello_d_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+
+]
+
exe = executable(
'{exe_name}',
- '{source_name}',
+ [sources],
dependencies : dependencies,
install : true,
)
@@ -84,10 +88,13 @@ lib_d_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+
+]
stlib = static_library(
'{lib_name}',
- '{source_file}',
+ [sources],
install : true,
gnu_symbol_visibility : 'hidden',
dependencies : dependencies,
diff --git a/mesonbuild/templates/javatemplates.py b/mesonbuild/templates/javatemplates.py
index c30c7f7b5..458142e6b 100644
--- a/mesonbuild/templates/javatemplates.py
+++ b/mesonbuild/templates/javatemplates.py
@@ -35,9 +35,13 @@ hello_java_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+
+]
+
exe = jar(
'{exe_name}',
- '{source_name}',
+ [sources],
main_class : '{exe_name}',
dependencies : dependencies,
install : true,
@@ -86,9 +90,13 @@ lib_java_meson_template = '''project(
dependencies = [{dependencies}
]
+sources = [{source_files}
+
+]
+
jarlib = jar(
'{class_name}',
- '{source_file}',
+ [sources],
dependencies : dependencies,
main_class : '{class_name}',
install : true,
diff --git a/mesonbuild/templates/sampleimpl.py b/mesonbuild/templates/sampleimpl.py
index d033f3c14..00735c498 100644
--- a/mesonbuild/templates/sampleimpl.py
+++ b/mesonbuild/templates/sampleimpl.py
@@ -3,6 +3,7 @@
# Copyright © 2023-2025 Intel Corporation
from __future__ import annotations
+from pathlib import Path
import abc
import os
@@ -17,6 +18,7 @@ class SampleImpl(metaclass=abc.ABCMeta):
def __init__(self, args: Arguments):
self.name = args.name
+ self.executable_name = args.executable if args.executable else None
self.version = args.version
self.lowercase_token = re.sub(r'[^a-z0-9]', '_', self.name.lower())
self.uppercase_token = self.lowercase_token.upper()
@@ -24,6 +26,7 @@ class SampleImpl(metaclass=abc.ABCMeta):
self.meson_version = '1.0.0'
self.force = args.force
self.dependencies = args.deps.split(',') if args.deps else []
+ self.sources: list[Path] = []
@abc.abstractmethod
def create_executable(self) -> None:
@@ -66,11 +69,18 @@ class SampleImpl(metaclass=abc.ABCMeta):
def _format_dependencies(self) -> str:
return ''.join(f"\n dependency('{d}')," for d in self.dependencies)
+ def _format_sources(self) -> str:
+ return ''.join(f"\n '{x}'," for x in self.sources)
+
class ClassImpl(SampleImpl):
"""For Class based languages, like Java and C#"""
+ def __init__(self, args: Arguments):
+ super().__init__(args)
+ self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.capitalized_token}.{self.source_ext}')]
+
def create_executable(self) -> None:
source_name = f'{self.capitalized_token}.{self.source_ext}'
if not os.path.exists(source_name):
@@ -80,29 +90,32 @@ class ClassImpl(SampleImpl):
if self.force or not os.path.exists('meson.build'):
with open('meson.build', 'w', encoding='utf-8') as f:
f.write(self.exe_meson_template.format(project_name=self.name,
- exe_name=self.name,
+ exe_name=self.executable_name,
source_name=source_name,
version=self.version,
meson_version=self.meson_version,
- dependencies=self._format_dependencies()))
+ dependencies=self._format_dependencies(),
+ source_files=self._format_sources()))
def create_library(self) -> None:
lib_name = f'{self.capitalized_token}.{self.source_ext}'
test_name = f'{self.capitalized_token}_test.{self.source_ext}'
- kwargs = {'utoken': self.uppercase_token,
- 'ltoken': self.lowercase_token,
- 'class_test': f'{self.capitalized_token}_test',
- 'class_name': self.capitalized_token,
- 'source_file': lib_name,
- 'test_source_file': test_name,
- 'test_exe_name': f'{self.lowercase_token}_test',
- 'project_name': self.name,
- 'lib_name': self.lowercase_token,
- 'test_name': self.lowercase_token,
- 'version': self.version,
- 'meson_version': self.meson_version,
- 'dependencies': self._format_dependencies(),
- }
+ kwargs = {
+ 'utoken': self.uppercase_token,
+ 'ltoken': self.lowercase_token,
+ 'class_test': f'{self.capitalized_token}_test',
+ 'class_name': self.capitalized_token,
+ 'source_file': lib_name,
+ 'test_source_file': test_name,
+ 'test_exe_name': f'{self.lowercase_token}_test',
+ 'project_name': self.name,
+ 'lib_name': self.lowercase_token,
+ 'test_name': self.lowercase_token,
+ 'version': self.version,
+ 'meson_version': self.meson_version,
+ 'dependencies': self._format_dependencies(),
+ 'source_files': self._format_sources(),
+ }
if not os.path.exists(lib_name):
with open(lib_name, 'w', encoding='utf-8') as f:
f.write(self.lib_template.format(**kwargs))
@@ -118,6 +131,10 @@ class FileImpl(SampleImpl):
"""File based languages without headers"""
+ def __init__(self, args: Arguments):
+ super().__init__(args)
+ self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.executable_name}.{self.source_ext}')]
+
def create_executable(self) -> None:
source_name = f'{self.lowercase_token}.{self.source_ext}'
if not os.path.exists(source_name):
@@ -126,11 +143,12 @@ class FileImpl(SampleImpl):
if self.force or not os.path.exists('meson.build'):
with open('meson.build', 'w', encoding='utf-8') as f:
f.write(self.exe_meson_template.format(project_name=self.name,
- exe_name=self.name,
+ exe_name=self.executable_name,
source_name=source_name,
version=self.version,
meson_version=self.meson_version,
- dependencies=self._format_dependencies()))
+ dependencies=self._format_dependencies(),
+ source_files=self._format_sources()))
def lib_kwargs(self) -> T.Dict[str, str]:
"""Get Language specific keyword arguments
@@ -153,6 +171,7 @@ class FileImpl(SampleImpl):
'version': self.version,
'meson_version': self.meson_version,
'dependencies': self._format_dependencies(),
+ 'source_files': self._format_sources(),
}
def create_library(self) -> None:
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 385b195ea..acf679541 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -2525,7 +2525,7 @@ class AllPlatformTests(BasePlatformTests):
for lang in langs:
for target_type in ('executable', 'library'):
- with self.subTest(f'Language: {lang}; type: {target_type}'):
+ with self.subTest(f'Language: {lang}; type: {target_type}; fresh: yes'):
if is_windows() and lang == 'fortran' and target_type == 'library':
# non-Gfortran Windows Fortran compilers do not do shared libraries in a Fortran standard way
# see "test cases/fortran/6 dynamic"
@@ -2540,17 +2540,44 @@ class AllPlatformTests(BasePlatformTests):
workdir=tmpdir)
self._run(ninja,
workdir=os.path.join(tmpdir, 'builddir'))
- # test directory with existing code file
- if lang in {'c', 'cpp', 'd'}:
- with tempfile.TemporaryDirectory() as tmpdir:
- with open(os.path.join(tmpdir, 'foo.' + lang), 'w', encoding='utf-8') as f:
- f.write('int main(void) {}')
- self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
- elif lang in {'java'}:
- with tempfile.TemporaryDirectory() as tmpdir:
- with open(os.path.join(tmpdir, 'Foo.' + lang), 'w', encoding='utf-8') as f:
- f.write('public class Foo { public static void main() {} }')
- self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
+
+ with self.subTest(f'Language: {lang}; type: {target_type}; fresh: no'):
+ # test directory with existing code file
+ if lang in {'c', 'cpp', 'd'}:
+ with tempfile.TemporaryDirectory() as tmpdir:
+ with open(os.path.join(tmpdir, 'foo.' + lang), 'w', encoding='utf-8') as f:
+ f.write('int main(void) {}')
+ self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
+
+ # Check for whether we're doing source collection by repeating
+ # with a bogus file we should pick up (and then fail to compile).
+ with tempfile.TemporaryDirectory() as tmpdir:
+ with open(os.path.join(tmpdir, 'bar.' + lang), 'w', encoding='utf-8') as f:
+ f.write('#error bar')
+ self._run(self.meson_command + ['init'], workdir=tmpdir)
+ self._run(self.setup_command + ['--backend=ninja', 'builddir'],
+ workdir=tmpdir)
+ with self.assertRaises(subprocess.CalledProcessError):
+ self._run(ninja,
+ workdir=os.path.join(tmpdir, 'builddir'))
+
+ elif lang in {'java'}:
+ with tempfile.TemporaryDirectory() as tmpdir:
+ with open(os.path.join(tmpdir, 'Foo.' + lang), 'w', encoding='utf-8') as f:
+ f.write('public class Foo { public static void main() {} }')
+ self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
+
+ # Check for whether we're doing source collection by repeating
+ # with a bogus file we should pick up (and then fail to compile).
+ with tempfile.TemporaryDirectory() as tmpdir:
+ with open(os.path.join(tmpdir, 'Bar.' + lang), 'w', encoding='utf-8') as f:
+ f.write('public class Bar { public private static void main() {} }')
+ self._run(self.meson_command + ['init'], workdir=tmpdir)
+ self._run(self.setup_command + ['--backend=ninja', 'builddir'],
+ workdir=tmpdir)
+ with self.assertRaises(subprocess.CalledProcessError):
+ self._run(ninja,
+ workdir=os.path.join(tmpdir, 'builddir'))
def test_compiler_run_command(self):
'''