cmake.py
Go to the documentation of this file.
1 import collections
2 import re
3 
4 VARIABLE_PATTERN = re.compile(r'\$\{([^\}]+)\}')
5 QUOTED_PATTERN = re.compile(r'"([^"]+)"')
6 
7 BUILD_TARGET_COMMANDS = ['add_library', 'add_executable', 'add_rostest', 'add_dependencies', 'target_link_libraries']
8 
9 ORDERING = ['cmake_minimum_required', 'project', 'set_directory_properties', 'find_package', 'pkg_check_modules',
10  'set', 'catkin_generate_virtualenv', 'catkin_python_setup', 'add_definitions',
11  'add_message_files', 'add_service_files', 'add_action_files',
12  'generate_dynamic_reconfigure_options', 'generate_messages', 'catkin_package', 'catkin_metapackage',
13  BUILD_TARGET_COMMANDS + ['include_directories'],
14  ['catkin_download_test_data', 'roslint_cpp', 'roslint_python', 'roslint_add_test', 'catkin_add_nosetests'],
15  'catkin_add_gtest', 'group',
16  ['install', 'catkin_install_python']]
17 
18 
19 def get_ordering_index(command_name):
20  for i, o in enumerate(ORDERING):
21  if type(o) == list:
22  if command_name in o:
23  return i
24  elif command_name == o:
25  return i
26  if command_name:
27  print('\tUnsure of ordering for', command_name)
28  return len(ORDERING)
29 
30 
31 def get_sort_key(content, anchors):
32  if content is None:
33  return len(ORDERING) + 1, None
34  index = None
35  key = None
36  if content.__class__ == CommandGroup:
37  index = get_ordering_index('group')
38  sections = content.initial_tag.get_real_sections()
39  if len(sections) > 0:
40  key = sections[0].name
41  else: # Command
42  index = get_ordering_index(content.command_name)
43  if content.command_name in BUILD_TARGET_COMMANDS:
44  token = content.first_token()
45  if token not in anchors:
46  anchors.append(token)
47  key = anchors.index(token), BUILD_TARGET_COMMANDS.index(content.command_name)
48  elif content.command_name == 'include_directories' and 'include_directories' in anchors:
49  key = anchors.index('include_directories')
50  return index, key
51 
52 
54  def __init__(self, prename='', name_val_sep=' ', val_sep=' '):
55  self.prename = prename
56  self.name_val_sep = name_val_sep
57  self.val_sep = val_sep
58 
59  def __repr__(self):
60  return 'SectionStyle(%s, %s, %s)' % (repr(self.prename), repr(self.name_val_sep), repr(self.val_sep))
61 
62 
63 class Section:
64  def __init__(self, name='', values=None, style=None):
65  self.name = name
66  if values is None:
67  self.values = []
68  else:
69  self.values = list(values)
70  if style:
71  self.style = style
72  else:
73  self.style = SectionStyle()
74 
75  def add(self, v):
76  self.values.append(v)
77 
78  def is_valid(self):
79  return len(self.name) > 0 or len(self.values) > 0
80 
81  def __repr__(self):
82  s = self.style.prename
83  if len(self.name) > 0:
84  s += self.name
85  if len(self.values) > 0:
86  s += self.style.name_val_sep
87  s += self.style.val_sep.join(self.values)
88  return s
89 
90 
91 class Command:
92  def __init__(self, command_name):
93  self.command_name = command_name
94  self.original = None
95  self.changed = False
96  self.pre_paren = ''
97  self.sections = []
98 
99  def get_real_sections(self):
100  return [s for s in self.sections if type(s) != str]
101 
102  def get_section(self, key):
103  for s in self.get_real_sections():
104  if s.name == key:
105  return s
106  return None
107 
108  def get_sections(self, key):
109  return [s for s in self.get_real_sections() if s.name == key]
110 
111  def add_section(self, key, values=None, style=None):
112  self.sections.append(Section(key, values, style))
113  self.changed = True
114 
115  def add(self, section):
116  if section:
117  self.sections.append(section)
118  self.changed = True
119 
120  def first_token(self):
121  return self.get_real_sections()[0].values[0]
122 
123  def remove_sections(self, key):
124  bad_sections = self.get_sections(key)
125  if not bad_sections:
126  return
127  self.changed = True
128  self.sections = [section for section in self.sections if section not in bad_sections]
129  if len(self.sections) == 1 and type(self.sections[0]) == str:
130  self.sections = []
131 
132  def get_tokens(self, include_name=False):
133  tokens = []
134  for section in self.get_real_sections():
135  if include_name and section.name:
136  tokens.append(section.name)
137  tokens += section.values
138  return tokens
139 
140  def add_token(self, s):
141  sections = self.get_real_sections()
142  if len(sections) == 0:
143  self.add(Section(values=[s]))
144  else:
145  last = sections[-1]
146  last.values.append(s)
147  self.changed = True
148 
149  def __repr__(self):
150  if self.original and not self.changed:
151  return self.original
152 
153  s = self.command_name + self.pre_paren + '('
154  for section in map(str, self.sections):
155  if s[-1] not in '( \n' and section[0] not in ' \n':
156  s += ' '
157  s += section
158  if '\n' in s and s[-1] != '\n':
159  s += '\n'
160  s += ')'
161  return s
162 
163 
165  def __init__(self, initial_tag, sub, close_tag):
166  self.initial_tag = initial_tag
167  self.sub = sub
168  self.close_tag = close_tag
169 
170  def __repr__(self):
171  return str(self.initial_tag) + str(self.sub) + str(self.close_tag)
172 
173 
174 class CMake:
175  def __init__(self, file_path=None, initial_contents=None, depth=0):
176  self.file_path = file_path
177  if initial_contents is None:
178  self.contents = []
179  else:
180  self.contents = initial_contents
181  self.content_map = collections.defaultdict(list)
182  for content in self.contents:
183  if content.__class__ == Command:
184  self.content_map[content.command_name].append(content)
185  elif content.__class__ == CommandGroup:
186  self.content_map['group'].append(content)
187  self.depth = depth
188 
189  self.variables = {}
190  for cmd in self.content_map['set']:
191  tokens = cmd.get_tokens(include_name=True)
192  self.variables[tokens[0]] = ' '.join(tokens[1:])
193  self.variables['PROJECT_NAME'] = self.get_project_name()
194 
195  def get_project_name(self):
196  project_tags = self.content_map['project']
197  if not project_tags:
198  return ''
199  # Get all tokens just in case the name is all caps
200  return project_tags[0].get_tokens(include_name=True)[0]
201 
202  def resolve_variables(self, var):
203  if type(var) == str:
204  s = var
205  m = VARIABLE_PATTERN.search(s)
206  if not m:
207  return s
208 
209  for k, v in self.variables.iteritems():
210  s = s.replace('${%s}' % k, v)
211  return s
212  else:
213  tokens = []
214  for token in var:
215  if token and token[0] == '#':
216  continue
217  m = QUOTED_PATTERN.match(token)
218  if m:
219  token = m.group(1)
220  token = self.resolve_variables(token)
221  tokens += token.split(' ')
222  return tokens
223 
224  def get_resolved_tokens(self, cmd, include_name=False):
225  return self.resolve_variables(cmd.get_tokens(include_name))
226 
227  def get_insertion_index(self, cmd):
228  anchors = self.get_ordered_build_targets()
229 
230  new_key = get_sort_key(cmd, anchors)
231  i_index = 0
232 
233  for i, content in enumerate(self.contents):
234  if type(content) == str:
235  continue
236  key = get_sort_key(content, anchors)
237  if key <= new_key:
238  i_index = i + 1
239  elif key[0] != len(ORDERING):
240  return i_index
241  return len(self.contents)
242 
243  def add_command(self, cmd):
244  i_index = self.get_insertion_index(cmd)
245  sub_contents = []
246  if i_index > 0 and type(self.contents[i_index - 1]) != str:
247  sub_contents.append('\n')
248  if self.depth > 0:
249  sub_contents.append(' ' * self.depth)
250  sub_contents.append(cmd)
251  sub_contents.append('\n')
252  else:
253  sub_contents.append(cmd)
254  if i_index == len(self.contents):
255  sub_contents.append('\n')
256 
257  self.contents = self.contents[:i_index] + sub_contents + self.contents[i_index:]
258 
259  if cmd.__class__ == Command:
260  self.content_map[cmd.command_name].append(cmd)
261  elif cmd.__class__ == CommandGroup:
262  self.content_map['group'].append(cmd)
263 
264  def remove_command(self, cmd):
265  print('\tRemoving %s' % str(cmd).replace('\n', ' ').replace(' ', ''))
266  self.contents.remove(cmd)
267  self.content_map[cmd.command_name].remove(cmd)
268 
269  def remove_all_commands(self, cmd_name):
270  cmds = list(self.content_map[cmd_name])
271  for cmd in cmds:
272  self.remove_command(cmd)
273 
274  def get_source_build_rules(self, tag, resolve_target_name=False):
275  rules = {}
276  for cmd in self.content_map[tag]:
277  resolved_tokens = self.get_resolved_tokens(cmd, True)
278 
279  if resolve_target_name:
280  target = resolved_tokens[0]
281  else:
282  tokens = cmd.get_tokens(True)
283  target = tokens[0]
284 
285  deps = resolved_tokens[1:]
286  rules[target] = deps
287  return rules
288 
289  def get_source_helper(self, tag):
290  lib_src = set()
291  for target, deps in self.get_source_build_rules(tag).iteritems():
292  lib_src.update(deps)
293  return lib_src
294 
296  return self.get_source_helper('add_library')
297 
299  return self.get_source_helper('add_executable')
300 
301  def get_libraries(self):
302  return self.get_source_build_rules('add_library').keys()
303 
304  def get_executables(self):
305  return self.get_source_build_rules('add_executable').keys()
306 
308  targets = {}
309  targets.update(self.get_source_build_rules('add_library'))
310  targets.update(self.get_source_build_rules('add_executable'))
311  return targets
312 
314  targets = []
315  for content in self.contents:
316  if content.__class__ != Command:
317  continue
318  if content.command_name == 'include_directories':
319  targets.append('include_directories')
320  continue
321  elif content.command_name not in BUILD_TARGET_COMMANDS:
322  continue
323  token = content.first_token()
324  if token not in targets:
325  targets.append(token)
326  return targets
327 
328  def get_test_sections(self):
329  sections = []
330  for content in self.content_map['group']:
331  cmd = content.initial_tag
332  if cmd.command_name != 'if' or len(cmd.sections) == 0 or cmd.sections[0].name != 'CATKIN_ENABLE_TESTING':
333  continue
334  sections.append(content.sub)
335  return sections
336 
337  def get_test_source(self):
338  test_files = set()
339  for sub in self.get_test_sections():
340  test_files.update(sub.get_library_source())
341  test_files.update(sub.get_executable_source())
342  return test_files
343 
344  def get_test_section(self, create_if_needed=False):
345  sections = self.get_test_sections()
346  if len(sections) > 0:
347  return sections[0]
348  if not create_if_needed:
349  return None
350 
351  # Create Test Section
352  initial_cmd = Command('if')
353  initial_cmd.add_section('CATKIN_ENABLE_TESTING')
354 
355  test_contents = CMake(initial_contents=['\n'], depth=self.depth + 1)
356 
357  final_cmd = Command('endif')
358 
359  cg = CommandGroup(initial_cmd, test_contents, final_cmd)
360  self.add_command(cg)
361  return cg.sub
362 
363  def get_command_section(self, command_name, section_name):
364  """ Return the first command that matches the command name and
365  has a matching section name. If the section name is not found,
366  return a command with the matching command name"""
367  if len(self.content_map[command_name]) == 0:
368  return None, None
369  for cmd in self.content_map[command_name]:
370  s = cmd.get_section(section_name)
371  if s:
372  return cmd, s
373  return self.content_map[command_name][0], None
374 
375  def section_check(self, items, cmd_name, section_name='', zero_okay=False):
376  """ This function ensures that there's a CMake command of the given type
377  with the given section name and items somewhere in the file. """
378  if len(items) == 0 and not zero_okay:
379  return
380 
381  cmd, section = self.get_command_section(cmd_name, section_name)
382 
383  if cmd is None:
384  cmd = Command(cmd_name)
385  self.add_command(cmd)
386 
387  if section is None:
388  cmd.add_section(section_name, sorted(items))
389  else:
390  existing = self.resolve_variables(section.values)
391  needed_items = [item for item in items if item not in existing]
392  section.values += sorted(needed_items)
393  cmd.changed = True
394 
395  def __repr__(self):
396  return ''.join(map(str, self.contents))
397 
398  def write(self, fn=None):
399  if fn is None:
400  fn = self.file_path
401  with open(fn, 'w') as cmake:
402  cmake.write(str(self))
def get_resolved_tokens(self, cmd, include_name=False)
Definition: cmake.py:224
def get_ordered_build_targets(self)
Definition: cmake.py:313
def remove_sections(self, key)
Definition: cmake.py:123
def __init__(self, file_path=None, initial_contents=None, depth=0)
Definition: cmake.py:175
def __init__(self, prename='', name_val_sep=' ', val_sep=' ')
Definition: cmake.py:54
def write(self, fn=None)
Definition: cmake.py:398
def remove_all_commands(self, cmd_name)
Definition: cmake.py:269
def get_source_helper(self, tag)
Definition: cmake.py:289
def get_target_build_rules(self)
Definition: cmake.py:307
def __init__(self, command_name)
Definition: cmake.py:92
def __init__(self, initial_tag, sub, close_tag)
Definition: cmake.py:165
def section_check(self, items, cmd_name, section_name='', zero_okay=False)
Definition: cmake.py:375
def get_tokens(self, include_name=False)
Definition: cmake.py:132
def add_section(self, key, values=None, style=None)
Definition: cmake.py:111
def remove_command(self, cmd)
Definition: cmake.py:264
def add_command(self, cmd)
Definition: cmake.py:243
def get_executable_source(self)
Definition: cmake.py:298
def get_sort_key(content, anchors)
Definition: cmake.py:31
def get_test_section(self, create_if_needed=False)
Definition: cmake.py:344
def get_section(self, key)
Definition: cmake.py:102
def get_ordering_index(command_name)
Definition: cmake.py:19
def resolve_variables(self, var)
Definition: cmake.py:202
def __init__(self, name='', values=None, style=None)
Definition: cmake.py:64
def get_sections(self, key)
Definition: cmake.py:108
def get_library_source(self)
Definition: cmake.py:295
def add(self, section)
Definition: cmake.py:115
def get_source_build_rules(self, tag, resolve_target_name=False)
Definition: cmake.py:274
def get_command_section(self, command_name, section_name)
Definition: cmake.py:363
def get_insertion_index(self, cmd)
Definition: cmake.py:227


ros_introspection
Author(s):
autogenerated on Wed Jun 19 2019 19:56:52