amalgamate.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/usr/bin/python
  2. #
  3. # Copyright (c) 2009-2021, Google LLC
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are met:
  8. # * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright
  11. # notice, this list of conditions and the following disclaimer in the
  12. # documentation and/or other materials provided with the distribution.
  13. # * Neither the name of Google LLC nor the
  14. # names of its contributors may be used to endorse or promote products
  15. # derived from this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. # DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
  21. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. import sys
  28. import re
  29. import os
  30. INCLUDE_RE = re.compile('^#include "([^"]*)"$')
  31. def parse_include(line):
  32. match = INCLUDE_RE.match(line)
  33. return match.groups()[0] if match else None
  34. class Amalgamator:
  35. def __init__(self, output_path, prefix):
  36. self.include_paths = ["."]
  37. self.included = set(["upb/port_def.inc", "upb/port_undef.inc"])
  38. self.output_h = open(output_path + prefix + "upb.h", "w")
  39. self.output_c = open(output_path + prefix + "upb.c", "w")
  40. self.output_c.write("/* Amalgamated source file */\n")
  41. self.output_c.write('#include "%supb.h"\n' % (prefix))
  42. self.output_c.write(open("upb/port_def.inc").read())
  43. self.output_h.write("/* Amalgamated source file */\n")
  44. self.output_h.write(open("upb/port_def.inc").read())
  45. def add_include_path(self, path):
  46. self.include_paths.append(path)
  47. def finish(self):
  48. self._add_header("upb/port_undef.inc")
  49. self.add_src("upb/port_undef.inc")
  50. def _process_file(self, infile_name, outfile):
  51. file = None
  52. for path in self.include_paths:
  53. try:
  54. full_path = os.path.join(path, infile_name)
  55. file = open(full_path)
  56. break
  57. except IOError:
  58. pass
  59. if not file:
  60. raise RuntimeError("Couldn't open file " + infile_name)
  61. lines = file.readlines()
  62. has_copyright = lines[1].startswith(" * Copyright")
  63. if has_copyright:
  64. while not lines[0].startswith(" */"):
  65. lines.pop(0)
  66. lines.pop(0)
  67. lines.insert(0, "\n/** " + infile_name + " " + ("*" * 60) +"/");
  68. for line in lines:
  69. if not self._process_include(line, outfile):
  70. outfile.write(line)
  71. def _process_include(self, line, outfile):
  72. include = parse_include(line)
  73. if not include:
  74. return False
  75. if not (include.startswith("upb") or include.startswith("google")):
  76. return False
  77. if include.endswith("hpp"):
  78. # Skip, we don't support the amalgamation from C++.
  79. return True
  80. else:
  81. # Include this upb header inline.
  82. if include not in self.included:
  83. self.included.add(include)
  84. self._add_header(include)
  85. return True
  86. def _add_header(self, filename):
  87. self._process_file(filename, self.output_h)
  88. def add_src(self, filename):
  89. self._process_file(filename, self.output_c)
  90. # ---- main ----
  91. output_path = sys.argv[1]
  92. prefix = sys.argv[2]
  93. amalgamator = Amalgamator(output_path, prefix)
  94. files = []
  95. for arg in sys.argv[3:]:
  96. arg = arg.strip()
  97. if arg.startswith("-I"):
  98. amalgamator.add_include_path(arg[2:])
  99. elif arg.endswith(".h") or arg.endswith(".inc"):
  100. pass
  101. else:
  102. files.append(arg)
  103. for filename in files:
  104. amalgamator.add_src(filename)
  105. amalgamator.finish()