From 0c4aab6eed77d62c41006d6944b46f881610599d Mon Sep 17 00:00:00 2001 From: Nicolas Schneider Date: Thu, 24 Mar 2016 22:19:55 +0100 Subject: vs2010: support same source file names in different subdirs --- mesonbuild/backend/vs2010backend.py | 5 +++++ mesonbuild/build.py | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 84ef8c309..fac73589b 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -566,6 +566,11 @@ class Vs2010Backend(backends.Backend): inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) self.add_additional_options(s, inc_cl, extra_args, additional_options_set) + basename = os.path.basename(s.fname) + if basename in target.sources_conflicts: + obj_name = '.'.join(s.split('.')[:-1]).replace('/', '_')\ + + '.' + self.environment.get_object_suffix() + ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + obj_name for s in gen_src: relpath = self.relpath(s, target.subdir) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 3f480e870..a7965aafa 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -184,6 +184,7 @@ class BuildTarget(): self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project. self.is_cross = is_cross self.sources = [] + self.sources_conflicts = {} self.objects = [] self.external_deps = [] self.include_dirs = [] @@ -244,6 +245,7 @@ class BuildTarget(): if not isinstance(sources, list): sources = [sources] added_sources = {} # If the same source is defined multiple times, use it only once. + conflicts = {} # We must resolve conflicts if multiple source files from different subdirs have the same name. for s in sources: # Holder unpacking. Ugly. if hasattr(s, 'held_object'): @@ -252,10 +254,19 @@ class BuildTarget(): if not s in added_sources: self.sources.append(s) added_sources[s] = True + basename = os.path.basename(s.fname) + conflicting_sources = conflicts.get(basename, None) + if conflicting_sources is None: + conflicting_sources = [] + conflicting_sources.append(s) + conflicts[basename] = conflicting_sources elif isinstance(s, GeneratedList) or isinstance(s, CustomTarget): self.generated.append(s) else: raise InvalidArguments('Bad source in target %s.' % self.name) + for basename, conflicting_sources in conflicts.items(): + if len(conflicting_sources) > 1: + self.sources_conflicts[basename] = conflicting_sources def validate_sources(self): if len(self.sources) > 0: -- cgit v1.2.3 From 3de7c3471406b3e800b4b87c15febb49e73a9d53 Mon Sep 17 00:00:00 2001 From: Nicolas Schneider Date: Thu, 24 Mar 2016 22:41:34 +0100 Subject: add test for extracting two objects with the same source file name --- test cases/common/110 extract same name/lib.c | 3 +++ test cases/common/110 extract same name/main.c | 6 ++++++ test cases/common/110 extract same name/meson.build | 6 ++++++ test cases/common/110 extract same name/src/lib.c | 3 +++ 4 files changed, 18 insertions(+) create mode 100644 test cases/common/110 extract same name/lib.c create mode 100644 test cases/common/110 extract same name/main.c create mode 100644 test cases/common/110 extract same name/meson.build create mode 100644 test cases/common/110 extract same name/src/lib.c diff --git a/test cases/common/110 extract same name/lib.c b/test cases/common/110 extract same name/lib.c new file mode 100644 index 000000000..6bdeda747 --- /dev/null +++ b/test cases/common/110 extract same name/lib.c @@ -0,0 +1,3 @@ +int func1() { + return 23; +} diff --git a/test cases/common/110 extract same name/main.c b/test cases/common/110 extract same name/main.c new file mode 100644 index 000000000..dc57dd598 --- /dev/null +++ b/test cases/common/110 extract same name/main.c @@ -0,0 +1,6 @@ +int func1(); +int func2(); + +int main(int argc, char **argv) { + return !(func1() == 23 && func2() == 42); +} diff --git a/test cases/common/110 extract same name/meson.build b/test cases/common/110 extract same name/meson.build new file mode 100644 index 000000000..9384c47a8 --- /dev/null +++ b/test cases/common/110 extract same name/meson.build @@ -0,0 +1,6 @@ +project('object extraction', 'c') + +lib = shared_library('somelib', ['lib.c', 'src/lib.c']) +obj = lib.extract_objects(['lib.c', 'src/lib.c']) +exe = executable('main', 'main.c', objects: obj) +test('extraction', exe) diff --git a/test cases/common/110 extract same name/src/lib.c b/test cases/common/110 extract same name/src/lib.c new file mode 100644 index 000000000..68e6ab975 --- /dev/null +++ b/test cases/common/110 extract same name/src/lib.c @@ -0,0 +1,3 @@ +int func2() { + return 42; +} -- cgit v1.2.3 From 8787ec3ea2aa2b06c48ef917a396e8912ad05303 Mon Sep 17 00:00:00 2001 From: Nicolas Schneider Date: Fri, 25 Mar 2016 09:49:30 +0100 Subject: vs2010: fix object extraction with same source file name This also refactors determine_ext_objs() to use inheritance instead of a method flag for determining the object output name. --- mesonbuild/backend/backends.py | 23 ++++++++--------------- mesonbuild/backend/ninjabackend.py | 1 - mesonbuild/backend/vs2010backend.py | 17 +++++++++++------ 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 8d0b0f613..af3f9f2be 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -142,7 +142,7 @@ class Backend(): return os.path.relpath(os.path.join('dummyprefixdir', todir),\ os.path.join('dummyprefixdir', fromdir)) - def flatten_object_list(self, target, proj_dir_to_build_root='', include_dir_names=True): + def flatten_object_list(self, target, proj_dir_to_build_root=''): obj_list = [] for obj in target.get_objects(): if isinstance(obj, str): @@ -150,7 +150,7 @@ class Backend(): self.build_to_src, target.get_subdir(), obj) obj_list.append(o) elif isinstance(obj, build.ExtractedObjects): - obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root, include_dir_names) + obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root) else: raise MesonException('Unknown data type in object list.') return obj_list @@ -210,28 +210,21 @@ class Backend(): return c raise RuntimeError('Unreachable code') - def determine_ext_objs(self, extobj, proj_dir_to_build_root='', include_dir_names=True): + def object_filename_from_source(self, target, source): + return source.fname.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix() + + def determine_ext_objs(self, extobj, proj_dir_to_build_root=''): result = [] targetdir = self.get_target_private_dir(extobj.target) - suffix = '.' + self.environment.get_object_suffix() for osrc in extobj.srclist: - osrc_base = osrc.fname - if not self.source_suffix_in_objs: - osrc_base = '.'.join(osrc.split('.')[:-1]) # If extracting in a subproject, the subproject # name gets duplicated in the file name. pathsegs = osrc.subdir.split(os.sep) if pathsegs[0] == 'subprojects': pathsegs = pathsegs[2:] fixedpath = os.sep.join(pathsegs) - if include_dir_names: - objbase = osrc_base.replace('/', '_').replace('\\', '_') - else: - # vs2010 backend puts all obj files without directory prefixes into build dir, so just - # use the file name without a directory (will be stripped by os.path.basename() below). - objbase = osrc_base - objname = os.path.join(proj_dir_to_build_root, - targetdir, os.path.basename(objbase) + suffix) + objname = os.path.join(proj_dir_to_build_root, targetdir, + self.object_filename_from_source(extobj.target, osrc)) result.append(objname) return result diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 8e8fa4285..7c430bf4c 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -129,7 +129,6 @@ class NinjaBackend(backends.Backend): def __init__(self, build): super().__init__(build) - self.source_suffix_in_objs = True self.ninja_filename = 'build.ninja' self.fortran_deps = {} self.all_outputs = {} diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index fac73589b..e6b00564c 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -35,8 +35,15 @@ class Vs2010Backend(backends.Backend): def __init__(self, build): super().__init__(build) self.project_file_version = '10.0.30319.1' - # foo.c compiles to foo.obj, not foo.c.obj - self.source_suffix_in_objs = False + + def object_filename_from_source(self, target, source): + basename = os.path.basename(source.fname) + filename_without_extension = '.'.join(basename.split('.')[:-1]) + if basename in target.sources_conflicts: + # If there are multiple source files with the same basename, we must resolve the conflict + # by giving each a unique object output file. + filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_') + return filename_without_extension + '.' + self.environment.get_object_suffix() def generate_custom_generator_commands(self, target, parent_node): all_output_files = [] @@ -525,7 +532,7 @@ class Vs2010Backend(backends.Backend): linkname = os.path.join(rel_path, lobj.get_import_filename()) additional_links.append(linkname) additional_objects = [] - for o in self.flatten_object_list(target, down, include_dir_names=False): + for o in self.flatten_object_list(target, down): assert(isinstance(o, str)) additional_objects.append(o) if len(additional_links) > 0: @@ -568,9 +575,7 @@ class Vs2010Backend(backends.Backend): self.add_additional_options(s, inc_cl, extra_args, additional_options_set) basename = os.path.basename(s.fname) if basename in target.sources_conflicts: - obj_name = '.'.join(s.split('.')[:-1]).replace('/', '_')\ - + '.' + self.environment.get_object_suffix() - ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + obj_name + ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s) for s in gen_src: relpath = self.relpath(s, target.subdir) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) -- cgit v1.2.3 From fd8180ddcbe223c564e352fde6d1e248021edc0e Mon Sep 17 00:00:00 2001 From: Nicolas Schneider Date: Mon, 28 Mar 2016 14:42:52 +0200 Subject: move source file conflict detection into Vs2010 backend --- mesonbuild/backend/vs2010backend.py | 27 +++++++++++++++++++++++++-- mesonbuild/build.py | 11 ----------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index e6b00564c..3516ac7d7 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -16,6 +16,8 @@ import os, sys import pickle from mesonbuild import compilers +from mesonbuild.build import BuildTarget +from mesonbuild.mesonlib import File from . import backends from .. import build from .. import dependencies @@ -35,16 +37,36 @@ class Vs2010Backend(backends.Backend): def __init__(self, build): super().__init__(build) self.project_file_version = '10.0.30319.1' + self.sources_conflicts = {} def object_filename_from_source(self, target, source): basename = os.path.basename(source.fname) filename_without_extension = '.'.join(basename.split('.')[:-1]) - if basename in target.sources_conflicts: + if basename in self.sources_conflicts[target.get_id()]: # If there are multiple source files with the same basename, we must resolve the conflict # by giving each a unique object output file. filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_') return filename_without_extension + '.' + self.environment.get_object_suffix() + def resolve_source_conflicts(self): + for name, target in self.build.targets.items(): + if not isinstance(target, BuildTarget): + continue + conflicts = {} + for s in target.get_sources(): + if hasattr(s, 'held_object'): + s = s.held_object + if not isinstance(s, File): + continue + basename = os.path.basename(s.fname) + conflicting_sources = conflicts.get(basename, None) + if conflicting_sources is None: + conflicting_sources = [] + conflicts[basename] = conflicting_sources + conflicting_sources.append(s) + self.sources_conflicts[target.get_id()] = {name: src_conflicts for name, src_conflicts in conflicts.items() + if len(src_conflicts) > 1} + def generate_custom_generator_commands(self, target, parent_node): all_output_files = [] commands = [] @@ -93,6 +115,7 @@ class Vs2010Backend(backends.Backend): return all_output_files def generate(self, interp): + self.resolve_source_conflicts() self.interpreter = interp self.platform = 'Win32' self.buildtype = self.environment.coredata.get_builtin_option('buildtype') @@ -574,7 +597,7 @@ class Vs2010Backend(backends.Backend): self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) self.add_additional_options(s, inc_cl, extra_args, additional_options_set) basename = os.path.basename(s.fname) - if basename in target.sources_conflicts: + if basename in self.sources_conflicts[target.get_id()]: ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s) for s in gen_src: relpath = self.relpath(s, target.subdir) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a7965aafa..3f480e870 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -184,7 +184,6 @@ class BuildTarget(): self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project. self.is_cross = is_cross self.sources = [] - self.sources_conflicts = {} self.objects = [] self.external_deps = [] self.include_dirs = [] @@ -245,7 +244,6 @@ class BuildTarget(): if not isinstance(sources, list): sources = [sources] added_sources = {} # If the same source is defined multiple times, use it only once. - conflicts = {} # We must resolve conflicts if multiple source files from different subdirs have the same name. for s in sources: # Holder unpacking. Ugly. if hasattr(s, 'held_object'): @@ -254,19 +252,10 @@ class BuildTarget(): if not s in added_sources: self.sources.append(s) added_sources[s] = True - basename = os.path.basename(s.fname) - conflicting_sources = conflicts.get(basename, None) - if conflicting_sources is None: - conflicting_sources = [] - conflicting_sources.append(s) - conflicts[basename] = conflicting_sources elif isinstance(s, GeneratedList) or isinstance(s, CustomTarget): self.generated.append(s) else: raise InvalidArguments('Bad source in target %s.' % self.name) - for basename, conflicting_sources in conflicts.items(): - if len(conflicting_sources) > 1: - self.sources_conflicts[basename] = conflicting_sources def validate_sources(self): if len(self.sources) > 0: -- cgit v1.2.3