If, some package are required for the installation of your package (for example here `cmake`), you should also add them to the `install_requires`list.
If, some package are required for the installation of your package (for example here `cmake`), you should also add them to the `install_requires`list.
Sometimes you’ll want to use packages that are properly arranged with setuptools, but aren’t published to PyPI. In those cases, you can specify a list of one or more `dependency_links` URLs where the package can be downloaded, along with some additional hints, and setuptools will find and install the package correctly.
Sometime, you code is slow and instead of blaming yourself for your poor algorithm, you can blame python. [pybind1](https://github.com/pybind/pybind11) allows you to do just that.
> **pybind11** is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent [Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time introspection.
So great you can now have a lightweight interface to recode some of your function into C/C++. But what about packaging ? `setuptools` almost only understand python (it can compile simple C/C++ code).
The https://github.com/pybind/cmake_example repository gives an example on how to use cmake within a `setup.py`script.
Ideally we want to:
- use `setuptools`to build standards pypi packages
- use[`cmake`](https://cmake.org/) to compile complex C/C++ library
- be able to include loots of C/C++ library (because writing C/C++ code is a pain, and some people do it better than ourselfs)
### Simple C/C++ code
The https://github.com/pybind/cmake_example repository gives an example on how to use cmake within a `setup.py`script.
The idea is to write a `CMakeExtension` class from the `Extension`class to rewrite the default `Extention` attributes (we don't want `setuptools`to try to do it's own compilation on top of our `cmake` compilation). And then use the informations retrived by `CMakeExtension` to run `cmake` as a subprocess in with a `CMakeBuild` class.
description='A test project using pybind11 and CMake',
long_description='',
ext_modules=[CMakeExtension('cmake_example')],
cmdclass=dict(build_ext=CMakeBuild),
zip_safe=False,
)
```
You just need to as your `CMakeList.txt` in your `src/`folder and your `.cpp` file in a folder of your choise within the `src/` folder (here `src/`).
```cmake
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)
add_subdirectory(pybind11)
pybind11_add_module(cmake_example src/main.cpp)
```
Finaly, you want your `main.cpp` file to be included in your package (by default only the `.py` files are going to be included). Therefore, you have to write a `MANIFEST.in` in your `src/`:
```bash
include README.md LICENSE
global-include CMakeLists.txt *.cmake
recursive-include src *
recursive-include pybind11/include *.h
```
## Built Distribution vs Source Archive
### Built Distribution
> A [Distribution](https://packaging.python.org/glossary/#term-Distribution-Package) format containing files and metadata that only need to be moved to the correct location on the target system, to be installed. [Wheel](https://packaging.python.org/glossary/#term-Wheel) is such a format, whereas distutil’s [Source Distribution](https://packaging.python.org/glossary/#term-Source-Distribution-or-sdist) is not, in that it requires a build step before it can be installed. This format does not imply that Python files have to be precompiled ([Wheel](https://packaging.python.org/glossary/#term-Wheel) intentionally does not include compiled Python files).
Advantages:
- Quick to install
Disadvantages:
- Can be system specific (especially with C/C++ dependencies)
### Source Archive
> An archive containing the raw source code for a [Release](https://packaging.python.org/glossary/#term-Release), prior to creation of a [Source Distribution](https://packaging.python.org/glossary/#term-Source-Distribution-or-sdist) or [Built Distribution](https://packaging.python.org/glossary/#term-Built-Distribution).
Advantages:
- Easily build on any systems
Disadvantages:
- You have to compile everything with each installation
### Manylinux project
Linux comes in many variants and flavors, such as Debian, CentOS, Fedora, and Pacman. Each of these may use slight variations in shared libraries, such as `libncurses`, and core C libraries, such as `glibc`.
If you’re writing a C/C++ extension, then this could create a problem. A source file written in C and compiled on Ubuntu Linux isn’t guaranteed to be executable on a CentOS machine or an Arch Linux distribution. Do you need to build a separate wheel for each and every Linux variant?
> The goal of the manylinux project is to provide a convenient way to distribute binary Python extensions as wheels on Linux. This effort has produced [PEP 513](https://www.python.org/dev/peps/pep-0513/) which is further enhanced by [PEP 571](https://www.python.org/dev/peps/pep-0571/) defining `manylinux2010_x86_64` and `manylinux2010_i686` platform tags.
>
> PEP 513 defined `manylinux1_x86_64` and `manylinux1_i686` platform tags and the wheels were built on Centos5. Centos5 reached End of Life (EOL) on March 31st, 2017 and thus PEP 571 was proposed.
Which mean that instead of having Built distribution file like that `midr-1.3.9-cp38-cp38-linux_x86_64.whl` which won't be accepted by pypi, we will get at `midr-1.3.9-cp36-cp36m-manylinux1_x86_64.whl` file.
For this we will build the package within a [manylinux container (hosted on quay.io)](https://quay.io/organization/pypa)
```bash
docker run -it--volume$(pwd):/root/ quay.io/pypa/manylinux1_x86_64
cd /root/
```
The image has different version of python installed in `/opt/python/`
```bash
cd /root/
/opt/python/cp38-cp38/bin/pip3 install cmake
PATH=$PATH:/opt/_internal/cpython-3.8.5/bin/
/opt/python/cp36-36mu/pip wheel ./ -w output
```
will produce a binary wheel in **/output**. However, this will *still* not be a **manylinux** wheel, since it is possible to build wheels that accidentally depend on other libraries.
The **auditwheel** tool will take that wheel, audit it, and copy it to a **manylinux** name: