build_info_gen.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import subprocess
  2. import os
  3. import sys
  4. import re
  5. indent = " "
  6. def escape_special_symbols(strval):
  7. retval = ""
  8. for c in strval:
  9. if c in ("\\", "\""):
  10. retval += "\\" + c
  11. elif ord(c) < 0x20:
  12. retval += c.encode('unicode_escape').decode('utf-8')
  13. else:
  14. retval += c
  15. return retval
  16. def escape_line_feed(strval):
  17. return re.sub(r'\\n', r'\\n"\\\n' + indent + '"', strval)
  18. def escaped_define(strkey, strval):
  19. return "#define " + strkey + " \"" + escape_line_feed(escape_special_symbols(strval)) + "\""
  20. def get_build_info(compiler, flags):
  21. build_info = "Build info:\n"
  22. build_info += indent + "Compiler: " + compiler + "\n"
  23. build_info += indent + "Compiler version: \n" + get_compiler_info(compiler) + "\n"
  24. build_info += indent + "Compile flags: " + (flags if flags else "no flags info")
  25. return build_info
  26. def get_compiler_info(compiler):
  27. compiler_binary = os.path.basename(compiler).lower()
  28. if len(compiler.split(' ')) > 1 or compiler_binary == "ymake" or compiler_binary == "ymake.exe":
  29. compiler_ver_out = "Build by wrapper. No useful info here."
  30. else:
  31. compiler_ver_cmd = [compiler]
  32. if compiler_binary not in ("cl", "cl.exe"):
  33. compiler_ver_cmd.append('--version')
  34. env = os.environ.copy()
  35. env['LOCALE'] = 'C'
  36. compiler_ver_out = (
  37. subprocess.Popen(compiler_ver_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
  38. .stdout.read()
  39. .decode('utf-8')
  40. )
  41. return "\n".join(
  42. # fmt: off
  43. f'{indent * 2}{line.strip()}'
  44. for line in compiler_ver_out.splitlines()
  45. if line.strip()
  46. # fmt: on
  47. )
  48. def filterflags(flags_str):
  49. badflgs = {
  50. '-fdebug-prefix-map',
  51. '-DARCADIA_ROOT',
  52. '-DARCADIA_BUILD_ROOT',
  53. '/DARCADIA_ROOT',
  54. '/DARCADIA_BUILD_ROOT',
  55. }
  56. def flags_iter():
  57. for flag in flags_str.split():
  58. if not flag:
  59. continue
  60. if flag.split('=', 1)[0] in badflgs:
  61. continue
  62. yield flag
  63. return ' '.join(flags_iter())
  64. def main():
  65. if len(sys.argv) != 4:
  66. print("Usage: build_info_gen.py <output file> <CXX compiler> <CXX flags>", file=sys.stderr)
  67. sys.exit(1)
  68. cxx_compiler = sys.argv[2]
  69. cxx_flags = filterflags(sys.argv[3])
  70. with open(sys.argv[1], 'w') as result:
  71. print("#pragma once\n", file=result)
  72. print(escaped_define("BUILD_INFO", get_build_info(cxx_compiler, cxx_flags)), file=result)
  73. print(escaped_define("BUILD_COMPILER", cxx_compiler), file=result)
  74. print(escaped_define("BUILD_COMPILER_VERSION", get_compiler_info(cxx_compiler)), file=result)
  75. print(escaped_define("BUILD_COMPILER_FLAGS", cxx_flags), file=result)
  76. if __name__ == "__main__":
  77. main()