generate_cmake 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #!/usr/bin/env python3
  2. import sys
  3. import os
  4. import shutil
  5. import subprocess
  6. import multiprocessing
  7. import json
  8. import stat
  9. import filecmp
  10. import urllib.request
  11. from argparse import ArgumentParser
  12. def mkdir(path):
  13. try:
  14. os.mkdir(path)
  15. except FileExistsError as e:
  16. pass
  17. def remove_file(path):
  18. try:
  19. os.remove(path)
  20. except FileNotFoundError as e:
  21. pass
  22. def compare_files(lhs_file_path, rhs_file_path):
  23. try:
  24. return filecmp.cmp(lhs_file_path, rhs_file_path)
  25. except FileNotFoundError as e:
  26. return False
  27. def rmtree(path):
  28. try:
  29. shutil.rmtree(path)
  30. except FileNotFoundError as e:
  31. pass
  32. def make_file_executable(file_path):
  33. st = os.stat(file_path)
  34. os.chmod(file_path, st.st_mode + stat.S_IEXEC)
  35. def get_binary_id(resource_file_path):
  36. with open(resource_file_path) as file:
  37. ymake_file_json = json.load(file)
  38. linux_uri = str(ymake_file_json["by_platform"]["linux"]["uri"])
  39. return linux_uri.split(":")[1]
  40. def download_binary(root_path, binary_name, binary_path):
  41. root_binary_resource_file_path = (
  42. f"{root_path}/build/external_resources/{binary_name}/resources.json"
  43. )
  44. tmp_binary_resource_file_path = binary_path + "_resources.json"
  45. if compare_files(root_binary_resource_file_path, tmp_binary_resource_file_path):
  46. print(f"Use {binary_name} binary from cache {binary_path}")
  47. else:
  48. binary_id = get_binary_id(root_binary_resource_file_path)
  49. devtools_registry_s3_url = "https://devtools-registry.s3.yandex.net"
  50. devtools_registry_s3_binary_url = f"{devtools_registry_s3_url}/{binary_id}"
  51. print(
  52. f"Download {binary_name} binary from {devtools_registry_s3_binary_url} into {binary_path}"
  53. )
  54. remove_file(binary_path)
  55. urllib.request.urlretrieve(devtools_registry_s3_binary_url, binary_path)
  56. make_file_executable(binary_path)
  57. shutil.copy(root_binary_resource_file_path, tmp_binary_resource_file_path)
  58. def generate_graph_for_platform(generate_graph_for_platform):
  59. platform = generate_graph_for_platform[0]
  60. generate_graph_command = generate_graph_for_platform[1]
  61. output = subprocess.check_output(
  62. generate_graph_command, stderr=subprocess.STDOUT, shell=True
  63. ).decode("utf-8")
  64. allowed_error_patterns = [
  65. "to directory without ya.make: [[imp]]$S/build/platform/",
  66. "to missing directory: [[imp]]$S/build/platform/",
  67. "to directory without ya.make: [[imp]]$S/build/external_resources/",
  68. "to missing directory: [[imp]]$S/build/external_resources/",
  69. "could not resolve include file: [[imp]]openssl",
  70. "could not resolve include file: [[imp]]zlib",
  71. "could not resolve include file: [[imp]]ares.h",
  72. "in $B/contrib/libs/openssl/",
  73. "in $B/contrib/libs/zlib",
  74. "in $B/contrib/libs/c-ares",
  75. "in $B/contrib/libs/libc_compat/ubuntu_14/liblibs-libc_compat-ubuntu_14.a",
  76. "in $B/contrib/libs/linux-headers/libcontrib-libs-linux-headers.a",
  77. "in $B/contrib/libs/farmhash/",
  78. "in $B/contrib/libs/curl/",
  79. "in $B/contrib/libs/libxml/",
  80. "in $B/contrib/libs/apache/arrow/",
  81. "in $B/contrib/libs/grpc/",
  82. "in $S/contrib/tools/protoc/plugins/cpp_styleguide/ya.make",
  83. "in $S/contrib/tools/protoc/plugins/grpc_cpp",
  84. "in $B/contrib/restricted/boost/",
  85. "in $B/library/cpp/charset/",
  86. "in $B/library/cpp/uri/",
  87. "in $B/library/cpp/unicode/punycode/",
  88. "in $B/library/cpp/config/",
  89. "in $S/tools/rescompiler/bin/",
  90. # Fix
  91. "in $B/library/cpp/actors/dnsresolver/ut/library-cpp-actors-dnsresolver-ut",
  92. "in $B/ydb/library/pdisk_io/libydb-library-pdisk_io",
  93. ]
  94. if platform == "windows-x86_64":
  95. # Fix
  96. allowed_error_patterns.append("in $B/ydb/core/tx/tiering/core-tx-tiering")
  97. allowed_error_patterns.append(
  98. "in $B/ydb/library/yql/providers/s3/serializations/providers-s3-serializations"
  99. )
  100. result_errors = []
  101. for line in output.split("\n"):
  102. if not line.startswith("Error"):
  103. continue
  104. error_is_allowed = False
  105. for allowed_error_pattern in allowed_error_patterns:
  106. if allowed_error_pattern in line:
  107. error_is_allowed = True
  108. break
  109. if error_is_allowed:
  110. continue
  111. result_errors.append(line)
  112. return result_errors
  113. if __name__ == "__main__":
  114. parser = ArgumentParser(description="Generate CMake files from Ya make files")
  115. parser.add_argument("--ymake_bin", help="Path to ymake binary")
  116. parser.add_argument("--yexport_bin", help="Path to yexport binary")
  117. parser.add_argument("--tmp", help="Path to tmp dir")
  118. parser.add_argument(
  119. "--debug", action="store_true", default=False, help="Run script in debug mode"
  120. )
  121. try:
  122. args = parser.parse_args()
  123. except Exception as e:
  124. print(e, file=sys.stderr)
  125. sys.exit(1)
  126. tmp_folder_path = args.tmp
  127. if tmp_folder_path is None:
  128. tmp_folder_path = "/tmp/ydb-generate-cmake"
  129. ymake_binary_path = args.ymake_bin
  130. yexport_binary_path = args.yexport_bin
  131. debug = args.debug
  132. ydb_tmp_folder_path = tmp_folder_path + "/ydb"
  133. ydb_metadata_folder_path = tmp_folder_path + "/metadata"
  134. ydb_bin_folder_path = tmp_folder_path + "/bin"
  135. plugins_folder_path = ydb_tmp_folder_path + "/build/plugins"
  136. mkdir(tmp_folder_path)
  137. mkdir(ydb_metadata_folder_path)
  138. mkdir(ydb_bin_folder_path)
  139. root_folder = os.getcwd()
  140. if ymake_binary_path is None:
  141. ymake_binary_path = ydb_bin_folder_path + "/ymake"
  142. download_binary(root_folder, "ymake", ymake_binary_path)
  143. if yexport_binary_path is None:
  144. yexport_binary_path = ydb_bin_folder_path + "/yexport"
  145. download_binary(root_folder, "yexport", yexport_binary_path)
  146. rmtree(ydb_tmp_folder_path)
  147. shutil.copytree(root_folder, ydb_tmp_folder_path)
  148. platforms = [
  149. ("linux-x86_64", "default-linux-x86_64"),
  150. ("linux-aarch64", "default-linux-aarch64"),
  151. ("darwin-x86_64", "default-darwin-x86_64"),
  152. ("windows-x86_64", "default-win-x86_64"),
  153. ]
  154. generate_graph_for_platform_commands = []
  155. for platform, target_platform in platforms:
  156. print(f"Platform {platform} target platform {target_platform}")
  157. dump_export_path = f"{ydb_metadata_folder_path}/{platform}.conf"
  158. graph_export_path = f"{ydb_metadata_folder_path}/sem.{platform}.json"
  159. generate_dump_command = f"{root_folder}/scripts/generate_dump.sh {platform} {target_platform} > {dump_export_path}"
  160. print(f"Generate dump command {generate_dump_command}")
  161. subprocess.check_output(generate_dump_command, shell=True)
  162. # In original script there are targets kikimr/docs/ru/docs_oss ydb ydb/tests/oss/launch library/cpp/actors tools/rescompiler/bin
  163. generate_graph_command = f'{ymake_binary_path} --build-root "{ydb_tmp_folder_path}" --config "{dump_export_path}"\
  164. --plugins-root "{plugins_folder_path}" --xs --xx --sem-graph --keep-going\
  165. ydb ydb/tests/oss/launch library/cpp/actors tools/rescompiler/bin > {graph_export_path}'
  166. print(f"Generate graph command {generate_graph_command}")
  167. generate_graph_for_platform_commands.append((platform, generate_graph_command))
  168. errors_for_platform = []
  169. with multiprocessing.Pool(len(generate_graph_for_platform_commands)) as pool:
  170. errors_for_platform = pool.map(
  171. generate_graph_for_platform, generate_graph_for_platform_commands
  172. )
  173. for index, (platform, target_platform) in enumerate(platforms):
  174. errors_for_platform_size = len(errors_for_platform[index])
  175. if errors_for_platform_size == 0:
  176. continue
  177. print(
  178. f"Found {errors_for_platform_size} errors for platform {platform}",
  179. file=sys.stderr,
  180. )
  181. for error in errors_for_platform[index]:
  182. print(error, file=sys.stderr)
  183. sys.exit(1)
  184. yexport_command = f"{yexport_binary_path} --export-root \"{ydb_tmp_folder_path}\" --target YDB \
  185. --semantic-graph \"{ydb_metadata_folder_path + '/sem.linux-x86_64.json'}\" --platforms linux-x86_64 \
  186. --semantic-graph \"{ydb_metadata_folder_path + '/sem.linux-aarch64.json'}\" --platforms linux-aarch64 \
  187. --semantic-graph \"{ydb_metadata_folder_path + '/sem.darwin-x86_64.json'}\" --platforms darwin-x86_64 \
  188. --semantic-graph \"{ydb_metadata_folder_path + '/sem.windows-x86_64.json'}\" --platforms windows-x86_64"
  189. print(f"yexport command {yexport_command}")
  190. yexport_output = subprocess.check_output(
  191. yexport_command, stderr=subprocess.STDOUT, shell=True
  192. ).decode("utf-8")
  193. if debug:
  194. print("yexport output")
  195. print(yexport_output)
  196. rsync_command = f'rsync --recursive --delete --perms\
  197. --exclude .git --exclude contrib --exclude library/cpp/actors\
  198. "{ydb_tmp_folder_path}/" "{root_folder}/"'
  199. print(f"rsync command {rsync_command}")
  200. subprocess.check_output(rsync_command, shell=True)
  201. sys.exit(0)