diff --git a/docs/markdown/snippets/non-unique-target-names.md b/docs/markdown/snippets/non-unique-target-names.md new file mode 100644 index 000000000..9b3f9173c --- /dev/null +++ b/docs/markdown/snippets/non-unique-target-names.md @@ -0,0 +1,9 @@ +## Relaxing of target name requirements + +In earlier versions of Meson you could only have one target of a given name for each type. +For example you could not have two executables named `foo`. This requirement is now +relaxed so that you can have multiple targets with the same name, as long as they are in +different subdirectories. + +Note that projects that have multiple targets with the same name can not be built with +the `flat` layout or any backend that writes outputs in the same directory. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 47c40a242..e70705376 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -310,11 +310,16 @@ a hard error in the future.''' % name) def get_id(self): # This ID must also be a valid file name on all OSs. # It should also avoid shell metacharacters for obvious - # reasons. - base = self.name + self.type_suffix() - if self.subproject == '': - return base - return self.subproject + '@@' + base + # reasons. '@' is not used as often as '_' in source code names. + # In case of collisions consider using checksums. + # FIXME replace with assert when slash in names is prohibited + name_part = self.name.replace('/', '@').replace('\\', '@') + assert not has_path_sep(self.type_suffix()) + myid = name_part + self.type_suffix() + if self.subdir: + subdir_part = self.subdir.replace('/', '@').replace('\\', '@') + myid = subdir_part + '@@' + myid + return myid def process_kwargs(self, kwargs): if 'build_by_default' in kwargs: diff --git a/run_unittests.py b/run_unittests.py index 19a8c87f4..775fd310b 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1117,7 +1117,7 @@ class AllPlatformTests(BasePlatformTests): incs = [a for a in shlex.split(execmd) if a.startswith("-I")] self.assertEqual(len(incs), 9) # target private dir - self.assertPathEqual(incs[0], "-Isub4/someexe@exe") + self.assertPathEqual(incs[0], "-Isub4/sub4@@someexe@exe") # target build subdir self.assertPathEqual(incs[1], "-Isub4") # target source subdir @@ -1917,6 +1917,15 @@ int main(int argc, char **argv) { self.init(testdir, extra_args=['--layout=flat']) self.build() + def test_identical_target_name_in_subdir_flat_layout(self): + ''' + Test that identical targets in different subdirs do not collide + if layout is flat. + ''' + testdir = os.path.join(self.common_test_dir, '189 same target name flat layout') + self.init(testdir, extra_args=['--layout=flat']) + self.build() + def test_flock(self): exception_raised = False with tempfile.TemporaryDirectory() as tdir: @@ -2601,8 +2610,8 @@ class LinuxlikeTests(BasePlatformTests): def test_unity_subproj(self): testdir = os.path.join(self.common_test_dir, '49 subproject') self.init(testdir, extra_args='--unity=subprojects') - self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/sublib@@simpletest@exe/simpletest-unity.c')) - self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/sublib@@sublib@sha/sublib-unity.c')) + self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@simpletest@exe/simpletest-unity.c')) + self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@sublib@sha/sublib-unity.c')) self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c')) self.build() diff --git a/test cases/failing/17 same name/file.c b/test cases/common/183 same target name/file.c similarity index 100% rename from test cases/failing/17 same name/file.c rename to test cases/common/183 same target name/file.c diff --git a/test cases/failing/17 same name/meson.build b/test cases/common/183 same target name/meson.build similarity index 100% rename from test cases/failing/17 same name/meson.build rename to test cases/common/183 same target name/meson.build diff --git a/test cases/failing/17 same name/sub/file2.c b/test cases/common/183 same target name/sub/file2.c similarity index 100% rename from test cases/failing/17 same name/sub/file2.c rename to test cases/common/183 same target name/sub/file2.c diff --git a/test cases/failing/17 same name/sub/meson.build b/test cases/common/183 same target name/sub/meson.build similarity index 100% rename from test cases/failing/17 same name/sub/meson.build rename to test cases/common/183 same target name/sub/meson.build diff --git a/test cases/common/189 same target name flat layout/foo.c b/test cases/common/189 same target name flat layout/foo.c new file mode 100644 index 000000000..ed427899a --- /dev/null +++ b/test cases/common/189 same target name flat layout/foo.c @@ -0,0 +1 @@ +int meson_test_main_foo(void) { return 10; } diff --git a/test cases/common/189 same target name flat layout/main.c b/test cases/common/189 same target name flat layout/main.c new file mode 100644 index 000000000..6f02aeb82 --- /dev/null +++ b/test cases/common/189 same target name flat layout/main.c @@ -0,0 +1,16 @@ +#include + +int meson_test_main_foo(void); +int meson_test_subproj_foo(void); + +int main(void) { + if (meson_test_main_foo() != 10) { + printf("Failed meson_test_main_foo\n"); + return 1; + } + if (meson_test_subproj_foo() != 20) { + printf("Failed meson_test_subproj_foo\n"); + return 1; + } + return 0; +} diff --git a/test cases/common/189 same target name flat layout/meson.build b/test cases/common/189 same target name flat layout/meson.build new file mode 100644 index 000000000..a3c95fa25 --- /dev/null +++ b/test cases/common/189 same target name flat layout/meson.build @@ -0,0 +1,11 @@ +project('subdir targets', 'c') + +# Idea behind this test is to create targets with identical name +# but different output files. We can do this by choosing different +# name_prefix of libraries. Target id does not depend on name_prefix. + +main_foo = static_library('foo', 'foo.c', name_prefix : 'main') +subdir('subdir') # defines subdir_foo + +exe = executable('prog', 'main.c', link_with : [main_foo, subdir_foo]) +test('main test', exe) diff --git a/test cases/common/189 same target name flat layout/subdir/foo.c b/test cases/common/189 same target name flat layout/subdir/foo.c new file mode 100644 index 000000000..f33429229 --- /dev/null +++ b/test cases/common/189 same target name flat layout/subdir/foo.c @@ -0,0 +1 @@ +int meson_test_subproj_foo(void) { return 20; } diff --git a/test cases/common/189 same target name flat layout/subdir/meson.build b/test cases/common/189 same target name flat layout/subdir/meson.build new file mode 100644 index 000000000..223a5ef90 --- /dev/null +++ b/test cases/common/189 same target name flat layout/subdir/meson.build @@ -0,0 +1 @@ +subdir_foo = static_library('foo', 'foo.c', name_prefix : 'subdir') diff --git a/test cases/failing/17 same target/file.c b/test cases/failing/17 same target/file.c new file mode 100644 index 000000000..741237235 --- /dev/null +++ b/test cases/failing/17 same target/file.c @@ -0,0 +1 @@ +int func() { return 0; } diff --git a/test cases/failing/17 same target/meson.build b/test cases/failing/17 same target/meson.build new file mode 100644 index 000000000..ee586d0f4 --- /dev/null +++ b/test cases/failing/17 same target/meson.build @@ -0,0 +1,4 @@ +project('same target', 'c') + +static_library('foo', 'file.c') +static_library('foo', 'file.c')