mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			277 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ############################################
 | |
| # 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')
 | |
| OS_NAME=None
 | |
| 
 | |
| 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 <sudir>, --build=<subdir>  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=<file>           sign the .NET assembly with the private key in <file>.")
 | |
|     print("  --arch=<arch>                 set architecture (to arm64) to force arm64 build")
 | |
|     print("  --nojava                      do not include Java bindings in the binary distribution files.")
 | |
|     print("  --os=<os>                     set OS version.")
 | |
|     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, PYTHON_ENABLED, OS_NAME
 | |
|     path = BUILD_DIR
 | |
|     options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=',
 | |
|                                                                    'help',
 | |
|                                                                    'silent',
 | |
|                                                                    'force',
 | |
|                                                                    'nojava',
 | |
|                                                                    'nodotnet',
 | |
|                                                                    'dotnet-key=',
 | |
|                                                                    'arch=',
 | |
|                                                                    'os=',
 | |
|                                                                    '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
 | |
|         elif opt == '--arch':
 | |
|             if arg == "arm64":
 | |
|                 mk_util.IS_ARCH_ARM64 = True
 | |
|             else:
 | |
|                 raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg)
 | |
|         elif opt == '--os':
 | |
|             OS_NAME = arg
 | |
|         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):
 | |
|     global LINUX_X64
 | |
|     if not check_build_dir(path) or FORCE_MK:
 | |
|         env = os.environ
 | |
|         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 mk_util.IS_ARCH_ARM64:
 | |
|             opts.append('--arm64=true')
 | |
|         if mk_util.IS_ARCH_ARM64 and LINUX_X64:
 | |
|             # we are machine x64 but build against arm64
 | |
|             # so we have to do cross compiling
 | |
|             # the cross compiler is download from ARM GNU
 | |
|             # toolchain
 | |
|             myvar = {
 | |
|                 "CC":  "aarch64-none-linux-gnu-gcc",
 | |
|                 "CXX": "aarch64-none-linux-gnu-g++"
 | |
|             }
 | |
|             env.update(myvar)
 | |
|         if subprocess.call(opts, env=env) != 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():
 | |
|     global LINUX_X64
 | |
|     if OS_NAME is not None:
 | |
|         return OS_NAME
 | |
|     import platform
 | |
|     basic = os.uname()[0].lower()
 | |
|     if basic == 'linux':
 | |
|         if mk_util.IS_ARCH_ARM64 and LINUX_X64:
 | |
|             # handle cross compiling
 | |
|             # example: 'ldd (GNU) 2.34'
 | |
|             lines = subprocess.check_output(["ldd", "--version"]).decode('ascii')
 | |
|             first_line = lines.split("\n")[0]
 | |
|             ldd_version = first_line.split()[-1]
 | |
|             # coerce the format to platform.libc_ver() return type
 | |
|             dist = ('glibc', ldd_version)
 | |
|         else:
 | |
|             dist = platform.libc_ver()
 | |
|         if len(dist) == 2 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():
 | |
|     import platform as platform_module
 | |
|     # Note that the platform name this function return
 | |
|     # has to work together with setup.py
 | |
|     # It's not the typical output from platform.machine()
 | |
|     major, minor, build, revision = get_version()
 | |
|     if mk_util.IS_ARCH_ARM64 or platform_module.machine() == "aarch64":
 | |
|         # the second case handle native build on aarch64
 | |
|         # TODO: we don't handle cross compile on host aarch64 to target x64
 | |
|         platform = "arm64"    
 | |
|     elif 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()
 | |
| 
 |