############################################ # Copyright (c) 2013 Microsoft Corporation # # Scripts for automatically generating # Linux/OSX/BSD distribution zip files. # # Author: Leonardo de Moura (leonardo) ############################################ import os import subprocess import zipfile import re import getopt import sys import shutil from mk_exception import * from fnmatch import fnmatch def getenv(name, default): try: return os.environ[name].strip(' "\'') except: return default BUILD_DIR = 'build-dist' DIST_DIR = 'dist' VERBOSE = True FORCE_MK = False ASSEMBLY_VERSION = None DOTNET_CORE_ENABLED = True DOTNET_KEY_FILE = None JAVA_ENABLED = True JULIA_ENABLED = False GIT_HASH = False PYTHON_ENABLED = True ARM64 = False MAKEJOBS = getenv("MAKEJOBS", "24") def set_verbose(flag): global VERBOSE VERBOSE = flag def is_verbose(): return VERBOSE def mk_dir(d): if not os.path.exists(d): if is_verbose(): print("Make directory", d) os.makedirs(d) def get_z3_name(): version = "4" if ASSEMBLY_VERSION: version = ASSEMBLY_VERSION print("Assembly version:", version) if GIT_HASH: return 'z3-%s.%s' % (version, get_git_hash()) else: return 'z3-%s' % (version) def get_build_dir(): return BUILD_DIR def get_build_dist(): return os.path.join(get_build_dir(), DIST_DIR) def get_build_dist_path(): return os.path.join(get_build_dist(), get_z3_name()) def set_build_dir(path): global BUILD_DIR BUILD_DIR = os.path.expanduser(os.path.normpath(path)) mk_dir(BUILD_DIR) def display_help(): print("mk_unix_dist_cmake.py: Z3 Unix distribution generator\n") print("This script generates the zip files containing executables, shared objects, header files for Unix.") print("It must be executed from the Z3 root directory.") print("\nOptions:") print(" -h, --help display this message.") print(" -s, --silent do not print verbose messages.") print(" -b , --build= subdirectory where Z3 will be built (default: build-dist).") print(" -f, --force force script to regenerate Makefiles.") print(" --version= release version.") print(" --assembly-version assembly version for dll") print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --julia build Julia bindings.") print(" --githash include git hash in the Zip file.") print(" --arm64 build for ARM64 architecture.") exit(0) # Parse configuration option for mk_make script def parse_options(): global FORCE_MK, JAVA_ENABLED, JULIA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, ARM64 path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', 'silent', 'force', 'nojava', 'nodotnet', 'dotnet-key=', 'assembly-version=', 'githash', 'nopython', 'julia', 'arm64' ]) for opt, arg in options: if opt in ('-b', '--build'): if arg == 'src': raise MKException('The src directory should not be used to host the Makefile') path = arg elif opt in ('-s', '--silent'): set_verbose(False) elif opt in ('-h', '--help'): display_help() elif opt in ('-f', '--force'): FORCE_MK = True elif opt == '--nodotnet': DOTNET_CORE_ENABLED = False elif opt == '--assembly-version': ASSEMBLY_VERSION = arg elif opt == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False elif opt == '--julia': JULIA_ENABLED = True elif opt == '--githash': GIT_HASH = True elif opt == '--arm64': ARM64 = True else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) def check_output(cmd): out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] if out != None: enc = sys.getdefaultencoding() if enc != None: return out.decode(enc).rstrip('\r\n') else: return out.rstrip('\r\n') else: return "" def get_git_hash(): try: branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) r = check_output(['git', 'show-ref', '--abbrev=12', 'refs/heads/%s' % branch]) except: raise MKException("Failed to retrieve git hash") ls = r.split(' ') if len(ls) != 2: raise MKException("Unexpected git output " + r) return ls[0] # Create a build directory using CMake def mk_build_dir(): build_path = get_build_dir() if not os.path.exists(build_path) or FORCE_MK: mk_dir(build_path) cmds = [] cmds.append(f"cd {build_path}") cmd = [] cmd.append("cmake -S .") if DOTNET_CORE_ENABLED: cmd.append(' -DZ3_BUILD_DOTNET_BINDINGS=ON') if JAVA_ENABLED: cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') cmd.append(' -DZ3_JAVA_JAR_INSTALLDIR=java') cmd.append(' -DZ3_JAVA_JNI_LIB_INSTALLDIR=bin/java') if PYTHON_ENABLED: cmd.append(' -DZ3_BUILD_PYTHON_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_PYTHON_BINDINGS=ON') cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python') if JULIA_ENABLED: cmd.append(' -DZ3_BUILD_JULIA_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_JULIA_BINDINGS=ON') if GIT_HASH: git_hash = get_git_hash() cmd.append(' -DGIT_HASH=' + git_hash) cmd.append(' -DZ3_USE_LIB_GMP=OFF') cmd.append(' -DZ3_BUILD_LIBZ3_SHARED=ON') cmd.append(' -DCMAKE_BUILD_TYPE=RelWithDebInfo') cmd.append(' -DCMAKE_INSTALL_PREFIX=' + get_build_dist_path()) cmd.append(' -G "Ninja"') cmd.append(' ..\n') cmds.append("".join(cmd)) print("CMAKE commands:", cmds) sys.stdout.flush() if exec_cmds(cmds) != 0: raise MKException("failed to run commands") def exec_cmds(cmds): cmd_file = 'z3_tmp.sh' f = open(cmd_file, 'w') for cmd in cmds: f.write(cmd) f.write('\n') f.close() res = 0 try: res = subprocess.call(['sh', cmd_file]) except: res = 1 try: os.remove(cmd_file) except: pass return res def build_z3(): if is_verbose(): print("build z3") build_dir = get_build_dir() cmds = [] cmds.append('cd %s' % build_dir) cmds.append('ninja install') if exec_cmds(cmds) != 0: raise MKException("Failed to make z3") def mk_zip(): build_dist = get_build_dist_path() dist_name = get_z3_name() old = os.getcwd() try: if is_verbose(): print("dist path", build_dist) mk_dir(build_dist) zfname = '%s.zip' % dist_name zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) os.chdir(get_build_dist()) for root, dirs, files in os.walk("."): for f in files: if is_verbose(): print("adding ", os.path.join(root, f)) zipout.write(os.path.join(root, f)) if is_verbose(): print("Generated '%s'" % zfname) except: pass os.chdir(old) def cp_license(): if is_verbose(): print("copy licence") path = get_build_dist_path() mk_dir(path) shutil.copy("LICENSE.txt", path) # Entry point def main(): parse_options() mk_build_dir() build_z3() cp_license() mk_zip() main()