Hi,
I am using SWIG 1.3.39 and GCC 4.4.1 (Ubuntu 4.4.1-4ubuntu9) on Ubuntu 9.10 (Linux efriedma-ux 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 02:39:34 UTC 2010 x86_64 GNU/Linux).
Normally on 64-bit Linux, int64_t is defined to be a `long int`. However, in SWIG (at least for Java), it is defined incorrectly, as seen in the following simple interface file:
// foo.i
%module foo
%{
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
BOOST_STATIC_ASSERT(( boost::is_same<int64_t, jlong>::value ));
%}
This may be compiled as follows:
$ swig -c++ -java foo.i
$ g++ foo_wrap.cxx
foo_wrap.cxx:216: error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
The error means the Boost static assertion has failed, which indicates that `int64_t` and `jlong` are not the same type. (The result is the same even if I include the SWIG import <stdint.i>.)
However, the following C++ program, which has the same check compiles without a problem:
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
int main()
{
BOOST_STATIC_ASSERT(( boost::is_same<int64_t, jlong>::value ));
return 0;
}
Trying to track this down, it seems as though the problem is due to the following lines in the SWIG-generated source file (foo_wrap.cxx):
/* Fix for jlong on 64-bit x86 Solaris */
#if defined(__x86_64)
# ifdef _LP64
# undef _LP64
# endif
#endif
Doing this causes the JNI headers to make the `jlong` type as a typedef for `long long int`. I don't understand why this is being done, as it's different from `int64_t`.
Thanks,
Eric
P.S. Looking at the Subversion history for this change, I came across the following:
http://swig.svn.sourceforge.net/viewvc/swig?view=rev&revision=6891
The commit message (from marcelomatus) is "fix warning(error?) with jlong + x86_64". Does that give any clue as to why this introduced? Are there other problems with SWIG on 64-bit platforms? (The uncertainty in the commit message is a bit unnerving.)
Generated foo_wrap.cxx
Also forgot to mention: I also checked with the latest version of SWIG (1.3.40), and it seems that this issue is still present there as well.
Looking further into this issue, I've come to the conclusion it's not just `int64_t` that's being defined incorrectly on 64-bit platforms but also `long` is being incorrectly typemapped. Specifically, it seems that at least the Java support in SWIG assumes a 32-bit target.
In particular, a C `long` is always mapped to a Java `int` (`jint`). However, on 64-bit platforms, a `long` is 64-bits and should be treated as a Java `long` (`jlong`). The same issue applies also for `unsigned long`.
I think what should be happening is that typemaps for `long` should not be defined at all. Instead, depending on the platform, either the typemaps for `int` (on a 32-bit platform) or for `long long` (on a 64-bit platform) should be copied (using %apply) to handle `long`. I've modified my java/java.swg accordingly (and removed the _LP64 business in java/javahead.swg) and it seems to solve the problem. I'll see if I can post a patch in the next few days.
Also, there is a further problem for 64-bit platforms (though seemingly unrelated):
swigarch.i seems to be broken unless SWIGWORDSIZE64 is manually defined (e.g., using -DSWIGWORDSIZE64). I see this has been reported elsewhere (http://old.nabble.com/-BUG--stdint.i-gets-int64_t-wrong-on-64bit-archs-td20695275.html) as well.
Unlike the issue with the core typemaps, this issue can at least be worked around in a straightforward way with the -D option. But to fix it correctly though seems to require changing the actual SWIG code generator (i.e., to automatically define a preprocessor symbol like __x86_64 or __WORDSIZE while processing interface files).
Fixes the issue with Java
The dubious undefining of
_LP64
was removed in 971e1154af7a608a0f2f96ee98189da4aa001412 which will be in the upcoming SWIG 4.2.0 release.The other points don't seem to have been addressed yet.
Note that SWIG aims to generate code that's independent of the architecture of the machine that it's run on, so we shouldn't be defining things like
__x86_64
or__WORDSIZE
during processing of the interface file but rather generating code that has suitable conditionals on symbols the compiler would then define or not.This recent commit (which will be in SWIG 4.2.0) looks like it addresses the remaining points here: