stale.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #! /usr/bin/env python
  2. # encoding: UTF-8
  3. # Thomas Nagy, 2006-2015 (ita)
  4. """
  5. Add a pre-build hook to remove build files (declared in the system)
  6. that do not have a corresponding target
  7. This can be used for example to remove the targets
  8. that have changed name without performing
  9. a full 'waf clean'
  10. Of course, it will only work if there are no dynamically generated
  11. nodes/tasks, in which case the method will have to be modified
  12. to exclude some folders for example.
  13. Make sure to set bld.post_mode = waflib.Build.POST_AT_ONCE
  14. """
  15. from waflib import Logs, Build
  16. from waflib.Runner import Parallel
  17. DYNAMIC_EXT = [] # add your non-cleanable files/extensions here
  18. MOC_H_EXTS = '.cpp .cxx .hpp .hxx .h'.split()
  19. def can_delete(node):
  20. """Imperfect moc cleanup which does not look for a Q_OBJECT macro in the files"""
  21. if not node.name.endswith('.moc'):
  22. return True
  23. base = node.name[:-4]
  24. p1 = node.parent.get_src()
  25. p2 = node.parent.get_bld()
  26. for k in MOC_H_EXTS:
  27. h_name = base + k
  28. n = p1.search_node(h_name)
  29. if n:
  30. return False
  31. n = p2.search_node(h_name)
  32. if n:
  33. return False
  34. # foo.cpp.moc, foo.h.moc, etc.
  35. if base.endswith(k):
  36. return False
  37. return True
  38. # recursion over the nodes to find the stale files
  39. def stale_rec(node, nodes):
  40. if node.abspath() in node.ctx.env[Build.CFG_FILES]:
  41. return
  42. if getattr(node, 'children', []):
  43. for x in node.children.values():
  44. if x.name != "c4che":
  45. stale_rec(x, nodes)
  46. else:
  47. for ext in DYNAMIC_EXT:
  48. if node.name.endswith(ext):
  49. break
  50. else:
  51. if not node in nodes:
  52. if can_delete(node):
  53. Logs.warn('Removing stale file -> %r', node)
  54. node.delete()
  55. old = Parallel.refill_task_list
  56. def refill_task_list(self):
  57. iit = old(self)
  58. bld = self.bld
  59. # execute this operation only once
  60. if getattr(self, 'stale_done', False):
  61. return iit
  62. self.stale_done = True
  63. # this does not work in partial builds
  64. if bld.targets != '*':
  65. return iit
  66. # this does not work in dynamic builds
  67. if getattr(bld, 'post_mode') == Build.POST_AT_ONCE:
  68. return iit
  69. # obtain the nodes to use during the build
  70. nodes = []
  71. for tasks in bld.groups:
  72. for x in tasks:
  73. try:
  74. nodes.extend(x.outputs)
  75. except AttributeError:
  76. pass
  77. stale_rec(bld.bldnode, nodes)
  78. return iit
  79. Parallel.refill_task_list = refill_task_list