Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: pylib/gyp/generator/analyzer.py

Issue 395483002: Fixes bug in path handling of analyzer (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2014 Google Inc. All rights reserved. 1 # Copyright (c) 2014 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of 6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
7 the generator flag file_path) the list of relative file paths to consider. If 7 the generator flag file_path) the list of relative file paths to consider. If
8 any target has at least one of the paths as a source (or input to an action or 8 any target has at least one of the paths as a source (or input to an action or
9 rule) then 'Found dependency' is output, otherwise 'No dependencies' is output. 9 rule) then 'Found dependency' is output, otherwise 'No dependencies' is output.
10 """ 10 """
11 11
12 import gyp.common 12 import gyp.common
13 import gyp.ninja_syntax as ninja_syntax 13 import gyp.ninja_syntax as ninja_syntax
14 import os 14 import os
15 import posixpath 15 import posixpath
16 16
17 debug = False
18
17 generator_supports_multiple_toolsets = True 19 generator_supports_multiple_toolsets = True
18 20
19 generator_wants_static_library_dependencies_adjusted = False 21 generator_wants_static_library_dependencies_adjusted = False
20 22
21 generator_default_variables = { 23 generator_default_variables = {
22 } 24 }
23 for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR', 25 for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
24 'LIB_DIR', 'SHARED_LIB_DIR']: 26 'LIB_DIR', 'SHARED_LIB_DIR']:
25 generator_default_variables[dirname] = '!!!' 27 generator_default_variables[dirname] = '!!!'
26 28
27 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', 29 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
28 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', 30 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
29 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', 31 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
30 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', 32 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
31 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', 33 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
32 'CONFIGURATION_NAME']: 34 'CONFIGURATION_NAME']:
33 generator_default_variables[unused] = '' 35 generator_default_variables[unused] = ''
34 36
35 def __MakeRelativeTargetName(path):
36 """Converts a gyp target name into a relative name. For example, the path to a
37 gyp file may be something like c:\foo\bar.gyp:target, this converts it to
38 bar.gyp.
39 """
40 prune_path = os.getcwd()
41 if path.startswith(prune_path):
42 path = path[len(prune_path):]
43 if len(path) and path.startswith(os.sep):
44 path = path[len(os.sep):]
45 # Gyp paths are always posix style.
46 path = path.replace('\\', '/')
47 if path.endswith('#target'):
48 path = path[0:len(path) - len('#target')]
49 return path
50
51 def __ExtractBasePath(target): 37 def __ExtractBasePath(target):
52 """Extracts the path components of the specified gyp target path.""" 38 """Extracts the path components of the specified gyp target path."""
53 last_index = target.rfind('/') 39 last_index = target.rfind('/')
54 if last_index == -1: 40 if last_index == -1:
55 return '' 41 return ''
56 return target[0:(last_index + 1)] 42 return target[0:(last_index + 1)]
57 43
58 def __ResolveParent(path, base_path_components): 44 def __ResolveParent(path, base_path_components):
59 """Resolves |path|, which starts with at least one '../'. Returns an empty 45 """Resolves |path|, which starts with at least one '../'. Returns an empty
60 string if the path shouldn't be considered. See __AddSources() for a 46 string if the path shouldn't be considered. See __AddSources() for a
(...skipping 16 matching lines...) Expand all
77 source file is relative to |base_path|, but may contain '..'. To make 63 source file is relative to |base_path|, but may contain '..'. To make
78 resolving '..' easier |base_path_components| contains each of the 64 resolving '..' easier |base_path_components| contains each of the
79 directories in |base_path|. Additionally each source may contain variables. 65 directories in |base_path|. Additionally each source may contain variables.
80 Such sources are ignored as it is assumed dependencies on them are expressed 66 Such sources are ignored as it is assumed dependencies on them are expressed
81 and tracked in some other means.""" 67 and tracked in some other means."""
82 # NOTE: gyp paths are always posix style. 68 # NOTE: gyp paths are always posix style.
83 for source in sources: 69 for source in sources:
84 if not len(source) or source.startswith('!!!') or source.startswith('$'): 70 if not len(source) or source.startswith('!!!') or source.startswith('$'):
85 continue 71 continue
86 # variable expansion may lead to //. 72 # variable expansion may lead to //.
73 org_source = source
87 source = source[0] + source[1:].replace('//', '/') 74 source = source[0] + source[1:].replace('//', '/')
88 if source.startswith('../'): 75 if source.startswith('../'):
89 source = __ResolveParent(source, base_path_components) 76 source = __ResolveParent(source, base_path_components)
90 if len(source): 77 if len(source):
91 result.append(source) 78 result.append(source)
92 continue 79 continue
93 result.append(base_path + source) 80 result.append(base_path + source)
81 if debug:
82 print 'AddSource', org_source, result[len(result) - 1]
94 83
95 def __ExtractSourcesFromAction(action, base_path, base_path_components, 84 def __ExtractSourcesFromAction(action, base_path, base_path_components,
96 results): 85 results):
97 if 'inputs' in action: 86 if 'inputs' in action:
98 __AddSources(action['inputs'], base_path, base_path_components, results) 87 __AddSources(action['inputs'], base_path, base_path_components, results)
99 88
100 def __ExtractSources(target, target_dict): 89 def __ExtractSources(target, target_dict, toplevel_dir):
101 base_path = posixpath.dirname(target) 90 # |target| is either absolute or relative and in the format of the OS. Gyp
91 # source paths are always posix. Convert |target| to a posix path relative to
92 # |toplevel_dir_|. This is done to make it easy to build source paths.
93 if target == toplevel_dir:
94 base_path = ''
95 elif target.startswith(toplevel_dir + os.sep):
96 base_path = target[len(toplevel_dir) + len(os.sep):]
97 else:
98 base_path = target
99 if os.sep == '\\' and os.altsep == '/':
Mark Mentovai 2014/07/16 20:28:17 I think that you should do this part first. Window
sky 2014/07/16 21:14:55 Done.
100 base_path = base_path.replace('\\', '/')
101 base_path = posixpath.dirname(base_path)
102 base_path_components = base_path.split('/') 102 base_path_components = base_path.split('/')
103
103 # Add a trailing '/' so that __AddSources() can easily build paths. 104 # Add a trailing '/' so that __AddSources() can easily build paths.
104 if len(base_path): 105 if len(base_path):
105 base_path += '/' 106 base_path += '/'
107
108 if debug:
109 print 'ExtractSources', target, base_path
110
106 results = [] 111 results = []
107 if 'sources' in target_dict: 112 if 'sources' in target_dict:
108 __AddSources(target_dict['sources'], base_path, base_path_components, 113 __AddSources(target_dict['sources'], base_path, base_path_components,
109 results) 114 results)
110 # Include the inputs from any actions. Any changes to these effect the 115 # Include the inputs from any actions. Any changes to these effect the
111 # resulting output. 116 # resulting output.
112 if 'actions' in target_dict: 117 if 'actions' in target_dict:
113 for action in target_dict['actions']: 118 for action in target_dict['actions']:
114 __ExtractSourcesFromAction(action, base_path, base_path_components, 119 __ExtractSourcesFromAction(action, base_path, base_path_components,
115 results) 120 results)
116 if 'rules' in target_dict: 121 if 'rules' in target_dict:
117 for rule in target_dict['rules']: 122 for rule in target_dict['rules']:
118 __ExtractSourcesFromAction(rule, base_path, base_path_components, results) 123 __ExtractSourcesFromAction(rule, base_path, base_path_components, results)
119 124
120 return results 125 return results
121 126
122 class Target(object): 127 class Target(object):
123 """Holds information about a particular target: 128 """Holds information about a particular target:
124 sources: set of source files defined by this target. This includes inputs to 129 sources: set of source files defined by this target. This includes inputs to
125 actions and rules. 130 actions and rules.
126 deps: list of direct dependencies.""" 131 deps: list of direct dependencies."""
127 def __init__(self): 132 def __init__(self):
128 self.sources = [] 133 self.sources = []
129 self.deps = [] 134 self.deps = []
130 135
131 def __GenerateTargets(target_list, target_dicts): 136 def __GenerateTargets(target_list, target_dicts, toplevel_dir):
132 """Generates a dictionary with the key the name of a target and the value a 137 """Generates a dictionary with the key the name of a target and the value a
133 Target.""" 138 Target. |toplevel_dir| is the root of the source tree."""
134 targets = {} 139 targets = {}
135 140
136 # Queue of targets to visit. 141 # Queue of targets to visit.
137 targets_to_visit = target_list[:] 142 targets_to_visit = target_list[:]
138 143
139 while len(targets_to_visit) > 0: 144 while len(targets_to_visit) > 0:
140 absolute_target_name = targets_to_visit.pop() 145 target_name = targets_to_visit.pop()
141 # |absolute_target| may be an absolute path and may include #target. 146 if target_name in targets:
142 # References to targets are relative, so we need to clean the name.
143 relative_target_name = __MakeRelativeTargetName(absolute_target_name)
144 if relative_target_name in targets:
145 continue 147 continue
146 148
147 target = Target() 149 target = Target()
148 targets[relative_target_name] = target 150 targets[target_name] = target
149 target.sources.extend(__ExtractSources(relative_target_name, 151 target.sources.extend(__ExtractSources(target_name,
150 target_dicts[absolute_target_name])) 152 target_dicts[target_name],
153 toplevel_dir))
151 154
152 for dep in target_dicts[absolute_target_name].get('dependencies', []): 155 for dep in target_dicts[target_name].get('dependencies', []):
153 targets[relative_target_name].deps.append(__MakeRelativeTargetName(dep)) 156 targets[target_name].deps.append(dep)
154 targets_to_visit.append(dep) 157 targets_to_visit.append(dep)
155 158
156 return targets 159 return targets
157 160
158 def __GetFiles(params): 161 def __GetFiles(params):
159 """Returns the list of files to analyze, or None if none specified.""" 162 """Returns the list of files to analyze, or None if none specified."""
160 generator_flags = params.get('generator_flags', {}) 163 generator_flags = params.get('generator_flags', {})
161 file_path = generator_flags.get('file_path', None) 164 file_path = generator_flags.get('file_path', None)
162 if not file_path: 165 if not file_path:
163 return None 166 return None
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 operating_system = 'linux' # Keep this legacy behavior for now. 200 operating_system = 'linux' # Keep this legacy behavior for now.
198 default_variables.setdefault('OS', operating_system) 201 default_variables.setdefault('OS', operating_system)
199 202
200 def GenerateOutput(target_list, target_dicts, data, params): 203 def GenerateOutput(target_list, target_dicts, data, params):
201 """Called by gyp as the final stage. Outputs results.""" 204 """Called by gyp as the final stage. Outputs results."""
202 files = __GetFiles(params) 205 files = __GetFiles(params)
203 if not files: 206 if not files:
204 print 'Must specify files to analyze via file_path generator flag' 207 print 'Must specify files to analyze via file_path generator flag'
205 return 208 return
206 209
207 targets = __GenerateTargets(target_list, target_dicts) 210 targets = __GenerateTargets(target_list, target_dicts,
211 os.path.abspath(params['options'].toplevel_dir))
208 212
209 files_set = frozenset(files) 213 files_set = frozenset(files)
210 found_in_all_sources = 0 214 found_in_all_sources = 0
211 for target_name, target in targets.iteritems(): 215 for target_name, target in targets.iteritems():
212 sources = files_set.intersection(target.sources) 216 sources = files_set.intersection(target.sources)
213 if len(sources): 217 if len(sources):
214 print 'Found dependency' 218 print 'Found dependency'
219 if debug:
220 print 'Found dependency in', target_name, target.sources
215 return 221 return
216 222
217 print 'No dependencies' 223 print 'No dependencies'
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698