generate_clang_module_map.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/env python3
  2. """
  3. Generates a clang module map for a given directory
  4. """
  5. import argparse
  6. import pathlib
  7. import yaml
  8. import sys
  9. def write_file_if_not_same(file_path, content):
  10. try:
  11. with open(file_path, 'r') as f:
  12. if f.read() == content:
  13. return
  14. except FileNotFoundError:
  15. pass
  16. with open(file_path, 'w') as f:
  17. f.write(content)
  18. def main():
  19. parser = argparse.ArgumentParser(
  20. epilog=__doc__,
  21. formatter_class=argparse.RawDescriptionHelpFormatter)
  22. parser.add_argument('directory', help='source directory to generate module map for')
  23. parser.add_argument('generated_files', nargs='+', help='extra files to include in the module map')
  24. parser.add_argument('-n', '--module-name', help='top-level module name')
  25. parser.add_argument('-m', '--module-map', required=True, help='output module map file')
  26. parser.add_argument('-v', '--vfs-map', required=True, help='output VFS map file')
  27. args = parser.parse_args()
  28. root = pathlib.Path(args.directory)
  29. if not root.is_dir():
  30. print(f"Error: {args.directory} is not a directory", file=sys.stderr)
  31. return 1
  32. pathlib.Path(args.module_map).parent.mkdir(parents=True, exist_ok=True)
  33. pathlib.Path(args.vfs_map).parent.mkdir(parents=True, exist_ok=True)
  34. header_files = [f for f in root.rglob('**/*.h') if f.is_file()]
  35. module_name = args.module_name if args.module_name else root.name
  36. module_map = f"module {module_name} {{\n"
  37. for header_file in header_files:
  38. module_map += f" header \"{header_file.relative_to(root)}\"\n"
  39. for generated_file in args.generated_files:
  40. module_map += f" header \"{generated_file}\"\n"
  41. module_map += " requires cplusplus\n"
  42. module_map += " export *\n"
  43. module_map += "}\n"
  44. vfs_map = {
  45. "version": 0,
  46. "use-external-names": False,
  47. "roots": [
  48. {
  49. "name": f"{root}/module.modulemap",
  50. "type": "file",
  51. "external-contents": f"{args.module_map}"
  52. }
  53. ]
  54. }
  55. write_file_if_not_same(args.module_map, module_map)
  56. write_file_if_not_same(args.vfs_map, yaml.dump(vfs_map))
  57. if __name__ == '__main__':
  58. sys.exit(main())