You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.8 KiB

  1. import argparse
  2. import subprocess
  3. import os
  4. from shutil import copyfile
  5. def get_dependencies(file):
  6. # Call otool -L file to obtain the dependencies.
  7. proc = subprocess.Popen(["otool", "-L", args.binary], stdout=subprocess.PIPE)
  8. result = {}
  9. for line_bytes in proc.stdout:
  10. line = line_bytes.decode("utf-8").strip()
  11. lib = line.split()[0]
  12. if (lib.startswith("@")):
  13. lib = lib.split("/", 1)[1]
  14. (base, file) = os.path.split(lib)
  15. print(base + " // " + file)
  16. return result
  17. def create_package(args):
  18. create_package_dirs(args.dir)
  19. copy_binary_to_package_dir(args.bin, args.binary_basename, args.dir)
  20. run_dylibbundler(args.bundler_binary, args.dir, args.binary_basename)
  21. pass
  22. def parse_arguments():
  23. parser = argparse.ArgumentParser(description='Package the storm binary on Mac OS.')
  24. parser.add_argument('--bin', dest='bin', help='the binary to package', default='storm')
  25. parser.add_argument('--dir', dest='dir', help='the root directory of the package (will be created if it does not exist)', default='.')
  26. parser.add_argument('--dylibbundler', dest='bundler_binary', help='the binary of the dylibbundler', default='dylibbundler')
  27. args = parser.parse_args()
  28. args.binary_dir = os.path.split(args.bin)[0]
  29. args.binary_basename = os.path.split(args.bin)[1]
  30. return args
  31. def create_package_dirs(root_dir):
  32. if not os.path.exists(root_dir):
  33. os.makedirs(root_dir)
  34. if not os.path.exists(root_dir + "/bin"):
  35. os.makedirs(root_dir + "/bin")
  36. if not os.path.exists(root_dir + "/lib"):
  37. os.makedirs(root_dir + "/bin")
  38. pass
  39. def copy_binary_to_package_dir(binary, binary_basename, root_dir):
  40. copyfile(binary, root_dir + "/bin/storm")
  41. pass
  42. def run_dylibbundler(bundler_binary, root_dir, binary_basename):
  43. command = [bundler_binary, "-cd", "-od", "-b", "-p", "@executable_path/../lib", "-x", root_dir + "/bin/" + binary_basename, "-d", root_dir + "/lib"]
  44. print("executing " + str(command))
  45. #proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  46. pass
  47. def fix_paths(root_dir, binary_basename):
  48. fix_paths_file(root_dir + "/bin/" + binary_basename)
  49. for file in os.listdir(root_dir + "/lib"):
  50. fix_paths_file(root_dir + "/lib/" + file)
  51. pass
  52. pass
  53. def fix_paths_file(file):
  54. print("fixing paths for " + file)
  55. fixable_deps = get_fixable_deps(file)
  56. for (path, lib) in fixable_deps:
  57. change_fixable_dep(file, path, lib)
  58. native_libs = ["libc++.1.dylib", "libSystem.B.dylib"]
  59. def get_fixable_deps(file):
  60. # Call otool -L file to obtain the dependencies.
  61. proc = subprocess.Popen(["otool", "-L", file], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  62. result = []
  63. for line_bytes in proc.stdout:
  64. line = line_bytes.decode("utf-8").strip()
  65. lib = line.split()[0]
  66. if lib.startswith("@rpath/"):
  67. result.append(("@rpath", lib.split("/", 1)[1]))
  68. elif lib.startswith("/"):
  69. path_file = os.path.split(lib)
  70. if path_file[1] not in native_libs:
  71. result.append((path_file[0], path_file[1]))
  72. return result
  73. def change_fixable_dep(file, path, lib):
  74. # Call install_name_tool to change the fixable dependencies
  75. command = ["install_name_tool", "-change", path + "/" + lib, "@executable_path/../lib/" + lib, file]
  76. print("executing " + str(command))
  77. proc = subprocess.Popen(command, stdout=subprocess.PIPE)
  78. #print ("after call to install_name_tool")
  79. #proc = subprocess.Popen(["otool", "-L", file], stdout=subprocess.PIPE)
  80. #for line_bytes in proc.stdout:
  81. # line = line_bytes.decode("utf-8").strip()
  82. # print(line)
  83. pass
  84. if __name__ == "__main__":
  85. args = parse_arguments()
  86. #create_package(args)
  87. fix_paths(args.dir, args.binary_basename)