5.8 KiB
SWIG Wrapper Generation
Using swig to generate wrapper it's easy thanks to the modern UseSWIG 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
UseSWIG is impacted by two policies:
- CMP0078:UseSWIG generates standard target names (CMake 3.13+).
- CMP0086: UseSWIG
honors
SWIG_MODULE_NAMEvia-moduleflag (CMake 3.14+).
That's why I recommnend to use CMake >= 3.14 with both policies set to new for SWIG development.
int64_t Management
When working on a k8 (aka x86_64) architecture, you may face issue with
int64_t and uint64_t management.
First long long and long int are different types and int64_t is just a
typedef on one of them...
Linux
On Linux we have:
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
Gcc
First try to find where and how the compiler define int64_t and uint64_t.
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
gcc -dM -E -x c /dev/null | grep __INT64
#define __INT64_C(c) c ## L
#define __INT64_MAX__ 0x7fffffffffffffffL
#define __INT64_TYPE__ long int
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
Clang
clang -dM -E -x c++ /dev/null | grep INT64_TYPE
#define __INT64_TYPE__ long int
#define __UINT64_TYPE__ long unsigned int
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
MacOS
On Catalina 10.15 we have:
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
Clang
clang -dM -E -x c++ /dev/null | grep INT64_TYPE
#define __INT64_TYPE__ long long int
#define __UINT64_TYPE__ long long unsigned int
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
Windows
Contrary to macOS and Linux, Windows 64bits (x86_64) try hard to keep compatibility, so we have:
sizeof(long int): 4
sizeof(long long): 8
sizeof(int64_t): 8
Visual Studio 2022
Thus, in stdint.h we have:
#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;
SWIG int64_t management stuff
First, take a look at
Swig stdint.i.
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
and
SWIG CSHARP
do not take it into account for typemaps...
So you may want to use this for Java:
#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:
#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)
So int64_t (i.e. long int in this case) will be correctly bind to Java/.Net
primitive type long.
swig_add_library()
You can use OUTPUT_DIR to change the output directory for the .py file e.g.:
swig_add_library(pyFoo
TYPE MODULE
LANGUAGE python
OUTPUT_DIR ${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}/Foo
SOURCES foo.i)
Doxygen
Since swig 4.0, swig can now extract doxygen comments from C++ to inject it in Python and Java.
Csharp documentation
note: Doxygen to csharp was planned but currently is not supported.