_cpp_extension_versioner.py 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import collections
  2. Entry = collections.namedtuple('Entry', 'version, hash')
  3. def update_hash(seed, value):
  4. # Good old boost::hash_combine
  5. # https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
  6. return seed ^ (hash(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2))
  7. def hash_source_files(hash_value, source_files):
  8. for filename in source_files:
  9. with open(filename) as file:
  10. hash_value = update_hash(hash_value, file.read())
  11. return hash_value
  12. def hash_build_arguments(hash_value, build_arguments):
  13. for group in build_arguments:
  14. if group:
  15. for argument in group:
  16. hash_value = update_hash(hash_value, argument)
  17. return hash_value
  18. class ExtensionVersioner:
  19. def __init__(self):
  20. self.entries = {}
  21. def get_version(self, name):
  22. entry = self.entries.get(name)
  23. return None if entry is None else entry.version
  24. def bump_version_if_changed(self,
  25. name,
  26. source_files,
  27. build_arguments,
  28. build_directory,
  29. with_cuda,
  30. is_python_module,
  31. is_standalone):
  32. hash_value = 0
  33. hash_value = hash_source_files(hash_value, source_files)
  34. hash_value = hash_build_arguments(hash_value, build_arguments)
  35. hash_value = update_hash(hash_value, build_directory)
  36. hash_value = update_hash(hash_value, with_cuda)
  37. hash_value = update_hash(hash_value, is_python_module)
  38. hash_value = update_hash(hash_value, is_standalone)
  39. entry = self.entries.get(name)
  40. if entry is None:
  41. self.entries[name] = entry = Entry(0, hash_value)
  42. elif hash_value != entry.hash:
  43. self.entries[name] = entry = Entry(entry.version + 1, hash_value)
  44. return entry.version