Closed jgvictores closed 6 years ago
This post and https://github.com/swig/swig/issues/737 gave me a hint. Probably a regression introduced by https://github.com/roboticslab-uc3m/kinematics-dynamics/commit/59f87ce6c96a3e365b4db189da470e71be2fd279 which triggers when the character to be expanded (e.g. b
in VOCAB('c','p','f','b')
) is used as a parameter in the macro definition:
I'll check this.
Probably a regression introduced by 59f87ce...
Confirmed.
...when the character to be expanded (e.g. b in VOCAB('c','p','f','b')) is used as a parameter in the macro definition
True, SWIG compiles successfully with the following definition, both in ICartesianSolver.h and ICartesianControl.h:
#define VOCAB(x1,x2,x3,x4) ((((int)(x4))<<24)+(((int)(x3))<<16)+(((int)(x2))<<8)+((int)(x1)))
It chokes whenever the macro definitions differ between both headers. However, now I get plenty of gcc warnings when compiling the project itself (not the associated bindings) because of the redefinition of VOCAB
wrt. YARP's own macro.
Sometimes I hear about C++11 constexpr
constants/functions/classes being a modern alternative to preprocessor macros. Perhaps this is something SWIG would not complain about.
constexpr
sounds interesting, but does not avoid the redeclaration issue.#ifndef
but cannot find the scenario where all possible redeclarations are avoided.Okay, so maybe it's late, but... : )
#define ROBOTICSLAB_VOCAB(x1,x2,x3,x4) ((((int)(x4))<<24)+(((int)(x3))<<16)+(((int)(x2))<<8)+((int)(x1)))
PS: Or always avoid a/b/c/d :joy:
constexpr sounds interesting, but does not avoid the redeclaration issue.
The original macro needs to be undefined prior to declaring the constexpr
function, which in turn would appear only once: in ICartesianSolver.h.
// ICartesianSolver.h
#undef VOCAB
constexpr int VOCAB(int a, int b, int c, int d) { return (d << 24) + (c << 16) + (b << 8) + a; }
This solution comes at the expense of losing explicitness, note that most of our macros are defined within ICartesianControl. (which, in turn, transcludes the solver header). Your proposal looks simpler and more elegant to me (albeit notably C-ish). On the other hand, consumers may want to define their own vocabs and scratch their head upon choosing between VOCAB
and ROBOTICSLAB_VOCAB
, then.
Well, with constexpr
s one could write:
constexpr int VOCAB_CC_OK = VOCAB2('o','k');
instead of:
#define VOCAB_CC_OK VOCAB('o','k',0,0) // note the two zeroes
I guess it's a matter of taste.
The original macro needs to be undefined prior to declaring (...)
Wouldn't that result in redefinitions if the compiler runs into YARP's version after running into ours?
Yes, but it works anyway. The other way around is what makes the compiler protest: first the macro, then the constexpr. Hence I had to #undef
the macro.
(Actually, it makes sense. All the preprocessor does is a raw substitution, so we end up with an useless VOCAB
symbol defined via constexpr
and all usages substed in the following code.)
(Edit: I wouldn't call it a redefinition, then :). Macros and constexpr
symbols are two different beasts.)
Did the #define ROBOTICSLAB_VOCAB(x1,x2,x3,x4) ((((int)(x4))<<24)+(((int)(x3))<<16)+(((int)(x2))<<8)+((int)(x1)))
hack. Result:
In [2]: kinematics_dynamics.ICartesianSolver.BASE_FRAME
Out[2]: 'c'
In [3]: kinematics_dynamics.ICartesianSolver.TCP_FRAME
Out[3]: 'c'
However:
In [2]: yarp.YARP_FEATURE_TILT
Out[2]: 18
In [3]: yarp.YARP_FEATURE_TRIGGER
Out[3]: 12
Tried with constexpr
, which result in a redefinition error.
Tried with constexpr, which result in a redefinition error.
Did you delete the copy in ICartesianControl.h
?
I thought it should be in both...
Anyway, I just found this code in a YARP enum:
VOCAB_PIXEL_BGRA = VOCAB4(98/*'b'*/,'g','r','a'), /* SWIG BUG */
...which traces back to a 2011 commit... https://github.com/robotology/yarp/commit/d7b4099f9ba20f7f7f3795457a8c548a08735e76 (which apparently mentions /me LOL).
I wonder if this has been finally fixed in SWIG 3.0.11 (currently stuck at 3.0.8 in Xenial, but Bionic moved on to 3.0.12), see https://sourceforge.net/p/swig/bugs/1168/.
(Edit: I mean the original issue as explained in the first comments here.)
I wonder if this has been finally fixed in SWIG 3.0.11 (currently stuck at 3.0.8 in Xenial, but Bionic moved on to 3.0.12), see https://sourceforge.net/p/swig/bugs/1168/.
Interesting.
Just tracking where this is done in YARP at time of writing:
libYARP_sig/include/yarp/sig/Image.h:48: VOCAB_PIXEL_BGRA = VOCAB4(98/*'b'*/,'g','r','a'), /* SWIG BUG */
libYARP_sig/include/yarp/sig/Image.h:51: VOCAB_PIXEL_BGR = VOCAB3(98/*'b'*/,'g','r'), /* SWIG BUG */
libYARP_sig/include/yarp/sig/Image.h:60: VOCAB_PIXEL_ENCODING_BAYER_BGGR8 = VOCAB4(98/*'b'*/, 'g', 'g', 'r'), //bggr8
libYARP_sig/include/yarp/sig/Image.h:61: VOCAB_PIXEL_ENCODING_BAYER_BGGR16 = VOCAB4(98/*'b'*/, 'g', '1', '6'), //bggr16
libYARP_dev/include/yarp/dev/IPidControl.h:28: VOCAB_PIDTYPE_CURRENT = VOCAB3(99/*'c'*/, 'u', 'r') // SWIG bug
libYARP_OS/include/yarp/os/PortInfo.h:40: PORTINFO_CONNECTION = VOCAB4(99/*c*/, 'o', 'n', 'n'),
So, maintaining our VOCAB duplicate off YARP, we can simply patch as them:
- BASE_FRAME = VOCAB('c','p','f','b'), //!< Base frame
- TCP_FRAME = VOCAB('c','p','f','t') //!< End-effector frame (TCP)
+ BASE_FRAME = VOCAB(99/*'c'*/,'p','f','b'), //!< Base frame
+ TCP_FRAME = VOCAB(99/*'c'*/,'p','f','t') //!< End-effector frame (TCP)
And get working results in Python:
In [3]: kinematics_dynamics.ICartesianSolver.BASE_FRAME
Out[3]: 1650880611
In [4]: kinematics_dynamics.ICartesianSolver.TCP_FRAME
Out[4]: 1952870499
Note that VOCABs that were breaking were in an enum
in a class
(the lines stated at the beginning of this issue): https://github.com/roboticslab-uc3m/kinematics-dynamics/blob/59f87ce6c96a3e365b4db189da470e71be2fd279/libraries/YarpPlugins/ICartesianSolver.h#L23-L32
VOCABs outside of that kind of scope do not suffer, or we cannot know as they are not "seen" by SWIG: https://github.com/roboticslab-uc3m/kinematics-dynamics/blob/59f87ce6c96a3e365b4db189da470e71be2fd279/libraries/YarpPlugins/ICartesianControl.h#L87
In the context of an enum
in a class
:
char
of this first letter, rather than the desired int
.int
s (I've even contrasted via yarp.Vocab.encode
).char
of this first letter, rather than the desired int
(edit: on second test, 98/99 hack seems to work).This makes me believe, yes, there are at least 2 issues here.
The only fast and safe mechanism seems to copy and use YARP's.
Wait... it seems like the, in the context of an enum
in a class
... the only good option is the unchanged YARP mechanism PLUS using the number hack ALWAYS... and even this is still untested.
Nothing strange from swig -E ICartesianSolver.h
(from SWIG Preprocessor docs):
BASE_FRAME = ((((int)('b'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)(99/*'c'*/))), //!< Base frame
TCP_FRAME = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)(99/*'c'*/))), //!< End-effector frame (TCP)
TCP_FRAMEA = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('a'))), //!< End-effector frame (TCP)
TCP_FRAMEB = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('b'))), //!< End-effector frame (TCP)
TCP_FRAMEC = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('c'))), //!< End-effector frame (TCP)
TCP_FRAMED = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('d'))), //!< End-effector frame (TCP)
TCP_FRAMEE = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('e'))), //!< End-effector frame (TCP)
TCP_FRAMEF = ((((int)('t'))<<24)+(((int)('f'))<<16)+(((int)('p'))<<8)+((int)('f'))) //!< End-effector frame (TCP)
I wonder if this has been finally fixed in SWIG 3.0.11 (currently stuck at 3.0.8 in Xenial, but Bionic moved on to 3.0.12)
Must check.
Just to update, SWIG bug is not fixed in 3.0.12.
A functional workaround is the one provided by 712894c (SWIG_PREPROCESSOR_SHOULD_SKIP_THIS
).
Fixed upstream
in YARP via PR https://github.com/robotology/yarp/pull/1655 merged at https://github.com/robotology/yarp/commit/c23b8d3944bb0a2cb64f03910e888e2954fa987a
Same fix applied in this repo at 651ceaa (undoing hack too) and 7a4fe85, and additionally in https://github.com/asrob-uc3m/yarp-devices at https://github.com/asrob-uc3m/yarp-devices/commit/400b195ad057723edd1c9f8bed7b47709bfc94c7.
Closing issue!
This is in fact the original issue, so continuing here.
The cast was an issue, but can be hacked. I've even tried this across files:
// example.h
#define VOCAB(x1,x2,x3,x4) ((x1+0)<<24)+((x2+0)<<16)+((x3+0)<<8)+(x4+0)
#define VOCAB3(a,b,c) VOCAB(a,b,c,0)
#define TEST1 VOCAB('b','b','c','d')
#define TEST2 VOCAB3('f','b','c')
// example2.h
#include "example.h"
#define TEST3 VOCAB('b','b','c','d')
#define TEST4 VOCAB3('f','b','c')
// example.i
%module example
%{
//#include "example.h" // Not even required for this.
//#include "example2.h" // Not even required for this.
%}
%include "example.h"
%include "example2.h"
Python wrapper can be compiled with:
rm -rf _example.so example_wrap.c example_wrap.o example.py __pycache__
swig -python example.i
gcc -c example_wrap.c -I /usr/include/python3.5m/ -fPIC
ld -shared example.o example_wrap.o -o _example.so
And check variables are created:
grep TEST example_wrap.c example.py
Outputs:
example_wrap.c: SWIG_Python_SetConstant(d, "TEST1",SWIG_From_int((int)((('b'+0) << 24) +(('b'+0) << 16) +(('c'+0) << 8) +('d'+0))));
example_wrap.c: SWIG_Python_SetConstant(d, "TEST2",SWIG_From_int((int)((('f'+0) << 24) +(('b'+0) << 16) +(('c'+0) << 8) +(0+0))));
example_wrap.c: SWIG_Python_SetConstant(d, "TEST3",SWIG_From_int((int)((('b'+0) << 24) +(('b'+0) << 16) +(('c'+0) << 8) +('d'+0))));
example_wrap.c: SWIG_Python_SetConstant(d, "TEST4",SWIG_From_int((int)((('f'+0) << 24) +(('b'+0) << 16) +(('c'+0) << 8) +(0+0))));
example.py:TEST1 = _example.TEST1
example.py:TEST2 = _example.TEST2
example.py:TEST3 = _example.TEST3
example.py:TEST4 = _example.TEST4
And values via python
/ipython
are correct.
Issue is most probably something in yarp.i
. In fact, the above VOCAB
hack allows whatever is in Vocab.h
to be generated correctly. There is, however, something strange (typedef? cstring.i?) that makes other files change from a char e.g. 'x'
to a variable with the same name (e.g. x
), see:
[100%] Building CXX object bindings/python/CMakeFiles/_yarp_python.dir/__/__/lib/python/yarpPYTHON_wrap.cxx.o
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx: In function ‘PyObject* PyInit__yarp()’:
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149928:93: error: ‘f’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_FRAMEGRABBER_IMAGE",SWIG_From_int(static_cast< int >((((f) +0) << 24) +(((g) +0) << 16) +(((i) +0) << 8) +((0) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149928:111: error: ‘g’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_FRAMEGRABBER_IMAGE",SWIG_From_int(static_cast< int >((((f) +0) << 24) +(((g) +0) << 16) +(((i) +0) << 8) +((0) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149928:129: error: ‘i’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_FRAMEGRABBER_IMAGE",SWIG_From_int(static_cast< int >((((f) +0) << 24) +(((g) +0) << 16) +(((i) +0) << 8) +((0) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149929:148: error: ‘r’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_FRAMEGRABBER_IMAGERAW",SWIG_From_int(static_cast< int >((((f) +0) << 24) +(((g) +0) << 16) +(((i) +0) << 8) +((r) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149930:85: error: ‘b’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_BRIGHTNESS",SWIG_From_int(static_cast< int >((((b) +0) << 24) +(((r) +0) << 16) +(((i) +0) << 8) +((0) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149931:83: error: ‘e’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_EXPOSURE",SWIG_From_int(static_cast< int >((((e) +0) << 24) +(((x) +0) << 16) +(((p) +0) << 8) +((o) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149931:101: error: ‘x’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_EXPOSURE",SWIG_From_int(static_cast< int >((((e) +0) << 24) +(((x) +0) << 16) +(((p) +0) << 8) +((o) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149931:119: error: ‘p’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_EXPOSURE",SWIG_From_int(static_cast< int >((((e) +0) << 24) +(((x) +0) << 16) +(((p) +0) << 8) +((o) +0))));
^
/home/yo/repos/yarp/build/lib/python/yarpPYTHON_wrap.cxx:149931:135: error: ‘o’ was not declared in this scope
SWIG_Python_SetConstant(d, "VOCAB_EXPOSURE",SWIG_From_int(static_cast< int >((((e) +0) << 24) +(((x) +0) << 16) +(((p) +0) << 8) +((o) +0))));
This, on the other hand, was in fact to be suspected given the conflicts with vocabs that started with 'b'/'c'/'d'.
Fix has been implemented and merged upstream, https://github.com/robotology/yarp/pull/1696
Blame: https://github.com/roboticslab-uc3m/kinematics-dynamics/blob/59f87ce6c96a3e365b4db189da470e71be2fd279/libraries/YarpPlugins/ICartesianSolver.h#L23-L32