amalgamate.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import re
  2. import shutil
  3. import os
  4. import sys
  5. import time
  6. from typing import List, Dict
  7. assert os.system("python prebuild.py") == 0
  8. with open("include/pocketpy/xmacros/opcodes.h", "rt", encoding='utf-8') as f:
  9. OPCODES_TEXT = '\n' + f.read() + '\n'
  10. class Header:
  11. path: str
  12. content: str # header+source (if exists)
  13. dependencies: List[str]
  14. def __init__(self, path: str):
  15. self.path = path
  16. self.dependencies = []
  17. # get raw content
  18. with open(f'include/pocketpy/{path}', 'rt', encoding='utf-8') as f:
  19. self.content = f.read()
  20. src_path = path.replace('.hpp', '.cpp').replace('.h', '.cpp')
  21. if os.path.exists(f'src/{src_path}'):
  22. with open(f'src/{src_path}', 'rt', encoding='utf-8') as f:
  23. self.content += f'\n\n/* {src_path} */\n\n'
  24. self.content += f.read()
  25. # process raw content and get dependencies
  26. self.content = self.content.replace('#pragma once', '')
  27. def _replace(m):
  28. path = m.group(1)
  29. if path == 'opcodes.h':
  30. return OPCODES_TEXT
  31. if path != self.path:
  32. self.dependencies.append(path)
  33. return ''
  34. self.content = re.sub(
  35. r'#include\s+"pocketpy/(.+)"\s*',
  36. _replace,
  37. self.content
  38. )
  39. def __repr__(self):
  40. return f'Header({self.path!r}, dependencies={self.dependencies})'
  41. headers: Dict[str, Header] = {}
  42. for path in ['pocketpy.hpp', 'pocketpy_c.h']:
  43. headers[path] = Header(path)
  44. directories = ['common', 'objects', 'interpreter', 'compiler', 'modules', 'tools']
  45. for directory in directories:
  46. files = os.listdir(f'include/pocketpy/{directory}')
  47. for file in sorted(files):
  48. assert file.endswith('.h') or file.endswith('.hpp')
  49. headers[f'{directory}/{file}'] = Header(f'{directory}/{file}')
  50. text = '''#pragma once
  51. /*
  52. * Copyright (c) 2024 blueloveTH
  53. * Distributed Under The MIT License
  54. * https://github.com/pocketpy/pocketpy
  55. */'''
  56. while True:
  57. for h in headers.values():
  58. if not h.dependencies:
  59. break
  60. else:
  61. if headers:
  62. print(headers)
  63. raise Exception("Circular dependencies detected")
  64. break
  65. print(h.path)
  66. text += h.content
  67. del headers[h.path]
  68. for h2 in headers.values():
  69. h2.dependencies = [d for d in h2.dependencies if d != h.path]
  70. if os.path.exists("amalgamated"):
  71. shutil.rmtree("amalgamated")
  72. time.sleep(0.5)
  73. os.mkdir("amalgamated")
  74. # use LF line endings instead of CRLF
  75. with open("amalgamated/pocketpy.h", "wt", encoding='utf-8', newline='\n') as f:
  76. f.write(text)
  77. shutil.copy("src2/main.cpp", "amalgamated/main.cpp")
  78. with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f:
  79. text = f.read()
  80. text = text.replace('#include "pocketpy/pocketpy.h"', '#include "pocketpy.h"')
  81. with open("amalgamated/main.cpp", "wt", encoding='utf-8', newline='\n') as f:
  82. f.write(text)
  83. if sys.platform in ['linux', 'darwin']:
  84. ok = os.system("clang++ -o main amalgamated/main.cpp -O1 --std=c++17 -frtti -stdlib=libc++")
  85. if ok == 0:
  86. print("Test build success!")
  87. print("amalgamated/pocketpy.h")
  88. def sync(path):
  89. shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h"))
  90. with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8', newline='\n') as f:
  91. f.write("#include \"pocketpy.h\"\n")
  92. sync("plugins/macos/pocketpy")