diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed4fe302b38d0730ed6aa213743b4f9c0d7967a0..93bc6fb666075b3591cc99300630b8d75f5adee4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,8 +8,22 @@ if(NOT DEFINED BGS_PYTHON_SUPPORT)
 elseif()
   # add_definitions(-DBGS_PYTHON_SUPPORT)
 endif()
+# cmake -D BGS_PYTHON_ONLY=ON ..
+if(NOT DEFINED BGS_PYTHON_ONLY)
+  set(BGS_PYTHON_ONLY OFF)
+elseif()
+  # add_definitions(-DBGS_PYTHON_ONLY)
+endif()
+# cmake -D BGS_CORE_STATIC=ON ..
+if(NOT DEFINED BGS_CORE_STATIC)
+  set(BGS_CORE_STATIC OFF)
+elseif()
+  # add_definitions(-DBGS_CORE_STATIC)
+endif()
 message(STATUS "")
-message(STATUS "BGSLIBRARY WITH PYTHON SUPPORT: ${BGS_PYTHON_SUPPORT}")
+message(STATUS "BGS_PYTHON_SUPPORT: ${BGS_PYTHON_SUPPORT}")
+message(STATUS "BGS_PYTHON_ONLY:    ${BGS_PYTHON_ONLY}")
+message(STATUS "BGS_CORE_STATIC:    ${BGS_CORE_STATIC}")
 
 # cmake -D BGS_PYTHON_SUPPORT=ON -D BGS_PYTHON_VERSION=3 ..
 if(NOT DEFINED BGS_PYTHON_VERSION)
@@ -146,8 +160,10 @@ if(BGS_PYTHON_SUPPORT)
   message(STATUS "NUMPY_INCLUDE_DIR: ${NUMPY_INCLUDE_DIR}\n")
 endif()
 
-file(GLOB main_src src/*.cpp src/*.c)
-file(GLOB main_inc src/*.h src/*.hpp)
+if(NOT BGS_PYTHON_ONLY)
+  file(GLOB main_src src/*.cpp src/*.c)
+  file(GLOB main_inc src/*.h src/*.hpp)
+endif()
 
 file(GLOB_RECURSE utils_src src/utils/*.cpp src/utils/*.c)
 file(GLOB_RECURSE utils_inc src/utils/*.h src/utils/*.hpp)
@@ -177,16 +193,20 @@ if(${OpenCV_VERSION} VERSION_LESS 2.4.3)
   list(REMOVE_ITEM bgs_src ${gmg})
 endif()
 
-add_library(bgslibrary_core SHARED ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc})
-# generates the export header bgslibrary_core_EXPORTS.h automatically
-include(GenerateExportHeader)
-GENERATE_EXPORT_HEADER(bgslibrary_core
-    BASE_NAME bgslibrary_core
-    EXPORT_MACRO_NAME bgslibrary_core_EXPORTS
-    EXPORT_FILE_NAME bgslibrary_core_EXPORTS.h
-    STATIC_DEFINE BGSLIBRARY_CORE_EXPORTS_BUILT_AS_STATIC)
-target_link_libraries(bgslibrary_core ${OpenCV_LIBS})
-set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc})
+if(BGS_CORE_STATIC)
+  add_library(bgslibrary_core STATIC ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc})
+elseif()
+  add_library(bgslibrary_core SHARED ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc})
+  # generates the export header bgslibrary_core_EXPORTS.h automatically
+  include(GenerateExportHeader)
+  GENERATE_EXPORT_HEADER(bgslibrary_core
+      BASE_NAME bgslibrary_core
+      EXPORT_MACRO_NAME bgslibrary_core_EXPORTS
+      EXPORT_FILE_NAME bgslibrary_core_EXPORTS.h
+      STATIC_DEFINE BGSLIBRARY_CORE_EXPORTS_BUILT_AS_STATIC)
+  target_link_libraries(bgslibrary_core ${OpenCV_LIBS})
+  set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc})
+endif()
 
 if(BGS_PYTHON_SUPPORT)
   #add_library(bgs_python SHARED ${bgs_src} ${tools_src})
@@ -223,9 +243,11 @@ endif()
 #  endif()
 #endif()
 
-add_executable(bgslibrary ${main_src} ${main_inc})
-target_link_libraries(bgslibrary ${OpenCV_LIBS} bgslibrary_core)
-# set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs)
+if(NOT BGS_PYTHON_ONLY)
+  add_executable(bgslibrary ${main_src} ${main_inc})
+  target_link_libraries(bgslibrary ${OpenCV_LIBS} bgslibrary_core)
+  # set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs)
+endif()
 
 if(UNIX AND BGS_PYTHON_SUPPORT)
   execute_process(
@@ -244,24 +266,26 @@ if(UNIX AND BGS_PYTHON_SUPPORT)
   #install(TARGETS bgs_python DESTINATION ${CMAKE_CURRENT_SOURCE_DIR})
 endif()
 
-install(TARGETS bgslibrary_core
-  bgslibrary
-  RUNTIME DESTINATION bin COMPONENT app
-  LIBRARY DESTINATION lib COMPONENT runtime
-  ARCHIVE DESTINATION lib COMPONENT runtime
-  #PUBLIC_HEADER DESTINATION include/bgslibrary COMPONENT dev
-  FRAMEWORK DESTINATION "/Library/Frameworks"
-)
+if(NOT BGS_PYTHON_ONLY)
+  install(TARGETS bgslibrary_core
+    bgslibrary
+    RUNTIME DESTINATION bin COMPONENT app
+    LIBRARY DESTINATION lib COMPONENT runtime
+    ARCHIVE DESTINATION lib COMPONENT runtime
+    #PUBLIC_HEADER DESTINATION include/bgslibrary COMPONENT dev
+    FRAMEWORK DESTINATION "/Library/Frameworks"
+  )
 
-if(UNIX)
-  # to avoid: error while loading shared libraries: libbgslibrary_core.so
-  message(STATUS "You might need to run:")
-  message(STATUS "$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib")
-  message(STATUS "$ export LD_LIBRARY_PATH")
-  message(STATUS "after 'make install' to avoid error while loading libbgslibrary_core\n")
-endif()
+  if(UNIX)
+    # to avoid: error while loading shared libraries: libbgslibrary_core.so
+    message(STATUS "You might need to run:")
+    message(STATUS "$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib")
+    message(STATUS "$ export LD_LIBRARY_PATH")
+    message(STATUS "after 'make install' to avoid error while loading libbgslibrary_core\n")
+  endif()
 
-if(WIN32)
-  message(STATUS "You might need to add ${CMAKE_CURRENT_BINARY_DIR} to your PATH to be able to run your applications.")
-  message(STATUS "> set PATH=%PATH%;${CMAKE_CURRENT_BINARY_DIR}\n")
+  if(WIN32)
+    message(STATUS "You might need to add ${CMAKE_CURRENT_BINARY_DIR} to your PATH to be able to run your applications.")
+    message(STATUS "> set PATH=%PATH%;${CMAKE_CURRENT_BINARY_DIR}\n")
+  endif()
 endif()
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..edea572f1cfbb9767e74a1568bab922d741c3bbd
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,22 @@
+include *.txt
+prune src
+recursive-include src/algorithms *.*
+recursive-include src/tools *.*
+recursive-include src/utils *.*
+prune wrapper
+recursive-include wrapper/python *.*
+recursive-include modules *.*
+recursive-include pybgs *.*
+prune build
+prune dist
+prune tools
+prune test
+prune gui
+prune examples
+prune docs
+prune dataset
+prune config
+prune cmake-modules
+prune _dist
+prune _wiki
+prune _opencv_cmake
diff --git a/setup.py b/setup.py
index ed07e0098bf47d99979ce334f027af39b7ae61ac..9dc2bfecd099f6359425dd680a1c5b5eee2587f2 100644
--- a/setup.py
+++ b/setup.py
@@ -3,6 +3,10 @@ To build the bgslibrary:
     python setup.py build
 To build and install:
     python setup.py install
+To install using pip:
+    pip install .
+To install using PyPI:
+    pip install pybgs
 To package the wheel (after pip installing twine and wheel):
     python setup.py bdist_wheel
 To upload the binary wheel to PyPi
@@ -11,88 +15,184 @@ To upload the source distribution to PyPi
     python setup.py sdist
     twine upload dist/pybgs-*.tar.gz
 """
-import os
-import re
-import sys
-import platform
-import subprocess
+import os, re, sys, shutil, pathlib, platform, subprocess
 
 from setuptools import setup, find_packages, Extension
 from setuptools.command.build_ext import build_ext
+from setuptools.command.install_lib import install_lib
+from setuptools.command.install_scripts import install_scripts
+from distutils.command.install_data import install_data
 from distutils.version import LooseVersion
 
-#import datetime
-#now = datetime.datetime.now()
-#
-#pkg_properties={}
-#with open('.properties') as fp:
-#    for line in fp:
-#        if '=' in line:
-#            name, value = line.replace('\n','').split('=', 1)
-#            if "SNAPSHOT" in value:
-#                dev_version = "." + now.strftime("%y%m%d%H%M") + ".dev"
-#                value = value.replace("-SNAPSHOT", dev_version)
-#            pkg_properties[name] = value
-
+PACKAGE_NAME = "pybgs"
 
 class CMakeExtension(Extension):
     def __init__(self, name, sourcedir=''):
         Extension.__init__(self, name, sources=[])
         self.sourcedir = os.path.abspath(sourcedir)
 
+class InstallCMakeLibsData(install_data):
+    """
+    Just a wrapper to get the install data into the egg-info
 
-class CMakeBuild(build_ext):
+    Listing the installed files in the egg-info guarantees that
+    all of the package files will be uninstalled when the user
+    uninstalls your package through pip
+    """
     def run(self):
-        try:
-            out = subprocess.check_output(['cmake', '--version'])
-        except OSError:
-            raise RuntimeError("CMake must be installed to build the following extensions: " +
-                               ", ".join(e.name for e in self.extensions))
+        """
+        Outfiles are the libraries that were built using cmake
+        """
+        # There seems to be no other way to do this; I tried listing the
+        # libraries during the execution of the InstallCMakeLibs.run() but
+        # setuptools never tracked them, seems like setuptools wants to
+        # track the libraries through package data more than anything...
+        # help would be appriciated
+        self.outfiles = self.distribution.data_files
+
+class InstallCMakeLibs(install_lib):
+    """
+    Get the libraries from the parent distribution, use those as the outfiles
 
-        if platform.system() == "Windows":
-            cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1))
-            if cmake_version < '3.10.0':
-                raise RuntimeError("CMake >= 3.10.0 is required on Windows")
+    Skip building anything; everything is already built, forward libraries to
+    the installation step
+    """
+    def run(self):
+        """
+        Copy libraries from the bin directory and place them as appropriate
+        """
+        self.announce("Moving library files", level=3)
+        # We have already built the libraries in the previous build_ext step
+        self.skip_build = True
+        if hasattr(self.distribution, 'bin_dir'):
+            bin_dir = self.distribution.bin_dir
+        else:
+            bin_dir = os.path.join(self.build_dir)
+        # Depending on the files that are generated from your cmake
+        # build chain, you may need to change the below code, such that
+        # your files are moved to the appropriate location when the installation
+        # is run
+        libs = [os.path.join(bin_dir, _lib) for _lib in 
+                os.listdir(bin_dir) if 
+                os.path.isfile(os.path.join(bin_dir, _lib)) and 
+                os.path.splitext(_lib)[1] in [".dll", ".so"]
+                and not (_lib.startswith("python") or _lib.startswith(PACKAGE_NAME))]
+        for lib in libs:
+            shutil.move(lib, os.path.join(self.build_dir,
+                                          os.path.basename(lib)))
+        # Mark the libs for installation, adding them to 
+        # distribution.data_files seems to ensure that setuptools' record 
+        # writer appends them to installed-files.txt in the package's egg-info
+        #
+        # Also tried adding the libraries to the distribution.libraries list, 
+        # but that never seemed to add them to the installed-files.txt in the 
+        # egg-info, and the online recommendation seems to be adding libraries 
+        # into eager_resources in the call to setup(), which I think puts them 
+        # in data_files anyways. 
+        # 
+        # What is the best way?
+        # These are the additional installation files that should be
+        # included in the package, but are resultant of the cmake build
+        # step; depending on the files that are generated from your cmake
+        # build chain, you may need to modify the below code
+        self.distribution.data_files = [os.path.join(self.install_dir, 
+                                                     os.path.basename(lib))
+                                        for lib in libs]
+        # Must be forced to run after adding the libs to data_files
+        self.distribution.run_command("install_data")
+        super().run()
 
-        for ext in self.extensions:
-            self.build_extension(ext)
+class InstallCMakeScripts(install_scripts):
+    """
+    Install the scripts in the build dir
+    """
+    def run(self):
+        """
+        Copy the required directory to the build directory and super().run()
+        """
+        self.announce("Moving scripts files", level=3)
+        # Scripts were already built in a previous step
+        self.skip_build = True
+        bin_dir = self.distribution.bin_dir
+        scripts_dirs = [os.path.join(bin_dir, _dir) for _dir in
+                        os.listdir(bin_dir) if
+                        os.path.isdir(os.path.join(bin_dir, _dir))]
+        for scripts_dir in scripts_dirs:
+            shutil.move(scripts_dir,
+                        os.path.join(self.build_dir,
+                                     os.path.basename(scripts_dir)))
+        # Mark the scripts for installation, adding them to 
+        # distribution.scripts seems to ensure that the setuptools' record 
+        # writer appends them to installed-files.txt in the package's egg-info
+        self.distribution.scripts = scripts_dirs
+        super().run()
+
+class BuildCMakeExt(build_ext):
+    """
+    Builds using cmake instead of the python setuptools implicit build
+    """
+    def run(self):
+        """
+        Perform build_cmake before doing the 'normal' stuff
+        """
+        for extension in self.extensions:
+            self.build_cmake(extension)
+        super().run()
 
-    def build_extension(self, ext):
+    def build_cmake(self, extension: Extension):
+        """
+        The steps required to build the extension
+        """
+        self.announce("Preparing the build environment", level=3)
+        build_dir = pathlib.Path(self.build_temp)
+        extension_path = pathlib.Path(self.get_ext_fullpath(extension.name))
+        os.makedirs(build_dir, exist_ok=True)
+        os.makedirs(extension_path.parent.absolute(), exist_ok=True)
         python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
-        extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
-        cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
-                      '-DPYTHON_EXECUTABLE=' + sys.executable,
+
+        # Now that the necessary directories are created, build
+        self.announce("Configuring cmake project", level=3)
+        cmake_args = ['-DPYTHON_EXECUTABLE=' + sys.executable,
+                      '-DBGS_CORE_STATIC=ON',
                       '-DBGS_PYTHON_SUPPORT=ON',
+                      '-DBGS_PYTHON_ONLY=ON',
                       '-DBGS_PYTHON_VERSION=' + python_version]
+        if not os.path.exists(self.build_temp):
+            os.makedirs(self.build_temp)
+        self.spawn(['cmake', '-H'+extension.sourcedir, '-B'+self.build_temp]+ cmake_args)
 
-        cfg = 'Debug' if self.debug else 'Release'
-        build_args = ['--config', cfg]
+        self.announce("Building binaries", level=3)
+        self.spawn(["cmake", "--build", self.build_temp, 
+                    "--config", "Release", '--', '-j8'])
 
-        if platform.system() == "Windows":
-            cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
-            if sys.maxsize > 2**32:
-                cmake_args += ['-A', 'x64']
-            build_args += ['--', '/m']
-        else:
-            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
-            build_args += ['--', '-j8']
+        # Build finished, now copy the files into the copy directory
+        # The copy directory is the parent directory of the extension (.pyd)
+        self.announce("Moving built python module", level=3)
+        bin_dir = os.path.join(build_dir)
+        self.distribution.bin_dir = bin_dir
+        pyd_path = [os.path.join(bin_dir, _pyd) for _pyd in
+                    os.listdir(bin_dir) if
+                    os.path.isfile(os.path.join(bin_dir, _pyd)) and
+                    os.path.splitext(_pyd)[0].startswith(PACKAGE_NAME) and
+                    os.path.splitext(_pyd)[1] in [".pyd", ".so"]][0]
+        shutil.move(pyd_path, extension_path)
 
-        env = os.environ.copy()
-        env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''),
-                                                              self.distribution.get_version())
-        if not os.path.exists(self.build_temp):
-            os.makedirs(self.build_temp)
-        subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env)
-        subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp)
-        print()
+        # After build_ext is run, the following commands will run:
+        # 
+        # install_lib
+        # install_scripts
+        # 
+        # These commands are subclassed above to avoid pitfalls that
+        # setuptools tries to impose when installing these, as it usually
+        # wants to build those libs and scripts as well or move them to a
+        # different place. See comments above for additional information
 
 with open("README.md", "r") as fh:
     long_description = fh.read()
 
 setup(
     name='pybgs',
-    version='3.0.0',
-    #version=pkg_properties["version"],
+    version='3.0.0.post0',
     author='Andrews Sobral',
     author_email='andrewssobral@gmail.com',
     url='https://github.com/andrewssobral/bgslibrary',
@@ -100,10 +200,14 @@ setup(
     description='Python wrapper for bgslibrary using pybind11 and CMake',
     long_description=long_description,
     long_description_content_type="text/markdown",
-    ext_modules=[CMakeExtension('src')],
-    cmdclass=dict(build_ext=CMakeBuild),
+    ext_modules=[CMakeExtension(name='pybgs', sourcedir='.')],
+    cmdclass={
+        'build_ext': BuildCMakeExt,
+        'install_data': InstallCMakeLibsData,
+        'install_lib': InstallCMakeLibs,
+        #'install_scripts': InstallCMakeScripts
+        },
     zip_safe=False,
-    #packages=find_packages('pybgs'),
-    #package_dir={'':'pybgs'},
+    packages=find_packages(),
     keywords=['BGSLibrary', 'Background Subtraction', 'Computer Vision', 'Machine Learning'],
 )