2022-03-24 17:19:17 +01:00
|
|
|
Linux | macOS | Windows
|
|
|
|
|
------------------------------------------------ | ------------------------------------------------ | -------
|
|
|
|
|
[![Status][linux_python_svg]][linux_python_link] | [![Status][macos_python_svg]][macos_python_link] | [![Status][windows_python_svg]][windows_python_link]
|
2020-03-04 17:42:26 +01:00
|
|
|
|
2022-05-16 11:27:02 +02:00
|
|
|
[linux_python_svg]: https://github.com/google/or-tools/actions/workflows/cmake_linux_python.yml/badge.svg?branch=main
|
2021-10-27 17:42:45 +02:00
|
|
|
[linux_python_link]: https://github.com/google/or-tools/actions/workflows/cmake_linux_python.yml
|
2022-05-16 11:27:02 +02:00
|
|
|
[macos_python_svg]: https://github.com/google/or-tools/actions/workflows/cmake_macos_python.yml/badge.svg?branch=main
|
2021-10-27 17:42:45 +02:00
|
|
|
[macos_python_link]: https://github.com/google/or-tools/actions/workflows/cmake_macos_python.yml
|
2022-05-16 11:27:02 +02:00
|
|
|
[windows_python_svg]: https://github.com/google/or-tools/actions/workflows/cmake_windows_python.yml/badge.svg?branch=main
|
2021-10-27 17:42:45 +02:00
|
|
|
[windows_python_link]: https://github.com/google/or-tools/actions/workflows/cmake_windows_python.yml
|
2020-03-04 17:42:26 +01:00
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
# Introduction
|
2020-03-04 17:42:26 +01:00
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
To be compliant with
|
|
|
|
|
[PEP513](https://www.python.org/dev/peps/pep-0513/#the-manylinux1-policy) a
|
|
|
|
|
python package should embbed all its C++ shared libraries.
|
|
|
|
|
|
|
|
|
|
Creating a Python native package containing all `.py` and `.so` (with good
|
|
|
|
|
rpath/loaderpath) is not so easy...
|
|
|
|
|
|
|
|
|
|
## Build the Binary Package
|
2020-03-04 17:42:26 +01:00
|
|
|
|
|
|
|
|
To build the Python wheel package, simply run:
|
2022-03-24 17:19:17 +01:00
|
|
|
|
2020-03-04 17:42:26 +01:00
|
|
|
```sh
|
|
|
|
|
cmake -S. -Bbuild -DBUILD_PYTHON=ON
|
|
|
|
|
cmake --build build --target python_package -v
|
|
|
|
|
```
|
2022-03-24 17:19:17 +01:00
|
|
|
note: Since `python_package` is in target `all`, you can also omit the
|
2020-03-04 17:42:26 +01:00
|
|
|
`--target` option.
|
|
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
## Testing
|
|
|
|
|
|
2020-09-19 17:21:22 +02:00
|
|
|
To list tests:
|
2022-03-24 17:19:17 +01:00
|
|
|
|
2020-09-19 17:21:22 +02:00
|
|
|
```sh
|
|
|
|
|
cd build
|
|
|
|
|
ctest -N
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
To only run Python tests:
|
2022-03-24 17:19:17 +01:00
|
|
|
|
2020-09-19 17:21:22 +02:00
|
|
|
```sh
|
|
|
|
|
cd build
|
|
|
|
|
ctest -R "python_.*"
|
|
|
|
|
```
|
|
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
## Technical Notes
|
|
|
|
|
|
|
|
|
|
First you should take a look at the
|
|
|
|
|
[ortools/python/README.md](../../ortools/python/README.md) to understand the
|
|
|
|
|
layout. \
|
2020-10-08 12:15:58 +02:00
|
|
|
Here I will only focus on the CMake/SWIG tips and tricks.
|
|
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
### Build directory layout
|
|
|
|
|
|
2020-03-04 17:42:26 +01:00
|
|
|
Since Python use the directory name where `__init__.py` file is located and we
|
2022-03-24 17:19:17 +01:00
|
|
|
want to use the
|
|
|
|
|
[CMAKE_BINARY_DIR](https://cmake.org/cmake/help/latest/variable/CMAKE_BINARY_DIR.html)
|
|
|
|
|
to generate the Python binary package.
|
2020-03-04 17:42:26 +01:00
|
|
|
|
|
|
|
|
We want this layout:
|
2022-03-24 17:19:17 +01:00
|
|
|
|
2020-03-04 17:42:26 +01:00
|
|
|
```shell
|
|
|
|
|
<CMAKE_BINARY_DIR>/python
|
|
|
|
|
├── setup.py
|
|
|
|
|
└── ortools
|
|
|
|
|
├── __init__.py
|
|
|
|
|
├── algorithms
|
2022-03-24 17:19:17 +01:00
|
|
|
│ ├── __init__.py
|
|
|
|
|
│ ├── _pywrap.so
|
|
|
|
|
│ └── pywrap.py
|
2020-03-04 17:42:26 +01:00
|
|
|
├── graph
|
2022-03-24 17:19:17 +01:00
|
|
|
│ ├── __init__.py
|
|
|
|
|
│ ├── pywrapgraph.py
|
|
|
|
|
│ └── _pywrapgraph.so
|
|
|
|
|
├── ...
|
2020-03-04 17:42:26 +01:00
|
|
|
└── .libs
|
|
|
|
|
├── libXXX.so.1.0
|
|
|
|
|
└── libXXX.so.1.0
|
|
|
|
|
```
|
2022-03-24 17:19:17 +01:00
|
|
|
|
2020-03-04 17:42:26 +01:00
|
|
|
src: `tree build --prune -U -P "*.py|*.so*" -I "build"`
|
|
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
note: On UNIX you always need `$ORIGIN/../../${PROJECT_NAME}/.libs` since
|
|
|
|
|
`_pywrapXXX.so` will depend on `libortools.so`. \
|
|
|
|
|
note: On APPLE you always need
|
|
|
|
|
`"@loader_path;@loader_path/../../${PROJECT_NAME}/.libs` since `_pywrapXXX.so`
|
|
|
|
|
will depend on `libortools.dylib`. \
|
|
|
|
|
note: on Windows since we are using static libraries we won't have the `.libs`
|
|
|
|
|
directory...
|
|
|
|
|
|
|
|
|
|
So we also need to create few `__init__.py` files to be able to use the build
|
|
|
|
|
directory to generate the Python package.
|
2020-03-04 17:42:26 +01:00
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
### Why on APPLE lib must be .so
|
2020-03-04 17:42:26 +01:00
|
|
|
|
|
|
|
|
Actually, the cpython code responsible for loading native libraries expect `.so`
|
|
|
|
|
on all UNIX platforms.
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
const char *_PyImport_DynLoadFiletab[] = {
|
|
|
|
|
#ifdef __CYGWIN__
|
|
|
|
|
".dll",
|
|
|
|
|
#else /* !__CYGWIN__ */
|
|
|
|
|
"." SOABI ".so",
|
|
|
|
|
#ifdef ALT_SOABI
|
|
|
|
|
"." ALT_SOABI ".so",
|
|
|
|
|
#endif
|
|
|
|
|
".abi" PYTHON_ABI_STRING ".so",
|
|
|
|
|
".so",
|
|
|
|
|
#endif /* __CYGWIN__ */
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
```
|
2022-03-24 17:19:17 +01:00
|
|
|
|
|
|
|
|
ref:
|
2022-05-16 11:59:15 +02:00
|
|
|
https://github.com/python/cpython/blob/main/Python/dynload_shlib.c#L37-L49
|
2020-03-04 17:42:26 +01:00
|
|
|
|
|
|
|
|
i.e. `pywrapXXX` -> `_pywrapXXX.so` -> `libortools.dylib`
|
|
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
### Why setup.py has to be generated
|
|
|
|
|
|
|
|
|
|
To avoid to put hardcoded path to SWIG `.so/.dylib` generated files, we could
|
|
|
|
|
use `$<TARGET_FILE_NAME:tgt>` to retrieve the file (and also deal with
|
|
|
|
|
Mac/Windows suffix, and target dependencies). \
|
2020-03-04 17:42:26 +01:00
|
|
|
In order for `setup.py` to use
|
|
|
|
|
[cmake generator expression](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#informational-expressions)
|
2022-03-24 17:19:17 +01:00
|
|
|
(e.g. `$<TARGET_FILE_NAME:_pyFoo>`). We need to generate it at build time (e.g.
|
|
|
|
|
using
|
|
|
|
|
[add_custom_command()](https://cmake.org/cmake/help/latest/command/add_custom_command.html)).
|
|
|
|
|
|
|
|
|
|
note: This will also add automatically a dependency between the command and the
|
|
|
|
|
TARGET !
|
2020-03-04 17:42:26 +01:00
|
|
|
|
2022-03-24 17:19:17 +01:00
|
|
|
todo(mizux): try to use
|
|
|
|
|
[`file(GENERATE ...)`](https://cmake.org/cmake/help/latest/command/file.html#generate)
|
|
|
|
|
instead.
|