############################################ # Copyright (c) 2012 Microsoft Corporation # # Scripts for automatically generating # Window 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 * BUILD_DIR='build-dist' BUILD_X64_DIR='build-dist/x64' BUILD_X86_DIR='build-dist/x86' VERBOSE=True DIST_DIR='dist' FORCE_MK=False 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 = path BUILD_X86_DIR = '%s/x86' % path BUILD_X64_DIR = '%s/x64' % path mk_dir(BUILD_X86_DIR) mk_dir(BUILD_X64_DIR) def display_help(): print "mk_win_dist.py: Z3 Windows distribution generator\n" print "This script generates the zip files containing executables, dlls, header files for Windows." 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." exit(0) # Parse configuration option for mk_make script def parse_options(): global FORCE_MK path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', 'silent', 'force' ]) 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 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('%s/Makefile' % path) # Create a build directory using mk_make.py def mk_build_dir(path, x64): if not check_build_dir(path) or FORCE_MK: opts = ["python", "scripts/mk_make.py", "-b", path] if x64: opts.append('-x') 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_X86_DIR, False) mk_build_dir(BUILD_X64_DIR, True) # Check if on Visual Studio command prompt def check_vc_cmd_prompt(): try: DEVNULL = open(os.devnull, 'wb') subprocess.call(['cl'], stdin=DEVNULL, stderr=DEVNULL) except: raise MKException("You must execute the mk_win_dist.py script on a Visual Studio Command Prompt") def exec_cmds(cmds): cmd_file = 'z3_tmp.cmd' f = open(cmd_file, 'w') for cmd in cmds: f.write(cmd) f.write('\n') f.close() res = 0 try: res = subprocess.call(cmd_file, shell=True) except: res = 1 try: os.erase(cmd_file) except: pass return res # Compile Z3 (if x64 == True, then it builds it in x64 mode). def mk_z3_core(x64): cmds = [] if x64: cmds.append('call "%VCINSTALLDIR%vcvarsall.bat" amd64') cmds.append('cd %s' % BUILD_X64_DIR) else: cmds.append('"call %VCINSTALLDIR%vcvarsall.bat" x86') cmds.append('cd %s' % BUILD_X86_DIR) cmds.append('nmake') if exec_cmds(cmds) != 0: raise MKException("Failed to make z3, x64: %s" % x64) def mk_z3(): mk_z3_core(False) mk_z3_core(True) def mk_dist_dir_core(x64): major, minor, build, revision = get_version() if x64: platform = "x64" build_path = BUILD_X64_DIR else: platform = "x86" build_path = BUILD_X86_DIR dist_path = '%s/z3-%s.%s.%s-%s' % (DIST_DIR, major, minor, build, platform) mk_dir(dist_path) mk_win_dist(build_path, dist_path) if is_verbose(): print "Generated %s distribution folder at '%s'" % (platform, dist_path) def mk_dist_dir(): mk_dist_dir_core(False) mk_dist_dir_core(True) ZIPOUT = None def mk_zip_visitor(pattern, dir, files): for filename in files: if fnmatch(filename, pattern): fname = os.path.join(dir, filename) if not os.path.isdir(fname): ZIPOUT.write(fname) def get_dist_path(x64): major, minor, build, revision = get_version() if x64: platform = "x64" else: platform = "x86" return 'z3-%s.%s.%s-%s' % (major, minor, build, platform) def mk_zip_core(x64): global ZIPOUT dist_path = get_dist_path(x64) old = os.getcwd() try: os.chdir(DIST_DIR) zfname = '%s.zip' % dist_path ZIPOUT = zipfile.ZipFile(zfname, 'w') os.path.walk(dist_path, mk_zip_visitor, '*') if is_verbose(): print "Generated '%s'" % zfname except: pass ZIPOUT = None os.chdir(old) # Create a zip file for each platform def mk_zip(): mk_zip_core(False) mk_zip_core(True) VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), re.compile('msvcp.*\.dll'), re.compile('msvcr.*\.dll')] VS_RUNTIME_FILES = [] def cp_vs_runtime_visitor(pattern, dir, files): global VS_RUNTIME_FILES for filename in files: for pat in VS_RUNTIME_PATS: if pat.match(filename): if fnmatch(filename, pattern): fname = os.path.join(dir, filename) if not os.path.isdir(fname): VS_RUNTIME_FILES.append(fname) break # Copy Visual Studio Runtime libraries def cp_vs_runtime_core(x64): global VS_RUNTIME_FILES if x64: platform = "x64" else: platform = "x86" vcdir = subprocess.check_output(['echo', '%VCINSTALLDIR%'], shell=True).rstrip('\r\n') path = '%sredist\\%s' % (vcdir, platform) VS_RUNTIME_FILES = [] os.path.walk(path, cp_vs_runtime_visitor, '*.dll') bin_dist_path = '%s/%s/bin' % (DIST_DIR, get_dist_path(x64)) for f in VS_RUNTIME_FILES: shutil.copy(f, bin_dist_path) if is_verbose(): print "Copied '%s' to '%s'" % (f, bin_dist_path) def cp_vs_runtime(): cp_vs_runtime_core(True) cp_vs_runtime_core(False) def cp_license(): shutil.copy("LICENSE.txt", "%s/%s" % (DIST_DIR, get_dist_path(True))) shutil.copy("LICENSE.txt", "%s/%s" % (DIST_DIR, get_dist_path(False))) # Entry point def main(): if os.name != 'nt': raise MKException("This script is for Windows only") parse_options() check_vc_cmd_prompt() mk_build_dirs() mk_z3() init_project_def() mk_dist_dir() cp_license() cp_vs_runtime() mk_zip() main()