diff --git a/mesonbuild/templates/cpptemplates.py b/mesonbuild/templates/cpptemplates.py index 77e61e417c05..79f88a5de8b5 100644 --- a/mesonbuild/templates/cpptemplates.py +++ b/mesonbuild/templates/cpptemplates.py @@ -40,7 +40,7 @@ exe = executable( '{exe_name}', - [sources], + sources, install : true, dependencies : dependencies, ) @@ -131,12 +131,11 @@ class {utoken}_PUBLIC {class_name} {{ lib_args = ['-DBUILDING_{utoken}'] sources = [{source_files} - ] lib = library( '{lib_name}', - [sources], + sources, install : true, cpp_shared_args : lib_args, gnu_symbol_visibility : 'hidden', diff --git a/mesonbuild/templates/cstemplates.py b/mesonbuild/templates/cstemplates.py index 59c718953271..e44cf6f646b6 100644 --- a/mesonbuild/templates/cstemplates.py +++ b/mesonbuild/templates/cstemplates.py @@ -35,9 +35,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, install : true, dependencies : dependencies, ) @@ -83,9 +86,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + stlib = shared_library( '{lib_name}', - '{source_file}', + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/ctemplates.py b/mesonbuild/templates/ctemplates.py index 134e43b3f24c..3db6477aabe1 100644 --- a/mesonbuild/templates/ctemplates.py +++ b/mesonbuild/templates/ctemplates.py @@ -82,7 +82,7 @@ lib = library( '{lib_name}', - [sources], + sources, install : true, c_shared_args : lib_args, gnu_symbol_visibility : 'hidden', @@ -147,7 +147,7 @@ exe = executable( '{exe_name}', - [sources], + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/cudatemplates.py b/mesonbuild/templates/cudatemplates.py index 252f44a276a9..d10fb76190bd 100644 --- a/mesonbuild/templates/cudatemplates.py +++ b/mesonbuild/templates/cudatemplates.py @@ -36,9 +36,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) @@ -122,9 +125,12 @@ class {utoken}_PUBLIC {class_name} {{ dependencies = [{dependencies} ] +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/dlangtemplates.py b/mesonbuild/templates/dlangtemplates.py index 4ca91a69b67a..727ee209c724 100644 --- a/mesonbuild/templates/dlangtemplates.py +++ b/mesonbuild/templates/dlangtemplates.py @@ -36,12 +36,11 @@ ] sources = [{source_files} - ] exe = executable( '{exe_name}', - [sources], + sources, dependencies : dependencies, install : true, ) @@ -89,12 +88,11 @@ ] sources = [{source_files} - ] stlib = static_library( '{lib_name}', - [sources], + sources, install : true, gnu_symbol_visibility : 'hidden', dependencies : dependencies, diff --git a/mesonbuild/templates/fortrantemplates.py b/mesonbuild/templates/fortrantemplates.py index 7aaa9d39cf40..03f0ff922e6a 100644 --- a/mesonbuild/templates/fortrantemplates.py +++ b/mesonbuild/templates/fortrantemplates.py @@ -56,9 +56,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + lib = library( '{lib_name}', - '{source_file}', + sources, install : true, fortran_shared_args : lib_args, gnu_symbol_visibility : 'hidden', @@ -110,9 +113,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/javatemplates.py b/mesonbuild/templates/javatemplates.py index 458142e6b487..ed32194fee88 100644 --- a/mesonbuild/templates/javatemplates.py +++ b/mesonbuild/templates/javatemplates.py @@ -36,12 +36,11 @@ ] sources = [{source_files} - ] exe = jar( '{exe_name}', - [sources], + sources, main_class : '{exe_name}', dependencies : dependencies, install : true, @@ -91,12 +90,11 @@ ] sources = [{source_files} - ] jarlib = jar( '{class_name}', - [sources], + sources, dependencies : dependencies, main_class : '{class_name}', install : true, diff --git a/mesonbuild/templates/objcpptemplates.py b/mesonbuild/templates/objcpptemplates.py index 1f4bef43183d..d80c37485282 100644 --- a/mesonbuild/templates/objcpptemplates.py +++ b/mesonbuild/templates/objcpptemplates.py @@ -73,13 +73,16 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + # These arguments are only used to build the shared library # not the executables that use the library. lib_args = ['-DBUILDING_{utoken}'] lib = library( '{lib_name}', - '{source_file}', + sources, install : true, objcpp_shared_args : lib_args, dependencies : dependencies, @@ -139,9 +142,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/objctemplates.py b/mesonbuild/templates/objctemplates.py index 8708d78e3de3..7dc3d4f989a3 100644 --- a/mesonbuild/templates/objctemplates.py +++ b/mesonbuild/templates/objctemplates.py @@ -73,13 +73,16 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + # These arguments are only used to build the shared library # not the executables that use the library. lib_args = ['-DBUILDING_{utoken}'] lib = library( '{lib_name}', - '{source_file}', + sources, install : true, objc_shared_args : lib_args, dependencies : dependencies, @@ -138,9 +141,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/rusttemplates.py b/mesonbuild/templates/rusttemplates.py index ee1f0081dcd6..b415be7c6b5f 100644 --- a/mesonbuild/templates/rusttemplates.py +++ b/mesonbuild/templates/rusttemplates.py @@ -50,9 +50,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + lib = static_library( '{lib_name}', - '{source_file}', + sources, dependencies : dependencies, install : true, ) @@ -86,9 +89,12 @@ dependencies = [{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) diff --git a/mesonbuild/templates/sampleimpl.py b/mesonbuild/templates/sampleimpl.py index 00735c498995..46f9a70aa3df 100644 --- a/mesonbuild/templates/sampleimpl.py +++ b/mesonbuild/templates/sampleimpl.py @@ -133,7 +133,7 @@ class FileImpl(SampleImpl): def __init__(self, args: Arguments): super().__init__(args) - self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.executable_name}.{self.source_ext}')] + self.sources = args.srcfiles if args.srcfiles else [Path(f'{self.name}.{self.source_ext}')] def create_executable(self) -> None: source_name = f'{self.lowercase_token}.{self.source_ext}' diff --git a/mesonbuild/templates/valatemplates.py b/mesonbuild/templates/valatemplates.py index b2aab3f31be0..de31877674b5 100644 --- a/mesonbuild/templates/valatemplates.py +++ b/mesonbuild/templates/valatemplates.py @@ -24,9 +24,12 @@ dependency('gobject-2.0'),{dependencies} ] +sources = [{source_files} +] + exe = executable( '{exe_name}', - '{source_name}', + sources, dependencies : dependencies, install : true, ) @@ -67,11 +70,14 @@ dependency('gobject-2.0'),{dependencies} ] +sources = [{source_files} +] + # These arguments are only used to build the shared library # not the executables that use the library. lib = shared_library( 'foo', - '{source_file}', + sources, dependencies : dependencies, install : true, install_dir : [true, true, true], diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 34b2f98fede5..5e20b385eecc 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2,6 +2,7 @@ # Copyright 2016-2021 The Meson development team # Copyright © 2023-2025 Intel Corporation +import itertools import subprocess import re import json @@ -46,7 +47,7 @@ from mesonbuild.compilers.cpp import VisualStudioCPPCompiler, ClangClCPPCompiler from mesonbuild.compilers import ( detect_static_linker, detect_c_compiler, compiler_from_language, - detect_compiler_for + detect_compiler_for, lang_suffixes ) from mesonbuild.linkers import linkers @@ -2509,7 +2510,7 @@ def test_templates(self): langs = ['c'] env = get_fake_env() - for l in ['cpp', 'cs', 'd', 'java', 'cuda', 'fortran', 'objc', 'objcpp', 'rust', 'vala']: + for l in ['cpp', 'cs', 'cuda', 'd', 'fortran', 'java', 'objc', 'objcpp', 'rust', 'vala']: try: comp = detect_compiler_for(env, l, MachineChoice.HOST, True, '') with tempfile.TemporaryDirectory() as d: @@ -2523,61 +2524,86 @@ def test_templates(self): if is_osx(): langs = [l for l in langs if l != 'd'] - for lang in langs: - for target_type in ('executable', 'library'): - 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" - fc = detect_compiler_for(env, 'fortran', MachineChoice.HOST, True, '') - if fc.get_id() in {'intel-cl', 'pgi'}: - continue - # test empty directory - with tempfile.TemporaryDirectory() as tmpdir: - self._run(self.meson_command + ['init', '--language', lang, '--type', target_type], - workdir=tmpdir) - self._run(self.setup_command + ['--backend=ninja', 'builddir'], - workdir=tmpdir) - self._run(ninja, - workdir=os.path.join(tmpdir, 'builddir')) - - 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 _template_test_fresh(lang, target_type): + 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" + fc = detect_compiler_for(env, 'fortran', MachineChoice.HOST, True, '') + if fc.get_id() in {'intel-cl', 'pgi'}: + return + + # test empty directory + with tempfile.TemporaryDirectory() as tmpdir: + self._run(self.meson_command + ['init', '--language', lang, '--type', target_type], + workdir=tmpdir) + self._run(self.setup_command + ['--backend=ninja', 'builddir'], + workdir=tmpdir) + self._run(ninja, + workdir=os.path.join(tmpdir, 'builddir')) + + # custom executable name + if target_type == 'executable': + with tempfile.TemporaryDirectory() as tmpdir: + self._run(self.meson_command + ['init', '--language', lang, '--type', target_type, + '--executable', 'foobar'], workdir=tmpdir) + self._run(self.setup_command + ['--backend=ninja', 'builddir'], + workdir=tmpdir) + self._run(ninja, + workdir=os.path.join(tmpdir, 'builddir')) + + if lang not in {'cs', 'java'}: + exe = os.path.join(tmpdir, 'builddir', 'foobar' + exe_suffix) + self.assertTrue(os.path.exists(exe)) + + def _template_test_dirty(lang, target_type): + 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" + fc = detect_compiler_for(env, 'fortran', MachineChoice.HOST, True, '') + if fc.get_id() in {'intel-cl', 'pgi'}: + return + + # test empty directory + with tempfile.TemporaryDirectory() as tmpdir: + self._run(self.meson_command + ['init', '--language', lang, '--type', target_type], + workdir=tmpdir) + self._run(self.setup_command + ['--backend=ninja', 'builddir'], + workdir=tmpdir) + self._run(ninja, + workdir=os.path.join(tmpdir, 'builddir')) + + # 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: + suffix = lang_suffixes[lang][0] + # Assume that this is a good enough string to error out + # in all languages. + with open(os.path.join(tmpdir, 'bar.' + suffix), 'w', encoding='utf-8') as f: + f.write('error bar') + self._run(self.meson_command + ['init', '--language', lang, '--type', target_type], + 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')) + + # 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) + + for lang, target_type, fresh in itertools.product(langs, ('executable', 'library'), (True, False)): + with self.subTest(f'Language: {lang}; type: {target_type}; fresh: {fresh}'): + _template_test_fresh(lang, target_type) if fresh else _template_test_dirty(lang, target_type) def test_compiler_run_command(self): '''