aboutsummaryrefslogtreecommitdiffstats
path: root/capstone/bindings/python/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'capstone/bindings/python/setup.py')
-rwxr-xr-xcapstone/bindings/python/setup.py233
1 files changed, 233 insertions, 0 deletions
diff --git a/capstone/bindings/python/setup.py b/capstone/bindings/python/setup.py
new file mode 100755
index 000000000..55934b5e0
--- /dev/null
+++ b/capstone/bindings/python/setup.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+
+import glob
+import os
+import shutil
+import sys
+import platform
+
+from distutils import log
+from setuptools import setup
+from distutils.util import get_platform
+from distutils.command.build import build
+from distutils.command.sdist import sdist
+from setuptools.command.bdist_egg import bdist_egg
+
+SYSTEM = sys.platform
+
+# adapted from commit e504b81 of Nguyen Tan Cong
+# Reference: https://docs.python.org/2/library/platform.html#cross-platform
+IS_64BITS = sys.maxsize > 2**32
+
+# are we building from the repository or from a source distribution?
+ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
+LIBS_DIR = os.path.join(ROOT_DIR, 'capstone', 'lib')
+HEADERS_DIR = os.path.join(ROOT_DIR, 'capstone', 'include')
+SRC_DIR = os.path.join(ROOT_DIR, 'src')
+BUILD_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
+
+# Parse version from pkgconfig.mk
+VERSION_DATA = {}
+with open(os.path.join(BUILD_DIR, 'pkgconfig.mk')) as fp:
+ lines = fp.readlines()
+ for line in lines:
+ line = line.strip()
+ if len(line) == 0:
+ continue
+ if line.startswith('#'):
+ continue
+ if '=' not in line:
+ continue
+
+ k, v = line.split('=', 1)
+ k = k.strip()
+ v = v.strip()
+ if len(k) == 0 or len(v) == 0:
+ continue
+ VERSION_DATA[k] = v
+
+if 'PKG_MAJOR' not in VERSION_DATA or \
+ 'PKG_MINOR' not in VERSION_DATA or \
+ 'PKG_EXTRA' not in VERSION_DATA:
+ raise Exception("Malformed pkgconfig.mk")
+
+if 'PKG_TAG' in VERSION_DATA:
+ VERSION = '{PKG_MAJOR}.{PKG_MINOR}.{PKG_EXTRA}.{PKG_TAG}'.format(**VERSION_DATA)
+else:
+ VERSION = '{PKG_MAJOR}.{PKG_MINOR}.{PKG_EXTRA}'.format(**VERSION_DATA)
+
+if SYSTEM == 'darwin':
+ VERSIONED_LIBRARY_FILE = "libcapstone.{PKG_MAJOR}.dylib".format(**VERSION_DATA)
+ LIBRARY_FILE = "libcapstone.dylib"
+ STATIC_LIBRARY_FILE = 'libcapstone.a'
+elif SYSTEM in ('win32', 'cygwin'):
+ VERSIONED_LIBRARY_FILE = "capstone.dll"
+ LIBRARY_FILE = "capstone.dll"
+ STATIC_LIBRARY_FILE = None
+else:
+ VERSIONED_LIBRARY_FILE = "libcapstone.so.{PKG_MAJOR}".format(**VERSION_DATA)
+ LIBRARY_FILE = "libcapstone.so"
+ STATIC_LIBRARY_FILE = 'libcapstone.a'
+
+def clean_bins():
+ shutil.rmtree(LIBS_DIR, ignore_errors=True)
+ shutil.rmtree(HEADERS_DIR, ignore_errors=True)
+
+def copy_sources():
+ """Copy the C sources into the source directory.
+ This rearranges the source files under the python distribution
+ directory.
+ """
+ src = []
+
+ try:
+ shutil.rmtree("src/")
+ except (IOError, OSError):
+ pass
+
+ shutil.copytree(os.path.join(BUILD_DIR, "arch"), os.path.join(SRC_DIR, "arch"))
+ shutil.copytree(os.path.join(BUILD_DIR, "include"), os.path.join(SRC_DIR, "include"))
+
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "*.[ch]")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "*.mk")))
+
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "Makefile")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "LICENSE*")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "README")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "*.TXT")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "RELEASE_NOTES")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "make.sh")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "CMakeLists.txt")))
+ src.extend(glob.glob(os.path.join(BUILD_DIR, "pkgconfig.mk")))
+
+ for filename in src:
+ outpath = os.path.join(SRC_DIR, os.path.basename(filename))
+ log.info("%s -> %s" % (filename, outpath))
+ shutil.copy(filename, outpath)
+
+def build_libraries():
+ """
+ Prepare the capstone directory for a binary distribution or installation.
+ Builds shared libraries and copies header files.
+
+ Will use a src/ dir if one exists in the current directory, otherwise assumes it's in the repo
+ """
+ cwd = os.getcwd()
+ clean_bins()
+ os.mkdir(HEADERS_DIR)
+ os.mkdir(LIBS_DIR)
+
+ # copy public headers
+ shutil.copytree(os.path.join(BUILD_DIR, 'include', 'capstone'), os.path.join(HEADERS_DIR, 'capstone'))
+
+ # if prebuilt libraries are available, use those and cancel build
+ if os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE)) and \
+ (not STATIC_LIBRARY_FILE or os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE))):
+ shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE), LIBS_DIR)
+ if STATIC_LIBRARY_FILE is not None:
+ shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE), LIBS_DIR)
+ return
+
+ os.chdir(BUILD_DIR)
+
+ # platform description refers at https://docs.python.org/2/library/sys.html#sys.platform
+ if SYSTEM == "win32":
+ # Windows build: this process requires few things:
+ # - CMake + MSVC installed
+ # - Run this command in an environment setup for MSVC
+ if not os.path.exists("build"): os.mkdir("build")
+ os.chdir("build")
+ # Do not build tests & static library
+ os.system('cmake -DCMAKE_BUILD_TYPE=RELEASE -DCAPSTONE_BUILD_TESTS=0 -DCAPSTONE_BUILD_STATIC=0 -G "NMake Makefiles" ..')
+ os.system("nmake")
+ else: # Unix incl. cygwin
+ os.system("CAPSTONE_BUILD_CORE_ONLY=yes bash ./make.sh")
+
+ shutil.copy(VERSIONED_LIBRARY_FILE, os.path.join(LIBS_DIR, LIBRARY_FILE))
+
+ # only copy static library if it exists (it's a build option)
+ if STATIC_LIBRARY_FILE and os.path.exists(STATIC_LIBRARY_FILE):
+ shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
+ os.chdir(cwd)
+
+
+class custom_sdist(sdist):
+ def run(self):
+ clean_bins()
+ copy_sources()
+ return sdist.run(self)
+
+
+class custom_build(build):
+ def run(self):
+ if 'LIBCAPSTONE_PATH' in os.environ:
+ log.info('Skipping building C extensions since LIBCAPSTONE_PATH is set')
+ else:
+ log.info('Building C extensions')
+ build_libraries()
+ return build.run(self)
+
+
+class custom_bdist_egg(bdist_egg):
+ def run(self):
+ self.run_command('build')
+ return bdist_egg.run(self)
+
+def dummy_src():
+ return []
+
+cmdclass = {}
+cmdclass['build'] = custom_build
+cmdclass['sdist'] = custom_sdist
+cmdclass['bdist_egg'] = custom_bdist_egg
+
+try:
+ from setuptools.command.develop import develop
+ class custom_develop(develop):
+ def run(self):
+ log.info("Building C extensions")
+ build_libraries()
+ return develop.run(self)
+
+ cmdclass['develop'] = custom_develop
+except ImportError:
+ print("Proper 'develop' support unavailable.")
+
+if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
+ idx = sys.argv.index('bdist_wheel') + 1
+ sys.argv.insert(idx, '--plat-name')
+ name = get_platform()
+ if 'linux' in name:
+ # linux_* platform tags are disallowed because the python ecosystem is fubar
+ # linux builds should be built in the centos 5 vm for maximum compatibility
+ # see https://github.com/pypa/manylinux
+ # see also https://github.com/angr/angr-dev/blob/master/bdist.sh
+ sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine())
+ else:
+ # https://www.python.org/dev/peps/pep-0425/
+ sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_'))
+
+setup(
+ provides=['capstone'],
+ packages=['capstone'],
+ name='capstone',
+ version=VERSION,
+ author='Nguyen Anh Quynh',
+ author_email='aquynh@gmail.com',
+ description='Capstone disassembly engine',
+ url='http://www.capstone-engine.org',
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+ classifiers=[
+ 'License :: OSI Approved :: BSD License',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ ],
+ requires=['ctypes'],
+ cmdclass=cmdclass,
+ zip_safe=True,
+ include_package_data=True,
+ package_data={
+ "capstone": ["lib/*", "include/capstone/*"],
+ }
+)