Files
ortools-clone/cmake/docs/swig.md

218 lines
5.8 KiB
Markdown
Raw Permalink Normal View History

2020-03-04 17:42:26 +01:00
# SWIG Wrapper Generation
2022-03-24 17:19:17 +01:00
Using [swig](https://github.com/swig/swig) to generate wrapper it's easy thanks
to the modern [UseSWIG](https://cmake.org/cmake/help/latest/module/UseSWIG.html)
module (**CMake >= 3.14**).
note: SWIG automatically put its target(s) in `all`, thus `cmake --build build`
will also call swig and generate `_module.so`.
## Policy
2020-03-04 17:42:26 +01:00
UseSWIG is impacted by two policies:
2022-03-24 17:19:17 +01:00
2022-05-18 14:20:41 +02:00
* [CMP0078](https://cmake.org/cmake/help/latest/policy/CMP0078.html):UseSWIG
generates standard target names (CMake 3.13+).
* [CMP0086](https://cmake.org/cmake/help/latest/policy/CMP0086.html): UseSWIG
honors `SWIG_MODULE_NAME` via `-module` flag (CMake 3.14+).
2020-03-04 17:42:26 +01:00
That's why I recommnend to use CMake >= 3.14 with both policies set to new for
SWIG development.
2022-03-24 17:19:17 +01:00
## int64_t Management
When working on a `k8` (aka `x86_64`) architecture, you may face issue with
`int64_t` and `uint64_t` management.
2020-03-04 17:42:26 +01:00
First `long long` and `long int` are **different** types and `int64_t` is just a
typedef on one of them...
2022-03-24 17:19:17 +01:00
### Linux
2020-03-04 17:42:26 +01:00
On Linux we have:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
```
2022-03-24 17:19:17 +01:00
#### Gcc
2020-03-04 17:42:26 +01:00
First try to find where and how the compiler define `int64_t` and `uint64_t`.
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```sh
grepc -rn "typedef.*int64_t;" /lib/gcc
/lib/gcc/x86_64-linux-gnu/9/include/stdint-gcc.h:43:typedef __INT64_TYPE__ int64_t;
/lib/gcc/x86_64-linux-gnu/9/include/stdint-gcc.h:55:typedef __UINT64_TYPE__ uint64_t;
```
So we need to find this compiler macro definition
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```sh
2022-05-16 17:44:50 +02:00
gcc -dM -E -x c /dev/null | grep __INT64
2020-03-04 17:42:26 +01:00
#define __INT64_C(c) c ## L
#define __INT64_MAX__ 0x7fffffffffffffffL
#define __INT64_TYPE__ long int
2020-11-19 09:20:36 +01:00
gcc -dM -E -x c /dev/null | grep __UINT64
#define __UINT64_C(c) c ## UL
#define __UINT64_MAX__ 0xffffffffffffffffUL
#define __UINT64_TYPE__ long unsigned int
2020-03-04 17:42:26 +01:00
```
2022-03-24 17:19:17 +01:00
#### Clang
2020-03-04 17:42:26 +01:00
```sh
clang -dM -E -x c++ /dev/null | grep INT64_TYPE
#define __INT64_TYPE__ long int
#define __UINT64_TYPE__ long unsigned int
```
2022-03-24 17:19:17 +01:00
Clang, GNU compilers: \
`-dM` dumps a list of macros. \
`-E` prints results to stdout instead of a file. \
`-x c` and `-x c++` select the programming language when using a file without a
filename extension, such as `/dev/null`
Ref:
https://web.archive.org/web/20190803041507/http://nadeausoftware.com/articles/2011/12/c_c_tip_how_list_compiler_predefined_macros
2020-03-04 17:42:26 +01:00
2022-03-24 17:19:17 +01:00
### MacOS
2020-03-04 17:42:26 +01:00
On Catalina 10.15 we have:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
```
2022-03-24 17:19:17 +01:00
#### Clang
2020-03-04 17:42:26 +01:00
```sh
clang -dM -E -x c++ /dev/null | grep INT64_TYPE
#define __INT64_TYPE__ long long int
#define __UINT64_TYPE__ long long unsigned int
```
2022-03-24 17:19:17 +01:00
with: `-dM` dumps a list of macros. \
`-E` prints results to stdout instead of a file. \
`-x c` and `-x c++` select the programming language when using a file without a
filename extension, such as `/dev/null`
Ref:
https://web.archive.org/web/20190803041507/http://nadeausoftware.com/articles/2011/12/c_c_tip_how_list_compiler_predefined_macros
### Windows
2020-03-04 17:42:26 +01:00
2022-05-18 14:20:41 +02:00
Contrary to macOS and Linux, Windows 64bits (x86_64) try hard to keep
compatibility, so we have:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```
sizeof(long int): 4
sizeof(long long): 8
sizeof(int64_t): 8
```
2023-10-30 14:36:28 +01:00
#### Visual Studio 2022
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
Thus, in `stdint.h` we have:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```cpp
#if _VCRT_COMPILER_PREPROCESSOR
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
```
2022-03-24 17:19:17 +01:00
### SWIG int64_t management stuff
2020-03-04 17:42:26 +01:00
2022-03-24 17:19:17 +01:00
First, take a look at
[Swig stdint.i](https://github.com/swig/swig/blob/3a329566f8ae6210a610012ecd60f6455229fe77/Lib/stdint.i#L20-L24).
So, when targeting Linux you **must use define SWIGWORDSIZE64** (i.e.
`-DSWIGWORDSIZE64`) while on macOS and Windows you **must not define it**.
Now the bad news, even if you can control the SWIG typedef using
`SWIGWORDSIZE64`,
[SWIG Java](https://github.com/swig/swig/blob/3a329566f8ae6210a610012ecd60f6455229fe77/Lib/java/java.swg#L74-L77)
and
[SWIG CSHARP](https://github.com/swig/swig/blob/1e36f51346d95f8b9848e682c2eb986e9cb9b4f4/Lib/csharp/csharp.swg#L117-L120)
do not take it into account for typemaps...
2020-03-04 17:42:26 +01:00
So you may want to use this for Java:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```swig
#if defined(SWIGJAVA)
#if defined(SWIGWORDSIZE64)
%define PRIMITIVE_TYPEMAP(NEW_TYPE, TYPE)
%clear NEW_TYPE;
%clear NEW_TYPE *;
%clear NEW_TYPE &;
%clear const NEW_TYPE &;
%apply TYPE { NEW_TYPE };
%apply TYPE * { NEW_TYPE * };
%apply TYPE & { NEW_TYPE & };
%apply const TYPE & { const NEW_TYPE & };
%enddef // PRIMITIVE_TYPEMAP
PRIMITIVE_TYPEMAP(long int, long long);
PRIMITIVE_TYPEMAP(unsigned long int, long long);
#undef PRIMITIVE_TYPEMAP
#endif // defined(SWIGWORDSIZE64)
#endif // defined(SWIGJAVA)
```
and this for .Net:
2022-05-16 17:44:50 +02:00
2020-03-04 17:42:26 +01:00
```swig
#if defined(SWIGCSHARP)
#if defined(SWIGWORDSIZE64)
%define PRIMITIVE_TYPEMAP(NEW_TYPE, TYPE)
%clear NEW_TYPE;
%clear NEW_TYPE *;
%clear NEW_TYPE &;
%clear const NEW_TYPE &;
%apply TYPE { NEW_TYPE };
%apply TYPE * { NEW_TYPE * };
%apply TYPE & { NEW_TYPE & };
%apply const TYPE & { const NEW_TYPE & };
%enddef // PRIMITIVE_TYPEMAP
PRIMITIVE_TYPEMAP(long int, long long);
PRIMITIVE_TYPEMAP(unsigned long int, unsigned long long);
#undef PRIMITIVE_TYPEMAP
#endif // defined(SWIGWORDSIZE64)
#endif // defined(SWIGCSHARP)
```
2022-03-24 17:19:17 +01:00
So `int64_t` (i.e. `long int` in this case) will be correctly bind to Java/.Net
primitive type `long`.
## swig_add_library()
2020-03-04 17:42:26 +01:00
You can use `OUTPUT_DIR` to change the output directory for the `.py` file e.g.:
2022-03-24 17:19:17 +01:00
2020-03-04 17:42:26 +01:00
```cmake
swig_add_library(pyFoo
TYPE MODULE
2020-03-04 17:42:26 +01:00
LANGUAGE python
OUTPUT_DIR ${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}/Foo
SOURCES foo.i)
```
2022-03-24 17:19:17 +01:00
## Doxygen
Since swig 4.0, swig can now
2023-02-02 13:05:30 +01:00
[extract doxygen comments](http://www.swig.org/Doc4.1/Doxygen.html) from C++ to
2022-03-24 17:19:17 +01:00
inject it in Python and Java.
### Csharp documentation
2020-03-04 17:42:26 +01:00
2022-03-24 17:19:17 +01:00
note: Doxygen to csharp was
[planned](https://github.com/swig/swig/wiki/SWIG-4.0-Development#doxygen-documentation)
but currently is not supported.