jdv has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to bind a C++ library that comes with a SWIG interface file. However, when I try to compile the wrapper code that is generated by

swig -c++ -perl5 pwiz_swigbindings.i

I get ~ 3k lines of warnings and errors. The first 50 lines are included here:

In file included from pwiz_swigbindings_wrap.cxx:745:0: /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:126:39: error: referen +ce to ‘CV’ is ambiguous #define XSPROTO(name) void name(pTHX_ CV* cv) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:145:44: note: in expan +sion of macro ‘XSPROTO’ # define XS_EXTERNAL(name) extern "C" XSPROTO(name) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:156:18: note: in expan +sion of macro ‘XS_EXTERNAL’ #define XS(name) XS_EXTERNAL(name) ^ pwiz_swigbindings_wrap.cxx:2149:1: note: in expansion of macro ‘XS’ XS(_wrap_new_vectord__SWIG_0) { ^ In file included from pwiz_swigbindings_wrap.cxx:744:0: /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/perl.h:2317:19: note: candida +tes are: typedef struct cv CV typedef struct cv CV; ^ In file included from pwiz_swigbindings_wrap.cxx:1862:0: ../../../data/common/cv.hpp:12996:22: note: struct pwi +z::cv::CV struct PWIZ_API_DECL CV ^ In file included from pwiz_swigbindings_wrap.cxx:745:0: /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:126:39: error: ‘CV’ ha +s not been declared #define XSPROTO(name) void name(pTHX_ CV* cv) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:145:44: note: in expan +sion of macro ‘XSPROTO’ # define XS_EXTERNAL(name) extern "C" XSPROTO(name) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:156:18: note: in expan +sion of macro ‘XS_EXTERNAL’ #define XS(name) XS_EXTERNAL(name) ^ pwiz_swigbindings_wrap.cxx:2149:1: note: in expansion of macro ‘XS’ XS(_wrap_new_vectord__SWIG_0) { ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:126:39: error: referen +ce to ‘CV’ is ambiguous #define XSPROTO(name) void name(pTHX_ CV* cv) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:145:44: note: in expan +sion of macro ‘XSPROTO’ # define XS_EXTERNAL(name) extern "C" XSPROTO(name) ^ /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:156:18: note: in expan +sion of macro ‘XS_EXTERNAL’ #define XS(name) XS_EXTERNAL(name) ^ pwiz_swigbindings_wrap.cxx:2177:1: note: in expansion of macro ‘XS’ XS(_wrap_new_vectord__SWIG_1) { ^ In file included from pwiz_swigbindings_wrap.cxx:744:0: /usr/lib/x86_64-linux-gnu/perl/5.20/CORE/perl.h:2317:19: note: candida +tes are: typedef struct cv CV typedef struct cv CV;

Please bear with me - I'm not much into C/C++ or the Perl internals - but it seems like CV is a core Perl symbol as well as being defined as a class by the library I'm binding, which is causing problems. The rest of the errors/warnings seems to relate to 'CV' as well. In the external library, 'CV' is defined within the "pwiz::cv::" namespace, but it still seems to be conflicting.

Has anyone dealt with a similar issue or have any guidance on how to get around this?

Replies are listed 'Best First'.
Re: SWIG and conflicting definitions
by hexcoder (Curate) on Jan 07, 2016 at 17:30 UTC
    Hello jdv!

    Lets see if I got this correctly:

    1. XSUB.h is included in line 745 of pwiz_swigbindings_wrap.cxx, defining typedef struct cv CV and macro XS.
    2. cv.hpp is included in line 1862 of pwiz_swigbindings_wrap.cxx, defining a different struct CV.
    3. the XS macro from Perl is used first in line 2149 of pwiz_swigbindings_wrap.cxx

    It is ugly, but the preprocessor can help to move the conflicting identifiers around. To do so I would manually modify the file pwiz_swigbindings_wrap.cxx and insert this line before
    #define CV __perl_CV
    and these ones after
    #undef XSPROTO
    #define XSPROTO(name) void name(pTHX_ __perl_CV* cv)
    #undef CV
    line 745.

    I checked this roughly with the following C code:
    #define CV __perl_CV /* beginning of include XSUB.h */ struct cv { int i; }; typedef struct cv CV; #define XSPROTO(name) CV name /* end of include XSUB.h */ #undef XSPROTO #define XSPROTO(name) __perl_CV name #undef CV struct CV { char c; }; XSPROTO(x); int main() { struct CV y; x.i = 0; y.c = '!'; return 0; }

      Thanks for the reply. This is all black magic to me (plus I think some newlines got lost in the code in your first paragraph) so I'm not sure if I got it right. Here is what I tried around the section you suggested:

      #include "EXTERN.h" #include "perl.h" #define CV __perl_CV #include "XSUB.h" #undef XSPROTO #define XSPROTO(name) void name(pTHX_ __perl_CV* cv) #undef CV

      That's just copying what you wrote and guessing at the newlines, so I'm not sure if the syntax is correct. If I try to compile this, the STDERR is down to ~ 1500 lines with a lot of messages like this:

      pwiz_swigbindings_wrap.cxx:748:39: error: ‘__perl_CV’ has not been dec +lared #define XSPROTO(name) void name(pTHX_ __perl_CV* cv)
        My error, sorry. I should have said to put the line

        #define CV __perl_CV

        before this one

        #include "perl.h"

        otherwise it looks ok.

        Update: some explanations added

        What I intend to do, is this:

        1. for the processing of perl.h, XSUB.h and the included header files therein, substitute the offending identifier CV by __perl_CV. This is done by the preprocessor directive #define CV __perl_CV
        2. Afterwards redeclare the macro XSPROTO, which was using CV also. Unfortunately the above substitution affects only C code, but not subsequent preprocessor directives, so we need to adjust this macro definition.
          This is done by first deleting the old macro definition (#undef XSPROTO), and then by defining it again, but this time with __perl_CV instead of CV.
        3. Finally delete the substitution for identifier CV (#undef CV, so that the following code can use it exclusively.
        4. This in total should remove the conflict between the two different definitions of CV by using __perl_CV for the first one instead.

        If you are curious, you can look at the difference of the preprocessed outputs with and without the modification (gcc -E -dDfile should produce them).