mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	* Enabling Control Flow Guard by default for MSVC on Windows, with options to disable it. * Fix configuration error for non-MSVC compilers. * Reviewed and updated configuration for Python build and added comment for CFG.
		
			
				
	
	
		
			3631 lines
		
	
	
	
		
			144 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			3631 lines
		
	
	
	
		
			144 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ############################################
 | |
| # Copyright (c) 2012 Microsoft Corporation
 | |
| #
 | |
| # Auxiliary scripts for generating Makefiles
 | |
| # and Visual Studio project files.
 | |
| #
 | |
| # Author: Leonardo de Moura (leonardo)
 | |
| ############################################
 | |
| import io
 | |
| import sys
 | |
| import os
 | |
| import re
 | |
| import getopt
 | |
| import shutil
 | |
| from mk_exception import *
 | |
| import mk_genfile_common
 | |
| from fnmatch import fnmatch
 | |
| import sysconfig
 | |
| import compileall
 | |
| import subprocess
 | |
| 
 | |
| def getenv(name, default):
 | |
|     try:
 | |
|         return os.environ[name].strip(' "\'')
 | |
|     except:
 | |
|         return default
 | |
| 
 | |
| CXX=getenv("CXX", None)
 | |
| CC=getenv("CC", None)
 | |
| CPPFLAGS=getenv("CPPFLAGS", "")
 | |
| CXXFLAGS=getenv("CXXFLAGS", "")
 | |
| AR=getenv("AR", "ar")
 | |
| EXAMP_DEBUG_FLAG=''
 | |
| LDFLAGS=getenv("LDFLAGS", "")
 | |
| JNI_HOME=getenv("JNI_HOME", None)
 | |
| OCAMLC=getenv("OCAMLC", "ocamlc")
 | |
| OCAMLOPT=getenv("OCAMLOPT", "ocamlopt")
 | |
| OCAML_LIB=getenv("OCAML_LIB", None)
 | |
| OCAMLFIND=getenv("OCAMLFIND", "ocamlfind")
 | |
| DOTNET="dotnet"
 | |
| # Standard install directories relative to PREFIX
 | |
| INSTALL_BIN_DIR=getenv("Z3_INSTALL_BIN_DIR", "bin")
 | |
| INSTALL_LIB_DIR=getenv("Z3_INSTALL_LIB_DIR", "lib")
 | |
| INSTALL_INCLUDE_DIR=getenv("Z3_INSTALL_INCLUDE_DIR", "include")
 | |
| INSTALL_PKGCONFIG_DIR=getenv("Z3_INSTALL_PKGCONFIG_DIR", os.path.join(INSTALL_LIB_DIR, 'pkgconfig'))
 | |
| 
 | |
| CXX_COMPILERS=['g++', 'clang++']
 | |
| C_COMPILERS=['gcc', 'clang']
 | |
| JAVAC=None
 | |
| JAR=None
 | |
| PYTHON_PACKAGE_DIR=sysconfig.get_path('purelib')
 | |
| BUILD_DIR='build'
 | |
| REV_BUILD_DIR='..'
 | |
| SRC_DIR='src'
 | |
| EXAMPLE_DIR='examples'
 | |
| # Required Components
 | |
| Z3_DLL_COMPONENT='api_dll'
 | |
| PATTERN_COMPONENT='pattern'
 | |
| UTIL_COMPONENT='util'
 | |
| API_COMPONENT='api'
 | |
| DOTNET_COMPONENT='dotnet'
 | |
| DOTNET_CORE_COMPONENT='dotnet'
 | |
| JAVA_COMPONENT='java'
 | |
| ML_COMPONENT='ml'
 | |
| CPP_COMPONENT='cpp'
 | |
| PYTHON_COMPONENT='python'
 | |
| #####################
 | |
| IS_WINDOWS=False
 | |
| IS_LINUX=False
 | |
| IS_HURD=False
 | |
| IS_OSX=False
 | |
| IS_ARCH_ARM64=False
 | |
| IS_FREEBSD=False
 | |
| IS_NETBSD=False
 | |
| IS_OPENBSD=False
 | |
| IS_SUNOS=False
 | |
| IS_CYGWIN=False
 | |
| IS_CYGWIN_MINGW=False
 | |
| IS_MSYS2=False
 | |
| VERBOSE=True
 | |
| DEBUG_MODE=False
 | |
| SHOW_CPPS = True
 | |
| VS_X64 = False
 | |
| VS_ARM = False
 | |
| LINUX_X64 = True
 | |
| ONLY_MAKEFILES = False
 | |
| Z3PY_SRC_DIR=None
 | |
| Z3JS_SRC_DIR=None
 | |
| VS_PROJ = False
 | |
| TRACE = False
 | |
| PYTHON_ENABLED=False
 | |
| DOTNET_CORE_ENABLED=False
 | |
| DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None)
 | |
| ASSEMBLY_VERSION=getenv("Z2_ASSEMBLY_VERSION", None)
 | |
| JAVA_ENABLED=False
 | |
| ML_ENABLED=False
 | |
| PYTHON_INSTALL_ENABLED=False
 | |
| STATIC_LIB=False
 | |
| STATIC_BIN=False
 | |
| VER_MAJOR=None
 | |
| VER_MINOR=None
 | |
| VER_BUILD=None
 | |
| VER_TWEAK=None
 | |
| PREFIX=sys.prefix
 | |
| GMP=False
 | |
| VS_PAR=False
 | |
| VS_PAR_NUM=8
 | |
| GPROF=False
 | |
| GIT_HASH=False
 | |
| GIT_DESCRIBE=False
 | |
| SLOW_OPTIMIZE=False
 | |
| LOG_SYNC=False
 | |
| SINGLE_THREADED=False
 | |
| GUARD_CF=False
 | |
| ALWAYS_DYNAMIC_BASE=False
 | |
| 
 | |
| FPMATH="Default"
 | |
| FPMATH_FLAGS="-mfpmath=sse -msse -msse2"
 | |
| FPMATH_ENABLED=getenv("FPMATH_ENABLED", "True")
 | |
| 
 | |
| 
 | |
| 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 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]
 | |
| 
 | |
| def is_windows():
 | |
|     return IS_WINDOWS
 | |
| 
 | |
| def is_linux():
 | |
|     return IS_LINUX
 | |
| 
 | |
| def is_hurd():
 | |
|     return IS_HURD
 | |
| 
 | |
| def is_freebsd():
 | |
|     return IS_FREEBSD
 | |
| 
 | |
| def is_netbsd():
 | |
|     return IS_NETBSD
 | |
| 
 | |
| def is_openbsd():
 | |
|     return IS_OPENBSD
 | |
| 
 | |
| def is_sunos():
 | |
|     return IS_SUNOS
 | |
| 
 | |
| def is_osx():
 | |
|     return IS_OSX
 | |
| 
 | |
| def is_cygwin():
 | |
|     return IS_CYGWIN
 | |
| 
 | |
| def is_cygwin_mingw():
 | |
|     return IS_CYGWIN_MINGW
 | |
| 
 | |
| def is_msys2():
 | |
|     return IS_MSYS2
 | |
| 
 | |
| def norm_path(p):
 | |
|     return os.path.expanduser(os.path.normpath(p))
 | |
| 
 | |
| def which(program):
 | |
|     import os
 | |
|     def is_exe(fpath):
 | |
|         return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
 | |
| 
 | |
|     fpath, fname = os.path.split(program)
 | |
|     if fpath:
 | |
|         if is_exe(program):
 | |
|             return program
 | |
|     else:
 | |
|         for path in getenv("PATH", "").split(os.pathsep):
 | |
|             exe_file = os.path.join(path, program)
 | |
|             if is_exe(exe_file):
 | |
|                 return exe_file
 | |
|     return None
 | |
| 
 | |
| class TempFile:
 | |
|     def __init__(self, name):
 | |
|         try:
 | |
|             self.name  = name
 | |
|             self.fname = open(name, 'w')
 | |
|         except:
 | |
|             raise MKException("Failed to create temporary file '%s'" % self.name)
 | |
| 
 | |
|     def add(self, s):
 | |
|         self.fname.write(s)
 | |
| 
 | |
|     def commit(self):
 | |
|         self.fname.close()
 | |
| 
 | |
|     def __del__(self):
 | |
|         self.fname.close()
 | |
|         try:
 | |
|             os.remove(self.name)
 | |
|         except:
 | |
|             pass
 | |
| 
 | |
| def exec_cmd(cmd):
 | |
|     if isinstance(cmd, str):
 | |
|         cmd = cmd.split(' ')
 | |
|     new_cmd = []
 | |
|     first = True
 | |
|     for e in cmd:
 | |
|         if first:
 | |
|             first = False
 | |
|             new_cmd.append(e)
 | |
|         else:
 | |
|             if e != "":
 | |
|                 se = e.split(' ')
 | |
|                 if len(se) > 1:
 | |
|                     for e2 in se:
 | |
|                         if e2 != "":
 | |
|                             new_cmd.append(e2)
 | |
|                 else:
 | |
|                     new_cmd.append(e)
 | |
|     cmd = new_cmd
 | |
|     null = open(os.devnull, 'wb')
 | |
|     try:
 | |
|         return subprocess.call(cmd, stdout=null, stderr=null)
 | |
|     except:
 | |
|         # Failed to create process
 | |
|         return 1
 | |
|     finally:
 | |
|         null.close()
 | |
| 
 | |
| # rm -f fname
 | |
| def rmf(fname):
 | |
|     if os.path.exists(fname):
 | |
|         os.remove(fname)
 | |
| 
 | |
| def exec_compiler_cmd(cmd):
 | |
|     r = exec_cmd(cmd)
 | |
|     # Windows
 | |
|     rmf('a.exe')
 | |
|     # Unix
 | |
|     rmf('a.out')
 | |
|     # Emscripten
 | |
|     rmf('a.wasm')
 | |
|     rmf('a.worker.js')
 | |
|     return r
 | |
| 
 | |
| def test_cxx_compiler(cc):
 | |
|     if is_verbose():
 | |
|         print("Testing %s..." % cc)
 | |
|     t = TempFile('tst.cpp')
 | |
|     t.add('#include<iostream>\nint main() { return 0; }\n')
 | |
|     t.commit()
 | |
|     return exec_compiler_cmd([cc, CPPFLAGS, CXXFLAGS, 'tst.cpp', LDFLAGS]) == 0
 | |
| 
 | |
| def test_c_compiler(cc):
 | |
|     if is_verbose():
 | |
|         print("Testing %s..." % cc)
 | |
|     t = TempFile('tst.c')
 | |
|     t.add('#include<stdio.h>\nint main() { return 0; }\n')
 | |
|     t.commit()
 | |
|     return exec_compiler_cmd([cc, CPPFLAGS, 'tst.c', LDFLAGS]) == 0
 | |
| 
 | |
| def test_gmp(cc):
 | |
|     if is_verbose():
 | |
|         print("Testing GMP...")
 | |
|     t = TempFile('tstgmp.cpp')
 | |
|     t.add('#include<gmp.h>\nint main() { mpz_t t; mpz_init(t); mpz_clear(t); return 0; }\n')
 | |
|     t.commit()
 | |
|     return exec_compiler_cmd([cc, CPPFLAGS, 'tstgmp.cpp', LDFLAGS, '-lgmp']) == 0
 | |
| 
 | |
| 
 | |
| 
 | |
| def test_fpmath(cc):
 | |
|     global FPMATH_FLAGS, IS_ARCH_ARM64, IS_OSX
 | |
|     if FPMATH_ENABLED == "False":
 | |
|         FPMATH_FLAGS=""
 | |
|         return "Disabled"
 | |
|     if IS_ARCH_ARM64 and IS_OSX:
 | |
|         FPMATH_FLAGS = ""
 | |
|         return "Disabled-ARM64"
 | |
|     if is_verbose():
 | |
|         print("Testing floating point support...")
 | |
|     t = TempFile('tstsse.cpp')
 | |
|     t.add('int main() { return 42; }\n')
 | |
|     t.commit()
 | |
|     # -Werror is needed because some versions of clang warn about unrecognized
 | |
|     # -m flags.
 | |
|     # TODO(ritave): Safari doesn't allow SIMD WebAssembly extension, add a flag to build script
 | |
|     if exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-msse -msse2 -msimd128']) == 0:
 | |
|         FPMATH_FLAGS='-msse -msse2 -msimd128'
 | |
|         return 'SSE2-EMSCRIPTEN'
 | |
|     if exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-mfpmath=sse -msse -msse2']) == 0:
 | |
|         FPMATH_FLAGS="-mfpmath=sse -msse -msse2"
 | |
|         return "SSE2-GCC"
 | |
|     elif exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-msse -msse2']) == 0:
 | |
|         FPMATH_FLAGS="-msse -msse2"
 | |
|         return "SSE2-CLANG"
 | |
|     elif exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-mfpu=vfp -mfloat-abi=hard']) == 0:
 | |
|         FPMATH_FLAGS="-mfpu=vfp -mfloat-abi=hard"
 | |
|         return "ARM-VFP"
 | |
|     else:
 | |
|         FPMATH_FLAGS=""
 | |
|         return "UNKNOWN"
 | |
| 
 | |
| def test_atomic_required(cc):
 | |
|     t = TempFile('tstatomic.cpp')
 | |
|     t.add("""
 | |
|     #include <atomic>
 | |
|     std::atomic<int> x;
 | |
|     std::atomic<short> y;
 | |
|     std::atomic<char> z;
 | |
|     std::atomic<long long> w;
 | |
|     int main() {
 | |
|         ++z;
 | |
|         ++y;
 | |
|         ++w;
 | |
|         return ++x;
 | |
|     }
 | |
|     """)
 | |
|     t.commit()
 | |
|     fails_without = exec_compiler_cmd([cc, CPPFLAGS, '', 'tstatomic.cpp', LDFLAGS, '']) != 0
 | |
|     ok_with = exec_compiler_cmd([cc, CPPFLAGS, '', 'tstatomic.cpp', LDFLAGS + ' -latomic', '']) == 0
 | |
|     return fails_without and ok_with
 | |
| 
 | |
| 
 | |
| def find_jni_h(path):
 | |
|     for root, dirs, files in os.walk(path):
 | |
|         for f in files:
 | |
|             if f == 'jni.h':
 | |
|                 return root
 | |
|     return False
 | |
| 
 | |
| def check_java():
 | |
|     global JNI_HOME
 | |
|     global JAVAC
 | |
|     global JAR
 | |
| 
 | |
|     JDK_HOME = getenv('JDK_HOME', None) # we only need to check this locally.
 | |
| 
 | |
|     if is_verbose():
 | |
|         print("Finding javac ...")
 | |
| 
 | |
|     if JDK_HOME is not None:
 | |
|         if IS_WINDOWS:
 | |
|             JAVAC = os.path.join(JDK_HOME, 'bin', 'javac.exe')
 | |
|         else:
 | |
|             JAVAC = os.path.join(JDK_HOME, 'bin', 'javac')
 | |
| 
 | |
|         if not os.path.exists(JAVAC):
 | |
|             raise MKException("Failed to detect javac at '%s/bin'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME))
 | |
|     else:
 | |
|         # Search for javac in the path.
 | |
|         ind = 'javac'
 | |
|         if IS_WINDOWS:
 | |
|             ind = ind + '.exe'
 | |
|         paths = os.getenv('PATH', None)
 | |
|         if paths:
 | |
|             spaths = paths.split(os.pathsep)
 | |
|             for i in range(0, len(spaths)):
 | |
|                 cmb = os.path.join(spaths[i], ind)
 | |
|                 if os.path.exists(cmb):
 | |
|                     JAVAC = cmb
 | |
|                     break
 | |
| 
 | |
|     if JAVAC is None:
 | |
|         raise MKException('No java compiler in the path, please adjust your PATH or set JDK_HOME to the location of the JDK.')
 | |
| 
 | |
|     if is_verbose():
 | |
|         print("Finding jar ...")
 | |
| 
 | |
|     if IS_WINDOWS:
 | |
|         JAR = os.path.join(os.path.dirname(JAVAC), 'jar.exe')
 | |
|     else:
 | |
|         JAR = os.path.join(os.path.dirname(JAVAC), 'jar')
 | |
| 
 | |
|     if not os.path.exists(JAR):
 | |
|         raise MKException("Failed to detect jar at '%s'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME))
 | |
| 
 | |
|     if is_verbose():
 | |
|         print("Testing %s..." % JAVAC)
 | |
| 
 | |
|     t = TempFile('Hello.java')
 | |
|     t.add('public class Hello { public static void main(String[] args) { System.out.println("Hello, World"); }}\n')
 | |
|     t.commit()
 | |
| 
 | |
|     oo = TempFile('output')
 | |
|     eo = TempFile('errout')
 | |
|     try:
 | |
|         subprocess.call([JAVAC, 'Hello.java', '-verbose', '-source', '1.8', '-target', '1.8' ], stdout=oo.fname, stderr=eo.fname)
 | |
|         oo.commit()
 | |
|         eo.commit()
 | |
|     except:
 | |
|         raise MKException('Found, but failed to run Java compiler at %s' % (JAVAC))
 | |
| 
 | |
|     os.remove('Hello.class')
 | |
| 
 | |
|     if is_verbose():
 | |
|         print("Finding jni.h...")
 | |
| 
 | |
|     if JNI_HOME is not None:
 | |
|         if not os.path.exists(os.path.join(JNI_HOME, 'jni.h')):
 | |
|             raise MKException("Failed to detect jni.h '%s'; the environment variable JNI_HOME is probably set to the wrong path." % os.path.join(JNI_HOME))
 | |
|     else:
 | |
|         # Search for jni.h in the library directories...
 | |
|         t = open('errout', 'r')
 | |
|         open_pat = re.compile(r"\[search path for class files: (.*)\]")
 | |
|         cdirs = []
 | |
|         for line in t:
 | |
|             m = open_pat.match(line)
 | |
|             if m:
 | |
|                 libdirs = m.group(1).split(',')
 | |
|                 for libdir in libdirs:
 | |
|                     q = os.path.dirname(libdir)
 | |
|                     if cdirs.count(q) == 0 and len(q) > 0:
 | |
|                         cdirs.append(q)
 | |
|         t.close()
 | |
| 
 | |
|         # ... plus some heuristic ones.
 | |
|         extra_dirs = []
 | |
| 
 | |
|         # For the libraries, even the JDK usually uses a JRE that comes with it. To find the
 | |
|         # headers we have to go a little bit higher up.
 | |
|         for dir in cdirs:
 | |
|             extra_dirs.append(os.path.abspath(os.path.join(dir, '..')))
 | |
| 
 | |
|         if IS_OSX: # Apparently Apple knows best where to put stuff...
 | |
|             extra_dirs.append('/System/Library/Frameworks/JavaVM.framework/Headers/')
 | |
| 
 | |
|         cdirs[len(cdirs):] = extra_dirs
 | |
| 
 | |
|         for dir in cdirs:
 | |
|             q = find_jni_h(dir)
 | |
|             if q is not False:
 | |
|                 JNI_HOME = q
 | |
| 
 | |
|         if JNI_HOME is None:
 | |
|             raise MKException("Failed to detect jni.h. Possible solution: set JNI_HOME with the path to JDK.")
 | |
| 
 | |
| def test_csc_compiler(c):
 | |
|     t = TempFile('hello.cs')
 | |
|     t.add('public class hello { public static void Main() {} }')
 | |
|     t.commit()
 | |
|     if is_verbose():
 | |
|         print ('Testing %s...' % c)
 | |
|     r = exec_cmd([c, 'hello.cs'])
 | |
|     try:
 | |
|         rmf('hello.cs')
 | |
|         rmf('hello.exe')
 | |
|     except:
 | |
|         pass
 | |
|     return r == 0
 | |
| 
 | |
| def check_dotnet_core():
 | |
|     if not IS_WINDOWS:
 | |
|         return
 | |
|     r = exec_cmd([DOTNET, '--help'])
 | |
|     if r != 0:
 | |
|         raise MKException('Failed testing dotnet. Make sure to install and configure dotnet core utilities')
 | |
| 
 | |
| def check_ml():
 | |
|     t = TempFile('hello.ml')
 | |
|     t.add('print_string "Hello world!\n";;')
 | |
|     t.commit()
 | |
|     if is_verbose():
 | |
|         print ('Testing %s...' % OCAMLC)
 | |
|     r = exec_cmd([OCAMLC, '-o', 'a.out', 'hello.ml'])
 | |
|     if r != 0:
 | |
|         raise MKException('Failed testing ocamlc compiler. Set environment variable OCAMLC with the path to the Ocaml compiler')
 | |
|     if is_verbose():
 | |
|         print ('Testing %s...' % OCAMLOPT)
 | |
|     r = exec_cmd([OCAMLOPT, '-o', 'a.out', 'hello.ml'])
 | |
|     if r != 0:
 | |
|         raise MKException('Failed testing ocamlopt compiler. Set environment variable OCAMLOPT with the path to the Ocaml native compiler. Note that ocamlopt may require flexlink to be in your path.')
 | |
|     try:
 | |
|         rmf('hello.cmi')
 | |
|         rmf('hello.cmo')
 | |
|         rmf('hello.cmx')
 | |
|         rmf('a.out')
 | |
|         rmf('hello.o')
 | |
|     except:
 | |
|         pass
 | |
|     find_ml_lib()
 | |
|     find_ocaml_find()
 | |
| 
 | |
| def find_ocaml_find():
 | |
|     global OCAMLFIND
 | |
|     if is_verbose():
 | |
|         print ("Testing %s..." % OCAMLFIND)
 | |
|     r = exec_cmd([OCAMLFIND, 'printconf'])
 | |
|     if r != 0:
 | |
|         OCAMLFIND = ''
 | |
| 
 | |
| def find_ml_lib():
 | |
|     global OCAML_LIB
 | |
|     if is_verbose():
 | |
|         print ('Finding OCAML_LIB...')
 | |
|     t = TempFile('output')
 | |
|     null = open(os.devnull, 'wb')
 | |
|     try:
 | |
|         subprocess.call([OCAMLC, '-where'], stdout=t.fname, stderr=null)
 | |
|         t.commit()
 | |
|     except:
 | |
|         raise MKException('Failed to find Ocaml library; please set OCAML_LIB')
 | |
|     finally:
 | |
|         null.close()
 | |
| 
 | |
|     t = open('output', 'r')
 | |
|     for line in t:
 | |
|         OCAML_LIB = line[:-1]
 | |
|     if is_verbose():
 | |
|         print ('OCAML_LIB=%s' % OCAML_LIB)
 | |
|     t.close()
 | |
|     rmf('output')
 | |
|     return
 | |
| 
 | |
| def is64():
 | |
|     global LINUX_X64
 | |
|     if is_sunos() and sys.version_info.major < 3:
 | |
|         return LINUX_X64
 | |
|     else:
 | |
|         return LINUX_X64 and sys.maxsize >= 2**32
 | |
| 
 | |
| def check_ar():
 | |
|     if is_verbose():
 | |
|         print("Testing ar...")
 | |
|     if which(AR) is None:
 | |
|         raise MKException('%s (archive tool) was not found' % AR)
 | |
| 
 | |
| def find_cxx_compiler():
 | |
|     global CXX, CXX_COMPILERS
 | |
|     if CXX is not None:
 | |
|         if test_cxx_compiler(CXX):
 | |
|             return CXX
 | |
|     for cxx in CXX_COMPILERS:
 | |
|         if test_cxx_compiler(cxx):
 | |
|             CXX = cxx
 | |
|             return CXX
 | |
|     raise MKException('C++ compiler was not found. Try to set the environment variable CXX with the C++ compiler available in your system.')
 | |
| 
 | |
| def find_c_compiler():
 | |
|     global CC, C_COMPILERS
 | |
|     if CC is not None:
 | |
|         if test_c_compiler(CC):
 | |
|             return CC
 | |
|     for c in C_COMPILERS:
 | |
|         if test_c_compiler(c):
 | |
|             CC = c
 | |
|             return CC
 | |
|     raise MKException('C compiler was not found. Try to set the environment variable CC with the C compiler available in your system.')
 | |
| 
 | |
| def set_version(major, minor, build, revision):
 | |
|     global ASSEMBLY_VERSION, VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK, GIT_DESCRIBE
 | |
| 
 | |
|     # We need to give the assembly a build specific version
 | |
|     # global version overrides local default expression
 | |
|     if ASSEMBLY_VERSION is not None:
 | |
|         versionSplits = ASSEMBLY_VERSION.split('.')
 | |
|         if len(versionSplits) > 3:
 | |
|             VER_MAJOR = versionSplits[0]
 | |
|             VER_MINOR = versionSplits[1]
 | |
|             VER_BUILD = versionSplits[2]
 | |
|             VER_TWEAK = versionSplits[3]
 | |
|             print("Set Assembly Version (BUILD):", VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK)
 | |
|             return
 | |
| 
 | |
|     # use parameters to set up version if not provided by script args
 | |
|     VER_MAJOR = major
 | |
|     VER_MINOR = minor
 | |
|     VER_BUILD = build
 | |
|     VER_TWEAK = revision
 | |
| 
 | |
|     # update VER_TWEAK base on github
 | |
|     if GIT_DESCRIBE:
 | |
|         branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
 | |
|         VER_TWEAK = int(check_output(['git', 'rev-list', '--count', 'HEAD']))
 | |
| 
 | |
|     print("Set Assembly Version (DEFAULT):", VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK)
 | |
| 
 | |
| def get_version():
 | |
|     return (VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK)
 | |
| 
 | |
| def get_version_string(n):
 | |
|     if n == 3:
 | |
|         return "{}.{}.{}".format(VER_MAJOR,VER_MINOR,VER_BUILD)
 | |
|     return "{}.{}.{}.{}".format(VER_MAJOR,VER_MINOR,VER_BUILD,VER_TWEAK)
 | |
| 
 | |
| def build_static_lib():
 | |
|     return STATIC_LIB
 | |
| 
 | |
| def build_static_bin():
 | |
|     return STATIC_BIN
 | |
| 
 | |
| def is_cr_lf(fname):
 | |
|     # Check whether text files use cr/lf
 | |
|     f = open(fname, 'r')
 | |
|     line = f.readline()
 | |
|     f.close()
 | |
|     sz = len(line)
 | |
|     return sz >= 2 and line[sz-2] == '\r' and line[sz-1] == '\n'
 | |
| 
 | |
| # dos2unix in python
 | |
| #    cr/lf --> lf
 | |
| def dos2unix(fname):
 | |
|     if is_cr_lf(fname):
 | |
|         fin  = open(fname, 'r')
 | |
|         fname_new = '%s.new' % fname
 | |
|         fout = open(fname_new, 'w')
 | |
|         for line in fin:
 | |
|             line = line.rstrip('\r\n')
 | |
|             fout.write(line)
 | |
|             fout.write('\n')
 | |
|         fin.close()
 | |
|         fout.close()
 | |
|         shutil.move(fname_new, fname)
 | |
|         if is_verbose():
 | |
|             print("dos2unix '%s'" % fname)
 | |
| 
 | |
| def dos2unix_tree():
 | |
|     for root, dirs, files in os.walk('src'):
 | |
|         for f in files:
 | |
|             dos2unix(os.path.join(root, f))
 | |
| 
 | |
| 
 | |
| def check_eol():
 | |
|     if not IS_WINDOWS:
 | |
|         # Linux/OSX/BSD check if the end-of-line is cr/lf
 | |
|         if is_cr_lf('LICENSE.txt'):
 | |
|             if is_verbose():
 | |
|                 print("Fixing end of line...")
 | |
|             dos2unix_tree()
 | |
| 
 | |
| if os.name == 'nt':
 | |
|     IS_WINDOWS=True
 | |
|     # Visual Studio already displays the files being compiled
 | |
|     SHOW_CPPS=False
 | |
|     # Enable Control Flow Guard by default on Windows with MSVC
 | |
|     # Note: Python build system on Windows assumes MSVC (cl.exe) compiler
 | |
|     GUARD_CF = True
 | |
| elif os.name == 'posix':
 | |
|     if os.uname()[0] == 'Darwin':
 | |
|         IS_OSX=True
 | |
|     elif os.uname()[0] == 'Linux':
 | |
|         IS_LINUX=True
 | |
|     elif os.uname()[0] == 'GNU':
 | |
|         IS_HURD=True
 | |
|     elif os.uname()[0] == 'FreeBSD':
 | |
|         IS_FREEBSD=True
 | |
|     elif os.uname()[0] == 'NetBSD':
 | |
|         IS_NETBSD=True
 | |
|     elif os.uname()[0] == 'OpenBSD':
 | |
|         IS_OPENBSD=True
 | |
|     elif os.uname()[0] == 'SunOS':
 | |
|         IS_SUNOS=True
 | |
|     elif os.uname()[0][:6] == 'CYGWIN':
 | |
|         IS_CYGWIN=True
 | |
|         if (CC != None and "mingw" in CC):
 | |
|             IS_CYGWIN_MINGW=True
 | |
|     elif os.uname()[0].startswith('MSYS_NT') or os.uname()[0].startswith('MINGW'):
 | |
|         IS_MSYS2=True
 | |
|         if os.uname()[4] == 'x86_64':
 | |
|             LINUX_X64=True
 | |
|         else:
 | |
|             LINUX_X64=False
 | |
| 
 | |
| 
 | |
| if os.name == 'posix' and os.uname()[4] == 'arm64':
 | |
|     IS_ARCH_ARM64 = True
 | |
| 
 | |
| 
 | |
| def display_help(exit_code):
 | |
|     print("mk_make.py: Z3 Makefile generator\n")
 | |
|     print("This script generates the Makefile for the Z3 theorem prover.")
 | |
|     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.")
 | |
|     if not IS_WINDOWS:
 | |
|         print("  -p <dir>, --prefix=<dir>      installation prefix (default: %s)." % PREFIX)
 | |
|     else:
 | |
|         print("  --parallel=num                use cl option /MP with 'num' parallel processes")
 | |
|     print("  --pypkgdir=<dir>              Force a particular Python package directory (default %s)" % PYTHON_PACKAGE_DIR)
 | |
|     print("  -b <subdir>, --build=<subdir>  subdirectory where Z3 will be built (default: %s)." % BUILD_DIR)
 | |
|     print("  --githash=hash                include the given hash in the binaries.")
 | |
|     print("  --git-describe                include the output of 'git describe' in the version information.")
 | |
|     print("  -d, --debug                   compile Z3 in debug mode.")
 | |
|     print("  -t, --trace                   enable tracing in release mode.")
 | |
|     if IS_WINDOWS:
 | |
|         print("  --guardcf                     enable Control Flow Guard runtime checks.")
 | |
|         print("                                (incompatible with /ZI, -ZI, /clr, and -clr options)")
 | |
|         print("  --no-guardcf                  disable Control Flow Guard runtime checks.")
 | |
|         print("  -x, --x64                     create 64 binary when using Visual Studio.")
 | |
|     else:
 | |
|         print("  --x86                         force 32-bit x86 build on x64 systems.")
 | |
|     print("  --arm64=<bool>                    forcearm64 bit build  on/off (supported for Darwin).")
 | |
|     print("  -m, --makefiles               generate only makefiles.")
 | |
|     if IS_WINDOWS:
 | |
|         print("  -v, --vsproj                  generate Visual Studio Project Files.")
 | |
|         print("  --optimize                    generate optimized code during linking.")
 | |
|     print("  --dotnet                      generate .NET platform bindings.")
 | |
|     print("  --dotnet-key=<file>           sign the .NET assembly using the private key in <file>.")
 | |
|     print("  --assembly-version=<x.x.x.x>  provide version number for build")
 | |
|     print("  --java                        generate Java bindings.")
 | |
|     print("  --ml                          generate OCaml bindings.")
 | |
|     print("  --js                          generate JScript bindings.")
 | |
|     print("  --python                      generate Python bindings.")
 | |
|     print("  --staticlib                   build Z3 static library.")
 | |
|     print("  --staticbin                   build a statically linked Z3 binary.")
 | |
|     if not IS_WINDOWS:
 | |
|         print("  -g, --gmp                     use GMP.")
 | |
|         print("  --gprof                       enable gprof")
 | |
|     print("  --log-sync                    synchronize access to API log files to enable multi-thread API logging.")
 | |
|     print("  --single-threaded             non-thread-safe build")
 | |
|     print("")
 | |
|     print("Some influential environment variables:")
 | |
|     if not IS_WINDOWS:
 | |
|         print("  CXX        C++ compiler")
 | |
|         print("  CC         C compiler")
 | |
|         print("  LDFLAGS    Linker flags, e.g., -L<lib dir> if you have libraries in a non-standard directory")
 | |
|         print("  CPPFLAGS   Preprocessor flags, e.g., -I<include dir> if you have header files in a non-standard directory")
 | |
|         print("  CXXFLAGS   C++ compiler flags")
 | |
|     print("  JDK_HOME   JDK installation directory (only relevant if -j or --java option is provided)")
 | |
|     print("  JNI_HOME   JNI bindings directory (only relevant if -j or --java option is provided)")
 | |
|     print("  OCAMLC     Ocaml byte-code compiler (only relevant with --ml)")
 | |
|     print("  OCAMLFIND  Ocaml find tool (only relevant with --ml)")
 | |
|     print("  OCAMLOPT   Ocaml native compiler (only relevant with --ml)")
 | |
|     print("  OCAML_LIB  Ocaml library directory (only relevant with --ml)")
 | |
|     print("  Z3_INSTALL_BIN_DIR Install directory for binaries relative to install prefix")
 | |
|     print("  Z3_INSTALL_LIB_DIR Install directory for libraries relative to install prefix")
 | |
|     print("  Z3_INSTALL_INCLUDE_DIR Install directory for header files relative to install prefix")
 | |
|     print("  Z3_INSTALL_PKGCONFIG_DIR Install directory for pkgconfig files relative to install prefix")
 | |
|     exit(exit_code)
 | |
| 
 | |
| # Parse configuration option for mk_make script
 | |
| def parse_options():
 | |
|     global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
 | |
|     global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
 | |
|     global LINUX_X64, SLOW_OPTIMIZE, LOG_SYNC, SINGLE_THREADED
 | |
|     global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64
 | |
|     try:
 | |
|         options, remainder = getopt.gnu_getopt(sys.argv[1:],
 | |
|                                                'b:df:sxa:hmcvtnp:gj',
 | |
|                                                ['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'no-guardcf',
 | |
|                                                 'trace', 'dotnet', 'dotnet-key=', 'assembly-version=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js',
 | |
|                                                 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded'])
 | |
|     except:
 | |
|         print("ERROR: Invalid command line option")
 | |
|         display_help(1)
 | |
| 
 | |
|     for opt, arg in options:
 | |
|         print('opt = %s, arg = %s' % (opt, arg))
 | |
|         if opt in ('-b', '--build'):
 | |
|             if arg == 'src':
 | |
|                 raise MKException('The src directory should not be used to host the Makefile')
 | |
|             set_build_dir(arg)
 | |
|         elif opt in ('-s', '--silent'):
 | |
|             VERBOSE = False
 | |
|         elif opt in ('-d', '--debug'):
 | |
|             DEBUG_MODE = True
 | |
|         elif opt in ('-x', '--x64'):
 | |
|             if not IS_WINDOWS:
 | |
|                 raise MKException('x64 compilation mode can only be specified when using Visual Studio')
 | |
|             VS_X64 = True
 | |
|         elif opt in ('--x86'):
 | |
|             LINUX_X64=False
 | |
|         elif opt in ('--arm64'):
 | |
|             IS_ARCH_ARM64 = arg in ('true','on','True','TRUE')
 | |
|         elif opt in ('-h', '--help'):
 | |
|             display_help(0)
 | |
|         elif opt in ('-m', '--makefiles'):
 | |
|             ONLY_MAKEFILES = True
 | |
|         elif opt in ('-c', '--showcpp'):
 | |
|             SHOW_CPPS = True
 | |
|         elif opt in ('-v', '--vsproj'):
 | |
|             VS_PROJ = True
 | |
|         elif opt in ('-t', '--trace'):
 | |
|             TRACE = True
 | |
|         elif opt in ('--dotnet',):
 | |
|             DOTNET_CORE_ENABLED = True
 | |
|         elif opt in ('--dotnet-key'):
 | |
|             DOTNET_KEY_FILE = arg
 | |
|         elif opt in ('--assembly-version'):
 | |
|             ASSEMBLY_VERSION = arg
 | |
|         elif opt in ('--staticlib'):
 | |
|             STATIC_LIB = True
 | |
|         elif opt in ('--staticbin'):
 | |
|             STATIC_BIN = True
 | |
|         elif opt in ('--optimize'):
 | |
|             SLOW_OPTIMIZE = True
 | |
|         elif not IS_WINDOWS and opt in ('-p', '--prefix'):
 | |
|             PREFIX = arg
 | |
|         elif opt in ('--pypkgdir'):
 | |
|             PYTHON_PACKAGE_DIR = arg
 | |
|         elif IS_WINDOWS and opt == '--parallel':
 | |
|             VS_PAR = True
 | |
|             VS_PAR_NUM = int(arg)
 | |
|         elif opt in ('-g', '--gmp'):
 | |
|             GMP = True
 | |
|         elif opt in ('-j', '--java'):
 | |
|             JAVA_ENABLED = True
 | |
|         elif opt == '--gprof':
 | |
|             GPROF = True
 | |
|         elif opt == '--githash':
 | |
|             GIT_HASH=arg
 | |
|         elif opt == '--git-describe':
 | |
|             GIT_DESCRIBE = True
 | |
|         elif opt in ('', '--ml'):
 | |
|             ML_ENABLED = True
 | |
|         elif opt in ('', '--log-sync'):
 | |
|             LOG_SYNC = True
 | |
|         elif opt == '--single-threaded':
 | |
|             SINGLE_THREADED = True
 | |
|         elif opt in ('--python'):
 | |
|             PYTHON_ENABLED = True
 | |
|             PYTHON_INSTALL_ENABLED = True
 | |
|         elif opt == '--guardcf':
 | |
|             GUARD_CF = True
 | |
|         elif opt == '--no-guardcf':
 | |
|             GUARD_CF = False
 | |
|             # Note: ALWAYS_DYNAMIC_BASE can remain True if set elsewhere
 | |
|         else:
 | |
|             print("ERROR: Invalid command line option '%s'" % opt)
 | |
|             display_help(1)
 | |
| 
 | |
|     # Ensure ALWAYS_DYNAMIC_BASE is True whenever GUARD_CF is enabled
 | |
|     # This is required because /GUARD:CF linker option requires /DYNAMICBASE
 | |
|     if GUARD_CF:
 | |
|         ALWAYS_DYNAMIC_BASE = True
 | |
| 
 | |
| def validate_guard_cf_compatibility(final_cxxflags):
 | |
|     """Validate that Control Flow Guard is compatible with the final compiler options.
 | |
|     
 | |
|     Args:
 | |
|         final_cxxflags: The complete CXXFLAGS string that will be used for compilation
 | |
|     """
 | |
|     global GUARD_CF
 | |
|     
 | |
|     if not GUARD_CF or not IS_WINDOWS:
 | |
|         return
 | |
|     
 | |
|     # Check the final compiler flags for incompatible options
 | |
|     zi_pattern = re.compile(r'[/-]ZI\b')
 | |
|     if zi_pattern.search(final_cxxflags):
 | |
|         raise MKException("Control Flow Guard (/guard:cf) is incompatible with Edit and Continue debug information (/ZI or -ZI). Disable Control Flow Guard with --no-guardcf.")
 | |
|     
 | |
|     clr_pattern = re.compile(r'[/-]clr(?::|$|\s)')
 | |
|     if clr_pattern.search(final_cxxflags):
 | |
|         raise MKException("Control Flow Guard (/guard:cf) is incompatible with Common Language Runtime compilation (/clr or -clr). Disable Control Flow Guard with --no-guardcf when using managed code.")
 | |
|     
 | |
|     # Note: /Zi or -Zi (Program Database debug info) is compatible with /guard:cf
 | |
|     if is_verbose() and GUARD_CF:
 | |
|         print("Control Flow Guard enabled and compatible with current compiler options.")
 | |
| 
 | |
| 
 | |
| # Return a list containing a file names included using '#include' in
 | |
| # the given C/C++ file named fname.
 | |
| def extract_c_includes(fname):
 | |
|     result = {}
 | |
|     # We look for well behaved #include directives
 | |
|     std_inc_pat     = re.compile(r"[ \t]*#include[ \t]*\"(.*)\"[ \t]*")
 | |
|     system_inc_pat  = re.compile(r"[ \t]*#include[ \t]*\<.*\>[ \t]*")
 | |
|     # We should generate and error for any occurrence of #include that does not match the previous pattern.
 | |
|     non_std_inc_pat = re.compile(".*#include.*")
 | |
| 
 | |
|     f = io.open(fname, encoding='utf-8', mode='r')
 | |
|     linenum = 1
 | |
|     for line in f:
 | |
|         m1 = std_inc_pat.match(line)
 | |
|         if m1:
 | |
|             root_file_name = m1.group(1)
 | |
|             slash_pos =  root_file_name.rfind('/')
 | |
|             if slash_pos >= 0  and root_file_name.find("..") < 0 : #it is a hack for lp include files that behave as continued from "src"
 | |
|                 # print(root_file_name)
 | |
|                 root_file_name = root_file_name[slash_pos+1:]
 | |
|             result[root_file_name] = m1.group(1)
 | |
|         elif not system_inc_pat.match(line) and non_std_inc_pat.match(line):
 | |
|             raise MKException("Invalid #include directive at '%s':%s" % (fname, line))
 | |
|         linenum = linenum + 1
 | |
|     f.close()
 | |
|     return result
 | |
| 
 | |
| 
 | |
| # Given a path dir1/subdir2/subdir3 returns ../../..
 | |
| def reverse_path(p):
 | |
|     # Filter out empty components (e.g. will have one if path ends in a slash)
 | |
|     l = list(filter(lambda x: len(x) > 0, p.split(os.sep)))
 | |
|     n = len(l)
 | |
|     r = '..'
 | |
|     for i in range(1, n):
 | |
|         r = os.path.join(r, '..')
 | |
|     return r
 | |
| 
 | |
| def mk_dir(d):
 | |
|     if not os.path.exists(d):
 | |
|         os.makedirs(d)
 | |
| 
 | |
| def set_build_dir(d):
 | |
|     global BUILD_DIR, REV_BUILD_DIR
 | |
|     BUILD_DIR = norm_path(d)
 | |
|     REV_BUILD_DIR = reverse_path(d)
 | |
| 
 | |
| def set_z3py_dir(p):
 | |
|     global SRC_DIR, Z3PY_SRC_DIR
 | |
|     p = norm_path(p)
 | |
|     full = os.path.join(SRC_DIR, p)
 | |
|     if not os.path.exists(full):
 | |
|         raise MKException("Python bindings directory '%s' does not exist" % full)
 | |
|     Z3PY_SRC_DIR = full
 | |
|     if VERBOSE:
 | |
|         print("Python bindings directory was detected.")
 | |
| 
 | |
| _UNIQ_ID = 0
 | |
| 
 | |
| def mk_fresh_name(prefix):
 | |
|     global _UNIQ_ID
 | |
|     r = '%s_%s' % (prefix, _UNIQ_ID)
 | |
|     _UNIQ_ID = _UNIQ_ID + 1
 | |
|     return r
 | |
| 
 | |
| _Id = 0
 | |
| _Components = []
 | |
| _ComponentNames = set()
 | |
| _Name2Component = {}
 | |
| _Processed_Headers = set()
 | |
| 
 | |
| # Return the Component object named name
 | |
| def get_component(name):
 | |
|     return _Name2Component[name]
 | |
| 
 | |
| def get_components():
 | |
|     return _Components
 | |
| 
 | |
| # Return the directory where the python bindings are located.
 | |
| def get_z3py_dir():
 | |
|     return Z3PY_SRC_DIR
 | |
| 
 | |
| 
 | |
| # Return true if in verbose mode
 | |
| def is_verbose():
 | |
|     return VERBOSE
 | |
| 
 | |
| def is_java_enabled():
 | |
|     return JAVA_ENABLED
 | |
| 
 | |
| def is_ml_enabled():
 | |
|     return ML_ENABLED
 | |
| 
 | |
| def is_dotnet_core_enabled():
 | |
|     return DOTNET_CORE_ENABLED
 | |
| 
 | |
| def is_python_enabled():
 | |
|     return PYTHON_ENABLED
 | |
| 
 | |
| def is_python_install_enabled():
 | |
|     return PYTHON_INSTALL_ENABLED
 | |
| 
 | |
| def is_compiler(given, expected):
 | |
|     """
 | |
|     Return True if the 'given' compiler is the expected one.
 | |
|     >>> is_compiler('g++', 'g++')
 | |
|     True
 | |
|     >>> is_compiler('/home/g++', 'g++')
 | |
|     True
 | |
|     >>> is_compiler(os.path.join('home', 'g++'), 'g++')
 | |
|     True
 | |
|     >>> is_compiler('clang++', 'g++')
 | |
|     False
 | |
|     >>> is_compiler(os.path.join('home', 'clang++'), 'clang++')
 | |
|     True
 | |
|     """
 | |
|     if given == expected:
 | |
|         return True
 | |
|     if len(expected) < len(given):
 | |
|         return given[len(given) - len(expected) - 1] == os.sep and given[len(given) - len(expected):] == expected
 | |
|     return False
 | |
| 
 | |
| def is_CXX_gpp():
 | |
|     return is_compiler(CXX, 'g++')
 | |
| 
 | |
| def is_clang_in_gpp_form(cc):
 | |
|     str = check_output([cc, '--version'])
 | |
|     try:
 | |
|        version_string = str.encode('utf-8')
 | |
|     except:
 | |
|        version_string = str
 | |
|     clang = 'clang'.encode('utf-8')
 | |
|     return version_string.find(clang) != -1
 | |
| 
 | |
| def is_CXX_clangpp():
 | |
|     if is_compiler(CXX, 'g++'):
 | |
|         return is_clang_in_gpp_form(CXX)
 | |
|     return is_compiler(CXX, 'clang++')
 | |
| 
 | |
| def get_files_with_ext(path, ext):
 | |
|     return filter(lambda f: f.endswith(ext), os.listdir(path))
 | |
| 
 | |
| def get_cpp_files(path):
 | |
|     return get_files_with_ext(path,'.cpp')
 | |
| 
 | |
| def get_c_files(path):
 | |
|     return get_files_with_ext(path,'.c')
 | |
| 
 | |
| def get_cs_files(path):
 | |
|     return get_files_with_ext(path,'.cs')
 | |
| 
 | |
| def get_java_files(path):
 | |
|     return get_files_with_ext(path,'.java')
 | |
| 
 | |
| def get_ml_files(path):
 | |
|     return get_files_with_ext(path,'.ml')
 | |
| 
 | |
| def find_all_deps(name, deps):
 | |
|     new_deps = []
 | |
|     for dep in deps:
 | |
|         if dep in _ComponentNames:
 | |
|             if not (dep in new_deps):
 | |
|                 new_deps.append(dep)
 | |
|             for dep_dep in get_component(dep).deps:
 | |
|                 if not (dep_dep in new_deps):
 | |
|                     new_deps.append(dep_dep)
 | |
|         else:
 | |
|             raise MKException("Unknown component '%s' at '%s'." % (dep, name))
 | |
|     return new_deps
 | |
| 
 | |
| class Component:
 | |
|     def __init__(self, name, path, deps):
 | |
|         global BUILD_DIR, SRC_DIR, REV_BUILD_DIR
 | |
|         if name in _ComponentNames:
 | |
|             raise MKException("Component '%s' was already defined." % name)
 | |
|         if path is None:
 | |
|             path = name
 | |
|         self.name = name
 | |
|         path = norm_path(path)
 | |
|         self.path = path
 | |
|         self.deps = find_all_deps(name, deps)
 | |
|         self.build_dir = path
 | |
|         self.src_dir   = os.path.join(SRC_DIR, path)
 | |
|         self.to_src_dir = os.path.join(REV_BUILD_DIR, self.src_dir)
 | |
| 
 | |
|     def get_link_name(self):
 | |
|         return os.path.join(self.build_dir, self.name) + '$(LIB_EXT)'
 | |
| 
 | |
| 
 | |
|     # Find fname in the include paths for the given component.
 | |
|     # ownerfile is only used for creating error messages.
 | |
|     # That is, we were looking for fname when processing ownerfile
 | |
|     def find_file(self, fname, ownerfile, orig_include=None):
 | |
|         full_fname = os.path.join(self.src_dir, fname)
 | |
| 
 | |
|         # Store all our possible locations
 | |
|         possibilities = set()
 | |
| 
 | |
|         # If the our file exists in the current directory, then we store it
 | |
|         if os.path.exists(full_fname):
 | |
| 
 | |
|             # We cannot return here, as we might have files with the same
 | |
|             # basename, but different include paths
 | |
|             possibilities.add(self)
 | |
| 
 | |
|         for dep in self.deps:
 | |
|             c_dep = get_component(dep)
 | |
|             full_fname = os.path.join(c_dep.src_dir, fname)
 | |
|             if os.path.exists(full_fname):
 | |
|                 possibilities.add(c_dep)
 | |
| 
 | |
|         if possibilities:
 | |
| 
 | |
|             # We have ambiguity
 | |
|             if len(possibilities) > 1:
 | |
| 
 | |
|                 # We expect orig_path to be non-None here, so we can disambiguate
 | |
|                 assert orig_include is not None
 | |
| 
 | |
|                 # Get the original directory name
 | |
|                 orig_dir = os.path.dirname(orig_include)
 | |
| 
 | |
|                 # Iterate through all of the possibilities
 | |
|                 for possibility in possibilities:
 | |
| 
 | |
|                     path = possibility.path.replace("\\","/")
 | |
|                     # If we match the suffix of the path ...
 | |
|                     if path.endswith(orig_dir):
 | |
| 
 | |
|                         # ... use our new match
 | |
|                         return possibility
 | |
| 
 | |
|             # This means we didn't make an exact match ...
 | |
|             #
 | |
|             # We return any one possibility, just to ensure we don't break Z3's
 | |
|             # builds
 | |
|             return possibilities.pop()
 | |
| 
 | |
|         raise MKException("Failed to find include file '%s' for '%s' when processing '%s'." % (fname, ownerfile, self.name))
 | |
| 
 | |
|     # Display all dependencies of file basename located in the given component directory.
 | |
|     # The result is displayed at out
 | |
|     def add_cpp_h_deps(self, out, basename):
 | |
|         includes = extract_c_includes(os.path.join(self.src_dir, basename))
 | |
|         out.write(os.path.join(self.to_src_dir, basename))
 | |
|         for include, orig_include in includes.items():
 | |
|             owner = self.find_file(include, basename, orig_include)
 | |
|             out.write(' %s.node' % os.path.join(owner.build_dir, include))
 | |
| 
 | |
|     # Add a rule for each #include directive in the file basename located at the current component.
 | |
|     def add_rule_for_each_include(self, out, basename):
 | |
|         fullname = os.path.join(self.src_dir, basename)
 | |
|         includes = extract_c_includes(fullname)
 | |
|         for include, orig_include in includes.items():
 | |
|             owner = self.find_file(include, fullname, orig_include)
 | |
|             owner.add_h_rule(out, include)
 | |
| 
 | |
|     # Display a Makefile rule for an include file located in the given component directory.
 | |
|     # 'include' is something of the form: ast.h, polynomial.h
 | |
|     # The rule displayed at out is of the form
 | |
|     #     ast/ast_pp.h.node : ../src/util/ast_pp.h util/util.h.node ast/ast.h.node
 | |
|     #       @echo "done" > ast/ast_pp.h.node
 | |
|     def add_h_rule(self, out, include):
 | |
|         include_src_path   = os.path.join(self.to_src_dir, include)
 | |
|         if include_src_path in _Processed_Headers:
 | |
|             return
 | |
|         _Processed_Headers.add(include_src_path)
 | |
|         self.add_rule_for_each_include(out, include)
 | |
|         include_node = '%s.node' % os.path.join(self.build_dir, include)
 | |
|         out.write('%s: ' % include_node)
 | |
|         self.add_cpp_h_deps(out, include)
 | |
|         out.write('\n')
 | |
|         out.write('\t@echo done > %s\n' % include_node)
 | |
| 
 | |
|     def add_cpp_rules(self, out, include_defs, cppfile):
 | |
|         self.add_rule_for_each_include(out, cppfile)
 | |
|         objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
 | |
|         srcfile = os.path.join(self.to_src_dir, cppfile)
 | |
|         out.write('%s: ' % objfile)
 | |
|         self.add_cpp_h_deps(out, cppfile)
 | |
|         out.write('\n')
 | |
|         if SHOW_CPPS:
 | |
|             out.write('\t@echo %s\n' % os.path.join(self.src_dir, cppfile))
 | |
|         out.write('\t@$(CXX) $(CXXFLAGS) $(%s) $(CXX_OUT_FLAG)%s %s\n' % (include_defs, objfile, srcfile))
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         include_defs = mk_fresh_name('includes')
 | |
|         out.write('%s =' % include_defs)
 | |
|         for dep in self.deps:
 | |
|             out.write(' -I%s' % get_component(dep).to_src_dir)
 | |
|         out.write(' -I%s' % os.path.join(REV_BUILD_DIR,"src"))
 | |
|         out.write('\n')
 | |
|         mk_dir(os.path.join(BUILD_DIR, self.build_dir))
 | |
|         if VS_PAR and IS_WINDOWS:
 | |
|             cppfiles = list(get_cpp_files(self.src_dir))
 | |
|             dependencies = set()
 | |
|             for cppfile in cppfiles:
 | |
|                 dependencies.add(os.path.join(self.to_src_dir, cppfile))
 | |
|                 self.add_rule_for_each_include(out, cppfile)
 | |
|                 includes = extract_c_includes(os.path.join(self.src_dir, cppfile))
 | |
|                 for include, orig_include in includes.items():
 | |
|                     owner = self.find_file(include, cppfile, orig_include)
 | |
|                     dependencies.add('%s.node' % os.path.join(owner.build_dir, include))
 | |
|             for cppfile in cppfiles:
 | |
|                 out.write('%s$(OBJ_EXT) ' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0]))
 | |
|             out.write(': ')
 | |
|             for dep in dependencies:
 | |
|                 out.write(dep)
 | |
|                 out.write(' ')
 | |
|             out.write('\n')
 | |
|             out.write('\t@$(CXX) $(CXXFLAGS) /MP%s $(%s)' % (VS_PAR_NUM, include_defs))
 | |
|             for cppfile in cppfiles:
 | |
|                 out.write(' ')
 | |
|                 out.write(os.path.join(self.to_src_dir, cppfile))
 | |
|             out.write('\n')
 | |
|             out.write('\tmove *.obj %s\n' % self.build_dir)
 | |
|         else:
 | |
|             for cppfile in get_cpp_files(self.src_dir):
 | |
|                 self.add_cpp_rules(out, include_defs, cppfile)
 | |
| 
 | |
|     # Return true if the component should be included in the all: rule
 | |
|     def main_component(self):
 | |
|         return False
 | |
| 
 | |
|     # Return true if the component contains an AssemblyInfo.cs file that needs to be updated.
 | |
|     def has_assembly_info(self):
 | |
|         return False
 | |
| 
 | |
|     # Return true if the component needs builder to generate an install_tactics.cpp file
 | |
|     def require_install_tactics(self):
 | |
|         return False
 | |
| 
 | |
|     # Return true if the component needs a def file
 | |
|     def require_def_file(self):
 | |
|         return False
 | |
| 
 | |
|     # Return true if the component needs builder to generate a mem_initializer.cpp file with mem_initialize() and mem_finalize() functions.
 | |
|     def require_mem_initializer(self):
 | |
|         return False
 | |
| 
 | |
|     def mk_install_deps(self, out):
 | |
|         return
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         return
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         return
 | |
| 
 | |
|     def is_example(self):
 | |
|         return False
 | |
| 
 | |
|     # Invoked when creating a (windows) distribution package using components at build_path, and
 | |
|     # storing them at dist_path
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         return
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         return
 | |
| 
 | |
|     # Used to print warnings or errors after mk_make.py is done, so that they
 | |
|     # are not quite as easy to miss.
 | |
|     def final_info(self):
 | |
|         pass
 | |
| 
 | |
| class LibComponent(Component):
 | |
|     def __init__(self, name, path, deps, includes2install):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         self.includes2install = includes2install
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         Component.mk_makefile(self, out)
 | |
|         # generate rule for lib
 | |
|         objs = []
 | |
|         for cppfile in get_cpp_files(self.src_dir):
 | |
|             objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
 | |
|             objs.append(objfile)
 | |
| 
 | |
|         libfile = '%s$(LIB_EXT)' % os.path.join(self.build_dir, self.name)
 | |
|         out.write('%s:' % libfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         out.write('\n')
 | |
|         out.write('\t@$(AR) $(AR_FLAGS) $(AR_OUTFLAG)%s' % libfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         out.write('\n')
 | |
|         out.write('%s: %s\n\n' % (self.name, libfile))
 | |
| 
 | |
|     def mk_install_deps(self, out):
 | |
|         return
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         for include in self.includes2install:
 | |
|             MakeRuleCmd.install_files(
 | |
|                 out,
 | |
|                 os.path.join(self.to_src_dir, include),
 | |
|                 os.path.join(INSTALL_INCLUDE_DIR, include)
 | |
|             )
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         for include in self.includes2install:
 | |
|             MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_INCLUDE_DIR, include))
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         mk_dir(os.path.join(dist_path, INSTALL_INCLUDE_DIR))
 | |
|         for include in self.includes2install:
 | |
|             shutil.copy(os.path.join(self.src_dir, include),
 | |
|                         os.path.join(dist_path, INSTALL_INCLUDE_DIR, include))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         self.mk_win_dist(build_path, dist_path)
 | |
| 
 | |
| # "Library" containing only .h files. This is just a placeholder for includes files to be installed.
 | |
| class HLibComponent(LibComponent):
 | |
|     def __init__(self, name, path, includes2install):
 | |
|         LibComponent.__init__(self, name, path, [], includes2install)
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         return
 | |
| 
 | |
| # Auxiliary function for sort_components
 | |
| def comp_components(c1, c2):
 | |
|     id1 = get_component(c1).id
 | |
|     id2 = get_component(c2).id
 | |
|     return id2 - id1
 | |
| 
 | |
| # Sort components based on (reverse) definition time
 | |
| def sort_components(cnames):
 | |
|     return sorted(cnames, key=lambda c: get_component(c).id, reverse=True)
 | |
| 
 | |
| class ExeComponent(Component):
 | |
|     def __init__(self, name, exe_name, path, deps, install):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         if exe_name is None:
 | |
|             exe_name = name
 | |
|         self.exe_name = exe_name
 | |
|         self.install = install
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         Component.mk_makefile(self, out)
 | |
|         # generate rule for exe
 | |
| 
 | |
|         exefile = '%s$(EXE_EXT)' % self.exe_name
 | |
|         out.write('%s:' % exefile)
 | |
|         deps = sort_components(self.deps)
 | |
|         objs = []
 | |
|         for cppfile in get_cpp_files(self.src_dir):
 | |
|             objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
 | |
|             objs.append(objfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         for dep in deps:
 | |
|             c_dep = get_component(dep)
 | |
|             out.write(' ' + c_dep.get_link_name())
 | |
|         out.write('\n')
 | |
|         extra_opt = '-static' if not IS_WINDOWS and STATIC_BIN else ''
 | |
|         out.write('\t$(LINK) %s $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (extra_opt, exefile))
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         for dep in deps:
 | |
|             c_dep = get_component(dep)
 | |
|             out.write(' ' + c_dep.get_link_name())
 | |
|         out.write(' $(LINK_EXTRA_FLAGS)\n')
 | |
|         out.write('%s: %s\n\n' % (self.name, exefile))
 | |
| 
 | |
|     def require_install_tactics(self):
 | |
|         return ('tactic' in self.deps) and ('cmd_context' in self.deps)
 | |
| 
 | |
|     def require_mem_initializer(self):
 | |
|         return True
 | |
| 
 | |
|     # All executables (to be installed) are included in the all: rule
 | |
|     def main_component(self):
 | |
|         return self.install
 | |
| 
 | |
|     def mk_install_deps(self, out):
 | |
|         if self.install:
 | |
|             exefile = '%s$(EXE_EXT)' % self.exe_name
 | |
|             out.write('%s' % exefile)
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         if self.install:
 | |
|             exefile = '%s$(EXE_EXT)' % self.exe_name
 | |
|             MakeRuleCmd.install_files(out, exefile, os.path.join(INSTALL_BIN_DIR, exefile))
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         if self.install:
 | |
|             exefile = '%s$(EXE_EXT)' % self.exe_name
 | |
|             MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_BIN_DIR, exefile))
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         if self.install:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.exe' % os.path.join(build_path, self.exe_name),
 | |
|                         '%s.exe' % os.path.join(dist_path, INSTALL_BIN_DIR, self.exe_name))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         if self.install:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy(os.path.join(build_path, self.exe_name),
 | |
|                         os.path.join(dist_path, INSTALL_BIN_DIR, self.exe_name))
 | |
| 
 | |
| 
 | |
| class ExtraExeComponent(ExeComponent):
 | |
|     def __init__(self, name, exe_name, path, deps, install):
 | |
|         ExeComponent.__init__(self, name, exe_name, path, deps, install)
 | |
| 
 | |
|     def main_component(self):
 | |
|         return False
 | |
| 
 | |
|     def require_mem_initializer(self):
 | |
|         return False
 | |
| 
 | |
| def get_so_ext():
 | |
|     sysname = os.uname()[0]
 | |
|     if sysname == 'Darwin':
 | |
|         return 'dylib'
 | |
|     elif sysname == 'Linux' or sysname == 'GNU' or sysname == 'FreeBSD' or sysname == 'NetBSD' or sysname == 'OpenBSD':
 | |
|         return 'so'
 | |
|     elif sysname == 'CYGWIN' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'):
 | |
|         return 'dll'
 | |
|     else:
 | |
|         assert(False)
 | |
|         return 'dll'
 | |
| 
 | |
| class DLLComponent(Component):
 | |
|     def __init__(self, name, dll_name, path, deps, export_files, reexports, install, static, staging_link=None):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         if dll_name is None:
 | |
|             dll_name = name
 | |
|         self.dll_name = dll_name
 | |
|         self.export_files = export_files
 | |
|         self.reexports = reexports
 | |
|         self.install = install
 | |
|         self.static = static
 | |
|         self.staging_link = staging_link    # link a copy of the shared object into this directory on build
 | |
| 
 | |
|     def get_link_name(self):
 | |
|         if self.static:
 | |
|             return os.path.join(self.build_dir, self.name) + '$(LIB_EXT)'
 | |
|         else:
 | |
|             return self.name + '$(SO_EXT)'
 | |
| 
 | |
|     def dll_file(self):
 | |
|         """
 | |
|             Return file name of component suitable for use in a Makefile
 | |
|         """
 | |
|         return '%s$(SO_EXT)' % self.dll_name
 | |
| 
 | |
|     def install_path(self):
 | |
|         """
 | |
|             Return install location of component (relative to prefix)
 | |
|             suitable for use in a Makefile
 | |
|         """
 | |
|         return os.path.join(INSTALL_LIB_DIR, self.dll_file())
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         Component.mk_makefile(self, out)
 | |
|         # generate rule for (SO_EXT)
 | |
|         out.write('%s:' % self.dll_file())
 | |
|         deps = sort_components(self.deps)
 | |
|         objs = []
 | |
|         for cppfile in get_cpp_files(self.src_dir):
 | |
|             objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
 | |
|             objs.append(objfile)
 | |
|         # Explicitly include obj files of reexport. This fixes problems with exported symbols on Linux and OSX.
 | |
|         for reexport in self.reexports:
 | |
|             reexport = get_component(reexport)
 | |
|             for cppfile in get_cpp_files(reexport.src_dir):
 | |
|                 objfile = '%s$(OBJ_EXT)' % os.path.join(reexport.build_dir, os.path.splitext(cppfile)[0])
 | |
|                 objs.append(objfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         for dep in deps:
 | |
|             if dep not in self.reexports:
 | |
|                 c_dep = get_component(dep)
 | |
|                 out.write(' ' + c_dep.get_link_name())
 | |
|         out.write('\n')
 | |
|         out.write('\t$(LINK) $(SLINK_OUT_FLAG)%s $(SLINK_FLAGS)' % self.dll_file())
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         for dep in deps:
 | |
|             if dep not in self.reexports:
 | |
|                 c_dep = get_component(dep)
 | |
|                 out.write(' ' + c_dep.get_link_name())
 | |
|         out.write(' $(SLINK_EXTRA_FLAGS)')
 | |
|         if IS_WINDOWS:
 | |
|             out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
 | |
|         if self.staging_link:
 | |
|             if IS_WINDOWS:
 | |
|                 out.write('\n\tcopy %s %s' % (self.dll_file(), self.staging_link))
 | |
|             elif IS_OSX:
 | |
|                 out.write('\n\tcp %s %s' % (self.dll_file(), self.staging_link))
 | |
|             else:
 | |
|                 out.write('\n\tln -f -s %s %s' % (os.path.join(reverse_path(self.staging_link), self.dll_file()), self.staging_link))
 | |
|         out.write('\n')
 | |
|         if self.static:
 | |
|             if IS_WINDOWS:
 | |
|                 libfile = '%s-static$(LIB_EXT)' % self.dll_name
 | |
|             else:
 | |
|                 libfile = '%s$(LIB_EXT)' % self.dll_name
 | |
|             self.mk_static(out, libfile)
 | |
|             out.write('%s: %s %s\n\n' % (self.name, self.dll_file(), libfile))
 | |
|         else:
 | |
|             out.write('%s: %s\n\n' % (self.name, self.dll_file()))
 | |
| 
 | |
|     def mk_static(self, out, libfile):
 | |
|         # generate rule for lib
 | |
|         objs = []
 | |
|         for cppfile in get_cpp_files(self.src_dir):
 | |
|             objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
 | |
|             objs.append(objfile)
 | |
|         # we have to "reexport" all object files
 | |
|         for dep in self.deps:
 | |
|             dep = get_component(dep)
 | |
|             for cppfile in get_cpp_files(dep.src_dir):
 | |
|                 objfile = '%s$(OBJ_EXT)' % os.path.join(dep.build_dir, os.path.splitext(cppfile)[0])
 | |
|                 objs.append(objfile)
 | |
|         out.write('%s:' % libfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         out.write('\n')
 | |
|         out.write('\t@$(AR) $(AR_FLAGS) $(AR_OUTFLAG)%s' % libfile)
 | |
|         for obj in objs:
 | |
|             out.write(' ')
 | |
|             out.write(obj)
 | |
|         out.write('\n')
 | |
| 
 | |
|     def main_component(self):
 | |
|         return self.install
 | |
| 
 | |
|     def require_install_tactics(self):
 | |
|         return ('tactic' in self.deps) and ('cmd_context' in self.deps)
 | |
| 
 | |
|     def require_mem_initializer(self):
 | |
|         return True
 | |
| 
 | |
|     def require_def_file(self):
 | |
|         return IS_WINDOWS and self.export_files
 | |
| 
 | |
|     def mk_install_deps(self, out):
 | |
|         out.write('%s$(SO_EXT)' % self.dll_name)
 | |
|         if self.static:
 | |
|             out.write(' %s$(LIB_EXT)' % self.dll_name)
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         if self.install:
 | |
|             MakeRuleCmd.install_files(out, self.dll_file(), self.install_path())
 | |
|             if self.static:
 | |
|                 libfile = '%s$(LIB_EXT)' % self.dll_name
 | |
|                 MakeRuleCmd.install_files(out, libfile, os.path.join(INSTALL_LIB_DIR, libfile))
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         MakeRuleCmd.remove_installed_files(out, self.install_path())
 | |
|         libfile = '%s$(LIB_EXT)' % self.dll_name
 | |
|         MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_LIB_DIR, libfile))
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         if self.install:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.lib' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.lib' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         if self.install:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             so = get_so_ext()
 | |
|             shutil.copy('%s.%s' % (os.path.join(build_path, self.dll_name), so),
 | |
|                         '%s.%s' % (os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name), so))
 | |
|             shutil.copy('%s.a' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
| 
 | |
| class JsComponent(Component):
 | |
|     def __init__(self):
 | |
|          Component.__init__(self, "js", None, [])
 | |
| 
 | |
|     def main_component(self):
 | |
|         return False
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         return
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         return
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         return
 | |
| 
 | |
| class PythonComponent(Component):
 | |
|     def __init__(self, name, libz3Component):
 | |
|         assert isinstance(libz3Component, DLLComponent)
 | |
|         global PYTHON_ENABLED
 | |
|         Component.__init__(self, name, None, [])
 | |
|         self.libz3Component = libz3Component
 | |
| 
 | |
|     def main_component(self):
 | |
|         return False
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         if not is_python_enabled():
 | |
|             return
 | |
| 
 | |
|         src = os.path.join(build_path, 'python', 'z3')
 | |
|         dst = os.path.join(dist_path, INSTALL_BIN_DIR, 'python', 'z3')
 | |
|         if os.path.exists(dst):
 | |
|             shutil.rmtree(dst)
 | |
|         shutil.copytree(src, dst)
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         self.mk_win_dist(build_path, dist_path)
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         return
 | |
| 
 | |
| class PythonInstallComponent(Component):
 | |
|     def __init__(self, name, libz3Component):
 | |
|         assert isinstance(libz3Component, DLLComponent)
 | |
|         global PYTHON_INSTALL_ENABLED
 | |
|         Component.__init__(self, name, None, [])
 | |
|         self.pythonPkgDir = None
 | |
|         self.in_prefix_install = True
 | |
|         self.libz3Component = libz3Component
 | |
| 
 | |
|         if not PYTHON_INSTALL_ENABLED:
 | |
|             return
 | |
| 
 | |
|         if IS_WINDOWS:
 | |
|             # Installing under Windows doesn't make sense as the install prefix is used
 | |
|             # but that doesn't make sense under Windows
 | |
|             # CMW: It makes perfectly good sense; the prefix is Python's sys.prefix,
 | |
|             # i.e., something along the lines of C:\Python\... At the moment we are not
 | |
|             # sure whether we would want to install libz3.dll into that directory though.
 | |
|             PYTHON_INSTALL_ENABLED = False
 | |
|             return
 | |
|         else:
 | |
|             PYTHON_INSTALL_ENABLED = True
 | |
| 
 | |
|         if IS_WINDOWS or IS_OSX:
 | |
|             # Use full path that is possibly outside of install prefix
 | |
|             self.in_prefix_install = PYTHON_PACKAGE_DIR.startswith(PREFIX)
 | |
|             self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX)
 | |
|         else:
 | |
|             # Use path inside the prefix (should be the normal case on Linux)
 | |
|             # CMW: Also normal on *BSD?
 | |
|             if not PYTHON_PACKAGE_DIR.startswith(PREFIX):
 | |
|                 raise MKException(('The python package directory ({}) must live ' +
 | |
|                     'under the install prefix ({}) to install the python bindings.' +
 | |
|                     'Use --pypkgdir and --prefix to set the python package directory ' +
 | |
|                     'and install prefix respectively. Note that the python package ' +
 | |
|                     'directory does not need to exist and will be created if ' +
 | |
|                     'necessary during install.').format(
 | |
|                         PYTHON_PACKAGE_DIR,
 | |
|                         PREFIX))
 | |
|             self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX)
 | |
|             self.in_prefix_install = True
 | |
| 
 | |
|         if self.in_prefix_install:
 | |
|             assert not os.path.isabs(self.pythonPkgDir)
 | |
| 
 | |
|     def final_info(self):
 | |
|         if not PYTHON_PACKAGE_DIR.startswith(PREFIX) and PYTHON_INSTALL_ENABLED:
 | |
|             print("Warning: The detected Python package directory (%s) is not "
 | |
|                   "in the installation prefix (%s). This can lead to a broken "
 | |
|                   "Python API installation. Use --pypkgdir= to change the "
 | |
|                   "Python package directory." % (PYTHON_PACKAGE_DIR, PREFIX))
 | |
| 
 | |
|     def main_component(self):
 | |
|         return False
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         if not is_python_install_enabled():
 | |
|             return
 | |
|         MakeRuleCmd.make_install_directory(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3'),
 | |
|                                            in_prefix=self.in_prefix_install)
 | |
|         MakeRuleCmd.make_install_directory(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3', 'lib'),
 | |
|                                            in_prefix=self.in_prefix_install)
 | |
| 
 | |
|         # Sym-link or copy libz3 into python package directory
 | |
|         if IS_WINDOWS or IS_OSX:
 | |
|             MakeRuleCmd.install_files(out,
 | |
|                                       self.libz3Component.dll_file(),
 | |
|                                       os.path.join(self.pythonPkgDir, 'z3', 'lib',
 | |
|                                                    self.libz3Component.dll_file()),
 | |
|                                       in_prefix=self.in_prefix_install
 | |
|                                      )
 | |
|         else:
 | |
|             # Create symbolic link to save space.
 | |
|             # It's important that this symbolic link be relative (rather
 | |
|             # than absolute) so that the install is relocatable (needed for
 | |
|             # staged installs that use DESTDIR).
 | |
|             MakeRuleCmd.create_relative_symbolic_link(out,
 | |
|                                                       self.libz3Component.install_path(),
 | |
|                                                       os.path.join(self.pythonPkgDir, 'z3', 'lib',
 | |
|                                                                    self.libz3Component.dll_file()
 | |
|                                                                   ),
 | |
|                                                      )
 | |
| 
 | |
|         MakeRuleCmd.install_files(out, os.path.join('python', 'z3', '*.py'),
 | |
|                                   os.path.join(self.pythonPkgDir, 'z3'),
 | |
|                                   in_prefix=self.in_prefix_install)
 | |
|         if sys.version >= "3":
 | |
|             pythonPycacheDir = os.path.join(self.pythonPkgDir, 'z3', '__pycache__')
 | |
|             MakeRuleCmd.make_install_directory(out,
 | |
|                                                pythonPycacheDir,
 | |
|                                                in_prefix=self.in_prefix_install)
 | |
|             MakeRuleCmd.install_files(out,
 | |
|                                       os.path.join('python', 'z3', '__pycache__', '*.pyc'),
 | |
|                                       pythonPycacheDir,
 | |
|                                       in_prefix=self.in_prefix_install)
 | |
|         else:
 | |
|             MakeRuleCmd.install_files(out,
 | |
|                                       os.path.join('python', 'z3', '*.pyc'),
 | |
|                                       os.path.join(self.pythonPkgDir,'z3'),
 | |
|                                       in_prefix=self.in_prefix_install)
 | |
| 
 | |
|         if PYTHON_PACKAGE_DIR != sysconfig.get_path('purelib'):
 | |
|             out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR)
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         if not is_python_install_enabled():
 | |
|             return
 | |
|         MakeRuleCmd.remove_installed_files(out,
 | |
|                                            os.path.join(self.pythonPkgDir,
 | |
|                                                         self.libz3Component.dll_file()),
 | |
|                                            in_prefix=self.in_prefix_install
 | |
|                                           )
 | |
|         MakeRuleCmd.remove_installed_files(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3', '*.py'),
 | |
|                                            in_prefix=self.in_prefix_install)
 | |
|         MakeRuleCmd.remove_installed_files(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3', '*.pyc'),
 | |
|                                            in_prefix=self.in_prefix_install)
 | |
|         MakeRuleCmd.remove_installed_files(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3', '__pycache__', '*.pyc'),
 | |
|                                            in_prefix=self.in_prefix_install
 | |
|                                           )
 | |
|         MakeRuleCmd.remove_installed_files(out,
 | |
|                                            os.path.join(self.pythonPkgDir, 'z3', 'lib',
 | |
|                                                         self.libz3Component.dll_file()))
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         return
 | |
| 
 | |
| def set_key_file(self):
 | |
|     global DOTNET_KEY_FILE
 | |
|     # We need to give the assembly a strong name so that it
 | |
|     # can be installed into the GAC with ``make install``
 | |
|     if not DOTNET_KEY_FILE is None:
 | |
|        self.key_file = DOTNET_KEY_FILE
 | |
| 
 | |
|     if not self.key_file is None:
 | |
|        if os.path.isfile(self.key_file):
 | |
|            self.key_file = os.path.abspath(self.key_file)
 | |
|        elif os.path.isfile(os.path.join(self.src_dir, self.key_file)):
 | |
|            self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file))
 | |
|        else:
 | |
|            print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name))
 | |
|            self.key_file = None
 | |
| 
 | |
| 
 | |
| # build for dotnet core
 | |
| class DotNetDLLComponent(Component):
 | |
|     def __init__(self, name, dll_name, path, deps, assembly_info_dir, default_key_file):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         if dll_name is None:
 | |
|             dll_name = name
 | |
|         if assembly_info_dir is None:
 | |
|             assembly_info_dir = "."
 | |
|         self.dll_name          = dll_name
 | |
|         self.assembly_info_dir = assembly_info_dir
 | |
|         self.key_file = default_key_file
 | |
| 
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         if not is_dotnet_core_enabled():
 | |
|             return
 | |
|         cs_fp_files = []
 | |
|         for cs_file in get_cs_files(self.src_dir):
 | |
|             cs_fp_files.append(os.path.join(self.to_src_dir, cs_file))
 | |
|         if self.assembly_info_dir != '.':
 | |
|             for cs_file in get_cs_files(os.path.join(self.src_dir, self.assembly_info_dir)):
 | |
|                 cs_fp_files.append(os.path.join(self.to_src_dir, self.assembly_info_dir, cs_file))
 | |
|         dllfile = '%s.dll' % self.dll_name
 | |
|         out.write('%s: %s$(SO_EXT)' % (dllfile, get_component(Z3_DLL_COMPONENT).dll_name))
 | |
|         for cs_file in cs_fp_files:
 | |
|             out.write(' ')
 | |
|             out.write(cs_file)
 | |
|         out.write('\n')
 | |
| 
 | |
|         set_key_file(self)
 | |
|         key = ""
 | |
|         if not self.key_file is None:
 | |
|             key = "<AssemblyOriginatorKeyFile>%s</AssemblyOriginatorKeyFile>" % self.key_file
 | |
|             key += "\n<SignAssembly>true</SignAssembly>"
 | |
| 
 | |
|         version = get_version_string(4)
 | |
| 
 | |
|         print("Version output to csproj:", version)
 | |
| 
 | |
|         core_csproj_str = r"""<Project Sdk="Microsoft.NET.Sdk">
 | |
| 
 | |
|   <PropertyGroup>
 | |
|     <TargetFramework>netstandard1.4</TargetFramework>
 | |
|     <LangVersion>8.0</LangVersion>
 | |
|     <DefineConstants>$(DefineConstants);DOTNET_CORE</DefineConstants>
 | |
|     <DebugType>full</DebugType>
 | |
|     <AssemblyName>Microsoft.Z3</AssemblyName>
 | |
|     <OutputType>Library</OutputType>
 | |
|     <PackageId>Microsoft.Z3</PackageId>
 | |
|     <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | |
|     <RuntimeFrameworkVersion>1.0.4</RuntimeFrameworkVersion>
 | |
|     <Version>%s</Version>
 | |
|     <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | |
|     <Authors>Microsoft</Authors>
 | |
|     <Company>Microsoft</Company>
 | |
|     <PackageReadmeFile>README.md</PackageReadmeFile>
 | |
|     <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
 | |
|     <Description>Z3 is a satisfiability modulo theories solver from Microsoft Research.</Description>
 | |
|     <Copyright>Copyright Microsoft Corporation. All rights reserved.</Copyright>
 | |
|     <PackageTags>smt constraint solver theorem prover</PackageTags>
 | |
|     %s
 | |
|   </PropertyGroup>
 | |
| 
 | |
|   <ItemGroup>
 | |
|     <Compile Include="..\%s\*.cs;*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
 | |
|     <None Include="..\%s\README.md" Pack="true" PackagePath="/"/>
 | |
|   </ItemGroup>
 | |
| 
 | |
| </Project>""" % (version, key, self.to_src_dir, self.to_src_dir)
 | |
| 
 | |
|         mk_dir(os.path.join(BUILD_DIR, 'dotnet'))
 | |
|         csproj = os.path.join('dotnet', 'z3.csproj')
 | |
|         with open(os.path.join(BUILD_DIR, csproj), 'w') as ous:
 | |
|             ous.write(core_csproj_str)
 | |
| 
 | |
|         dotnetCmdLine = [DOTNET, "build", csproj]
 | |
| 
 | |
|         dotnetCmdLine.extend(['-c'])
 | |
|         if DEBUG_MODE:
 | |
|             dotnetCmdLine.extend(['Debug'])
 | |
|         else:
 | |
|             dotnetCmdLine.extend(['Release'])
 | |
| 
 | |
|         path = os.path.join(os.path.abspath(BUILD_DIR), ".")
 | |
|         dotnetCmdLine.extend(['-o', "\"%s\"" % path])
 | |
| 
 | |
|         MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine))
 | |
|         out.write('\n')
 | |
|         out.write('%s: %s\n\n' % (self.name, dllfile))
 | |
| 
 | |
|     def main_component(self):
 | |
|         return is_dotnet_core_enabled()
 | |
| 
 | |
|     def has_assembly_info(self):
 | |
|         # TBD: is this required for dotnet core given that version numbers are in z3.csproj file?
 | |
|         return False
 | |
| 
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         if is_dotnet_core_enabled():
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.deps.json' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.deps.json' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             if DEBUG_MODE:
 | |
|                 shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name),
 | |
|                             '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         if is_dotnet_core_enabled():
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
|             shutil.copy('%s.deps.json' % os.path.join(build_path, self.dll_name),
 | |
|                         '%s.deps.json' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
 | |
| 
 | |
|     def mk_install_deps(self, out):
 | |
|         pass
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         pass
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         pass
 | |
| 
 | |
| class JavaDLLComponent(Component):
 | |
|     def __init__(self, name, dll_name, package_name, manifest_file, path, deps):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         if dll_name is None:
 | |
|             dll_name = name
 | |
|         self.dll_name     = dll_name
 | |
|         self.package_name = package_name
 | |
|         self.manifest_file = manifest_file
 | |
|         self.install = not is_windows()
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         global JAVAC
 | |
|         global JAR
 | |
| 
 | |
|         if is_java_enabled():
 | |
|             mk_dir(os.path.join(BUILD_DIR, 'api', 'java', 'classes'))
 | |
|             dllfile = '%s$(SO_EXT)' % self.dll_name
 | |
|             out.write('libz3java$(SO_EXT): libz3$(SO_EXT) %s\n' % os.path.join(self.to_src_dir, 'Native.cpp'))
 | |
|             t = '\t$(CXX) $(CXXFLAGS) $(CXX_OUT_FLAG)api/java/Native$(OBJ_EXT) -I"%s" -I"%s/PLATFORM" -I%s %s/Native.cpp\n' % (JNI_HOME, JNI_HOME, get_component('api').to_src_dir, self.to_src_dir)
 | |
|             if IS_OSX:
 | |
|                 t = t.replace('PLATFORM', 'darwin')
 | |
|             elif is_linux():
 | |
|                 t = t.replace('PLATFORM', 'linux')
 | |
|             elif is_hurd():
 | |
|                 t = t.replace('PLATFORM', 'hurd')
 | |
|             elif IS_FREEBSD:
 | |
|                 t = t.replace('PLATFORM', 'freebsd')
 | |
|             elif IS_NETBSD:
 | |
|                 t = t.replace('PLATFORM', 'netbsd')
 | |
|             elif IS_OPENBSD:
 | |
|                 t = t.replace('PLATFORM', 'openbsd')
 | |
|             elif IS_SUNOS:
 | |
|                 t = t.replace('PLATFORM', 'SunOS')
 | |
|             elif IS_CYGWIN:
 | |
|                 t = t.replace('PLATFORM', 'cygwin')
 | |
|             elif IS_MSYS2:
 | |
|                 t = t.replace('PLATFORM', 'win32')
 | |
|             else:
 | |
|                 t = t.replace('PLATFORM', 'win32')
 | |
|             out.write(t)
 | |
|             if IS_WINDOWS: # On Windows, CL creates a .lib file to link against.
 | |
|                 out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(LIB_EXT)\n' %
 | |
|                           os.path.join('api', 'java', 'Native'))
 | |
|             elif IS_OSX and IS_ARCH_ARM64:
 | |
|                 out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) -arch arm64 %s$(OBJ_EXT) libz3$(SO_EXT)\n' %
 | |
|                           os.path.join('api', 'java', 'Native'))
 | |
|             else:
 | |
|                 out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(SO_EXT)\n' %
 | |
|                           os.path.join('api', 'java', 'Native'))
 | |
|             out.write('%s.jar: libz3java$(SO_EXT) ' % self.package_name)
 | |
|             deps = ''
 | |
|             for jfile in get_java_files(self.src_dir):
 | |
|                 deps += ('%s ' % os.path.join(self.to_src_dir, jfile))
 | |
|             for jfile in get_java_files(os.path.join(self.src_dir, "enumerations")):
 | |
|                 deps += '%s ' % os.path.join(self.to_src_dir, 'enumerations', jfile)
 | |
|             out.write(deps)
 | |
|             out.write('\n')
 | |
|             #if IS_WINDOWS:
 | |
|             JAVAC = '"%s"' % JAVAC
 | |
|             JAR = '"%s"' % JAR
 | |
|             t = ('\t%s -source 1.8 -target 1.8 %s.java -d %s\n' % (JAVAC, os.path.join(self.to_src_dir, 'enumerations', '*'), os.path.join('api', 'java', 'classes')))
 | |
|             out.write(t)
 | |
|             t = ('\t%s -source 1.8 -target 1.8 -cp %s %s.java -d %s\n' % (JAVAC,
 | |
|                                                   os.path.join('api', 'java', 'classes'),
 | |
|                                                   os.path.join(self.to_src_dir, '*'),
 | |
|                                                   os.path.join('api', 'java', 'classes')))
 | |
|             out.write(t)
 | |
|             out.write('\t%s cfm %s.jar %s -C %s .\n' % (JAR, self.package_name,
 | |
|                                                          os.path.join(self.to_src_dir, 'manifest'),
 | |
|                                                          os.path.join('api', 'java', 'classes')))
 | |
|             out.write('java: %s.jar\n\n' % self.package_name)
 | |
| 
 | |
|     def main_component(self):
 | |
|         return is_java_enabled()
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         if JAVA_ENABLED:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.jar' % os.path.join(build_path, self.package_name),
 | |
|                         '%s.jar' % os.path.join(dist_path, INSTALL_BIN_DIR, self.package_name))
 | |
|             shutil.copy(os.path.join(build_path, 'libz3java.dll'),
 | |
|                         os.path.join(dist_path, INSTALL_BIN_DIR, 'libz3java.dll'))
 | |
|             shutil.copy(os.path.join(build_path, 'libz3java.lib'),
 | |
|                         os.path.join(dist_path, INSTALL_BIN_DIR, 'libz3java.lib'))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         if JAVA_ENABLED:
 | |
|             mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
 | |
|             shutil.copy('%s.jar' % os.path.join(build_path, self.package_name),
 | |
|                         '%s.jar' % os.path.join(dist_path, INSTALL_BIN_DIR, self.package_name))
 | |
|             so = get_so_ext()
 | |
|             shutil.copy(os.path.join(build_path, 'libz3java.%s' % so),
 | |
|                         os.path.join(dist_path, INSTALL_BIN_DIR, 'libz3java.%s' % so))
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         if is_java_enabled() and self.install:
 | |
|             dllfile = '%s$(SO_EXT)' % self.dll_name
 | |
|             MakeRuleCmd.install_files(out, dllfile, os.path.join(INSTALL_LIB_DIR, dllfile))
 | |
|             jarfile = '{}.jar'.format(self.package_name)
 | |
|             MakeRuleCmd.install_files(out, jarfile, os.path.join(INSTALL_LIB_DIR, jarfile))
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         if is_java_enabled() and self.install:
 | |
|             dllfile = '%s$(SO_EXT)' % self.dll_name
 | |
|             MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_LIB_DIR, dllfile))
 | |
|             jarfile = '{}.jar'.format(self.package_name)
 | |
|             MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_LIB_DIR, jarfile))
 | |
| 
 | |
| class MLComponent(Component):
 | |
| 
 | |
|     def __init__(self, name, lib_name, path, deps):
 | |
|         Component.__init__(self, name, path, deps)
 | |
|         if lib_name is None:
 | |
|             lib_name = name
 | |
|         self.lib_name = lib_name
 | |
|         self.modules = ["z3enums", "z3native", "z3"]  # dependencies in this order!
 | |
|         self.stubs = "z3native_stubs"
 | |
|         self.sub_dir = os.path.join('api', 'ml')
 | |
| 
 | |
|         self.destdir = ""
 | |
|         self.ldconf = ""
 | |
|         # Calling _init_ocamlfind_paths() is postponed to later because
 | |
|         # OCAMLFIND hasn't been checked yet.
 | |
| 
 | |
|     def _install_bindings(self):
 | |
|         # FIXME: Depending on global state is gross.  We can't pre-compute this
 | |
|         # in the constructor because we haven't tested for ocamlfind yet
 | |
|         return OCAMLFIND != ''
 | |
| 
 | |
|     def _init_ocamlfind_paths(self):
 | |
|         """
 | |
|             Initialises self.destdir and self.ldconf
 | |
|             Do not call this from the MLComponent constructor because OCAMLFIND
 | |
|             has not been checked at that point
 | |
|         """
 | |
|         if self.destdir != "" and self.ldconf != "":
 | |
|             # Initialisation already done
 | |
|             return
 | |
|         # Use Ocamlfind to get the default destdir and ldconf path
 | |
|         self.destdir = check_output([OCAMLFIND, 'printconf', 'destdir'])
 | |
|         if self.destdir == "":
 | |
|             raise MKException('Failed to get OCaml destdir')
 | |
| 
 | |
|         if not os.path.isdir(self.destdir):
 | |
|             raise MKException('The destdir reported by {ocamlfind} ({destdir}) does not exist'.format(ocamlfind=OCAMLFIND, destdir=self.destdir))
 | |
| 
 | |
|         self.ldconf = check_output([OCAMLFIND, 'printconf', 'ldconf'])
 | |
|         if self.ldconf == "":
 | |
|             raise MKException('Failed to get OCaml ldconf path')
 | |
| 
 | |
|     def final_info(self):
 | |
|         if not self._install_bindings():
 | |
|             print("WARNING: Could not find ocamlfind utility. OCaml bindings will not be installed")
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         if is_ml_enabled():
 | |
|             CP_CMD = 'cp'
 | |
|             if IS_WINDOWS:
 | |
|                 CP_CMD='copy'
 | |
| 
 | |
|             OCAML_FLAGS = ''
 | |
|             if DEBUG_MODE:
 | |
|                 OCAML_FLAGS += '-g'
 | |
| 
 | |
|             if OCAMLFIND:
 | |
|                 OCAMLCF = OCAMLFIND + ' ' + 'ocamlc -package zarith' + ' ' + OCAML_FLAGS
 | |
|                 OCAMLOPTF = OCAMLFIND + ' ' + 'ocamlopt -package zarith' + ' ' + OCAML_FLAGS
 | |
|             else:
 | |
|                 OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS
 | |
|                 OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS
 | |
| 
 | |
|             src_dir = self.to_src_dir
 | |
|             mk_dir(os.path.join(BUILD_DIR, self.sub_dir))
 | |
|             api_src = get_component(API_COMPONENT).to_src_dir
 | |
|             # remove /GL and -std=c++20; the ocaml tools don't like them.
 | |
|             if IS_WINDOWS:
 | |
|                 out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n')
 | |
|             else:
 | |
|                 out.write('CXXFLAGS_OCAML=$(subst -std=c++20,,$(CXXFLAGS))\n')
 | |
| 
 | |
|             substitutions = { 'VERSION': "{}.{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK) }
 | |
| 
 | |
|             configure_file(os.path.join(self.src_dir, 'META.in'),
 | |
|                            os.path.join(BUILD_DIR, self.sub_dir, 'META'),
 | |
|                            substitutions)
 | |
| 
 | |
|             stubsc = os.path.join(src_dir, self.stubs + '.c')
 | |
|             stubso = os.path.join(self.sub_dir, self.stubs) + '$(OBJ_EXT)'
 | |
|             base_dll_name = get_component(Z3_DLL_COMPONENT).dll_name
 | |
|             if STATIC_LIB:
 | |
|                 z3link = 'z3-static'
 | |
|                 z3linkdep = base_dll_name + '-static$(LIB_EXT)'
 | |
|                 out.write('%s: %s\n' % (z3linkdep, base_dll_name + '$(LIB_EXT)'))
 | |
|                 out.write('\tcp $< $@\n')
 | |
|             else:
 | |
|                 z3link = 'z3'
 | |
|                 z3linkdep = base_dll_name + '$(SO_EXT)'
 | |
|             out.write('%s: %s %s\n' % (stubso, stubsc, z3linkdep))
 | |
|             out.write('\t%s -ccopt "$(CXXFLAGS_OCAML) -I %s -I %s -I %s $(CXX_OUT_FLAG)%s" -c %s\n' %
 | |
|                       (OCAMLCF, OCAML_LIB, api_src, src_dir, stubso, stubsc))
 | |
| 
 | |
|             cmos = ''
 | |
|             for m in self.modules:
 | |
|                 ml = os.path.join(src_dir, m + '.ml')
 | |
|                 cmo = os.path.join(self.sub_dir, m + '.cmo')
 | |
|                 existing_mli = os.path.join(src_dir, m + '.mli')
 | |
|                 mli = os.path.join(self.sub_dir, m + '.mli')
 | |
|                 cmi = os.path.join(self.sub_dir, m + '.cmi')
 | |
|                 out.write('%s: %s %s\n' % (cmo, ml, cmos))
 | |
|                 if (os.path.exists(existing_mli[3:])):
 | |
|                     out.write('\t%s %s %s\n' % (CP_CMD, existing_mli, mli))
 | |
|                 else:
 | |
|                     out.write('\t%s -i -I %s -c %s > %s\n' % (OCAMLCF, self.sub_dir, ml, mli))
 | |
|                 out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLCF, self.sub_dir, cmi, mli))
 | |
|                 out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLCF, self.sub_dir, cmo, ml))
 | |
|                 cmos = cmos + cmo + ' '
 | |
| 
 | |
|             cmxs = ''
 | |
|             for m in self.modules:
 | |
|                 ff = os.path.join(src_dir, m + '.ml')
 | |
|                 ft = os.path.join(self.sub_dir, m + '.cmx')
 | |
|                 out.write('%s: %s %s %s\n' % (ft, ff, cmos, cmxs))
 | |
|                 out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLOPTF, self.sub_dir, ft, ff))
 | |
|                 cmxs = cmxs + ' ' + ft
 | |
| 
 | |
| 
 | |
|             OCAMLMKLIB = 'ocamlmklib'
 | |
| 
 | |
|             LIBZ3 = '-l' + z3link + ' -lstdc++'
 | |
|             if is_cygwin() and not(is_cygwin_mingw()):
 | |
|                 LIBZ3 = z3linkdep
 | |
| 
 | |
|             LIBZ3 = LIBZ3 + ' ' + ' '.join(map(lambda x: '-cclib ' + x, LDFLAGS.split()))
 | |
| 
 | |
|             stubs_install_path = '$$(%s printconf destdir)/stublibs' % OCAMLFIND
 | |
|             if not STATIC_LIB:
 | |
|                 loadpath = '-ccopt -L' + stubs_install_path
 | |
|                 dllpath = '-dllpath ' + stubs_install_path
 | |
|                 LIBZ3 = LIBZ3 + ' ' + loadpath + ' ' + dllpath
 | |
| 
 | |
|             if DEBUG_MODE and not(is_cygwin()):
 | |
|                 # Some ocamlmklib's don't like -g; observed on cygwin, but may be others as well.
 | |
|                 OCAMLMKLIB += ' -g'
 | |
| 
 | |
|             if IS_OSX:
 | |
|                 OCAMLMKLIB += ' -ldopt -Wl,-headerpad_max_install_names'
 | |
| 
 | |
|             z3mls = os.path.join(self.sub_dir, 'z3ml')
 | |
| 
 | |
|             LIBZ3ML = ''
 | |
|             if STATIC_LIB:
 | |
|                 LIBZ3ML = '-oc ' + os.path.join(self.sub_dir, 'z3ml-static')
 | |
| 
 | |
|             out.write('%s.cma: %s %s %s\n' % (z3mls, cmos, stubso, z3linkdep))
 | |
|             out.write('\t%s -o %s %s -I %s -L. %s %s %s\n' % (OCAMLMKLIB, z3mls, LIBZ3ML, self.sub_dir, stubso, cmos, LIBZ3))
 | |
|             out.write('%s.cmxa: %s %s %s %s.cma\n' % (z3mls, cmxs, stubso, z3linkdep, z3mls))
 | |
|             out.write('\t%s -o %s %s -I %s -L. %s %s %s\n' % (OCAMLMKLIB, z3mls, LIBZ3ML, self.sub_dir, stubso, cmxs, LIBZ3))
 | |
|             out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls))
 | |
|             out.write('\t%s -linkall -shared -o %s.cmxs -I . -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls))
 | |
| 
 | |
|             out.write('\n')
 | |
|             out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls))
 | |
|             if IS_OSX:
 | |
|                 out.write('\tinstall_name_tool -id %s/libz3.dylib libz3.dylib\n' % (stubs_install_path))
 | |
|                 out.write('\tinstall_name_tool -change libz3.dylib %s/libz3.dylib api/ml/dllz3ml.so\n' % (stubs_install_path))
 | |
|             out.write('\n')
 | |
| 
 | |
|             if IS_WINDOWS:
 | |
|                 out.write('ocamlfind_install: ')
 | |
|                 self.mk_install_deps(out)
 | |
|                 out.write('\n')
 | |
|                 self.mk_install(out)
 | |
|                 out.write('\n')
 | |
|                 out.write('ocamlfind_uninstall:\n')
 | |
|                 self.mk_uninstall(out)
 | |
|                 out.write('\n')
 | |
| 
 | |
|     # The following three functions may be out of date.
 | |
|     def mk_install_deps(self, out):
 | |
|         if is_ml_enabled() and self._install_bindings():
 | |
|             out.write(get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT) ')
 | |
|             out.write(os.path.join(self.sub_dir, 'META '))
 | |
|             out.write(os.path.join(self.sub_dir, 'z3ml.cma '))
 | |
|             out.write(os.path.join(self.sub_dir, 'z3ml.cmxa '))
 | |
|             out.write(os.path.join(self.sub_dir, 'z3ml.cmxs '))
 | |
| 
 | |
|     def mk_install(self, out):
 | |
|         if is_ml_enabled() and self._install_bindings():
 | |
|             self._init_ocamlfind_paths()
 | |
|             in_prefix = self.destdir.startswith(PREFIX)
 | |
|             maybe_stripped_destdir = strip_path_prefix(self.destdir, PREFIX)
 | |
|             # Note that when doing a staged install with DESTDIR that modifying
 | |
|             # OCaml's ``ld.conf`` may fail. Therefore packagers will need to
 | |
|             # make their packages modify it manually at package install time
 | |
|             # as opposed to ``make install`` time.
 | |
|             MakeRuleCmd.make_install_directory(out,
 | |
|                                                maybe_stripped_destdir,
 | |
|                                                in_prefix=in_prefix)
 | |
|             out.write('\t@{ocamlfind} install -ldconf $(DESTDIR){ldconf} -destdir $(DESTDIR){ocaml_destdir} Z3 {metafile}'.format(
 | |
|                 ldconf=self.ldconf,
 | |
|                 ocamlfind=OCAMLFIND,
 | |
|                 ocaml_destdir=self.destdir,
 | |
|                 metafile=os.path.join(self.sub_dir, 'META')))
 | |
| 
 | |
|             for m in self.modules:
 | |
|                 mli = os.path.join(self.src_dir, m) + '.mli'
 | |
|                 if os.path.exists(mli):
 | |
|                     out.write(' ' + os.path.join(self.to_src_dir, m) + '.mli')
 | |
|                 else:
 | |
|                     out.write(' ' + os.path.join(self.sub_dir, m) + '.mli')
 | |
|                 out.write(' ' + os.path.join(self.sub_dir, m) + '.cmi')
 | |
|                 out.write(' ' + os.path.join(self.sub_dir, m) + '.cmx')
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'libz3ml$(LIB_EXT)'))))
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml$(LIB_EXT)'))))
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cma'))))
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxa'))))
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxs'))))
 | |
|             out.write(' %s' % ((os.path.join(self.sub_dir, 'dllz3ml'))))
 | |
|             if is_windows() or is_cygwin_mingw() or is_msys2():
 | |
|                 out.write('.dll')
 | |
|             else:
 | |
|                 out.write('.so') # .so also on OSX!
 | |
|             out.write('\n')
 | |
| 
 | |
|     def mk_uninstall(self, out):
 | |
|         if is_ml_enabled() and self._install_bindings():
 | |
|             self._init_ocamlfind_paths()
 | |
|             out.write('\t@{ocamlfind} remove -ldconf $(DESTDIR){ldconf} -destdir $(DESTDIR){ocaml_destdir} Z3\n'.format(
 | |
|                 ldconf=self.ldconf,
 | |
|                 ocamlfind=OCAMLFIND,
 | |
|                 ocaml_destdir=self.destdir))
 | |
| 
 | |
|     def main_component(self):
 | |
|         return is_ml_enabled()
 | |
| 
 | |
| class ExampleComponent(Component):
 | |
|     def __init__(self, name, path):
 | |
|         Component.__init__(self, name, path, [])
 | |
|         self.ex_dir   = os.path.join(EXAMPLE_DIR, self.path)
 | |
|         self.to_ex_dir = os.path.join(REV_BUILD_DIR, self.ex_dir)
 | |
| 
 | |
|     def is_example(self):
 | |
|         return True
 | |
| 
 | |
| class CppExampleComponent(ExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         ExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     def compiler(self):
 | |
|         return "$(CXX)"
 | |
| 
 | |
|     def src_files(self):
 | |
|         return get_cpp_files(self.ex_dir)
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         dll_name = get_component(Z3_DLL_COMPONENT).dll_name
 | |
|         dll = '%s$(SO_EXT)' % dll_name
 | |
| 
 | |
|         objfiles = ''
 | |
|         for cppfile in self.src_files():
 | |
|             objfile = '%s$(OBJ_EXT)' % (cppfile[:cppfile.rfind('.')])
 | |
|             objfiles = objfiles + ('%s ' % objfile)
 | |
|             out.write('%s: %s\n' % (objfile, os.path.join(self.to_ex_dir, cppfile)));
 | |
|             out.write('\t%s $(CXXFLAGS) $(OS_DEFINES) $(EXAMP_DEBUG_FLAG) $(CXX_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), objfile))
 | |
|             # Add include dir components
 | |
|             out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir)
 | |
|             out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir)
 | |
|             out.write(' %s' % os.path.join(self.to_ex_dir, cppfile))
 | |
|             out.write('\n')
 | |
| 
 | |
|         exefile = '%s$(EXE_EXT)' % self.name
 | |
|         out.write('%s: %s %s\n' % (exefile, dll, objfiles))
 | |
|         out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles))
 | |
|         if IS_WINDOWS:
 | |
|             out.write('%s.lib' % dll_name)
 | |
|         else:
 | |
|             out.write(dll)
 | |
|         out.write(' $(LINK_EXTRA_FLAGS)\n')
 | |
|         out.write('_ex_%s: %s\n\n' % (self.name, exefile))
 | |
| 
 | |
| class CExampleComponent(CppExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         CppExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     def compiler(self):
 | |
|         return "$(CC)"
 | |
| 
 | |
|     def src_files(self):
 | |
|         return get_c_files(self.ex_dir)
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         dll_name = get_component(Z3_DLL_COMPONENT).dll_name
 | |
|         dll = '%s$(SO_EXT)' % dll_name
 | |
| 
 | |
|         objfiles = ''
 | |
|         for cfile in self.src_files():
 | |
|             objfile = '%s$(OBJ_EXT)' % (cfile[:cfile.rfind('.')])
 | |
|             objfiles = objfiles + ('%s ' % objfile)
 | |
|             out.write('%s: %s\n' % (objfile, os.path.join(self.to_ex_dir, cfile)));
 | |
|             out.write('\t%s $(CFLAGS) $(OS_DEFINES) $(EXAMP_DEBUG_FLAG) $(C_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), objfile))
 | |
|             out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir)
 | |
|             out.write(' %s' % os.path.join(self.to_ex_dir, cfile))
 | |
|             out.write('\n')
 | |
| 
 | |
|         exefile = '%s$(EXE_EXT)' % self.name
 | |
|         out.write('%s: %s %s\n' % (exefile, dll, objfiles))
 | |
|         out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles))
 | |
|         if IS_WINDOWS:
 | |
|             out.write('%s.lib' % dll_name)
 | |
|         else:
 | |
|             out.write(dll)
 | |
|         out.write(' $(LINK_EXTRA_FLAGS)\n')
 | |
|         out.write('_ex_%s: %s\n\n' % (self.name, exefile))
 | |
| 
 | |
| class DotNetExampleComponent(ExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         ExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     def is_example(self):
 | |
|         return is_dotnet_core_enabled()
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         if is_dotnet_core_enabled():
 | |
|             proj_name = 'dotnet_example.csproj'
 | |
|             out.write('_ex_%s:' % self.name)
 | |
|             for csfile in get_cs_files(self.ex_dir):
 | |
|                 out.write(' ')
 | |
|                 out.write(os.path.join(self.to_ex_dir, csfile))
 | |
| 
 | |
|             mk_dir(os.path.join(BUILD_DIR, 'dotnet_example'))
 | |
|             csproj = os.path.join('dotnet_example', proj_name)
 | |
|             if VS_X64:
 | |
|                 platform = 'x64'
 | |
|             elif VS_ARM:
 | |
|                 platform = 'ARM'
 | |
|             else:
 | |
|                 platform = 'x86'
 | |
| 
 | |
|             dotnet_proj_str = r"""<Project Sdk="Microsoft.NET.Sdk">
 | |
|   <PropertyGroup>
 | |
|     <OutputType>Exe</OutputType>
 | |
|     <TargetFramework>netcoreapp2.0</TargetFramework>
 | |
|     <PlatformTarget>%s</PlatformTarget>
 | |
|   </PropertyGroup>
 | |
|   <ItemGroup>
 | |
|     <Compile Include="..\%s/*.cs" />
 | |
|     <Reference Include="Microsoft.Z3">
 | |
|       <HintPath>..\Microsoft.Z3.dll</HintPath>
 | |
|     </Reference>
 | |
|   </ItemGroup>
 | |
| </Project>""" % (platform, self.to_ex_dir)
 | |
| 
 | |
|             with open(os.path.join(BUILD_DIR, csproj), 'w') as ous:
 | |
|                 ous.write(dotnet_proj_str)
 | |
| 
 | |
|             out.write('\n')
 | |
|             dotnetCmdLine = [DOTNET, "build", csproj]
 | |
|             dotnetCmdLine.extend(['-c'])
 | |
|             if DEBUG_MODE:
 | |
|                 dotnetCmdLine.extend(['Debug'])
 | |
|             else:
 | |
|                 dotnetCmdLine.extend(['Release'])
 | |
|             MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine))
 | |
|             out.write('\n')
 | |
| 
 | |
| class JavaExampleComponent(ExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         ExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     def is_example(self):
 | |
|         return JAVA_ENABLED
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         if JAVA_ENABLED:
 | |
|             pkg = get_component(JAVA_COMPONENT).package_name + '.jar'
 | |
|             out.write('JavaExample.class: %s' % (pkg))
 | |
|             deps = ''
 | |
|             for jfile in get_java_files(self.ex_dir):
 | |
|                 out.write(' %s' % os.path.join(self.to_ex_dir, jfile))
 | |
|             if IS_WINDOWS:
 | |
|                 deps = deps.replace('/', '\\')
 | |
|             out.write('%s\n' % deps)
 | |
|             out.write('\t%s -cp %s ' % (JAVAC, pkg))
 | |
|             win_ex_dir = self.to_ex_dir
 | |
|             for javafile in get_java_files(self.ex_dir):
 | |
|                 out.write(' ')
 | |
|                 out.write(os.path.join(win_ex_dir, javafile))
 | |
|             out.write(' -d .\n')
 | |
|             out.write('_ex_%s: JavaExample.class\n\n' % (self.name))
 | |
| 
 | |
| class MLExampleComponent(ExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         ExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     def is_example(self):
 | |
|         return ML_ENABLED
 | |
| 
 | |
|     def mk_makefile(self, out):
 | |
|         if ML_ENABLED:
 | |
|             out.write('ml_example.byte: api/ml/z3ml.cma')
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s' % os.path.join(self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
|             out.write('\tocamlfind %s ' % OCAMLC)
 | |
|             if DEBUG_MODE:
 | |
|                 out.write('-g ')
 | |
|             out.write('-custom -o ml_example.byte -package zarith -I api/ml -cclib "-L. -lpthread -lstdc++ -lz3" -linkpkg z3ml.cma')
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s/%s' % (self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
|             out.write('ml_example$(EXE_EXT): api/ml/z3ml.cmxa')
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s' % os.path.join(self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
|             out.write('\tocamlfind %s ' % OCAMLOPT)
 | |
|             if DEBUG_MODE:
 | |
|                 out.write('-g ')
 | |
|             out.write('-o ml_example$(EXE_EXT) -package zarith -I api/ml -cclib "-L. -lpthread -lstdc++ -lz3" -linkpkg z3ml.cmxa')
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s/%s' % (self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
|             out.write('_ex_%s: ml_example.byte ml_example$(EXE_EXT)\n\n' % self.name)
 | |
| 
 | |
|         debug_opt = '-g ' if DEBUG_MODE else ''
 | |
| 
 | |
|         if STATIC_LIB:
 | |
|             opam_z3_opts = '-thread -package z3-static -linkpkg'
 | |
|             ml_post_install_tests = [
 | |
|                 (OCAMLC,              'ml_example_static.byte'),
 | |
|                 (OCAMLC + ' -custom', 'ml_example_static_custom.byte'),
 | |
|                 (OCAMLOPT,            'ml_example_static$(EXE_EXT)')
 | |
|             ]
 | |
|         else:
 | |
|             opam_z3_opts = '-thread -package z3 -linkpkg'
 | |
|             ml_post_install_tests = [
 | |
|                 (OCAMLC,              'ml_example_shared.byte'),
 | |
|                 (OCAMLC + ' -custom', 'ml_example_shared_custom.byte'),
 | |
|                 (OCAMLOPT,            'ml_example_shared$(EXE_EXT)')
 | |
|             ]
 | |
| 
 | |
|         for ocaml_compiler, testname in ml_post_install_tests:
 | |
|             out.write(testname + ':')
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s' % os.path.join(self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
|             out.write('\tocamlfind %s -o %s %s %s ' % (ocaml_compiler, debug_opt, testname, opam_z3_opts))
 | |
|             for mlfile in get_ml_files(self.ex_dir):
 | |
|                 out.write(' %s/%s' % (self.to_ex_dir, mlfile))
 | |
|             out.write('\n')
 | |
| 
 | |
|         if STATIC_LIB:
 | |
|             out.write('_ex_ml_example_post_install: ml_example_static.byte ml_example_static_custom.byte ml_example_static$(EXE_EXT)\n')
 | |
|         else:
 | |
|             out.write('_ex_ml_example_post_install: ml_example_shared.byte ml_example_shared_custom.byte ml_example_shared$(EXE_EXT)\n')
 | |
| 
 | |
|         out.write('\n')
 | |
| 
 | |
| 
 | |
| class PythonExampleComponent(ExampleComponent):
 | |
|     def __init__(self, name, path):
 | |
|         ExampleComponent.__init__(self, name, path)
 | |
| 
 | |
|     # Python examples are just placeholders, we just copy the *.py files when mk_makefile is invoked.
 | |
|     # We don't need to include them in the :examples rule
 | |
|     def mk_makefile(self, out):
 | |
|         full = os.path.join(EXAMPLE_DIR, self.path)
 | |
|         for py in filter(lambda f: f.endswith('.py'), os.listdir(full)):
 | |
|             shutil.copyfile(os.path.join(full, py), os.path.join(BUILD_DIR, 'python', py))
 | |
|             if is_verbose():
 | |
|                 print("Copied Z3Py example '%s' to '%s'" % (py, os.path.join(BUILD_DIR, 'python')))
 | |
|         out.write('_ex_%s: \n\n' % self.name)
 | |
| 
 | |
|     def mk_win_dist(self, build_path, dist_path):
 | |
|         full = os.path.join(EXAMPLE_DIR, self.path)
 | |
|         py = 'example.py'
 | |
|         shutil.copyfile(os.path.join(full, py),
 | |
|                         os.path.join(dist_path, INSTALL_BIN_DIR, 'python', py))
 | |
| 
 | |
|     def mk_unix_dist(self, build_path, dist_path):
 | |
|         self.mk_win_dist(build_path, dist_path)
 | |
| 
 | |
| 
 | |
| def reg_component(name, c):
 | |
|     global _Id, _Components, _ComponentNames, _Name2Component
 | |
|     c.id = _Id
 | |
|     _Id = _Id + 1
 | |
|     _Components.append(c)
 | |
|     _ComponentNames.add(name)
 | |
|     _Name2Component[name] = c
 | |
|     if VERBOSE:
 | |
|         print("New component: '%s'" % name)
 | |
| 
 | |
| def add_lib(name, deps=[], path=None, includes2install=[]):
 | |
|     c = LibComponent(name, path, deps, includes2install)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_clib(name, deps=[], path=None, includes2install=[]):
 | |
|     c = CLibComponent(name, path, deps, includes2install)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_hlib(name, path=None, includes2install=[]):
 | |
|     c = HLibComponent(name, path, includes2install)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_exe(name, deps=[], path=None, exe_name=None, install=True):
 | |
|     c = ExeComponent(name, exe_name, path, deps, install)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_extra_exe(name, deps=[], path=None, exe_name=None, install=True):
 | |
|     c = ExtraExeComponent(name, exe_name, path, deps, install)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_dll(name, deps=[], path=None, dll_name=None, export_files=[], reexports=[], install=True, static=False, staging_link=None):
 | |
|     c = DLLComponent(name, dll_name, path, deps, export_files, reexports, install, static, staging_link)
 | |
|     reg_component(name, c)
 | |
|     return c
 | |
| 
 | |
| def add_dot_net_core_dll(name, deps=[], path=None, dll_name=None, assembly_info_dir=None, default_key_file=None):
 | |
|     c = DotNetDLLComponent(name, dll_name, path, deps, assembly_info_dir, default_key_file)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_java_dll(name, deps=[], path=None, dll_name=None, package_name=None, manifest_file=None):
 | |
|     c = JavaDLLComponent(name, dll_name, package_name, manifest_file, path, deps)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_python(libz3Component):
 | |
|     name = 'python'
 | |
|     reg_component(name, PythonComponent(name, libz3Component))
 | |
| 
 | |
| def add_js():
 | |
|     reg_component('js', JsComponent())
 | |
| 
 | |
| def add_python_install(libz3Component):
 | |
|     name = 'python_install'
 | |
|     reg_component(name, PythonInstallComponent(name, libz3Component))
 | |
| 
 | |
| def add_ml_lib(name, deps=[], path=None, lib_name=None):
 | |
|     c = MLComponent(name, lib_name, path, deps)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_cpp_example(name, path=None):
 | |
|     c = CppExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_c_example(name, path=None):
 | |
|     c = CExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_dotnet_example(name, path=None):
 | |
|     c = DotNetExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_java_example(name, path=None):
 | |
|     c = JavaExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_ml_example(name, path=None):
 | |
|     c = MLExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def add_z3py_example(name, path=None):
 | |
|     c = PythonExampleComponent(name, path)
 | |
|     reg_component(name, c)
 | |
| 
 | |
| def mk_config():
 | |
|     if ONLY_MAKEFILES:
 | |
|         return
 | |
|     config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w')
 | |
|     global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED, IS_ARCH_ARM64
 | |
|     if IS_WINDOWS:
 | |
|         # On Windows, Python build system assumes MSVC (cl.exe) compiler
 | |
|         # GUARD_CF is only supported with MSVC, which is the default on Windows
 | |
|         CXXFLAGS = '/nologo /Zi /D WIN32 /D _WINDOWS /EHsc /GS /Gd /std:c++20 -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR'
 | |
|         config.write(
 | |
|             'CC=cl\n'
 | |
|             'CXX=cl\n'
 | |
|             'CXX_OUT_FLAG=/Fo\n'
 | |
|             'C_OUT_FLAG=/Fo\n'
 | |
|             'OBJ_EXT=.obj\n'
 | |
|             'LIB_EXT=.lib\n'
 | |
|             'AR=lib\n'
 | |
|             'AR_OUTFLAG=/OUT:\n'
 | |
|             'EXE_EXT=.exe\n'
 | |
|             'LINK=cl\n'
 | |
|             'LINK_OUT_FLAG=/Fe\n'
 | |
|             'SO_EXT=.dll\n'
 | |
|             'SLINK=cl\n'
 | |
|             'SLINK_OUT_FLAG=/Fe\n'
 | |
|             'OS_DEFINES=/D _WINDOWS\n')
 | |
|         extra_opt = ''
 | |
|         link_extra_opt = ''
 | |
|         if LOG_SYNC:
 | |
|             extra_opt = '%s /DZ3_LOG_SYNC' % extra_opt
 | |
|         if SINGLE_THREADED:
 | |
|             extra_opt = '%s /DSINGLE_THREAD' % extra_opt
 | |
|         if GIT_HASH:
 | |
|             extra_opt = ' %s /D Z3GITHASH=%s' % (extra_opt, GIT_HASH)
 | |
|         if GUARD_CF:
 | |
|             extra_opt = ' %s /guard:cf' % extra_opt
 | |
|             link_extra_opt = ' %s /GUARD:CF' % link_extra_opt
 | |
|         else:
 | |
|             # Explicitly disable Control Flow Guard when GUARD_CF is False
 | |
|             extra_opt = ' %s /guard:cf-' % extra_opt
 | |
|             link_extra_opt = ' %s /GUARD:NO' % link_extra_opt
 | |
|         if STATIC_BIN:
 | |
|             static_opt = '/MT'
 | |
|         else:
 | |
|             static_opt = '/MD'
 | |
|         maybe_disable_dynamic_base = '/DYNAMICBASE' if ALWAYS_DYNAMIC_BASE else '/DYNAMICBASE:NO'
 | |
|         if DEBUG_MODE:
 | |
|             static_opt = static_opt + 'd'
 | |
|             config.write(
 | |
|                 'AR_FLAGS=/nologo\n'
 | |
|                 'LINK_FLAGS=/nologo %s\n'
 | |
|                 'SLINK_FLAGS=/nologo /LDd\n' % static_opt)
 | |
|             if VS_X64:
 | |
|                 final_cxxflags = '/c %s /Zi /W3 /WX- /Od /Oy- /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /Gm- /RTC1 %s %s' % (CXXFLAGS, extra_opt, static_opt)
 | |
|                 validate_guard_cf_compatibility(final_cxxflags)
 | |
|                 config.write(
 | |
|                     'CXXFLAGS=%s\n' % final_cxxflags)
 | |
|                 config.write(
 | |
|                     'LINK_EXTRA_FLAGS=/link /PROFILE /DEBUG:full /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
 | |
|                     'SLINK_EXTRA_FLAGS=/link /PROFILE /DEBUG:full /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt))
 | |
|             elif VS_ARM:
 | |
|                 print("ARM on VS is unsupported")
 | |
|                 exit(1)
 | |
|             else:
 | |
|                 final_cxxflags = '/c %s /Zi /W3 /WX- /Od /Oy- /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /Gm- /RTC1 /arch:SSE2 %s %s' % (CXXFLAGS, extra_opt, static_opt)
 | |
|                 validate_guard_cf_compatibility(final_cxxflags)
 | |
|                 config.write(
 | |
|                     'CXXFLAGS=%s\n' % final_cxxflags)
 | |
|                 config.write(
 | |
|                     'LINK_EXTRA_FLAGS=/link /PROFILE /DEBUG:full /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
 | |
|                     'SLINK_EXTRA_FLAGS=/link /PROFILE /DEBUG:full /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt))
 | |
|         else:
 | |
|             # Windows Release mode
 | |
|             LTCG=' /LTCG' if SLOW_OPTIMIZE else ''
 | |
|             GL = ' /GL' if SLOW_OPTIMIZE else ''
 | |
|             config.write(
 | |
|                 'AR_FLAGS=/nologo %s\n'
 | |
|                 'LINK_FLAGS=/nologo %s\n'
 | |
|                 'SLINK_FLAGS=/nologo /LD\n' % (LTCG, static_opt))
 | |
|             if TRACE:
 | |
|                 extra_opt = '%s /D _TRACE ' % extra_opt
 | |
|             if VS_X64:
 | |
|                 final_cxxflags = '/c%s %s /Zi /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D NDEBUG /D _LIB /D UNICODE /Gm- /GF /Gy /TP %s %s' % (GL, CXXFLAGS, extra_opt, static_opt)
 | |
|                 validate_guard_cf_compatibility(final_cxxflags)
 | |
|                 config.write(
 | |
|                     'CXXFLAGS=%s\n' % final_cxxflags)
 | |
|                 config.write(
 | |
|                     'LINK_EXTRA_FLAGS=/link%s /PROFILE /DEBUG:full /profile /MACHINE:X64 /SUBSYSTEM:CONSOLE /STACK:8388608 %s\n'
 | |
|                     'SLINK_EXTRA_FLAGS=/link%s /PROFILE /DEBUG:full /profile /MACHINE:X64 /SUBSYSTEM:WINDOWS /STACK:8388608 %s\n' % (LTCG, link_extra_opt, LTCG, link_extra_opt))
 | |
|             elif VS_ARM:
 | |
|                 print("ARM on VS is unsupported")
 | |
|                 exit(1)
 | |
|             else:
 | |
|                 final_cxxflags = '/c%s %s /Zi /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D NDEBUG /D _CONSOLE /D ASYNC_COMMANDS /Gm- /arch:SSE2 %s %s' % (GL, CXXFLAGS, extra_opt, static_opt)
 | |
|                 validate_guard_cf_compatibility(final_cxxflags)
 | |
|                 config.write(
 | |
|                     'CXXFLAGS=%s\n' % final_cxxflags)
 | |
|                 config.write(
 | |
|                     'LINK_EXTRA_FLAGS=/link%s /PROFILE /DEBUG:full /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
 | |
|                     'SLINK_EXTRA_FLAGS=/link%s /PROFILE /DEBUG:full /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (LTCG, link_extra_opt, LTCG, maybe_disable_dynamic_base, link_extra_opt))
 | |
| 
 | |
|         config.write('CFLAGS=$(CXXFLAGS)\n')
 | |
| 
 | |
|         # End of Windows VS config.mk
 | |
|         if is_verbose():
 | |
|             print('64-bit:         %s' % is64())
 | |
|             if is_java_enabled():
 | |
|                 print('JNI Bindings:   %s' % JNI_HOME)
 | |
|                 print('Java Compiler:  %s' % JAVAC)
 | |
|             if is_ml_enabled():
 | |
|                 print('OCaml Compiler: %s' % OCAMLC)
 | |
|                 print('OCaml Find tool: %s' % OCAMLFIND)
 | |
|                 print('OCaml Native:   %s' % OCAMLOPT)
 | |
|                 print('OCaml Library:  %s' % OCAML_LIB)
 | |
|     else:
 | |
|         OS_DEFINES = ""
 | |
|         ARITH = "internal"
 | |
|         check_ar()
 | |
|         CXX = find_cxx_compiler()
 | |
|         CC  = find_c_compiler()
 | |
|         SLIBEXTRAFLAGS = ''
 | |
| #       SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so.0' % LDFLAGS
 | |
|         EXE_EXT = ''
 | |
|         LIB_EXT = '.a'
 | |
|         if GPROF:
 | |
|             CXXFLAGS = '%s -pg' % CXXFLAGS
 | |
|             LDFLAGS  = '%s -pg' % LDFLAGS
 | |
|         if GMP:
 | |
|             test_gmp(CXX)
 | |
|             ARITH = "gmp"
 | |
|             CPPFLAGS = '%s -D_MP_GMP' % CPPFLAGS
 | |
|             LDFLAGS  = '%s -lgmp' % LDFLAGS
 | |
|             SLIBEXTRAFLAGS = '%s -lgmp' % SLIBEXTRAFLAGS
 | |
|         else:
 | |
|             CPPFLAGS = '%s -D_MP_INTERNAL' % CPPFLAGS
 | |
|         if GIT_HASH:
 | |
|             CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
 | |
|         CXXFLAGS = '%s -std=c++20' % CXXFLAGS
 | |
|         CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS
 | |
|         FPMATH = test_fpmath(CXX)
 | |
|         CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS)
 | |
|         atomic_required = test_atomic_required(CXX)
 | |
|         if atomic_required:
 | |
|             LDFLAGS  = '%s -latomic' % LDFLAGS
 | |
|         if LOG_SYNC:
 | |
|             CXXFLAGS = '%s -DZ3_LOG_SYNC' % CXXFLAGS
 | |
|         if SINGLE_THREADED:
 | |
|             CXXFLAGS = '%s -DSINGLE_THREAD' % CXXFLAGS
 | |
|         if DEBUG_MODE:
 | |
|             CXXFLAGS     = '%s -g -Wall' % CXXFLAGS
 | |
|             EXAMP_DEBUG_FLAG = '-g'
 | |
|             CPPFLAGS     = '%s -DZ3DEBUG -D_DEBUG' % CPPFLAGS
 | |
|         else:
 | |
|             CXXFLAGS     = '%s -O3' % CXXFLAGS
 | |
|             if GPROF:
 | |
|                 CXXFLAGS     += '-fomit-frame-pointer'
 | |
|             CPPFLAGS     = '%s -DNDEBUG -D_EXTERNAL_RELEASE' % CPPFLAGS
 | |
|         if is_CXX_clangpp():
 | |
|             CXXFLAGS   = '%s -Wno-unknown-pragmas -Wno-overloaded-virtual -Wno-unused-value' % CXXFLAGS
 | |
|         sysname, _, _, _, machine = os.uname()
 | |
|         if sysname == 'Darwin':
 | |
|             SO_EXT         = '.dylib'
 | |
|             SLIBFLAGS      = '-dynamiclib'
 | |
|         elif sysname == 'Linux':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|             SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS
 | |
|         elif sysname == 'GNU':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|         elif sysname == 'FreeBSD':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|             SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS
 | |
|         elif sysname == 'NetBSD':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|         elif sysname == 'OpenBSD':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|         elif sysname  == 'SunOS':
 | |
|             SO_EXT         = '.so'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|             SLIBEXTRAFLAGS = '%s -mimpure-text' % SLIBEXTRAFLAGS
 | |
|         elif sysname.startswith('CYGWIN'):
 | |
|             SO_EXT         = '.dll'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|         elif sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'):
 | |
|             SO_EXT         = '.dll'
 | |
|             SLIBFLAGS      = '-shared'
 | |
|             EXE_EXT        = '.exe'
 | |
|             LIB_EXT        = '.lib'
 | |
|         else:
 | |
|             raise MKException('Unsupported platform: %s' % sysname)
 | |
|         if is64():
 | |
|             if not sysname.startswith('CYGWIN') and not sysname.startswith('MSYS') and not sysname.startswith('MINGW'):
 | |
|                 CXXFLAGS     = '%s -fPIC' % CXXFLAGS
 | |
|         elif not LINUX_X64:
 | |
|             CXXFLAGS     = '%s -m32' % CXXFLAGS
 | |
|             LDFLAGS      = '%s -m32' % LDFLAGS
 | |
|             SLIBFLAGS    = '%s -m32' % SLIBFLAGS
 | |
|         if TRACE or DEBUG_MODE:
 | |
|             CPPFLAGS     = '%s -D_TRACE' % CPPFLAGS
 | |
|         if is_cygwin_mingw() or is_msys2():
 | |
|             # when cross-compiling with MinGW, we need to statically link its standard libraries
 | |
|             # and to make it create an import library.
 | |
|             SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS
 | |
|             LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS
 | |
|         if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'):
 | |
|             CXXFLAGS = '%s -fpic' % CXXFLAGS
 | |
|         if IS_ARCH_ARM64 and IS_OSX:
 | |
|             print("Setting arm64")
 | |
|             CXXFLAGS = '%s -arch arm64' % CXXFLAGS
 | |
|             LDFLAGS = '%s -arch arm64' % LDFLAGS
 | |
|             SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS
 | |
|         if IS_OSX and is_ml_enabled():
 | |
|             SLIBFLAGS += ' -Wl,-headerpad_max_install_names'
 | |
| 
 | |
|         config.write('PREFIX=%s\n' % PREFIX)
 | |
|         config.write('CC=%s\n' % CC)
 | |
|         config.write('CXX=%s\n' % CXX)
 | |
|         config.write('CXXFLAGS=%s %s\n' % (CPPFLAGS, CXXFLAGS))
 | |
|         config.write('CFLAGS=%s %s\n' % (CPPFLAGS, CXXFLAGS.replace('-std=c++20', '')))
 | |
|         config.write('EXAMP_DEBUG_FLAG=%s\n' % EXAMP_DEBUG_FLAG)
 | |
|         config.write('CXX_OUT_FLAG=-o \n')
 | |
|         config.write('C_OUT_FLAG=-o \n')
 | |
|         config.write('OBJ_EXT=.o\n')
 | |
|         config.write('LIB_EXT=%s\n' % LIB_EXT)
 | |
|         config.write('AR=%s\n' % AR)
 | |
|         config.write('AR_FLAGS=rcs\n')
 | |
|         config.write('AR_OUTFLAG=\n')
 | |
|         config.write('EXE_EXT=%s\n' % EXE_EXT)
 | |
|         config.write('LINK=%s\n' % CXX)
 | |
|         config.write('LINK_FLAGS=\n')
 | |
|         config.write('LINK_OUT_FLAG=-o \n')
 | |
|         if is_linux() and (build_static_lib() or build_static_bin()):
 | |
|             config.write('LINK_EXTRA_FLAGS=-Wl,--whole-archive -lrt -lpthread -Wl,--no-whole-archive %s\n' % LDFLAGS)
 | |
|         else:
 | |
|             config.write('LINK_EXTRA_FLAGS=-lpthread %s\n' % LDFLAGS)
 | |
|         config.write('SO_EXT=%s\n' % SO_EXT)
 | |
|         config.write('SLINK=%s\n' % CXX)
 | |
|         config.write('SLINK_FLAGS=%s\n' % SLIBFLAGS)
 | |
|         config.write('SLINK_EXTRA_FLAGS=-lpthread %s\n' % SLIBEXTRAFLAGS)
 | |
|         config.write('SLINK_OUT_FLAG=-o \n')
 | |
|         config.write('OS_DEFINES=%s\n' % OS_DEFINES)
 | |
|         if is_verbose():
 | |
|             print('Host platform:  %s' % sysname)
 | |
|             print('C++ Compiler:   %s' % CXX)
 | |
|             print('C Compiler  :   %s' % CC)
 | |
|             if is_cygwin_mingw():
 | |
|                 print('MinGW32 cross:  %s' % (is_cygwin_mingw()))
 | |
|             print('Archive Tool:   %s' % AR)
 | |
|             print('Arithmetic:     %s' % ARITH)
 | |
|             print('Prefix:         %s' % PREFIX)
 | |
|             print('64-bit:         %s' % is64())
 | |
|             print('FP math:        %s' % FPMATH)
 | |
|             print('libatomic:      %s' % ('required' if atomic_required else 'not required'))
 | |
|             print("Python pkg dir: %s" % PYTHON_PACKAGE_DIR)
 | |
|             if GPROF:
 | |
|                 print('gprof:          enabled')
 | |
|             print('Python version: %s' % sysconfig.get_python_version())
 | |
|             if is_java_enabled():
 | |
|                 print('JNI Bindings:   %s' % JNI_HOME)
 | |
|                 print('Java Compiler:  %s' % JAVAC)
 | |
|             if is_ml_enabled():
 | |
|                 print('OCaml Compiler: %s' % OCAMLC)
 | |
|                 print('OCaml Find tool: %s' % OCAMLFIND)
 | |
|                 print('OCaml Native:   %s' % OCAMLOPT)
 | |
|                 print('OCaml Library:  %s' % OCAML_LIB)
 | |
|             if is_dotnet_core_enabled():
 | |
|                 print('C# Compiler:    %s' % DOTNET)
 | |
| 
 | |
|     config.close()
 | |
| 
 | |
| def mk_install(out):
 | |
|     out.write('install: ')
 | |
|     for c in get_components():
 | |
|         c.mk_install_deps(out)
 | |
|         out.write(' ')
 | |
|     out.write('\n')
 | |
|     MakeRuleCmd.make_install_directory(out, INSTALL_BIN_DIR)
 | |
|     MakeRuleCmd.make_install_directory(out, INSTALL_INCLUDE_DIR)
 | |
|     MakeRuleCmd.make_install_directory(out, INSTALL_LIB_DIR)
 | |
|     for c in get_components():
 | |
|         c.mk_install(out)
 | |
|     out.write('\t@echo Z3 was successfully installed.\n')
 | |
|     out.write('\n')
 | |
| 
 | |
| def mk_uninstall(out):
 | |
|     out.write('uninstall:\n')
 | |
|     for c in get_components():
 | |
|         c.mk_uninstall(out)
 | |
|     out.write('\t@echo Z3 was successfully uninstalled.\n')
 | |
|     out.write('\n')
 | |
| 
 | |
| # Generate the Z3 makefile
 | |
| def mk_makefile():
 | |
|     mk_dir(BUILD_DIR)
 | |
|     mk_config()
 | |
|     if VERBOSE:
 | |
|         print("Writing %s" % os.path.join(BUILD_DIR, 'Makefile'))
 | |
|     out = open(os.path.join(BUILD_DIR, 'Makefile'), 'w')
 | |
|     out.write('# Automatically generated file.\n')
 | |
|     out.write('include config.mk\n')
 | |
|     # Generate :all rule
 | |
|     out.write('all:')
 | |
|     for c in get_components():
 | |
|         if c.main_component():
 | |
|             out.write(' %s' % c.name)
 | |
|     out.write('\n\t@echo Z3 was successfully built.\n')
 | |
|     out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % os.path.join(BUILD_DIR, 'python'))
 | |
|     pathvar = "DYLD_LIBRARY_PATH" if IS_OSX else "PATH" if IS_WINDOWS else "LD_LIBRARY_PATH"
 | |
|     out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH environment variable and the \'%s\' directory is added to the %s environment variable.\"\n" % (os.path.join(BUILD_DIR, 'python'), BUILD_DIR, pathvar))
 | |
|     if not IS_WINDOWS:
 | |
|         out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n")
 | |
|         out.write('\t@echo "    sudo make install"\n\n')
 | |
|         # out.write("\t@echo If you are doing a staged install you can use DESTDIR.\n")
 | |
|         # out.write('\t@echo "    make DESTDIR=/some/temp/directory install"\n')
 | |
|     # Generate :examples rule
 | |
|     out.write('examples:')
 | |
|     for c in get_components():
 | |
|         if c.is_example():
 | |
|             out.write(' _ex_%s' % c.name)
 | |
|     out.write('\n\t@echo Z3 examples were successfully built.\n')
 | |
|     # Generate components
 | |
|     for c in get_components():
 | |
|         c.mk_makefile(out)
 | |
|     # Generate install/uninstall rules if not WINDOWS
 | |
|     if not IS_WINDOWS:
 | |
|         mk_install(out)
 | |
|         mk_uninstall(out)
 | |
|     for c in get_components():
 | |
|         c.final_info()
 | |
|     out.close()
 | |
|     # Finalize
 | |
|     if VERBOSE:
 | |
|         print("Makefile was successfully generated.")
 | |
|         if DEBUG_MODE:
 | |
|             print("  compilation mode: Debug")
 | |
|         else:
 | |
|             print("  compilation mode: Release")
 | |
|         if IS_WINDOWS:
 | |
|             if VS_X64:
 | |
|                 print("  platform: x64\n")
 | |
|                 print("To build Z3, open a [Visual Studio x64 Command Prompt], then")
 | |
|             elif VS_ARM:
 | |
|                 print("  platform: ARM\n")
 | |
|                 print("To build Z3, open a [Visual Studio ARM Command Prompt], then")
 | |
|             else:
 | |
|                 print("  platform: x86")
 | |
|                 print("To build Z3, open a [Visual Studio Command Prompt], then")
 | |
|             print("type 'cd %s && nmake'\n" % os.path.join(os.getcwd(), BUILD_DIR))
 | |
|             print('Remark: to open a Visual Studio Command Prompt, go to: "Start > All Programs > Visual Studio > Visual Studio Tools"')
 | |
|         else:
 | |
|             print("Type 'cd %s; make' to build Z3" % BUILD_DIR)
 | |
| 
 | |
| # Generate automatically generated source code
 | |
| def mk_auto_src():
 | |
|     if not ONLY_MAKEFILES:
 | |
|         exec_pyg_scripts()
 | |
|         mk_pat_db()
 | |
|         mk_all_install_tactic_cpps()
 | |
|         mk_all_mem_initializer_cpps()
 | |
|         mk_all_gparams_register_modules()
 | |
| 
 | |
| 
 | |
| def _execfile(file, globals=globals(), locals=locals()):
 | |
|     if sys.version < "2.7":
 | |
|         execfile(file, globals, locals)
 | |
|     else:
 | |
|         with open(file, "r") as fh:
 | |
|             exec(fh.read()+"\n", globals, locals)
 | |
| 
 | |
| # Execute python auxiliary scripts that generate extra code for Z3.
 | |
| def exec_pyg_scripts():
 | |
|     for root, dirs, files in os.walk('src'):
 | |
|         for f in files:
 | |
|             if f.endswith('.pyg'):
 | |
|                 script = os.path.join(root, f)
 | |
|                 generated_file = mk_genfile_common.mk_hpp_from_pyg(script, root)
 | |
|                 if is_verbose():
 | |
|                     print("Generated '{}'".format(generated_file))
 | |
| 
 | |
| # TODO: delete after src/ast/pattern/expr_pattern_match
 | |
| # database.smt ==> database.h
 | |
| def mk_pat_db():
 | |
|     c = get_component(PATTERN_COMPONENT)
 | |
|     fin  = os.path.join(c.src_dir, 'database.smt2')
 | |
|     fout = os.path.join(c.src_dir, 'database.h')
 | |
|     mk_genfile_common.mk_pat_db_internal(fin, fout)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}'".format(fout))
 | |
| 
 | |
| # Update version numbers
 | |
| def update_version():
 | |
|     major = VER_MAJOR
 | |
|     minor = VER_MINOR
 | |
|     build = VER_BUILD
 | |
|     revision = VER_TWEAK
 | |
| 
 | |
|     print("UpdateVersion:", get_full_version_string(major, minor, build, revision))
 | |
| 
 | |
|     if major is None or minor is None or build is None or revision is None:
 | |
|         raise MKException("set_version(major, minor, build, revision) must be used before invoking update_version()")
 | |
|     if not ONLY_MAKEFILES:
 | |
|         mk_version_dot_h(major, minor, build, revision)
 | |
|         mk_all_assembly_infos(major, minor, build, revision)
 | |
|         mk_def_files()
 | |
| 
 | |
| def get_full_version_string(major, minor, build, revision):
 | |
|     global GIT_HASH, GIT_DESCRIBE
 | |
|     res = "Z3 %s.%s.%s.%s" % (major, minor, build, revision)
 | |
|     if GIT_HASH:
 | |
|         res += " " + GIT_HASH
 | |
|     if GIT_DESCRIBE:
 | |
|         branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
 | |
|         res += " " + branch + " " + check_output(['git', 'describe'])
 | |
|     return '"' + res + '"'
 | |
| 
 | |
| # Update files with the version number
 | |
| def mk_version_dot_h(major, minor, build, revision):
 | |
|     c = get_component(UTIL_COMPONENT)
 | |
|     version_template = os.path.join(c.src_dir, 'z3_version.h.in')
 | |
|     version_header_output = os.path.join(c.src_dir, 'z3_version.h')
 | |
|     # Note the substitution names are what is used by the CMake
 | |
|     # builds system. If you change these you should change them
 | |
|     # in the CMake build too
 | |
|     configure_file(version_template, version_header_output,
 | |
|         { 'Z3_VERSION_MAJOR': str(major),
 | |
|           'Z3_VERSION_MINOR': str(minor),
 | |
|           'Z3_VERSION_PATCH': str(build),
 | |
|           'Z3_VERSION_TWEAK': str(revision),
 | |
|           'Z3_FULL_VERSION': get_full_version_string(major, minor, build, revision)
 | |
|         }
 | |
|     )
 | |
|     if VERBOSE:
 | |
|         print("Generated '%s'" % version_header_output)
 | |
| 
 | |
| # Generate AssemblyInfo.cs files with the right version numbers by using ``AssemblyInfo.cs.in`` files as a template
 | |
| def mk_all_assembly_infos(major, minor, build, revision):
 | |
|     for c in get_components():
 | |
|         if c.has_assembly_info():
 | |
|             c.make_assembly_info(major, minor, build, revision)
 | |
| 
 | |
| def get_header_files_for_components(component_src_dirs):
 | |
|     assert isinstance(component_src_dirs, list)
 | |
|     h_files_full_path = []
 | |
|     for component_src_dir in sorted(component_src_dirs):
 | |
|         h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
 | |
|         h_files = list(map(lambda p: os.path.join(component_src_dir, p), h_files))
 | |
|         h_files_full_path.extend(h_files)
 | |
|     return h_files_full_path
 | |
| 
 | |
| def mk_install_tactic_cpp(cnames, path):
 | |
|     component_src_dirs = []
 | |
|     for cname in cnames:
 | |
|         print("Component %s" % cname)
 | |
|         c = get_component(cname)
 | |
|         component_src_dirs.append(c.src_dir)
 | |
|     h_files_full_path = get_header_files_for_components(component_src_dirs)
 | |
|     generated_file = mk_genfile_common.mk_install_tactic_cpp_internal(h_files_full_path, path)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}'".format(generated_file))
 | |
| 
 | |
| def mk_all_install_tactic_cpps():
 | |
|     if not ONLY_MAKEFILES:
 | |
|         for c in get_components():
 | |
|             if c.require_install_tactics():
 | |
|                 cnames = []
 | |
|                 cnames.extend(c.deps)
 | |
|                 cnames.append(c.name)
 | |
|                 mk_install_tactic_cpp(cnames, c.src_dir)
 | |
| 
 | |
| def mk_mem_initializer_cpp(cnames, path):
 | |
|     component_src_dirs = []
 | |
|     for cname in cnames:
 | |
|         c = get_component(cname)
 | |
|         component_src_dirs.append(c.src_dir)
 | |
|     h_files_full_path = get_header_files_for_components(component_src_dirs)
 | |
|     generated_file = mk_genfile_common.mk_mem_initializer_cpp_internal(h_files_full_path, path)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}'".format(generated_file))
 | |
| 
 | |
| def mk_all_mem_initializer_cpps():
 | |
|     if not ONLY_MAKEFILES:
 | |
|         for c in get_components():
 | |
|             if c.require_mem_initializer():
 | |
|                 cnames = []
 | |
|                 cnames.extend(c.deps)
 | |
|                 cnames.append(c.name)
 | |
|                 mk_mem_initializer_cpp(cnames, c.src_dir)
 | |
| 
 | |
| def mk_gparams_register_modules(cnames, path):
 | |
|     component_src_dirs = []
 | |
|     for cname in cnames:
 | |
|         c = get_component(cname)
 | |
|         component_src_dirs.append(c.src_dir)
 | |
|     h_files_full_path = get_header_files_for_components(component_src_dirs)
 | |
|     generated_file = mk_genfile_common.mk_gparams_register_modules_internal(h_files_full_path, path)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}'".format(generated_file))
 | |
| 
 | |
| def mk_all_gparams_register_modules():
 | |
|     if not ONLY_MAKEFILES:
 | |
|         for c in get_components():
 | |
|             if c.require_mem_initializer():
 | |
|                 cnames = []
 | |
|                 cnames.extend(c.deps)
 | |
|                 cnames.append(c.name)
 | |
|                 mk_gparams_register_modules(cnames, c.src_dir)
 | |
| 
 | |
| # Generate a .def based on the files at c.export_files slot.
 | |
| def mk_def_file(c):
 | |
|     defname = '%s.def' % os.path.join(c.src_dir, c.name)
 | |
|     dll_name = c.dll_name
 | |
|     export_header_files = []
 | |
|     for dot_h in c.export_files:
 | |
|         dot_h_c = c.find_file(dot_h, c.name)
 | |
|         api = os.path.join(dot_h_c.src_dir, dot_h)
 | |
|         export_header_files.append(api)
 | |
|     mk_genfile_common.mk_def_file_internal(defname, dll_name, export_header_files)
 | |
|     if VERBOSE:
 | |
|         print("Generated '%s'" % defname)
 | |
| 
 | |
| def mk_def_files():
 | |
|     if not ONLY_MAKEFILES:
 | |
|         for c in get_components():
 | |
|             if c.require_def_file():
 | |
|                 mk_def_file(c)
 | |
| 
 | |
| def cp_z3py_to_build():
 | |
|     mk_dir(BUILD_DIR)
 | |
|     mk_dir(os.path.join(BUILD_DIR, 'python'))
 | |
|     z3py_dest = os.path.join(BUILD_DIR, 'python', 'z3')
 | |
|     z3py_src = os.path.join(Z3PY_SRC_DIR, 'z3')
 | |
| 
 | |
|     # Erase existing .pyc files
 | |
|     for root, dirs, files in os.walk(Z3PY_SRC_DIR):
 | |
|         for f in files:
 | |
|             if f.endswith('.pyc'):
 | |
|                 rmf(os.path.join(root, f))
 | |
|     # We do not want a second copy of the compiled files in the system-wide cache,
 | |
|     # so we disable it temporarily. This is an issue with recent versions of MacOS
 | |
|     # where XCode's Python has a cache, but the build scripts don't have access to
 | |
|     # it (e.g. during OPAM package installation).
 | |
|     have_cache = hasattr(sys, 'pycache_prefix') and sys.pycache_prefix is not None
 | |
|     if have_cache:
 | |
|         pycache_prefix_before = sys.pycache_prefix
 | |
|         sys.pycache_prefix = None
 | |
|     # Compile Z3Py files
 | |
|     if compileall.compile_dir(z3py_src, force=1) != 1:
 | |
|         raise MKException("failed to compile Z3Py sources")
 | |
|     if have_cache:
 | |
|         sys.pycache_prefix = pycache_prefix_before
 | |
|     if is_verbose:
 | |
|         print("Generated python bytecode")
 | |
|     # Copy sources to build
 | |
|     mk_dir(z3py_dest)
 | |
|     for py in filter(lambda f: f.endswith('.py'), os.listdir(z3py_src)):
 | |
|         shutil.copyfile(os.path.join(z3py_src, py), os.path.join(z3py_dest, py))
 | |
|         if is_verbose():
 | |
|             print("Copied '%s'" % py)
 | |
|     # Python 2.x support
 | |
|     for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(z3py_src)):
 | |
|         shutil.copyfile(os.path.join(z3py_src, pyc), os.path.join(z3py_dest, pyc))
 | |
|         if is_verbose():
 | |
|             print("Copied '%s'" % pyc)
 | |
|     # Python 3.x support
 | |
|     src_pycache = os.path.join(z3py_src, '__pycache__')
 | |
|     target_pycache = os.path.join(z3py_dest, '__pycache__')
 | |
|     if os.path.exists(src_pycache):
 | |
|         for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(src_pycache)):
 | |
|             mk_dir(target_pycache)
 | |
|             shutil.copyfile(os.path.join(src_pycache, pyc), os.path.join(target_pycache, pyc))
 | |
|             if is_verbose():
 | |
|                 print("Copied '%s'" % pyc)
 | |
|     # Copy z3test.py
 | |
|     shutil.copyfile(os.path.join(Z3PY_SRC_DIR, 'z3test.py'), os.path.join(BUILD_DIR, 'python', 'z3test.py'))
 | |
| 
 | |
| def mk_bindings(api_files):
 | |
|     if not ONLY_MAKEFILES:
 | |
|         mk_z3consts_py(api_files)
 | |
|         new_api_files = []
 | |
|         api = get_component(API_COMPONENT)
 | |
|         for api_file in api_files:
 | |
|             api_file_path = api.find_file(api_file, api.name)
 | |
|             new_api_files.append(os.path.join(api_file_path.src_dir, api_file))
 | |
|         g = globals()
 | |
|         g["API_FILES"] = new_api_files
 | |
|         if is_java_enabled():
 | |
|             check_java()
 | |
|             mk_z3consts_java(api_files)
 | |
|         # Generate some of the bindings and "api" module files
 | |
|         import update_api
 | |
|         dotnet_output_dir = None
 | |
|         if is_dotnet_core_enabled():
 | |
|           dotnet_output_dir = os.path.join(BUILD_DIR, 'dotnet')
 | |
|           mk_dir(dotnet_output_dir)
 | |
|         java_input_dir = None
 | |
|         java_output_dir = None
 | |
|         java_package_name = None
 | |
|         if is_java_enabled():
 | |
|           java_output_dir = get_component('java').src_dir
 | |
|           java_input_dir = get_component('java').src_dir
 | |
|           java_package_name = get_component('java').package_name
 | |
|         ml_output_dir = None
 | |
|         if is_ml_enabled():
 | |
|           ml_output_dir = get_component('ml').src_dir
 | |
|         # Get the update_api module to do the work for us
 | |
|         update_api.VERBOSE = is_verbose()
 | |
|         update_api.generate_files(api_files=new_api_files,
 | |
|           api_output_dir=get_component('api').src_dir,
 | |
|           z3py_output_dir=get_z3py_dir(),
 | |
|           dotnet_output_dir=dotnet_output_dir,
 | |
|           java_input_dir=java_input_dir,
 | |
|           java_output_dir=java_output_dir,
 | |
|           java_package_name=java_package_name,
 | |
|           ml_output_dir=ml_output_dir,
 | |
|           ml_src_dir=ml_output_dir
 | |
|         )
 | |
|         cp_z3py_to_build()
 | |
|         if is_ml_enabled():
 | |
|             check_ml()
 | |
|             mk_z3consts_ml(api_files)
 | |
|         if  is_dotnet_core_enabled():
 | |
|             check_dotnet_core()
 | |
|             mk_z3consts_dotnet(api_files, dotnet_output_dir)
 | |
| 
 | |
| # Extract enumeration types from API files, and add python definitions.
 | |
| def mk_z3consts_py(api_files):
 | |
|     if Z3PY_SRC_DIR is None:
 | |
|         raise MKException("You must invoke set_z3py_dir(path):")
 | |
|     full_path_api_files = []
 | |
|     api_dll = get_component(Z3_DLL_COMPONENT)
 | |
|     for api_file in api_files:
 | |
|         api_file_c = api_dll.find_file(api_file, api_dll.name)
 | |
|         api_file   = os.path.join(api_file_c.src_dir, api_file)
 | |
|         full_path_api_files.append(api_file)
 | |
|     generated_file = mk_genfile_common.mk_z3consts_py_internal(full_path_api_files, Z3PY_SRC_DIR)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}".format(generated_file))
 | |
| 
 | |
| # Extract enumeration types from z3_api.h, and add .Net definitions
 | |
| def mk_z3consts_dotnet(api_files, output_dir):
 | |
|     dotnet = get_component(DOTNET_COMPONENT)
 | |
|     if not dotnet:
 | |
|        dotnet = get_component(DOTNET_CORE_COMPONENT)
 | |
|     full_path_api_files = []
 | |
|     for api_file in api_files:
 | |
|         api_file_c = dotnet.find_file(api_file, dotnet.name)
 | |
|         api_file   = os.path.join(api_file_c.src_dir, api_file)
 | |
|         full_path_api_files.append(api_file)
 | |
|     generated_file = mk_genfile_common.mk_z3consts_dotnet_internal(full_path_api_files, output_dir)
 | |
|     if VERBOSE:
 | |
|         print("Generated '{}".format(generated_file))
 | |
| 
 | |
| # Extract enumeration types from z3_api.h, and add Java definitions
 | |
| def mk_z3consts_java(api_files):
 | |
|     java = get_component(JAVA_COMPONENT)
 | |
|     full_path_api_files = []
 | |
|     for api_file in api_files:
 | |
|         api_file_c = java.find_file(api_file, java.name)
 | |
|         api_file   = os.path.join(api_file_c.src_dir, api_file)
 | |
|         full_path_api_files.append(api_file)
 | |
|     generated_files = mk_genfile_common.mk_z3consts_java_internal(
 | |
|         full_path_api_files,
 | |
|         java.package_name,
 | |
|         java.src_dir)
 | |
|     if VERBOSE:
 | |
|         for generated_file in generated_files:
 | |
|             print("Generated '{}'".format(generated_file))
 | |
| 
 | |
| # Extract enumeration types from z3_api.h, and add ML definitions
 | |
| def mk_z3consts_ml(api_files):
 | |
|     ml = get_component(ML_COMPONENT)
 | |
|     full_path_api_files = []
 | |
|     for api_file in api_files:
 | |
|         api_file_c = ml.find_file(api_file, ml.name)
 | |
|         api_file   = os.path.join(api_file_c.src_dir, api_file)
 | |
|         full_path_api_files.append(api_file)
 | |
|     generated_file = mk_genfile_common.mk_z3consts_ml_internal(
 | |
|         full_path_api_files,
 | |
|         ml.src_dir)
 | |
|     if VERBOSE:
 | |
|         print ('Generated "%s"' % generated_file)
 | |
| 
 | |
| def mk_gui_str(id):
 | |
|     return '4D2F40D8-E5F9-473B-B548-%012d' % id
 | |
| 
 | |
| def get_platform_toolset_str():
 | |
|     default = 'v110';
 | |
|     vstr = check_output(['msbuild', '/ver'])
 | |
|     lines = vstr.split('\n')
 | |
|     lline = lines[-1]
 | |
|     tokens = lline.split('.')
 | |
|     if len(tokens) < 2:
 | |
|         return default
 | |
|     else:
 | |
|         if tokens[0] == "15":
 | |
|             # Visual Studio 2017 reports 15.* but the PlatformToolsetVersion is 141
 | |
|             return "v141"
 | |
|         else:
 | |
|             return 'v' + tokens[0] + tokens[1]
 | |
| 
 | |
| def mk_vs_proj_property_groups(f, name, target_ext, type):
 | |
|     f.write('  <ItemGroup Label="ProjectConfigurations">\n')
 | |
|     f.write('    <ProjectConfiguration Include="Debug|Win32">\n')
 | |
|     f.write('      <Configuration>Debug</Configuration>\n')
 | |
|     f.write('      <Platform>Win32</Platform>\n')
 | |
|     f.write('    </ProjectConfiguration>\n')
 | |
|     f.write('    <ProjectConfiguration Include="Release|Win32">\n')
 | |
|     f.write('      <Configuration>Release</Configuration>\n')
 | |
|     f.write('      <Platform>Win32</Platform>\n')
 | |
|     f.write('    </ProjectConfiguration>\n')
 | |
|     f.write('  </ItemGroup>\n')
 | |
|     f.write('  <PropertyGroup Label="Globals">\n')
 | |
|     f.write('    <ProjectGuid>{%s}</ProjectGuid>\n' % mk_gui_str(0))
 | |
|     f.write('    <ProjectName>%s</ProjectName>\n' % name)
 | |
|     f.write('    <Keyword>Win32Proj</Keyword>\n')
 | |
|     f.write('    <PlatformToolset>%s</PlatformToolset>\n' % get_platform_toolset_str())
 | |
|     f.write('  </PropertyGroup>\n')
 | |
|     f.write('  <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />\n')
 | |
|     f.write('  <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'" Label="Configuration">\n')
 | |
|     f.write('    <ConfigurationType>%s</ConfigurationType>\n' % type)
 | |
|     f.write('    <CharacterSet>Unicode</CharacterSet>\n')
 | |
|     f.write('    <UseOfMfc>false</UseOfMfc>\n')
 | |
|     f.write('  </PropertyGroup>\n')
 | |
|     f.write('  <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'" Label="Configuration">\n')
 | |
|     f.write('    <ConfigurationType>%s</ConfigurationType>\n' % type)
 | |
|     f.write('    <CharacterSet>Unicode</CharacterSet>\n')
 | |
|     f.write('    <UseOfMfc>false</UseOfMfc>\n')
 | |
|     f.write('  </PropertyGroup>\n')
 | |
|     f.write('  <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />\n')
 | |
|     f.write('  <ImportGroup Label="ExtensionSettings" />\n')
 | |
|     f.write('   <ImportGroup Label="PropertySheets">\n')
 | |
|     f.write('    <Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists(\'$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\')" Label="LocalAppDataPlatform" />  </ImportGroup>\n')
 | |
|     f.write('  <PropertyGroup Label="UserMacros" />\n')
 | |
|     f.write('  <PropertyGroup>\n')
 | |
|     f.write('    <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">$(SolutionDir)\\$(ProjectName)\\$(Configuration)\\</OutDir>\n')
 | |
|     f.write('    <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">%s</TargetName>\n' % name)
 | |
|     f.write('    <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">.%s</TargetExt>\n' % target_ext)
 | |
|     f.write('    <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">$(SolutionDir)\\$(ProjectName)\\$(Configuration)\\</OutDir>\n')
 | |
|     f.write('    <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">%s</TargetName>\n' % name)
 | |
|     f.write('    <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">.%s</TargetExt>\n' % target_ext)
 | |
|     f.write('  </PropertyGroup>\n')
 | |
|     f.write('  <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">\n')
 | |
|     f.write('        <IntDir>$(ProjectName)\\$(Configuration)\\</IntDir>\n')
 | |
|     f.write('  </PropertyGroup>\n')
 | |
|     f.write('  <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">\n')
 | |
|     f.write('    <IntDir>$(ProjectName)\\$(Configuration)\\</IntDir>\n')
 | |
|     f.write('  </PropertyGroup>\n')
 | |
| 
 | |
| 
 | |
| def mk_vs_proj_cl_compile(f, name, components, debug):
 | |
|     f.write('    <ClCompile>\n')
 | |
|     f.write('      <Optimization>Disabled</Optimization>\n')
 | |
|     if debug:
 | |
|         f.write('      <PreprocessorDefinitions>WIN32;_DEBUG;Z3DEBUG;_TRACE;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n')
 | |
|     else:
 | |
|         f.write('      <PreprocessorDefinitions>WIN32;NDEBUG;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n')
 | |
|     if VS_PAR:
 | |
|         f.write('      <MinimalRebuild>false</MinimalRebuild>\n')
 | |
|         f.write('      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n')
 | |
|     else:
 | |
|         f.write('      <MinimalRebuild>true</MinimalRebuild>\n')
 | |
|     f.write('      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n')
 | |
|     f.write('      <WarningLevel>Level3</WarningLevel>\n')
 | |
|     if debug:
 | |
|         f.write('      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n')
 | |
|     else:
 | |
|         f.write('      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n')
 | |
|     f.write('      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n')
 | |
|     f.write('      <AdditionalIncludeDirectories>')
 | |
|     deps = find_all_deps(name, components)
 | |
|     first = True
 | |
|     for dep in deps:
 | |
|         if first:
 | |
|             first = False
 | |
|         else:
 | |
|             f.write(';')
 | |
|         f.write(get_component(dep).to_src_dir)
 | |
|     f.write(';%s\n' % os.path.join(REV_BUILD_DIR, SRC_DIR))
 | |
|     f.write('</AdditionalIncludeDirectories>\n')
 | |
|     f.write('    </ClCompile>\n')
 | |
| 
 | |
| def mk_vs_proj_dep_groups(f, name, components):
 | |
|     f.write('  <ItemGroup>\n')
 | |
|     deps = find_all_deps(name, components)
 | |
|     for dep in deps:
 | |
|         dep = get_component(dep)
 | |
|         for cpp in filter(lambda f: f.endswith('.cpp'), os.listdir(dep.src_dir)):
 | |
|             f.write('    <ClCompile Include="%s" />\n' % os.path.join(dep.to_src_dir, cpp))
 | |
|     f.write('  </ItemGroup>\n')
 | |
| 
 | |
| def mk_vs_proj_link_exe(f, name, debug):
 | |
|     f.write('    <Link>\n')
 | |
|     f.write('      <OutputFile>$(OutDir)%s.exe</OutputFile>\n' % name)
 | |
|     f.write('      <GenerateDebugInformation>true</GenerateDebugInformation>\n')
 | |
|     f.write('      <SubSystem>Console</SubSystem>\n')
 | |
|     f.write('      <StackReserveSize>8388608</StackReserveSize>\n')
 | |
|     f.write('      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n')
 | |
|     f.write('      <DataExecutionPrevention/>\n')
 | |
|     f.write('      <TargetMachine>MachineX86</TargetMachine>\n')
 | |
|     f.write('      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n')
 | |
|     f.write('      <AdditionalDependencies>psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n')
 | |
|     f.write('    </Link>\n')
 | |
| 
 | |
| def mk_vs_proj(name, components):
 | |
|     if not VS_PROJ:
 | |
|         return
 | |
|     proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
 | |
|     modes=['Debug', 'Release']
 | |
|     PLATFORMS=['Win32']
 | |
|     f = open(proj_name, 'w')
 | |
|     f.write('<?xml version="1.0" encoding="utf-8"?>\n')
 | |
|     f.write('<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\n')
 | |
|     mk_vs_proj_property_groups(f, name, 'exe', 'Application')
 | |
|     f.write('  <ItemDefinitionGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">\n')
 | |
|     mk_vs_proj_cl_compile(f, name, components, debug=True)
 | |
|     mk_vs_proj_link_exe(f, name, debug=True)
 | |
|     f.write('  </ItemDefinitionGroup>\n')
 | |
|     f.write('  <ItemDefinitionGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">\n')
 | |
|     mk_vs_proj_cl_compile(f, name, components, debug=False)
 | |
|     mk_vs_proj_link_exe(f, name, debug=False)
 | |
|     f.write('  </ItemDefinitionGroup>\n')
 | |
|     mk_vs_proj_dep_groups(f, name, components)
 | |
|     f.write('  <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />\n')
 | |
|     f.write('  <ImportGroup Label="ExtensionTargets">\n')
 | |
|     f.write('  </ImportGroup>\n')
 | |
|     f.write('</Project>\n')
 | |
|     f.close()
 | |
|     if is_verbose():
 | |
|         print("Generated '%s'" % proj_name)
 | |
| 
 | |
| def mk_vs_proj_link_dll(f, name, debug):
 | |
|     f.write('    <Link>\n')
 | |
|     f.write('      <OutputFile>$(OutDir)%s.dll</OutputFile>\n' % name)
 | |
|     f.write('      <GenerateDebugInformation>true</GenerateDebugInformation>\n')
 | |
|     f.write('      <SubSystem>Console</SubSystem>\n')
 | |
|     f.write('      <StackReserveSize>8388608</StackReserveSize>\n')
 | |
|     f.write('      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n')
 | |
|     f.write('      <DataExecutionPrevention/>\n')
 | |
|     f.write('      <TargetMachine>MachineX86</TargetMachine>\n')
 | |
|     f.write('      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n')
 | |
|     f.write('      <AdditionalDependencies>psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n')
 | |
|     f.write('      <ModuleDefinitionFile>%s</ModuleDefinitionFile>' % os.path.join(get_component('api_dll').to_src_dir, 'api_dll.def'))
 | |
|     f.write('    </Link>\n')
 | |
| 
 | |
| def mk_vs_proj_dll(name, components):
 | |
|     if not VS_PROJ:
 | |
|         return
 | |
|     proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
 | |
|     modes=['Debug', 'Release']
 | |
|     PLATFORMS=['Win32']
 | |
|     f = open(proj_name, 'w')
 | |
|     f.write('<?xml version="1.0" encoding="utf-8"?>\n')
 | |
|     f.write('<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\n')
 | |
|     mk_vs_proj_property_groups(f, name, 'dll', 'DynamicLibrary')
 | |
|     f.write('  <ItemDefinitionGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">\n')
 | |
|     mk_vs_proj_cl_compile(f, name, components, debug=True)
 | |
|     mk_vs_proj_link_dll(f, name, debug=True)
 | |
|     f.write('  </ItemDefinitionGroup>\n')
 | |
|     f.write('  <ItemDefinitionGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">\n')
 | |
|     mk_vs_proj_cl_compile(f, name, components, debug=False)
 | |
|     mk_vs_proj_link_dll(f, name, debug=False)
 | |
|     f.write('  </ItemDefinitionGroup>\n')
 | |
|     mk_vs_proj_dep_groups(f, name, components)
 | |
|     f.write('  <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />\n')
 | |
|     f.write('  <ImportGroup Label="ExtensionTargets">\n')
 | |
|     f.write('  </ImportGroup>\n')
 | |
|     f.write('</Project>\n')
 | |
|     f.close()
 | |
|     if is_verbose():
 | |
|         print("Generated '%s'" % proj_name)
 | |
| 
 | |
| def mk_win_dist(build_path, dist_path):
 | |
|     for c in get_components():
 | |
|         c.mk_win_dist(build_path, dist_path)
 | |
| 
 | |
| def mk_unix_dist(build_path, dist_path):
 | |
|     for c in get_components():
 | |
|         c.mk_unix_dist(build_path, dist_path)
 | |
|     # Add Z3Py to bin directory
 | |
|     for pyc in filter(lambda f: f.endswith('.pyc') or f.endswith('.py'), os.listdir(build_path)):
 | |
|         shutil.copy(os.path.join(build_path, pyc),
 | |
|                     os.path.join(dist_path, INSTALL_BIN_DIR, pyc))
 | |
| 
 | |
| class MakeRuleCmd(object):
 | |
|     """
 | |
|         These class methods provide a convenient way to emit frequently
 | |
|         needed commands used in Makefile rules
 | |
|         Note that several of the method are meant for use during ``make
 | |
|         install`` and ``make uninstall``.  These methods correctly use
 | |
|         ``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferable
 | |
|         to writing commands manually which can be error prone.
 | |
|     """
 | |
|     @classmethod
 | |
|     def install_root(cls):
 | |
|         """
 | |
|             Returns a string that will expand to the
 | |
|             install location when used in a makefile rule.
 | |
|         """
 | |
|         # Note: DESTDIR is to support staged installs
 | |
|         return "$(DESTDIR)$(PREFIX)/"
 | |
| 
 | |
|     @classmethod
 | |
|     def _is_str(cls, obj):
 | |
|         if sys.version_info.major > 2:
 | |
|             # Python 3 or newer. Strings are always unicode and of type str
 | |
|             return isinstance(obj, str)
 | |
|         else:
 | |
|             # Python 2. Has byte-string and unicode representation, allow both
 | |
|             return isinstance(obj, str) or isinstance(obj, unicode)
 | |
| 
 | |
|     @classmethod
 | |
|     def _install_root(cls, path, in_prefix, out, is_install=True):
 | |
|         if not in_prefix:
 | |
|             # The Python bindings on OSX are sometimes not installed inside the prefix.
 | |
|             install_root = "$(DESTDIR)"
 | |
|             action_string = 'install' if is_install else 'uninstall'
 | |
|             cls.write_cmd(out, 'echo "WARNING: {}ing files/directories ({}) that are not in the install prefix ($(PREFIX))."'.format(
 | |
|                     action_string, path))
 | |
|             #print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format(
 | |
|             #        action_string, 'to' if is_install else 'from', path, PREFIX))
 | |
|         else:
 | |
|             # assert not os.path.isabs(path)
 | |
|             install_root = cls.install_root()
 | |
|         return install_root
 | |
| 
 | |
|     @classmethod
 | |
|     def install_files(cls, out, src_pattern, dest, in_prefix=True):
 | |
|         assert len(dest) > 0
 | |
|         assert cls._is_str(src_pattern)
 | |
|         assert not ' ' in src_pattern
 | |
|         assert cls._is_str(dest)
 | |
|         assert not ' ' in dest
 | |
|         assert not os.path.isabs(src_pattern)
 | |
|         install_root = cls._install_root(dest, in_prefix, out)
 | |
| 
 | |
|         cls.write_cmd(out, "cp {src_pattern} {install_root}{dest}".format(
 | |
|             src_pattern=src_pattern,
 | |
|             install_root=install_root,
 | |
|             dest=dest))
 | |
| 
 | |
|     @classmethod
 | |
|     def remove_installed_files(cls, out, pattern, in_prefix=True):
 | |
|         assert len(pattern) > 0
 | |
|         assert cls._is_str(pattern)
 | |
|         assert not ' ' in pattern
 | |
|         install_root = cls._install_root(pattern, in_prefix, out, is_install=False)
 | |
| 
 | |
|         cls.write_cmd(out, "rm -f {install_root}{pattern}".format(
 | |
|             install_root=install_root,
 | |
|             pattern=pattern))
 | |
| 
 | |
|     @classmethod
 | |
|     def make_install_directory(cls, out, dir, in_prefix=True):
 | |
|         assert len(dir) > 0
 | |
|         assert cls._is_str(dir)
 | |
|         assert not ' ' in dir
 | |
|         install_root = cls._install_root(dir, in_prefix, out)
 | |
| 
 | |
|         if is_windows():
 | |
|             cls.write_cmd(out, "IF NOT EXIST {dir} (mkdir {dir})".format(
 | |
|                 install_root=install_root,
 | |
|                 dir=dir))
 | |
|         else:
 | |
|             cls.write_cmd(out, "mkdir -p {install_root}{dir}".format(
 | |
|                 install_root=install_root,
 | |
|                 dir=dir))
 | |
| 
 | |
|     @classmethod
 | |
|     def _is_path_prefix_of(cls, temp_path, target_as_abs):
 | |
|         """
 | |
|             Returns True iff ``temp_path`` is a path prefix
 | |
|             of ``target_as_abs``
 | |
|         """
 | |
|         assert cls._is_str(temp_path)
 | |
|         assert cls._is_str(target_as_abs)
 | |
|         assert len(temp_path) > 0
 | |
|         assert len(target_as_abs) > 0
 | |
|         assert os.path.isabs(temp_path)
 | |
|         assert os.path.isabs(target_as_abs)
 | |
| 
 | |
|         # Need to stick extra slash in front otherwise we might think that
 | |
|         # ``/lib`` is a prefix of ``/lib64``.  Of course if ``temp_path ==
 | |
|         # '/'`` then we shouldn't else we would check if ``//`` (rather than
 | |
|         # ``/``) is a prefix of ``/lib64``, which would fail.
 | |
|         if len(temp_path) > 1:
 | |
|             temp_path += os.sep
 | |
|         return target_as_abs.startswith(temp_path)
 | |
| 
 | |
|     @classmethod
 | |
|     def create_relative_symbolic_link(cls, out, target, link_name):
 | |
|         assert cls._is_str(target)
 | |
|         assert cls._is_str(link_name)
 | |
|         assert len(target) > 0
 | |
|         assert len(link_name) > 0
 | |
|         assert not os.path.isabs(target)
 | |
|         assert not os.path.isabs(link_name)
 | |
| 
 | |
|         # We can't test to see if link_name is a file or directory
 | |
|         # because it may not exist yet. Instead follow the convention
 | |
|         # that if there is a leading slash target is a directory otherwise
 | |
|         # it's a file
 | |
|         if link_name[-1] != '/':
 | |
|             # link_name is a file
 | |
|             temp_path = os.path.dirname(link_name)
 | |
|         else:
 | |
|             # link_name is a directory
 | |
|             temp_path = link_name[:-1]
 | |
|         temp_path = '/' + temp_path
 | |
|         relative_path = ""
 | |
|         targetAsAbs = '/' + target
 | |
|         assert os.path.isabs(targetAsAbs)
 | |
|         assert os.path.isabs(temp_path)
 | |
|         # Keep walking up the directory tree until temp_path
 | |
|         # is a prefix of targetAsAbs
 | |
|         while not cls._is_path_prefix_of(temp_path, targetAsAbs):
 | |
|             assert temp_path != '/'
 | |
|             temp_path = os.path.dirname(temp_path)
 | |
|             relative_path += '../'
 | |
| 
 | |
|         # Now get the path from the common prefix directory to the target
 | |
|         target_from_prefix = targetAsAbs[len(temp_path):]
 | |
|         relative_path += target_from_prefix
 | |
|         # Remove any double slashes
 | |
|         relative_path = relative_path.replace('//','/')
 | |
|         cls.create_symbolic_link(out, relative_path, link_name)
 | |
| 
 | |
|     @classmethod
 | |
|     def create_symbolic_link(cls, out, target, link_name):
 | |
|         assert cls._is_str(target)
 | |
|         assert cls._is_str(link_name)
 | |
|         assert not os.path.isabs(target)
 | |
| 
 | |
|         cls.write_cmd(out, 'ln -s {target} {install_root}{link_name}'.format(
 | |
|             target=target,
 | |
|             install_root=cls.install_root(),
 | |
|             link_name=link_name))
 | |
| 
 | |
|     # TODO: Refactor all of the build system to emit commands using this
 | |
|     # helper to simplify code. This will also let us replace ``@`` with
 | |
|     # ``$(Verb)`` and have it set to ``@`` or empty at build time depending on
 | |
|     # a variable (e.g. ``VERBOSE``) passed to the ``make`` invocation. This
 | |
|     # would be very helpful for debugging.
 | |
|     @classmethod
 | |
|     def write_cmd(cls, out, line):
 | |
|         out.write("\t@{}\n".format(line))
 | |
| 
 | |
| def strip_path_prefix(path, prefix):
 | |
|     if path.startswith(prefix):
 | |
|         stripped_path = path[len(prefix):]
 | |
|         stripped_path.replace('//','/')
 | |
|         if stripped_path[0] == '/':
 | |
|             stripped_path = stripped_path[1:]
 | |
|         assert not os.path.isabs(stripped_path)
 | |
|         return stripped_path
 | |
|     else:
 | |
|         return path
 | |
| 
 | |
| def configure_file(template_file_path, output_file_path, substitutions):
 | |
|     """
 | |
|         Read a template file ``template_file_path``, perform substitutions
 | |
|         found in the ``substitutions`` dictionary and write the result to
 | |
|         the output file ``output_file_path``.
 | |
|         The template file should contain zero or more template strings of the
 | |
|         form ``@NAME@``.
 | |
|         The substitutions dictionary maps old strings (without the ``@``
 | |
|         symbols) to their replacements.
 | |
|     """
 | |
|     assert isinstance(template_file_path, str)
 | |
|     assert isinstance(output_file_path, str)
 | |
|     assert isinstance(substitutions, dict)
 | |
|     assert len(template_file_path) > 0
 | |
|     assert len(output_file_path) > 0
 | |
|     print("Generating {} from {}".format(output_file_path, template_file_path))
 | |
| 
 | |
|     if not os.path.exists(template_file_path):
 | |
|         raise MKException('Could not find template file "{}"'.format(template_file_path))
 | |
| 
 | |
|     # Read whole template file into string
 | |
|     template_string = None
 | |
|     with open(template_file_path, 'r') as f:
 | |
|         template_string = f.read()
 | |
| 
 | |
|     # Do replacements
 | |
|     for (old_string, replacement) in substitutions.items():
 | |
|         template_string = template_string.replace('@{}@'.format(old_string), replacement)
 | |
| 
 | |
|     # Write the string to the file
 | |
|     with open(output_file_path, 'w') as f:
 | |
|         f.write(template_string)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     import doctest
 | |
|     doctest.testmod()
 |