############################################ # Copyright (c) 2013 Microsoft Corporation # # Scripts for automatically generating # Linux/OSX/BSD distribution zip files. # # Author: Leonardo de Moura (leonardo) ############################################ import os import glob import re import getopt import sys import shutil import subprocess import zipfile from mk_exception import * from mk_project import * import mk_util BUILD_DIR='build-dist' VERBOSE=True DIST_DIR='dist' FORCE_MK=False DOTNET_CORE_ENABLED=True DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True MAKEJOBS=getenv("MAKEJOBS", '8') def set_verbose(flag): global VERBOSE VERBOSE = flag def is_verbose(): return VERBOSE def mk_dir(d): if not os.path.exists(d): os.makedirs(d) def set_build_dir(path): global BUILD_DIR BUILD_DIR = mk_util.norm_path(path) mk_dir(BUILD_DIR) def display_help(): print("mk_unix_dist.py: Z3 Linux/OSX/BSD distribution generator\n") print("This script generates the zip files containing executables, shared objects, header files for Linux/OSX/BSD.") 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 x86 and x64 Z3 versions will be built (default: build-dist).") print(" -f, --force force script to regenerate Makefiles.") print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= 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(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script def parse_options(): global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', 'silent', 'force', 'nojava', 'nodotnet', 'dotnet-key=', 'githash', 'nopython' ]) 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 == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False elif opt == '--githash': GIT_HASH = True else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) # Check whether build directory already exists or not def check_build_dir(path): return os.path.exists(path) and os.path.exists(os.path.join(path, 'Makefile')) # Create a build directory using mk_make.py def mk_build_dir(path): if not check_build_dir(path) or FORCE_MK: opts = [sys.executable, os.path.join('scripts', 'mk_make.py'), "-b", path, "--staticlib"] if DOTNET_CORE_ENABLED: opts.append('--dotnet') if not DOTNET_KEY_FILE is None: opts.append('--dotnet-key=' + DOTNET_KEY_FILE) if JAVA_ENABLED: opts.append('--java') if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) opts.append('--git-describe') if PYTHON_ENABLED: opts.append('--python') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) # Create build directories def mk_build_dirs(): mk_build_dir(BUILD_DIR) class cd: def __init__(self, newPath): self.newPath = newPath def __enter__(self): self.savedPath = os.getcwd() os.chdir(self.newPath) def __exit__(self, etype, value, traceback): os.chdir(self.savedPath) def mk_z3(): with cd(BUILD_DIR): try: return subprocess.call(['make', '-j', MAKEJOBS]) except: return 1 def get_os_name(): import platform basic = os.uname()[0].lower() if basic == 'linux': dist = platform.linux_distribution() if len(dist) == 3 and len(dist[0]) > 0 and len(dist[1]) > 0: return '%s-%s' % (dist[0].lower(), dist[1].lower()) else: return basic elif basic == 'darwin': ver = platform.mac_ver() if len(ver) == 3 and len(ver[0]) > 0: return 'osx-%s' % ver[0] else: return 'osx' elif basic == 'freebsd': ver = platform.version() idx1 = ver.find(' ') idx2 = ver.find('-') if idx1 < 0 or idx2 < 0 or idx1 >= idx2: return basic else: return 'freebsd-%s' % ver[(idx1+1):idx2] else: return basic def get_z3_name(): major, minor, build, revision = get_version() if sys.maxsize >= 2**32: platform = "x64" else: platform = "x86" osname = get_os_name() if GIT_HASH: return 'z3-%s.%s.%s.%s-%s-%s' % (major, minor, build, mk_util.git_hash(), platform, osname) else: return 'z3-%s.%s.%s-%s-%s' % (major, minor, build, platform, osname) def mk_dist_dir(): build_path = BUILD_DIR dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) mk_util.DOTNET_CORE_ENABLED = DOTNET_CORE_ENABLED mk_util.DOTNET_ENABLED = False mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED mk_unix_dist(build_path, dist_path) if is_verbose(): print("Generated distribution folder at '%s'" % dist_path) def get_dist_path(): return get_z3_name() def mk_zip(): dist_path = get_dist_path() old = os.getcwd() try: os.chdir(DIST_DIR) zfname = '%s.zip' % dist_path zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) for root, dirs, files in os.walk(dist_path): for f in files: zipout.write(os.path.join(root, f)) if is_verbose(): print("Generated '%s'" % zfname) except: pass os.chdir(old) def cp_license(): shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path())) # Entry point def main(): parse_options() mk_build_dirs() mk_z3() init_project_def() mk_dist_dir() cp_license() mk_zip() main()