Skip to content

Commit 9104bb6

Browse files
thesamesamjpakkane
authored andcommitted
templates: respect parameters
Respect collected sources for `meson init` as well as --executable. This regressed in 9f0ac31 (part of #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: #15286
1 parent 06242bc commit 9104bb6

File tree

6 files changed

+112
-38
lines changed

6 files changed

+112
-38
lines changed

mesonbuild/templates/cpptemplates.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@
3535
dependencies = [{dependencies}
3636
]
3737
38+
sources = [{source_files}
39+
]
40+
3841
exe = executable(
3942
'{exe_name}',
40-
'{source_name}',
43+
[sources],
4144
install : true,
4245
dependencies : dependencies,
4346
)
@@ -121,9 +124,13 @@ class {utoken}_PUBLIC {class_name} {{
121124
# not the executables that use the library.
122125
lib_args = ['-DBUILDING_{utoken}']
123126
127+
sources = [{source_files}
128+
129+
]
130+
124131
lib = library(
125132
'{lib_name}',
126-
'{source_file}',
133+
[sources],
127134
install : true,
128135
cpp_shared_args : lib_args,
129136
gnu_symbol_visibility : 'hidden',

mesonbuild/templates/ctemplates.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@
7171
dependencies = [{dependencies}
7272
]
7373
74+
sources = [{source_files}
75+
]
76+
7477
lib = library(
7578
'{lib_name}',
76-
'{source_file}',
79+
[sources],
7780
install : true,
7881
c_shared_args : lib_args,
7982
gnu_symbol_visibility : 'hidden',
@@ -133,9 +136,12 @@
133136
dependencies = [{dependencies}
134137
]
135138
139+
sources = [{source_files}
140+
]
141+
136142
exe = executable(
137143
'{exe_name}',
138-
'{source_name}',
144+
[sources],
139145
dependencies : dependencies,
140146
install : true,
141147
)

mesonbuild/templates/dlangtemplates.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@
3535
dependencies = [{dependencies}
3636
]
3737
38+
sources = [{source_files}
39+
40+
]
41+
3842
exe = executable(
3943
'{exe_name}',
40-
'{source_name}',
44+
[sources],
4145
dependencies : dependencies,
4246
install : true,
4347
)
@@ -84,10 +88,13 @@
8488
dependencies = [{dependencies}
8589
]
8690
91+
sources = [{source_files}
92+
93+
]
8794
8895
stlib = static_library(
8996
'{lib_name}',
90-
'{source_file}',
97+
[sources],
9198
install : true,
9299
gnu_symbol_visibility : 'hidden',
93100
dependencies : dependencies,

mesonbuild/templates/javatemplates.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@
3535
dependencies = [{dependencies}
3636
]
3737
38+
sources = [{source_files}
39+
40+
]
41+
3842
exe = jar(
3943
'{exe_name}',
40-
'{source_name}',
44+
[sources],
4145
main_class : '{exe_name}',
4246
dependencies : dependencies,
4347
install : true,
@@ -86,9 +90,13 @@
8690
dependencies = [{dependencies}
8791
]
8892
93+
sources = [{source_files}
94+
95+
]
96+
8997
jarlib = jar(
9098
'{class_name}',
91-
'{source_file}',
99+
[sources],
92100
dependencies : dependencies,
93101
main_class : '{class_name}',
94102
install : true,

mesonbuild/templates/sampleimpl.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Copyright © 2023-2025 Intel Corporation
44

55
from __future__ import annotations
6+
from pathlib import Path
67

78
import abc
89
import os
@@ -17,13 +18,15 @@ class SampleImpl(metaclass=abc.ABCMeta):
1718

1819
def __init__(self, args: Arguments):
1920
self.name = args.name
21+
self.executable_name = args.executable if args.executable else None
2022
self.version = args.version
2123
self.lowercase_token = re.sub(r'[^a-z0-9]', '_', self.name.lower())
2224
self.uppercase_token = self.lowercase_token.upper()
2325
self.capitalized_token = self.lowercase_token.capitalize()
2426
self.meson_version = '1.0.0'
2527
self.force = args.force
2628
self.dependencies = args.deps.split(',') if args.deps else []
29+
self.sources: list[Path] = []
2730

2831
@abc.abstractmethod
2932
def create_executable(self) -> None:
@@ -66,11 +69,18 @@ def source_ext(self) -> str:
6669
def _format_dependencies(self) -> str:
6770
return ''.join(f"\n dependency('{d}')," for d in self.dependencies)
6871

72+
def _format_sources(self) -> str:
73+
return ''.join(f"\n '{x}'," for x in self.sources)
74+
6975

7076
class ClassImpl(SampleImpl):
7177

7278
"""For Class based languages, like Java and C#"""
7379

80+
def __init__(self, args: Arguments):
81+
super().__init__(args)
82+
self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.capitalized_token}.{self.source_ext}')]
83+
7484
def create_executable(self) -> None:
7585
source_name = f'{self.capitalized_token}.{self.source_ext}'
7686
if not os.path.exists(source_name):
@@ -80,29 +90,32 @@ def create_executable(self) -> None:
8090
if self.force or not os.path.exists('meson.build'):
8191
with open('meson.build', 'w', encoding='utf-8') as f:
8292
f.write(self.exe_meson_template.format(project_name=self.name,
83-
exe_name=self.name,
93+
exe_name=self.executable_name,
8494
source_name=source_name,
8595
version=self.version,
8696
meson_version=self.meson_version,
87-
dependencies=self._format_dependencies()))
97+
dependencies=self._format_dependencies(),
98+
source_files=self._format_sources()))
8899

89100
def create_library(self) -> None:
90101
lib_name = f'{self.capitalized_token}.{self.source_ext}'
91102
test_name = f'{self.capitalized_token}_test.{self.source_ext}'
92-
kwargs = {'utoken': self.uppercase_token,
93-
'ltoken': self.lowercase_token,
94-
'class_test': f'{self.capitalized_token}_test',
95-
'class_name': self.capitalized_token,
96-
'source_file': lib_name,
97-
'test_source_file': test_name,
98-
'test_exe_name': f'{self.lowercase_token}_test',
99-
'project_name': self.name,
100-
'lib_name': self.lowercase_token,
101-
'test_name': self.lowercase_token,
102-
'version': self.version,
103-
'meson_version': self.meson_version,
104-
'dependencies': self._format_dependencies(),
105-
}
103+
kwargs = {
104+
'utoken': self.uppercase_token,
105+
'ltoken': self.lowercase_token,
106+
'class_test': f'{self.capitalized_token}_test',
107+
'class_name': self.capitalized_token,
108+
'source_file': lib_name,
109+
'test_source_file': test_name,
110+
'test_exe_name': f'{self.lowercase_token}_test',
111+
'project_name': self.name,
112+
'lib_name': self.lowercase_token,
113+
'test_name': self.lowercase_token,
114+
'version': self.version,
115+
'meson_version': self.meson_version,
116+
'dependencies': self._format_dependencies(),
117+
'source_files': self._format_sources(),
118+
}
106119
if not os.path.exists(lib_name):
107120
with open(lib_name, 'w', encoding='utf-8') as f:
108121
f.write(self.lib_template.format(**kwargs))
@@ -118,6 +131,10 @@ class FileImpl(SampleImpl):
118131

119132
"""File based languages without headers"""
120133

134+
def __init__(self, args: Arguments):
135+
super().__init__(args)
136+
self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.executable_name}.{self.source_ext}')]
137+
121138
def create_executable(self) -> None:
122139
source_name = f'{self.lowercase_token}.{self.source_ext}'
123140
if not os.path.exists(source_name):
@@ -126,11 +143,12 @@ def create_executable(self) -> None:
126143
if self.force or not os.path.exists('meson.build'):
127144
with open('meson.build', 'w', encoding='utf-8') as f:
128145
f.write(self.exe_meson_template.format(project_name=self.name,
129-
exe_name=self.name,
146+
exe_name=self.executable_name,
130147
source_name=source_name,
131148
version=self.version,
132149
meson_version=self.meson_version,
133-
dependencies=self._format_dependencies()))
150+
dependencies=self._format_dependencies(),
151+
source_files=self._format_sources()))
134152

135153
def lib_kwargs(self) -> T.Dict[str, str]:
136154
"""Get Language specific keyword arguments
@@ -153,6 +171,7 @@ def lib_kwargs(self) -> T.Dict[str, str]:
153171
'version': self.version,
154172
'meson_version': self.meson_version,
155173
'dependencies': self._format_dependencies(),
174+
'source_files': self._format_sources(),
156175
}
157176

158177
def create_library(self) -> None:

unittests/allplatformstests.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,7 @@ def test_templates(self):
25252525

25262526
for lang in langs:
25272527
for target_type in ('executable', 'library'):
2528-
with self.subTest(f'Language: {lang}; type: {target_type}'):
2528+
with self.subTest(f'Language: {lang}; type: {target_type}; fresh: yes'):
25292529
if is_windows() and lang == 'fortran' and target_type == 'library':
25302530
# non-Gfortran Windows Fortran compilers do not do shared libraries in a Fortran standard way
25312531
# see "test cases/fortran/6 dynamic"
@@ -2540,17 +2540,44 @@ def test_templates(self):
25402540
workdir=tmpdir)
25412541
self._run(ninja,
25422542
workdir=os.path.join(tmpdir, 'builddir'))
2543-
# test directory with existing code file
2544-
if lang in {'c', 'cpp', 'd'}:
2545-
with tempfile.TemporaryDirectory() as tmpdir:
2546-
with open(os.path.join(tmpdir, 'foo.' + lang), 'w', encoding='utf-8') as f:
2547-
f.write('int main(void) {}')
2548-
self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
2549-
elif lang in {'java'}:
2550-
with tempfile.TemporaryDirectory() as tmpdir:
2551-
with open(os.path.join(tmpdir, 'Foo.' + lang), 'w', encoding='utf-8') as f:
2552-
f.write('public class Foo { public static void main() {} }')
2553-
self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
2543+
2544+
with self.subTest(f'Language: {lang}; type: {target_type}; fresh: no'):
2545+
# test directory with existing code file
2546+
if lang in {'c', 'cpp', 'd'}:
2547+
with tempfile.TemporaryDirectory() as tmpdir:
2548+
with open(os.path.join(tmpdir, 'foo.' + lang), 'w', encoding='utf-8') as f:
2549+
f.write('int main(void) {}')
2550+
self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
2551+
2552+
# Check for whether we're doing source collection by repeating
2553+
# with a bogus file we should pick up (and then fail to compile).
2554+
with tempfile.TemporaryDirectory() as tmpdir:
2555+
with open(os.path.join(tmpdir, 'bar.' + lang), 'w', encoding='utf-8') as f:
2556+
f.write('#error bar')
2557+
self._run(self.meson_command + ['init'], workdir=tmpdir)
2558+
self._run(self.setup_command + ['--backend=ninja', 'builddir'],
2559+
workdir=tmpdir)
2560+
with self.assertRaises(subprocess.CalledProcessError):
2561+
self._run(ninja,
2562+
workdir=os.path.join(tmpdir, 'builddir'))
2563+
2564+
elif lang in {'java'}:
2565+
with tempfile.TemporaryDirectory() as tmpdir:
2566+
with open(os.path.join(tmpdir, 'Foo.' + lang), 'w', encoding='utf-8') as f:
2567+
f.write('public class Foo { public static void main() {} }')
2568+
self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
2569+
2570+
# Check for whether we're doing source collection by repeating
2571+
# with a bogus file we should pick up (and then fail to compile).
2572+
with tempfile.TemporaryDirectory() as tmpdir:
2573+
with open(os.path.join(tmpdir, 'Bar.' + lang), 'w', encoding='utf-8') as f:
2574+
f.write('public class Bar { public private static void main() {} }')
2575+
self._run(self.meson_command + ['init'], workdir=tmpdir)
2576+
self._run(self.setup_command + ['--backend=ninja', 'builddir'],
2577+
workdir=tmpdir)
2578+
with self.assertRaises(subprocess.CalledProcessError):
2579+
self._run(ninja,
2580+
workdir=os.path.join(tmpdir, 'builddir'))
25542581

25552582
def test_compiler_run_command(self):
25562583
'''

0 commit comments

Comments
 (0)