Fun with SWIG

Moderators: Gully, peteru

Post Reply
prl
Wizard God
Posts: 32709
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Fun with SWIG

Post by prl » Mon Nov 28, 2016 16:09

Some of the tweaks to SWIG when it wraps C++ classes in enigma2 is a bit convoluted, especially around classes that have an associated smart pointer class. It's particularly odd (at least to me) where smart pointer wrapped classes contain enums in the main class.

A comment in service/iservice.h is all I have to go on:
some words to structs like struct iServiceInformation_ENUMS
For some classes we need in python just the SmartPointer Variants.
So we prevent building wrapper classes for the non smart pointer classes with the SWIG_IGNORE makro.
But now we have the problem that swig do not export enums for smart pointer classes (i dont know why).
So we move all enum's to own classes (with _ENUMS as name ending) and let our real
class inherit from the *_ENUMS class. This *_ENUMS classes are normally exportet via swig to python.
But in the python code we doesn't like to write iServiceInformation_ENUMS.sVideoType....
we like to write iServiceInformation.sVideoType.
So until swig have no Solution for this Problem we call in lib/python/Makefile.am a python script named
enigma_py_patcher.py to remove the "_ENUMS" strings in enigma.py at all needed locations.
Here's a small example of how it's done:

Code: Select all

// in swig.h
#define SWIG_IGNORE(x) %ignore x
#define SWIG_TEMPLATE_TYPEDEF(x, y) %template(y) x; %typemap_output_ptr(x)

// in service/iservice.h
class iCueSheet_ENUMS
{
#ifdef SWIG
	iCueSheet_ENUMS();
	~iCueSheet_ENUMS();
#endif
public:
	enum { cutIn = 0, cutOut = 1, cutMark = 2 };
};

SWIG_IGNORE(iCueSheet);
class iCueSheet: public iCueSheet_ENUMS, public iObject
{
#ifdef SWIG
	iCueSheet();
	~iCueSheet();
#endif
public:
	/* returns a list of (pts, what)-tuples */
	virtual PyObject *getCutList() = 0;
	virtual void setCutList(SWIG_PYOBJECT(ePyObject) list) = 0;
	virtual void setCutListEnable(int enable) = 0;
};
SWIG_TEMPLATE_TYPEDEF(ePtr<iCueSheet>, iCueSheetPtr);
That results in a class definition for iCueSheet that contains the enum definitions:

Code: Select all

class iCueSheet(object):
    ...
    cutIn = _enigma.iCueSheet_ENUMS_cutIn
    cutOut = _enigma.iCueSheet_ENUMS_cutOut
    cutMark = _enigma.iCueSheet_ENUMS_cutMark
I want to add an enum definition to eServiceEvent (service/event.h). It's defined in a similar way to iCueSheet, but with one nasty difference:

Code: Select all

SWIG_IGNORE(eServiceEvent);
class eServiceEvent: public iObject
{
	DECLARE_REF(eServiceEvent);
	static std::string crid_scheme;
	...
};
SWIG_TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEvent);
SWIG_EXTEND(ePtr<eServiceEvent>,
	static void setEPGLanguage(const std::string& language)
	{
		eServiceEvent::setEPGLanguage(language);
	}
);
SWIG_EXTEND(ePtr<eServiceEvent>,
	static void setEPGLanguageAlternative(const std::string& language)
	{
		eServiceEvent::setEPGLanguageAlternative(language);
	}
);
The thing that seems to be causing the problem is that in the first case it uses
SWIG_TEMPLATE_TYPEDEF(ePtr<iCueSheet>, iCueSheetPtr)
(the second argument has "Ptr" added to the class name, while in the eServiceEvent case, the same class name is used:
SWIG_TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEvent).

That means that if I try to do a similar thing with enums to the iCueSheet case:

Code: Select all

struct eServiceEvent_ENUMS
{
public:
	// CRID matches are for all CRIDs of that class:
	// SERIES_MATCH matches both SERIES and SERIES_AU
	enum {
		SERIES_MATCH = 1 << eCridData::SERIES,
		EPISODE_MATCH = 1 << eCridData::EPISODE,
		RECOMMENDATION_MATCH = 1 << eCridData::RECOMMENDATION,
		ALL_MATCH = SERIES_MATCH | EPISODE_MATCH | RECOMMENDATION_MATCH,
	};
};

SWIG_IGNORE(eServiceEvent);
class eServiceEvent: public eServiceEvent_ENUMS, public iObject
{
	DECLARE_REF(eServiceEvent);
	...
};
SWIG_TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEvent);
SWIG_EXTEND(ePtr<eServiceEvent>,
	static void setEPGLanguage(const std::string& language)
	{
		eServiceEvent::setEPGLanguage(language);
	}
);
SWIG_EXTEND(ePtr<eServiceEvent>,
	static void setEPGLanguageAlternative(const std::string& language)
	{
		eServiceEvent::setEPGLanguageAlternative(language);
	}
);
I get a class definition of eServiceEvent that has the enum definitions in it, but it's then immediately over-ridden by a definition of the class without enum definitions:

Code: Select all

class eServiceEvent(object):
    ...
    SERIES_MATCH = _enigma.eServiceEvent_ENUMS_SERIES_MATCH
    EPISODE_MATCH = _enigma.eServiceEvent_ENUMS_EPISODE_MATCH
    RECOMMENDATION_MATCH = _enigma.eServiceEvent_ENUMS_RECOMMENDATION_MATCH
    ALL_MATCH = _enigma.eServiceEvent_ENUMS_ALL_MATCH
    ...

class eServiceEvent(object):
    ...
    # no definitions of the *_MATCH constants.
    ...
Is there any way around this that doesn't involve changing the name of the wrapped class from eServiceEvent to something else (like eServiceEventPtr)?
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

User avatar
peteru
Uber Wizard
Posts: 9741
Joined: Tue Jun 12, 2007 23:06
Location: Sydney, Australia
Contact:

Re: Fun with SWIG

Post by peteru » Tue Nov 29, 2016 03:06

I'm afraid, I'm out of my depth on this one.

What I can suggest, is to perhaps have a look through git history to see if you can identify the original author of the SWIG patcher and seek expertise there. If you can't track down the original author, see if git history can help you figure out how others have dealt with SWIG issues and see if you can get help from someone experienced in this aspect.

"Beauty lies in the hands of the beer holder."
Blog.

User avatar
peteru
Uber Wizard
Posts: 9741
Joined: Tue Jun 12, 2007 23:06
Location: Sydney, Australia
Contact:

Re: Fun with SWIG

Post by peteru » Tue Nov 29, 2016 03:36

It's also possible that newer versions of SWIG may not need this approach. We are currently building enigma2 with swig 3.0.8

"Beauty lies in the hands of the beer holder."
Blog.

prl
Wizard God
Posts: 32709
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Fun with SWIG

Post by prl » Tue Nov 29, 2016 07:46

I have a workaround, just putting the enums in a class like eServiceEventEnums and referencing them from there. It's not as neat on the Python side, though.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

Post Reply

Return to “Developers Community”