Merge branch 'feat/better_python_setup_next' of https://github.com/angr/capstone into angr-feat/better_python_setup_next
diff --git a/bindings/python/.gitignore b/bindings/python/.gitignore
index 31c196e..61178e6 100644
--- a/bindings/python/.gitignore
+++ b/bindings/python/.gitignore
@@ -1,3 +1,9 @@
 MANIFEST
 dist/
-src/
\ No newline at end of file
+src/
+capstone/lib
+capstone/include
+pyx/lib
+pyx/include
+pyx/*.c
+pyx/*.pyx
diff --git a/bindings/python/BUILDING.txt b/bindings/python/BUILDING.txt
new file mode 100644
index 0000000..13938ad
--- /dev/null
+++ b/bindings/python/BUILDING.txt
@@ -0,0 +1,77 @@
+0. This documentation explains how to install the Python bindings for Capstone
+   from source. If you want to install it from a PyPi package (recommended if
+   you are on Windows), see README.txt.
+
+1. To install capstone and the python bindings on *nix, run the command below:
+
+		$ sudo make install
+
+   To install capstone for python 3, run the command below:
+   (Note: this requires python3 installed in your machine)
+
+		$ sudo make install3
+
+   To control the install destination, set the DESTDIR environment variable.
+
+2. For better Python performance, install cython-based binding with:
+
+		$ sudo make install_cython
+
+	Note that this requires cython installed first. To install cython, see
+	below.
+	
+3. To install cython, you have to ensure that the header files
+   and the static library for Python are installed beforehand.
+
+	E.g. on Ubuntu, do:
+
+		$ sudo apt-get install python-dev
+
+	Depending on if you already have pip or easy_install installed, install
+	cython with either:
+
+		$ sudo pip install cython
+	or:
+		$ sudo easy_install cython
+
+	NOTE: Depending on your distribution you might also be able to
+	      install the required cython version using your repository.
+
+	E.g. on Ubuntu, do:
+	
+		$ sudo apt-get install cython
+
+	However, our cython-based binding requires cython version 0.19 or newer,
+	but sometimes distributions only provide older version. Make sure to
+	verify the current installed version before going into section 2 above.
+	
+	E.g, on Ubuntu, you can verify the current cython version with:
+
+		$ apt-cache policy cython
+
+	Which should at least print version 0.19
+
+4. This directory contains some test code to show how to use the Capstone API.
+
+- test_basic.py
+  This code shows the most simple form of API where we only want to get basic
+  information out of disassembled instruction, such as address, mnemonic and
+  operand string.
+
+- test_lite.py
+  Similarly to test_basic.py, but this code shows how to use disasm_lite(), a lighter
+  method to disassemble binary. Unlike disasm() API (used by test_basic.py), which returns
+  CsInsn objects, this API just returns tuples of (address, size, mnemonic, op_str).
+
+  The main reason for using this API is better performance: disasm_lite() is at least
+  20% faster than disasm(). Memory usage is also less. So if you just need basic
+  information out of disassembler, use disasm_lite() instead of disasm().
+
+- test_detail.py:
+  This code shows how to access to architecture-neutral information in disassembled
+  instructions, such as implicit registers read/written, or groups of instructions
+  that this instruction belong to.
+
+- test_<arch>.py
+  These code show how to access architecture-specific information for each
+  architecture.
diff --git a/bindings/python/MANIFEST.in b/bindings/python/MANIFEST.in
index 0be11e6..98776c7 100644
--- a/bindings/python/MANIFEST.in
+++ b/bindings/python/MANIFEST.in
@@ -1,5 +1,5 @@
-recursive-include capstone *
 recursive-include src *
-recursive-include prebuilt *
 include LICENSE.TXT
-include README
+include README.txt
+include BUILDING.txt
+include Makefile
diff --git a/bindings/python/Makefile b/bindings/python/Makefile
index ca4ebf8..102503c 100644
--- a/bindings/python/Makefile
+++ b/bindings/python/Makefile
@@ -1,130 +1,68 @@
-ifndef BUILDDIR
-OBJDIR = build
-else
-OBJDIR = $(abspath $(BUILDDIR))/obj/bindings/python
-endif
-
-.PHONY: gen_const install install3 install_cython clean
+.PHONY: gen_const install install3 install_cython sdist sdist3 bdist bdist3 clean check
 
 gen_const:
 	cd .. && python const_generator.py python
 
 install:
-	rm -rf $(OBJDIR) src/
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
+	rm -rf src/
 	if test -n "${DESTDIR}"; then \
-		python setup.py build -b $(OBJDIR) install --root="${DESTDIR}"; \
+		python setup.py build install --root="${DESTDIR}"; \
 	else \
-		python setup.py build -b $(OBJDIR) install; \
+		python setup.py build install; \
 	fi
 
 install3:
-	rm -rf $(OBJDIR) src/
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
+	rm -rf src/
 	if test -n "${DESTDIR}"; then \
-		python3 setup.py build -b $(OBJDIR) install --root="${DESTDIR}"; \
+		python3 setup.py build install --root="${DESTDIR}"; \
 	else \
-		python3 setup.py build -b $(OBJDIR) install; \
+		python3 setup.py build install; \
 	fi
 
 # NOTE: Newer cython can be installed by: sudo pip install --upgrade cython
 install_cython:
-	rm -rf $(OBJDIR) src/ dist/
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
-	mkdir -p $(OBJDIR)/pyx
-	cp setup_cython.py $(OBJDIR)
-	cp pyx/ccapstone* $(OBJDIR)/pyx/
-	cp capstone/__init__.py $(OBJDIR)/pyx/__init__.py
-	cp capstone/arm.py $(OBJDIR)/pyx/arm.pyx
-	cp capstone/arm_const.py $(OBJDIR)/pyx/arm_const.pyx
-	cp capstone/arm64.py $(OBJDIR)/pyx/arm64.pyx
-	cp capstone/arm64_const.py $(OBJDIR)/pyx/arm64_const.pyx
-	cp capstone/m68k.py $(OBJDIR)/pyx/m68k.pyx
-	cp capstone/m68k_const.py $(OBJDIR)/pyx/m68k_const.pyx
-	cp capstone/mips.py $(OBJDIR)/pyx/mips.pyx
-	cp capstone/mips_const.py $(OBJDIR)/pyx/mips_const.pyx
-	cp capstone/ppc.py $(OBJDIR)/pyx/ppc.pyx
-	cp capstone/ppc_const.py $(OBJDIR)/pyx/ppc_const.pyx
-	cp capstone/sparc.py $(OBJDIR)/pyx/sparc.pyx
-	cp capstone/sparc_const.py $(OBJDIR)/pyx/sparc_const.pyx
-	cp capstone/systemz.py $(OBJDIR)/pyx/systemz.pyx
-	cp capstone/sysz_const.py $(OBJDIR)/pyx/sysz_const.pyx
-	cp capstone/x86.py $(OBJDIR)/pyx/x86.pyx
-	cp capstone/x86_const.py $(OBJDIR)/pyx/x86_const.pyx
-	cp capstone/xcore.py $(OBJDIR)/pyx/xcore.pyx
-	cp capstone/xcore_const.py $(OBJDIR)/pyx/xcore_const.pyx
-	cd $(OBJDIR) && python setup_cython.py build -b ./tmp install --home=$(OBJDIR)
-	mv $(OBJDIR)/build/lib/python/capstone/* capstone
-	cd $(OBJDIR) && python setup_cython.py build -b ./tmp install
+	rm -rf src/
+	if test -n "${DESTDIR}"; then \
+		python setup_cython.py build install --root="${DESTDIR}"; \
+	else \
+		python setup_cython.py build install; \
+	fi
 
-build_cython:
-	rm -rf $(OBJDIR) src/ dist/
-	mkdir -p $(OBJDIR)/pyx
-	cp setup_cython.py $(OBJDIR)
-	cp pyx/ccapstone* $(OBJDIR)/pyx/
-	cp capstone/__init__.py $(OBJDIR)/pyx/__init__.py
-	cp capstone/arm.py $(OBJDIR)/pyx/arm.pyx
-	cp capstone/arm_const.py $(OBJDIR)/pyx/arm_const.pyx
-	cp capstone/arm64.py $(OBJDIR)/pyx/arm64.pyx
-	cp capstone/arm64_const.py $(OBJDIR)/pyx/arm64_const.pyx
-	cp capstone/m68k.py $(OBJDIR)/pyx/m68k.pyx
-	cp capstone/m68k_const.py $(OBJDIR)/pyx/m68k_const.pyx
-	cp capstone/mips.py $(OBJDIR)/pyx/mips.pyx
-	cp capstone/mips_const.py $(OBJDIR)/pyx/mips_const.pyx
-	cp capstone/ppc.py $(OBJDIR)/pyx/ppc.pyx
-	cp capstone/ppc_const.py $(OBJDIR)/pyx/ppc_const.pyx
-	cp capstone/sparc.py $(OBJDIR)/pyx/sparc.pyx
-	cp capstone/sparc_const.py $(OBJDIR)/pyx/sparc_const.pyx
-	cp capstone/systemz.py $(OBJDIR)/pyx/systemz.pyx
-	cp capstone/sysz_const.py $(OBJDIR)/pyx/sysz_const.pyx
-	cp capstone/x86.py $(OBJDIR)/pyx/x86.pyx
-	cp capstone/x86_const.py $(OBJDIR)/pyx/x86_const.pyx
-	cp capstone/xcore.py $(OBJDIR)/pyx/xcore.pyx
-	cp capstone/xcore_const.py $(OBJDIR)/pyx/xcore_const.pyx
-	cd $(OBJDIR) && python setup_cython.py build
+install3_cython:
+	rm -rf src/
+	if test -n "${DESTDIR}"; then \
+		python3 setup_cython.py build install --root="${DESTDIR}"; \
+	else \
+		python3 setup_cython.py build install; \
+	fi
 
 # build & upload PyPi package with source code of the core
 sdist:
 	rm -rf src/ dist/
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
-	cp README.pypi-src README
-	cp PKG-INFO.src PKG-INFO
 	python setup.py sdist register upload
 
 # build & upload PyPi package with source code of the core
 sdist3:
 	rm -rf src/ dist/
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
-	cp README.pypi-src README
-	cp PKG-INFO.src PKG-INFO
 	python3 setup.py sdist register upload
 
 # build & upload PyPi package with prebuilt core
-# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
-sdist_win:
+bdist:
 	rm -rf src/ dist/
-	cp README.pypi-win README
-	cp PKG-INFO.win PKG-INFO
-	python setup.py sdist register upload
+	python setup.py bdist_wheel register upload
 
 # build & upload PyPi package with prebuilt core
-# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
-sdist3_win:
+bdist3:
 	rm -rf src/ dist/
-	cp README.pypi-win README
-	cp PKG-INFO.win PKG-INFO
-	python3 setup.py sdist register upload
+	python3 setup.py bdist_wheel register upload
 
 clean:
-	rm -rf $(OBJDIR) src/ dist/ README
-	rm -f capstone/*.so
-	rm -rf prebuilt/win64/capstone.dll
-	rm -rf prebuilt/win32/capstone.dll
+	rm -rf build/ src/ dist/ *.egg-info
+	rm -rf capstone/lib capstone/include pyx/lib pyx/include
+	rm -f pyx/*.c pyx/__init__.py
+	for f in capstone/*.py; do rm -f pyx/$$(basename $$f)x; done
+	rm -f MANIFEST
+	rm -f *.pyc capstone/*.pyc
 
 
 TESTS = test_basic.py test_detail.py test_arm.py test_arm64.py test_m68k.py test_mips.py
diff --git a/bindings/python/PKG-INFO.src b/bindings/python/PKG-INFO.src
deleted file mode 100644
index b093395..0000000
--- a/bindings/python/PKG-INFO.src
+++ /dev/null
@@ -1,14 +0,0 @@
-Metadata-Version: 1.3
-Name: capstone
-Version: 4.0
-Author: Nguyen Anh Quynh
-Author-email: aquynh at gmail com
-Maintainer: Nguyen Anh Quynh
-Maintainer-email: aquynh at gmail com
-Home-page: http://www.capstone-engine.org
-Download-url: www.capstone-engine.org
-Summary: Capstone disassembly framework
-License: BSD
-Description: Capstone is a lightweight multi-platform, multi-architecture disassembly framework with some advanced features. Further information is available at the homepage http://www.capstone-engine.org
-Keywords: disassembly reverse binary arm arm64 aarch64 powerpc ppc m68k mips x86 x86_64 sparc systemz xcore
-Platform: Windows MacOSX Linux NetBSD FreeBSD OpenBSD Solaris Android iOS
diff --git a/bindings/python/PKG-INFO.win b/bindings/python/PKG-INFO.win
deleted file mode 100644
index 8da8ba6..0000000
--- a/bindings/python/PKG-INFO.win
+++ /dev/null
@@ -1,14 +0,0 @@
-Metadata-Version: 1.3
-Name: capstone
-Version: 4.0
-Author: Nguyen Anh Quynh
-Author-email: aquynh at gmail com
-Maintainer: Nguyen Anh Quynh
-Maintainer-email: aquynh at gmail com
-Home-page: http://www.capstone-engine.org
-Download-url: www.capstone-engine.org
-Summary: Capstone disassembly framework with Windows prebuilt core ready inside.
-License: BSD
-Description: Capstone is a lightweight multi-platform, multi-architecture disassembly framework with some advanced features. Further information is available at the homepage http://www.capstone-engine.org
-Keywords: disassembly reverse binary arm arm64 aarch64 powerpc ppc m68k mips x86 x86_64 sparc systemz xcore
-Platform: Windows MacOSX Linux NetBSD FreeBSD OpenBSD Solaris Android iOS
diff --git a/bindings/python/README.TXT b/bindings/python/README.TXT
deleted file mode 100644
index 1fdc36e..0000000
--- a/bindings/python/README.TXT
+++ /dev/null
@@ -1,106 +0,0 @@
-0. This documentation explains how to install Python binding for Capstone
-   from source. If you want to install it from PyPi package, see the below
-   docs instead:
-
-   - README.pypi-src: How to compile the Capstone core & install binding
-     at the same time from PyPi package "capstone"
-
-   - README.pypi-win: How to install binding for Windows from PyPi package
-     "capstone-windows". Note that this package already has prebuilt core
-     inside, so no compilation is needed.
-
-1. To install pure Python binding on *nix, run the command below:
-
-		$ sudo make install
-
-   To install Python3 binding package, run the command below:
-   (Note: this requires python3 installed in your machine)
-
-		$ sudo make install3
-
-2. For better Python performance, install cython-based binding with:
-
-		$ sudo make install_cython
-
-	Note that this requires cython installed in your machine first.
-	To install cython, see section 3 below.
-	
-3. To install cython, you have to ensure that the header files
-   and the static library for Python are installed beforehand.
-
-	E.g. on Ubuntu, do:
-
-		$ sudo apt-get install python-dev
-
-	Depending on if you already have pip or easy_install
-	installed, install cython with either:
-
-		$ sudo pip install cython
-	or:
-		$ sudo easy_install cython
-
-	NOTE: Depending on your distribution you might also be able to
-	      install the required cython version using your repository.
-
-	E.g. on Ubuntu, do:
-	
-		$ sudo apt-get install cython
-
-	However, our cython-based binding requires cython version 0.19 or newer,
-	but sometimes distributions only provide older version. Make sure to
-	verify the current installed version before going into section 2 above.
-	
-	E.g, on Ubuntu, you can verify the current cython version with:
-
-		$ apt-cache policy cython
-
-	Which should at least print version 0.19
-
-
-This directory contains some test code to show how to use Capstone API.
-
-- test_basic.py
-  This code shows the most simple form of API where we only want to get basic
-  information out of disassembled instruction, such as address, mnemonic and
-  operand string.
-
-- test_lite.py
-  Similarly to test_basic.py, but this code shows how to use disasm_lite(), a lighter
-  method to disassemble binary. Unlike disasm() API (used by test_basic.py), which returns
-  CsInsn objects, this API just returns tuples of (address, size, mnemonic, op_str).
-
-  The main reason for using this API is better performance: disasm_lite() is at least
-  20% faster than disasm(). Memory usage is also less. So if you just need basic
-  information out of disassembler, use disasm_lite() instead of disasm().
-
-- test_detail.py:
-  This code shows how to access to architecture-neutral information in disassembled
-  instructions, such as implicit registers read/written, or groups of instructions
-  that this instruction belong to.
-
-- test_<arch>.py
-  These code show how to access architecture-specific information for each
-  architecture.
-
-
-2. To install Python binding on Windows:
-
-Recommended method:
-
-	Use the Python module installer for 32/64 bit Windows from:
-
-		http://www.capstone-engine.org/download.html
-
-
-Manual method:
-
-	If the module installer fails to locate your Python install, or if you have
-	additional Python installs (e.g. Anaconda / virtualenv), run the following
-	command in command prompt:
-
-		C:\> C:\location_to_python\python.exe setup.py install
-
-	Next, copy capstone.dll from the 'Core engine for Windows' package available
-	on the same Capstone download page and paste it in the path:
-
-		C:\location_to_python\Lib\site-packages\capstone\
diff --git a/bindings/python/README.pypi-win b/bindings/python/README.pypi-win
deleted file mode 100644
index f37f9f7..0000000
--- a/bindings/python/README.pypi-win
+++ /dev/null
@@ -1,52 +0,0 @@
-NOTE: This package includes prebuilt Windows core of Capstone, so no external
-Capstone library is needed.
-
-On Windows, download this PyPi package and run "python setup.py install" from
-"Command Prompt" is all you need to install it.
-
-If you want to compile everything from source code instead, use the
-PyPi package "capstone" instead.
-
-    https://pypi.python.org/pypi/capstone
-
---------------------------------------------------------------------------------
-
-Capstone is a disassembly framework with the target of becoming the ultimate
-disasm engine for binary analysis and reversing in the security community.
-
-Created by Nguyen Anh Quynh, then developed and maintained by a small community,
-Capstone offers some unparalleled features:
-
-- Support multiple hardware architectures: ARM, ARM64 (ARMv8), Mips, PPC, Sparc,
-  SystemZ, XCore and X86 (including X86_64).
-
-- Having clean/simple/lightweight/intuitive architecture-neutral API.
-
-- Provide details on disassembled instruction (called “decomposer” by others).
-
-- Provide semantics of the disassembled instruction, such as list of implicit
-  registers read & written.
-
-- Implemented in pure C language, with lightweight wrappers for C++, C#, Go,
-  Java, NodeJS, Ocaml, Python, Ruby & Vala ready (available in main code,
-  or provided externally by the community).
-
-- Native support for all popular platforms: Windows, Mac OSX, iOS, Android,
-  Linux, *BSD, Solaris, etc.
-
-- Thread-safe by design.
-
-- Special support for embedding into firmware or OS kernel.
-
-- High performance & suitable for malware analysis (capable of handling various
-  X86 malware tricks).
-
-- Distributed under the open source BSD license.
-
-Further information is available at http://www.capstone-engine.org
-
-
-[License]
-
-This project is released under the BSD license. If you redistribute the binary
-or source code of Capstone, please attach file LICENSE.TXT with your products.
diff --git a/bindings/python/README.pypi-src b/bindings/python/README.txt
similarity index 64%
rename from bindings/python/README.pypi-src
rename to bindings/python/README.txt
index d8350b5..82fe148 100644
--- a/bindings/python/README.pypi-src
+++ b/bindings/python/README.txt
@@ -1,16 +1,18 @@
-NOTE: This PyPi package "capstone" includes source code of the core of Capstone.
-So installing this would also compile the core with C compiler (either "gcc" or
-"msvc" on Windows).
+To install Capstone, you should run `pip install capstone`.
 
-On Windows, MSVC needs compiler environmental setup, you would need to either
-run "pip install capstone" or "python setup.py install" from "Developer Command
-Prompt".
+If you would like to build Capstone with just the source distribution, without
+pip, just run `python setup.py install` in the folder with setup.py in it.
 
-For Windows, if you do not want to compile the core, try the "capstone-windows"
-package instead, which already includes the prebuilt "capstone.dll" inside.
+In order to use this source distribution, you will need an environment that can
+compile C code. On Linux, this is usually easy, but on Windows, this involves
+installing Visual Studio and using the "Developer Command Prompt" to perform the
+installation. See BUILDING.txt for more information.
 
-
-    https://pypi.python.org/pypi/capstone-windows
+If you don't want to build your own copy of Capstone, you can use a precompiled
+binary distribution from PyPI. Saying `pip install capstone` should
+automatically obtain an appropriate copy for your system. If it does not, please
+open an issue at https://github.com/aquynh/capstone and tag @rhelmot - they
+will fix this, probably!
 
 --------------------------------------------------------------------------------
 
diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py
index 62d57cd..2f16533 100644
--- a/bindings/python/capstone/__init__.py
+++ b/bindings/python/capstone/__init__.py
@@ -233,66 +233,56 @@
 CS_OP    = {v:k for k,v in locals().items() if k.startswith('CS_OP_')}
 CS_OPT   = {v:k for k,v in locals().items() if k.startswith('CS_OPT_')}
 
-import ctypes, ctypes.util, sys
+import ctypes, ctypes.util
 from os.path import split, join, dirname
 import distutils.sysconfig
-
+import pkg_resources
 
 import inspect
 if not hasattr(sys.modules[__name__], '__file__'):
     __file__ = inspect.getfile(inspect.currentframe())
 
-_lib_path = split(__file__)[0]
-_all_libs = ['capstone.dll', 'libcapstone.so', 'libcapstone.dylib']
+if sys.platform == 'darwin':
+    _lib = "libcapstone.dylib"
+elif sys.platform in ('win32', 'cygwin'):
+    _lib = "capstone.dll"
+else:
+    _lib = "libcapstone.so"
+
 _found = False
 
-for _lib in _all_libs:
+def _load_lib(path):
+    lib_file = join(path, _lib)
     try:
-        _lib_file = join(_lib_path, _lib)
-        # print "Trying to load:", _lib_file
-        _cs = ctypes.cdll.LoadLibrary(_lib_file)
-        _found = True
-        break
+        return ctypes.cdll.LoadLibrary(lib_file)
     except OSError:
-        pass
-if _found == False:
-    # try loading from default paths
-    for _lib in _all_libs:
-        try:
-            _cs = ctypes.cdll.LoadLibrary(_lib)
-            _found = True
-            break
-        except OSError:
-            pass
+        # if we're on linux, try again with .so.4 extension
+        if lib_file.endswith('.so'):
+            try:
+                return ctypes.cdll.LoadLibrary(lib_file + '.4')
+            except OSError:
+                return None
+        return None
 
-if _found == False:
-    # last try: loading from python lib directory
-    _lib_path = distutils.sysconfig.get_python_lib()
-    for _lib in _all_libs:
-        try:
-            _lib_file = join(_lib_path, 'capstone', _lib)
-            # print "Trying to load:", _lib_file
-            _cs = ctypes.cdll.LoadLibrary(_lib_file)
-            _found = True
-            break
-        except OSError:
-            pass
+_cs = None
 
-# Attempt Darwin specific load (10.11 specific),
-# since LD_LIBRARY_PATH is not guaranteed to exist
-if (_found == False) and (system() == 'Darwin'):
-    _lib_path = '/usr/local/lib/'
-    for _lib in _all_libs:
-        try:
-            _lib_file = join(_lib_path, _lib)
-            # print "Trying to load:", _lib_file
-            _cs = ctypes.cdll.LoadLibrary(_lib_file)
-            _found = True
-            break
-        except OSError:
-            pass
+# Loading attempts, in order
+# - pkg_resources can get us the path to the local libraries
+# - we can get the path to the local libraries by parsing our filename
+# - global load
+# - python's lib directory
+# - last-gasp attempt at some hardcoded paths on darwin and linux
 
-if _found == False:
+_path_list = [pkg_resources.resource_filename(__name__, 'lib'),
+              join(split(__file__)[0], 'lib'),
+              '',
+              distutils.sysconfig.get_python_lib(),
+              "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64']
+
+for _path in _path_list:
+    _cs = _load_lib(_path)
+    if _cs is not None: break
+else:
     raise ImportError("ERROR: fail to load the dynamic library.")
 
 
diff --git a/bindings/python/prebuilt/win32/.gitignore b/bindings/python/prebuilt/win32/.gitignore
deleted file mode 100644
index 46d0c85..0000000
--- a/bindings/python/prebuilt/win32/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-capstone.dll
-# Except this file
-!.gitignore
diff --git a/bindings/python/prebuilt/win64/.gitignore b/bindings/python/prebuilt/win64/.gitignore
deleted file mode 100644
index 46d0c85..0000000
--- a/bindings/python/prebuilt/win64/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-capstone.dll
-# Except this file
-!.gitignore
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 9c1d422..04983b2 100755
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -1,51 +1,45 @@
 #!/usr/bin/env python
+
 import glob
 import os
 import shutil
-import stat
 import sys
+import platform
 
 from distutils import log
-from distutils import dir_util
-from distutils.command.build_clib import build_clib
-from setuptools.command.sdist import sdist
 from setuptools import setup
-from distutils.sysconfig import get_python_lib
-
-# prebuilt libraries for Windows - for sdist
-PATH_LIB64 = "prebuilt/win64/capstone.dll"
-PATH_LIB32 = "prebuilt/win32/capstone.dll"
-
-# package name can be 'capstone' or 'capstone-windows'
-PKG_NAME = 'capstone'
-if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
-    PKG_NAME = 'capstone-windows'
+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
 VERSION = '4.0'
 
-# virtualenv breaks import, but get_python_lib() will work.
-SITE_PACKAGES = os.path.join(get_python_lib(), "capstone")
-if "--user" in sys.argv:
-    try:
-        from site import getusersitepackages
-        SITE_PACKAGES = os.path.join(getusersitepackages(), "capstone")
-    except ImportError:
-        pass
-
-# If building a wheel, the path listed in data_files is interpreted relative to
-# python's site-packages directory, even if it starts with a slash. So we need
-# to use only `/capstone` as path in this case.
-#
-# Note: using `capstone` does not work, since that for some reason is interpreted
-# relative to the the python installation prefix, not to the site-packages directory.
-if "bdist_wheel" in sys.argv:
-    SITE_PACKAGES = "/capstone"
-
-
 # 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
+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, '../..')
+
+if SYSTEM == 'darwin':
+    LIBRARY_FILE = "libcapstone.dylib"
+    STATIC_LIBRARY_FILE = 'libcapstone.a'
+elif SYSTEM in ('win32', 'cygwin'):
+    LIBRARY_FILE = "capstone.dll"
+    STATIC_LIBRARY_FILE = None
+else:
+    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.
@@ -55,130 +49,124 @@
     src = []
 
     try:
-        dir_util.remove_tree("src/")
+        shutil.rmtree("src/")
     except (IOError, OSError):
         pass
 
-    dir_util.copy_tree("../../arch", "src/arch/")
-    dir_util.copy_tree("../../include", "src/include/")
-    if SYSTEM == "win32":
-        dir_util.copy_tree("../../msvc/headers", "src/msvc/headers")
+    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("../../*.[ch]"))
-    src.extend(glob.glob("../../*.mk"))
+    src.extend(glob.glob(os.path.join(BUILD_DIR, "*.[ch]")))
+    src.extend(glob.glob(os.path.join(BUILD_DIR, "*.mk")))
 
-    src.extend(glob.glob("../../Makefile"))
-    src.extend(glob.glob("../../LICENSE*"))
-    src.extend(glob.glob("../../README"))
-    src.extend(glob.glob("../../*.TXT"))
-    src.extend(glob.glob("../../RELEASE_NOTES"))
-    src.extend(glob.glob("../../make.sh"))
-    src.extend(glob.glob("../../CMakeLists.txt"))
+    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")))
 
     for filename in src:
-        outpath = os.path.join("./src/", os.path.basename(filename))
+        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'))
+
+    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")
+
+    if LIBRARY_FILE.endswith('.so'):
+        shutil.copy(LIBRARY_FILE + '.4', os.path.join(LIBS_DIR, LIBRARY_FILE))
+    else:
+        shutil.copy(LIBRARY_FILE, LIBS_DIR)
+    if STATIC_LIBRARY_FILE: shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
+    os.chdir(cwd)
+
 
 class custom_sdist(sdist):
-    """Reshuffle files for distribution."""
-
     def run(self):
-        for filename in (glob.glob("capstone/*.dll")
-                         + glob.glob("capstone/*.so")
-                         + glob.glob("capstone/*.dylib")):
-            try:
-                os.unlink(filename)
-            except Exception:
-                pass
-
-        # if prebuilt libraries are existent, then do not copy source
-        if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
-            return sdist.run(self)
+        clean_bins()
         copy_sources()
         return sdist.run(self)
 
 
-class custom_build_clib(build_clib):
-    """Customized build_clib command."""
-
+class custom_build(build):
     def run(self):
-        log.info('running custom_build_clib')
-        build_clib.run(self)
+        log.info('Building C extensions')
+        build_libraries()
+        return build.run(self)
 
-    def finalize_options(self):
-        # We want build-clib to default to build-lib as defined by the "build"
-        # command.  This is so the compiled library will be put in the right
-        # place along side the python code.
-        self.set_undefined_options('build',
-                                   ('build_lib', 'build_clib'),
-                                   ('build_temp', 'build_temp'),
-                                   ('compiler', 'compiler'),
-                                   ('debug', 'debug'),
-                                   ('force', 'force'))
 
-        build_clib.finalize_options(self)
-
-    def build_libraries(self, libraries):
-        if SYSTEM in ("win32", "cygwin"):
-            # if Windows prebuilt library is available, then include it
-            if is_64bits and os.path.exists(PATH_LIB64):
-                shutil.copy(PATH_LIB64, "capstone")
-                return
-            elif os.path.exists(PATH_LIB32):
-                shutil.copy(PATH_LIB32, "capstone")
-                return
-
-        # build library from source if src/ is existent
-        if not os.path.exists('src'):
-            return
-
-        for (lib_name, build_info) in libraries:
-            log.info("building '%s' library", lib_name)
-
-            os.chdir("src")
-
-            # 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
-                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")
-                os.chdir("..")
-                so = "src/build/capstone.dll"
-            elif SYSTEM == "cygwin":
-                os.chmod("make.sh", stat.S_IREAD|stat.S_IEXEC)
-                if is_64bits:
-                    os.system("CAPSTONE_BUILD_CORE_ONLY=yes ./make.sh cygwin-mingw64")
-                else:
-                    os.system("CAPSTONE_BUILD_CORE_ONLY=yes ./make.sh cygwin-mingw32")
-
-                so = "src/capstone.dll"
-            else:   # Unix
-                os.chmod("make.sh", stat.S_IREAD|stat.S_IEXEC)
-                os.system("CAPSTONE_BUILD_CORE_ONLY=yes ./make.sh")
-                if SYSTEM == "darwin":
-                    so = "src/libcapstone.dylib"
-                else:   # Non-OSX
-                    so = "src/libcapstone.so"
-
-            os.chdir("..")
-            shutil.copy(so, "capstone")
-
+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=PKG_NAME,
+    name='capstone',
     version=VERSION,
     author='Nguyen Anh Quynh',
     author_email='aquynh@gmail.com',
@@ -190,20 +178,10 @@
         'Programming Language :: Python :: 3',
     ],
     requires=['ctypes'],
-    cmdclass=dict(
-        build_clib=custom_build_clib,
-        sdist=custom_sdist,
-    ),
-
-    libraries=[(
-        'capstone', dict(
-            package='capstone',
-            sources=dummy_src()
-        ),
-    )],
-    zip_safe=False,
+    cmdclass=cmdclass,
+    zip_safe=True,
     include_package_data=True,
     package_data={
-        "capstone": ["*.so", "*.dll", "*.dylib"],
+        "capstone": ["lib/*", "include/capstone/*"],
     }
 )
diff --git a/bindings/python/setup_cython.py b/bindings/python/setup_cython.py
index 585aea5..a81985f 100644
--- a/bindings/python/setup_cython.py
+++ b/bindings/python/setup_cython.py
@@ -1,33 +1,113 @@
+import os
+import sys
+import shutil
+
+from distutils import log
 from distutils.core import setup
 from distutils.extension import Extension
-from distutils.command.install_lib import install_lib as _install
+from distutils.command.build import build
 from Cython.Distutils import build_ext
 
 VERSION = '4.0'
+SYSTEM = sys.platform
 
-compile_args = ['-O3', '-fomit-frame-pointer']
+# 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
 
-ext_modules = [
-    Extension("capstone.ccapstone", ["pyx/ccapstone.pyx"], libraries=["capstone"], extra_compile_args=compile_args),
-    Extension("capstone.arm", ["pyx/arm.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.arm_const", ["pyx/arm_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.arm64", ["pyx/arm64.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.arm64_const", ["pyx/arm64_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.m68k", ["pyx/m68k.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.m68k_const", ["pyx/m68k_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.mips", ["pyx/mips.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.mips_const", ["pyx/mips_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.ppc", ["pyx/ppc.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.ppc_const", ["pyx/ppc_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.x86", ["pyx/x86.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.x86_const", ["pyx/x86_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.sparc", ["pyx/sparc.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.sparc_const", ["pyx/sparc_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.systemz", ["pyx/systemz.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.sysz_const", ["pyx/sysz_const.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.xcore", ["pyx/xcore.pyx"], extra_compile_args=compile_args),
-    Extension("capstone.xcore_const", ["pyx/xcore_const.pyx"], extra_compile_args=compile_args)
-]
+# 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, 'pyx', 'lib')
+HEADERS_DIR = os.path.join(ROOT_DIR, 'pyx', '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, '../..')
+PYPACKAGE_DIR = os.path.join(ROOT_DIR, 'capstone')
+CYPACKAGE_DIR = os.path.join(ROOT_DIR, 'pyx')
+
+if SYSTEM == 'darwin':
+    LIBRARY_FILE = "libcapstone.dylib"
+    STATIC_LIBRARY_FILE = 'libcapstone.a'
+elif SYSTEM in ('win32', 'cygwin'):
+    LIBRARY_FILE = "capstone.dll"
+    STATIC_LIBRARY_FILE = None
+else:
+    LIBRARY_FILE = "libcapstone.so"
+    STATIC_LIBRARY_FILE = 'libcapstone.a'
+
+compile_args = ['-O3', '-fomit-frame-pointer', '-I' + HEADERS_DIR]
+link_args = ['-L' + LIBS_DIR]
+
+ext_module_names = ['arm', 'arm_const', 'arm64', 'arm64_const', 'm68k', 'm68k_const', 'mips', 'mips_const', 'ppc', 'ppc_const', 'x86', 'x86_const', 'sparc', 'sparc_const', 'systemz', 'sysz_const', 'xcore', 'xcore_const']
+ext_modules = [Extension("capstone.ccapstone",
+                         ["pyx/ccapstone.pyx"],
+                         libraries=["capstone"],
+                         extra_compile_args=compile_args,
+                         extra_link_args=link_args)]
+ext_modules += [Extension("capstone.%s" % name,
+                          ["pyx/%s.pyx" % name],
+                          extra_compile_args=compile_args,
+                          extra_link_args=link_args)
+                for name in ext_module_names]
+
+def clean_bins():
+    shutil.rmtree(LIBS_DIR, ignore_errors=True)
+    shutil.rmtree(HEADERS_DIR, ignore_errors=True)
+
+def copy_pysources():
+    for fname in os.listdir(PYPACKAGE_DIR):
+        if not fname.endswith('.py'):
+            continue
+
+        if fname == '__init__.py':
+            shutil.copy(os.path.join(PYPACKAGE_DIR, fname), os.path.join(CYPACKAGE_DIR, fname))
+        else:
+            shutil.copy(os.path.join(PYPACKAGE_DIR, fname), os.path.join(CYPACKAGE_DIR, fname + 'x'))
+
+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'))
+
+    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")
+
+    if LIBRARY_FILE.endswith('.so'):
+        shutil.copy(LIBRARY_FILE + '.4', os.path.join(LIBS_DIR, LIBRARY_FILE))
+    else:
+        shutil.copy(LIBRARY_FILE, LIBS_DIR)
+    if STATIC_LIBRARY_FILE: shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
+    os.chdir(cwd)
+
+
+class custom_build(build):
+    def run(self):
+        log.info('Copying python sources')
+        copy_pysources()
+        log.info('Building C extensions')
+        build_libraries()
+        return build.run(self)
 
 # clean package directory first
 #import os.path, shutil, sys
@@ -46,7 +126,7 @@
     packages     = ['capstone'],
     name         = 'capstone',
     version      = VERSION,
-    cmdclass     = {'build_ext': build_ext},
+    cmdclass     = {'build_ext': build_ext, 'build': custom_build},
     ext_modules  = ext_modules,
     author       = 'Nguyen Anh Quynh',
     author_email = 'aquynh@gmail.com',
@@ -56,4 +136,8 @@
                 'License :: OSI Approved :: BSD License',
                 'Programming Language :: Python :: 2',
                 ],
+    include_package_data=True,
+    package_data={
+        "capstone": ["lib/*", "include/capstone/*"],
+    }
 )