cmake/docs/swig.md
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.
UseSWIG is impacted by two policies:
SWIG_MODULE_NAME via -module flag (CMake 3.14+).That's why I recommnend to use CMake >= 3.14 with both policies set to new for SWIG development.
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...
On Linux we have:
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
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 -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
On Catalina 10.15 we have:
sizeof(long long): 8
sizeof(long int): 8
sizeof(int64_t): 8
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
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
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;
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.
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)
Since swig 4.0, swig can now extract doxygen comments from C++ to inject it in Python and Java.
note: Doxygen to csharp was planned but currently is not supported.