I am learning how to call C++ code from Perl and to start I am trying to create a basic C++ object from a Perl script.
To do this, I started by executing the h2xs command:
h2xs -A -nMyClass
Then I added the following two arguments to the generated Makefile.PL to use the g++ compiler.
CC => 'g++',
LD => 'g++',
I created my simple class in the .xs file and wrote the XS code to map it with Perl
MyClass.xs
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#ifdef __cplusplus
}
#endif
class MyClass {
public:
MyClass(int value) {
value_ = value;
}
~MyClass() {}
int value() { return value_; }
void set_value(int value) {
value_ = value;
}
private:
int value_;
};
MODULE = MyClass PACKAGE = MyClass
MyClass *
MyClass::new(int value)
void
MyClass::DESTROY()
int
MyClass::value()
void
MyClass::set_value(int value)
Then I created the typemap file to map the new type to Perl.
typemap
TYPEMAP
MyClass * O_OBJECT
######################################################################
OUTPUT
# The Perl object is blessed into 'CLASS', which should be a
# char* having the name of the package for the blessing.
O_OBJECT
sv_setref_pv( $arg, CLASS, (void*)$var );
######################################################################
INPUT
O_OBJECT
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
$var = ($type)SvIV((SV*)SvRV( $arg ));
else{
warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
XSRETURN_UNDEF;
}
Finally I created a simple test.
t/MyClass.t
use Test::More tests => 2;
BEGIN { use_ok('MyClass') };
my $obj = MyClass->new(1);
ok($obj->isa('MyClass'), 'MyClass object constructed');
I then successfully built the code and ran the tests.
perl Makefile.PL
make
make test
Although everything works fine, I get some warnings with the build:
MyClass.c: In function 'void XS_MyClass_new(PerlInterpreter*, CV*)':
MyClass.c:95: warning: unused variable 'Perl___notused'
MyClass.c: In function 'void XS_MyClass_DESTROY(PerlInterpreter*, CV*)':
MyClass.c:119: warning: unused variable 'Perl___notused'
MyClass.c: In function 'void XS_MyClass_value(PerlInterpreter*, CV*)':
MyClass.c:145: warning: unused variable 'Perl___notused'
MyClass.c: In function 'void XS_MyClass_set_value(PerlInterpreter*, CV*)':
MyClass.c:174: warning: unused variable 'Perl___notused'
MyClass.c: In function 'void boot_MyClass(PerlInterpreter*, CV*)':
MyClass.c:203: warning: unused variable 'Perl___notused'
I searched all over trying to find the cause for these warnings, and can't figure out what is going on. All of the warnings seem come from the same repeated section in the code that occurs at the beginning of every function definition.
inside MyClass.c
XS(XS_MyClass_new); /* prototype to pass -Wmissing-prototypes */
XS(XS_MyClass_new)
{
#ifdef dVAR
dVAR; dXSARGS; // <-- warning occurs here
#else
dXSARGS;
#endif
// function body continues...
Can someone please tell me the root cause of these warnings?
I am using Perl v5.10.1 and g++ version 4.4.7
The solution is to use a newer version of Perl. v5.10.1 is very outdated and these problems don't occur in later versions.
I am posting an answer to my own question because it was answered in the comments, but an official answer was never posted.
Related
I'd like to doctest some conversion expression with C++ doctest.
I'm using a code similar to the following
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
TEST_CASE("operator int()") {
CHECK_THROWS_AS(int(2), std::invalid_argument);
int i;
CHECK_THROWS_AS(i = int(2), std::invalid_argument);
}
However in both case I get a warning:
dd.cpp:7:7: warning: variable 'i' set but not used [-Wunused-but-set-variable]
int i;
^
dd.cpp:6:19: warning: expression result unused [-Wunused-value]
CHECK_THROWS_AS(int(2), std::invalid_argument);
^ ~
How do I silence the warning in proper C++ (not using a particular compiler feature).
By the way, in my real code, 2 is actually replaced by an object of a class whose int operator may throw.
I am using an if constexpr to test the presence of a method in a class. If the method is not present, I wish to tell the user the function was ignored and he should implement it but it is not mandatory.
The idea is to give a message similar to #warning but the preprocessor is processed before the template thus this will never work.
Is there any compilation time feedback alternative that came with C++17? Or any planned for C++20?
Runnable example
template <typename State>
void callStateFunction(const State& state) {
if constexpr (false) {
state.method();
} else {
#warning The method State::method() was not implemented
}
}
Not a great solution, I suppose, but...
If your compiler activate all warnings (-Wall for g++ and clang++, by example), you can substitute the #warning row with something that generate a warning.
By example, an unused (maybe with a talking name) variable.
I've tried with
template <typename State>
void callStateFunction(const State& state) {
if constexpr (false) {
state.method();
} else {
int method_not_implemented[sizeof(State)];
}
}
and calling with a non-method value (callStateFunction(1), by example), I get
prog.cc: In instantiation of 'void callStateFunction(const State&) [with State = int]':
prog.cc:13:23: required from here
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
7 | int method_not_implemented[sizeof(State)];
| ^~~~~~~~~~~~~~~~~~~~~~
from g++ (head 11.0.0) and
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
int method_not_implemented[sizeof(State)];
^
prog.cc:13:4: note: in instantiation of function template specialization 'callStateFunction<int>' requested here
callStateFunction(1);
^
from clang++ (head 11.0.0)
I suggest that the unused variable depends from the template typename (State) otherwise, if I define a non-dependent variable as
int method_not_implement;
I get a warning from clang++
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
int method_not_implemented;
^
also without calling the function with a non-method object.
If I have
namespace foo {
inline int bar() {
return 1119;
}
}
__attribute__((deprecated)) inline int bar() {
return 138;
}
in header.h and
#include "header.h"
#include <iostream>
int main() {
int x = bar();
int y = foo::bar();
std::cout << x << std::endl;
std::cout << y << std::endl;
}
in source.cpp, then
g++ source.cpp -o deprecated-test
results in
source.cpp: In function ‘int main()’:
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
^~~
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
(on Ubuntu 18.10 with g++ 8.2.0).
Why does the deprecated warning print twice?
Heading off some suggestions that would be unhelpful:
[[deprecated]]:
I know with C++14 on you can use the [[deprecated]] attribute, but I need to work with C++11.
Declaration vs. definition: The docs seem to imply it should be used with function declaration rather than definition, but
I need to define the functions inline in a header rather than declare in the header and define in source files; and
Trying this approach didn't stop the warning from printing twice anyway.
As per the documentation of GCC 8.2.0:
The deprecated attribute results in a warning if the function is used anywhere
in the source file. This is useful when identifying functions that are expected
to be removed in a future version of a program. The warning also includes the
location of the declaration of the deprecated function, to enable users to easily
find further information about why the function is deprecated, or what they
should do instead. Note that the warnings only occurs for uses...
There should be only one warning and not two. So this is a bug in GCC.
There is a related bug for Type attributes (rather than Function attributes) titled: C/C++ __attribute__((deprecated)) does not appear to wrap declarations as implied from the doc.
It has been confirmed as a bug.
I stumbled across the below code and really found it complex to understand the nested macro and type casting in it.
Also when i tried to compile the code , i have encountered an error
Would need an explanantion of the below code.
why BEGIN_STATE_MAP and END_STATE_MAP set as labels in Motor.h , This is really new to me
Thanks in advance
Motor.h
// the Motor state machine class
class Motor : public StateMachine
{
public:
Motor() : StateMachine(ST_MAX_STATES) {}
// external events taken by this state machine
void Halt();
void SetSpeed(MotorData*);
private:
// state machine state functions
void ST_Idle();
void ST_Stop();
void ST_Start(MotorData*);
void ST_ChangeSpeed(MotorData*);
// state map to define state function order
BEGIN_STATE_MAP
STATE_MAP_ENTRY(ST_Idle)
STATE_MAP_ENTRY(ST_Stop)
STATE_MAP_ENTRY(ST_Start)
STATE_MAP_ENTRY(ST_ChangeSpeed)
END_STATE_MAP
// state enumeration order must match the order of state
// method entries in the state map
enum E_States {
ST_IDLE = 0,
ST_STOP,
ST_START,
ST_CHANGE_SPEED,
ST_MAX_STATES
};
};
#endif //MOTOR_H
what are BEGIN_STATE_MAP and END_STATE_MAP, This definition i found i really new,
BEGIN_STATE_MAP and END_STATE_MAP are the Macros defined in the below header file.
StateMachine.h
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
#include <stdio.h>
#include "EventData.h"
struct StateStruct;
// base class for state machines
class StateMachine
{
public:
StateMachine(int maxStates);
virtual ~StateMachine() {}
protected:
enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN };
unsigned char currentState;
void ExternalEvent(unsigned char, EventData* = NULL);
void InternalEvent(unsigned char, EventData* = NULL);
virtual const StateStruct* GetStateMap() = 0;
private:
const int _maxStates;
bool _eventGenerated;
EventData* _pEventData;
void StateEngine(void);
};
typedef void (StateMachine::*StateFunc)(EventData *);
struct StateStruct
{
StateFunc pStateFunc;
};
#define BEGIN_STATE_MAP \
public:\
const StateStruct* GetStateMap() {\
static const StateStruct StateMap[] = {
#define STATE_MAP_ENTRY(entry)\
{ reinterpret_cast<StateFunc>(entry) },
#define END_STATE_MAP \
{ reinterpret_cast<StateFunc>(NULL) }\
}; \
return &StateMap[0]; }
#define BEGIN_TRANSITION_MAP \
static const unsigned char TRANSITIONS[] = {\
#define TRANSITION_MAP_ENTRY(entry)\
entry,
#define END_TRANSITION_MAP(data) \
0 };\
ExternalEvent(TRANSITIONS[currentState], data);
#endif
EventData.h
#ifndef EVENT_DATA_H
#define EVENT_DATA_H
class EventData
{
public:
virtual ~EventData() {};
};
#endif //EVENT_DATA_H
While i tried to compile the code above.Below is the error that was encountered
Error
-------------- Build: Debug in StateMachine (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g -pedantic -Wzero-as-null-pointer-constant -std=c++0x -Wextra -Wall -c C:\Users\xprk569\StateMachine\main.cpp -o obj\Debug\main.o
In file included from C:\Users\xprk569\StateMachine\main.cpp:2:0:
C:\Users\xprk569\StateMachine\Motor.h: In member function 'virtual const StateStruct* Motor::GetStateMap()':
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Idle)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:30:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Stop)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:31:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Start)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:32:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_ChangeSpeed)
^
C:\Users\xprk569\StateMachine\StateMachine.h:43:39: error: invalid cast from type 'int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}'
{ reinterpret_cast<StateFunc>(NULL) }\
^
C:\Users\xprk569\StateMachine\Motor.h:33:5: note: in expansion of macro 'END_STATE_MAP'
END_STATE_MAP
^
Process terminated with status 1 (0 minute(s), 0 second(s))
5 error(s), 0 warning(s) (0 minute(s), 0 second(s))
Can some please explain why is the macro written that way in Motor.h,
why is it declared like that in StateMachine.h and
why is the error being thrown ?
Thanks in Advance
It looks like this code depends on some nonstandard compiler extensions/errors.
To get it to compile (no idea if it will actually work) you need to replace the function names with full qualified member function pointers:
e.g.
BEGIN_STATE_MAP
STATE_MAP_ENTRY(&Motor::ST_Idle)
STATE_MAP_ENTRY(&Motor::ST_Stop)
STATE_MAP_ENTRY(&Motor::ST_Start)
STATE_MAP_ENTRY(&Motor::ST_ChangeSpeed)
END_STATE_MAP
After that, you need to figure out a way to overcome the non-conforming cast:
/tmp/gcc-explorer-compiler116314-75-1uiyu0/example.cpp: In member function 'virtual const StateStruct* Motor::GetStateMap()':
44 : error: invalid cast from type 'long int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}'
{ reinterpret_cast<StateFunc>(NULL) }\
^
83 : note: in expansion of macro 'END_STATE_MAP'
This cast is completely illegal. If I were you I would throw the code in the trash and rewrite - or use a proven state machine framework like boost meta state machine or boost statechart.
So you're quickly learning why Macros are no-nos in readable C++. If you get an error, you must expand the macro out to identify where the error is, also you cannot debug into them in most IDEs.
Anyway that said lets get to the expanding, their all the same error so we'll just look at the first one:
C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro STATE_MAP_ENTRY
STATE_MAP_ENTRY(ST_Idle)
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the & ?)
{ reinterpret_cast<StateFunc>(entry) },
So this is complaining about line 29: STATE_MAP_ENTRY(ST_Idle) So lets expand that:
{ reinterpret_cast<StateFunc>(entry) },
Obviously this is bad syntax all together outside the scoping of BEGIN_STATE_MAP and END_STATE_MAP, so in debugging many Macros you'd also have to look at the scoping macros... sometimes they may not be clearly named or delineated unfortunately, but let's finish defining the line we got the error on first. What is this StateFunc we're trying to cast to?
typedef void (StateMachine::*StateFunc)(EventData *);
It's a pointer to a member function which returns a void and accepts an EventData *. And alarm bells should be going off. You cannot cast to that! ST_Idle is of the format: void (StateMachine::*)() so you cannot cast to void (StateMachine::*StateFunc)(EventData *). This is the same problem for all your functions passed into the macros none of them return a void and take an EventData*, so even if you fix the syntax, these reinterpret_casts will always return a pointer to a method which is invalid to call, meaning this entire block of Macros is pointless at best and toxic at worst. In the current state you may just as well use none of these Macros or if you need to define the method just do:
BEGIN_STATE_MAP
END_STATE_MAP
But if you were going to change your method declarations to something more like:
void ST_Idle(EventData*);
Then you'd need to use this syntax:
STATE_MAP_ENTRY(&Motor::ST_Idle)
If you're not down with the method pointers they are quite complex. I've typed up a quick example here: http://ideone.com/nL0HnQ Feel free to comment with questions.
EDIT:
To expand the Macros here we'll get:
public: // BEGIN_STATE_MAP
const StateStruct* GetStateMap() { // BEGIN_STATE_MAP
static const StateStruct StateMap[] = { // BEGIN_STATE_MAP
{ reinterpret_cast<StateFunc>(ST_Idle) } // STATE_MAP_ENTRY(ST_Idle)
{ reinterpret_cast<StateFunc>(ST_Stop) } // STATE_MAP_ENTRY(ST_Stop)
{ reinterpret_cast<StateFunc>(ST_Start) } // STATE_MAP_ENTRY(ST_Start)
{ reinterpret_cast<StateFunc>(ST_ChangeSpeed) } // STATE_MAP_ENTRY(ST_ChangeSpeed)
{ reinterpret_cast<StateFunc>(NULL) } // END_STATE_MAP
}; // END_STATE_MAP
return &StateMap[0]; } // END_STATE_MAP
So this set of macros will:
Set the scope to public
Declare the method GetStateMap
Declare StateMap statically local to GetStateMap, it will be an array of StateStructs
On the first call of the GetStateMap method StateMap will be initialized to contain method pointers to ST_Idle, ST_Stop, ST_Start, ST_ChangeSpeed, and NULL reinterpret_cast to StateFuncs
Define GetStateMap to return the StateMap array
I'm using SWIG to create a Ruby Wrapper for some C++ classes. This is the signature of the C++ method which is giving me trouble:
virtual LogP wordProb(VocabIndex word, const VocabIndex *context);
This is the definition of VocabIndex:
#ifdef USE_SHORT_VOCAB
typedef unsigned short VocabIndex;
#else
typedef unsigned int VocabIndex;
#endif
This is the way I'm calling it from a Ruby script:
index = 8
context = [index]
puts ngram.wordProb(index, context)
This is the error I'm getting when I run my script:
ngram.rb:26:in `wordProb': Expected argument 2 of type VocabIndex const *, but got Array [8] (TypeError)
in SWIG method 'wordProb'
from ngram.rb:26:in `<main>'
My attempted solution:
After reading the docs (yes, I'm using SWIG 2.0), I tried this in my .i file:
%module rubylm
%{
#include "srilm-1.7.1/lm/src/Ngram.h"
%}
%include "srilm-1.7.1/lm/src/Counts.h"
%include "srilm-1.7.1/lm/src/Ngram.h"
%include "typemaps.i"
virtual LogP Ngram::wordProb(VocabIndex word, const VocabIndex *INPUT);
The swig command ran fine, but when I tried to build the wrapper library, I got this:
NgramWrapper_wrap.cxx:148:17: fatal error: tcl.h: No such file or directory
#include <tcl.h>
So I fired up a terminal (this is an Ubuntu box) and ran:
sudo apt-get install tcl-dev
This installed tcl 8.6, which placed its header files in the /usr/include/tcl8.6 directory. So I added that include directory in the Makefile line which builds NgramWrapper_wrap.o:
NgramWrapper_wrap.o: NgramWrapper_wrap.cxx
$(CC) $(CFLAGS) NgramWrapper_wrap.cxx -I $(RUBY_SRC) -I $(MISC_INCLUDE) -I $(DSTRUCT_INCLUDE) -I /usr/include/tcl8.6
However, I'm still getting build errors. And here's where I got stumped:
NgramWrapper_wrap.cxx:10812:34: error: ‘RARRAY_LEN’ was not declared in this scope
int size = RARRAY_LEN(objv[3]);
^
NgramWrapper_wrap.cxx:10816:5: error: ‘VALUE’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10816:12: error: ‘ptr’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10816:36: error: ‘RARRAY_PTR’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10819:35: error: ‘StringValuePtr’ was not declared in this scope
arg3[i]= StringValuePtr(*ptr);
^
NgramWrapper_wrap.cxx: In function ‘int _wrap_NgramCountWrapper_run(ClientData, Tcl_Interp*, int, Tcl_Obj* const*)’:
NgramWrapper_wrap.cxx:10908:34: error: ‘RARRAY_LEN’ was not declared in this scope
int size = RARRAY_LEN(objv[3]);
^
NgramWrapper_wrap.cxx:10912:5: error: ‘VALUE’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10912:12: error: ‘ptr’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10912:36: error: ‘RARRAY_PTR’ was not declared in this scope
VALUE *ptr = RARRAY_PTR(objv[3]);
^
NgramWrapper_wrap.cxx:10915:35: error: ‘StringValuePtr’ was not declared in this scope
arg3[i]= StringValuePtr(*ptr);
All I can think of is some version mismatch between Ruby, Swig and Tcl. But how can I know which Tcl version to use? I scoured the docs to no avail...
Hmm.
I just did the following
vocal.i
%module rubylm
%{
#include "Ngram.h"
%}
%include "Ngram.h"
%include "typemaps.i"
virtual LogP Ngram::wordProb(VocabIndex word, const VocabIndex *INPUT);
Ngram.h
#pragma once
#ifdef USE_SHORT_VOCAB
typedef unsigned short VocabIndex;
#else
typedef unsigned int VocabIndex;
#endif
typedef int LogP;
class NGram {
public:
LogP wordProb(VocabIndex word, const VocabIndex *context);
};
Command executed
swig2.0 -ruby -c++ vocal.i
followed by
g++ -c vocal_wrap.cxx -I/usr/include/ruby-2.1.0 -I/usr/include/x86_64-linux-gnu/ruby-2.1.0
without any errors. Have you forgot the -c++ option and why do you need tcl.h