Wrapping C++ function to take Lua table of strings using SWIG - c++

I'm trying to wrap a C++ function that can receive Lua table of strings and use it as an array of strings in C++ function.
I could successfully do this using float type instead of string.
Here's my function.
static void readTable(float values[], int len) {
for (int i=0; i<len; ++i)
printf("VALUE : %g", values[i]);
}
And here's the typemaps part from SWIG interface (.i) file
// using typemaps
%include <typemaps.i>
%apply (float INPUT[], int) {(float values[], int len)};
It works fine when I call this function in Lua.
However, if I change the type to std::string instead of float and pass table of strings to the function, I get the following error in Lua.
Error in readTable expected 2..2 args, got 1
I don't know what this means and how to fix this.
Maybe I have to add something more to the SWIG interface (.i) file?
I would appreciate any help. Thanks!

The typemaps.i file only defines typemaps for arrays of the primitive numeric types.
Thus I recommend that you write your own typemap. Then you can also take an argument of type std::vector<std::string>, so you don't even need the length parameter.
%module table_of_strings
%{
#include <iostream>
#include <string>
#include <vector>
void readTable(std::vector<std::string> values) {
for (size_t i=0; i<values.size(); ++i) {
std::cout << "VALUE : " << values[i] << '\n';
}
}
%}
%include "exception.i"
%typemap(in) std::vector<std::string>
{
if (!lua_istable(L,1)) {
SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
}
lua_len(L,1);
size_t len = lua_tointeger(L,-1);
$1.reserve(len);
for (size_t i = 0; i < len; ++i) {
lua_pushinteger(L,i+1);
lua_gettable(L,1);
$1.push_back(lua_tostring(L,-1));
}
}
void readTable(std::vector<std::string> values);
swig -c++ -lua test.i
clang++ -Wall -Wextra -Wpedantic -I/usr/include/lua5.3 -fPIC -shared test_wrap.cxx -o table_of_strings.so -llua5.3
local tos = require"table_of_strings"
tos.readTable({"ABC", "DEF", "GHI"})
VALUE : ABC
VALUE : DEF
VALUE : GHI

Related

Program using STL hash_map: output depends on optimization level

I'm messing around with (a bit old) SimIt-ARM 3.0. The SimIt-ARM 3.0 has issgen (ISS generator) based on (ARMv5) ISA defined using internal language defined using Lex specification & Yacc grammar. In particular it has a symbol_table class based on STL hash_map (which is not part of the C++ Standard Library, and which is now deprecated).
The problem: the hash_map behaves unexpectedly. Here is a demo using the original test. We see that output differs between -O0 and -O1.
Can someone help me to figure out what it the root cause?
UPD: here is the MRE:
#ifdef __GNUC__
#if __GNUC__ < 3
#include <hash_map.h>
namespace Sgi { using ::hash_map; using ::hash; }; // inherit globals
#else
#include <ext/hash_map>
#if __GNUC_MINOR__ == 0 && __GNU_C__ == 3
namespace Sgi = std; // GCC 3.0
#else
namespace Sgi = ::__gnu_cxx; // GCC 3.1 and later
#endif
#endif
#endif
#include <string>
#include <iostream>
#include <vector>
#include <cstring>
struct strEql
{
bool operator()(const char* sz1, const char* sz2)
{
return strcmp(sz1,sz2) == 0;
}
};
typedef Sgi::hash_map<const char *, unsigned int,
Sgi::hash<char *>, strEql> hash_map;
hash_map hasher;
unsigned int idx = 1;
void insert(const std::string& key)
{
hash_map::iterator it = hasher.find(key.c_str());
if (it==hasher.end())
{
hasher[key.c_str()] = idx++;
}
}
void print_hasher(void)
{
for(hash_map::iterator it = hasher.begin(); it != hasher.end(); it++)
{
std::cout << "fisrt: " << it->first << ", second: " << it->second << std::endl;
}
}
int main(void)
{
insert("xxx");
insert("yyy");
print_hasher();
}
Invocations and output:
$ g++ mre.cpp -Wno-deprecated -O0
fisrt: xxx, second: 1
fisrt: yyy, second: 2
$ g++ mre.cpp -Wno-deprecated -O1
fisrt: xxx, second: 1
In insert you are creating a temporary std::string key, the pointer returned from key.c_str() is therefore only valid until the end of the function.
Even if it was still valid then multiple calls to insert with the same string wouldn't necessarily produce the same address, equally calls with different strings might produce the same address so your hash table will be completely broken.
If you really want to hash based on the addresses you need to make sure you are only using string literals which will always have the same address (though I don't think there is any guarantee that two literals with the same value will have the same address) and will be valid for the duration of your program:
void insert(const char* key)
{
hash_map::iterator it = hasher.find(key);
if (it==hasher.end())
{
hasher[key] = idx++;
}
}
https://godbolt.org/z/6r18T16P9
You still need to be careful as its easily possible to pass a non-literal to insert and you'll be back to your original problem:
insert(std::string("yyy").c_str());
https://godbolt.org/z/EaGMvhPrE

[swig-JavaScript]is it support std::vector<std::string>* as a OUTPUT?

I use swig to write NodeJS's addon and encountered an error.
is it support std::vector* as a OUTPUT?
my *.i:
%apply std::vector<std::string> *OUTPUT {std::vector<std::string>* result};
when I run swig:
swig -javascript -node -c++ -DV8_VERSION=0x040599 export.i
has error:
export.i:19: Warning 453: Can't apply (std::vector< std::string > *OUTPUT). No typemaps are defined.
I encountered an error at swig-javascript, but it works fine at swig-python.
Anyone can help?
thanks
Adding:
%include "std_string.i"
%include "std_vector.i"
namespace std {
%template(StringVector) vector<string>;
}
early in your file seems to be enough to make it work, eg. for a C++ class
class MyClass {
public:
std::vector<std::string> getNames();
(...)
the following code will work on the Javascript side:
var o = ...
a = o.getNames();
console.log("size: " + a.size());
for (i = 0; i < a.size(); i++) {
console.log(a.get(i));
}
This is for SWIG 3, and it works as documented in http://www.swig.org/Doc1.3/Library.html#Library_nn15

Loading symbols from so file and calling method

I have a problem in C++.
I've created a function called execute
int* execute(int tab[], int n)
{
for (int i = 0; i<n; i++)
{
for (int j = 0; j < n-1; j++)
{
if (tab[j] > tab[j+1])
{
int tmp = tab[j];
tab[j] = tab[j+1];
tab[j+1] = tmp;
}
}
}
return tab;
}
So, this is simple BubbleSort function. I have this function in file BubbleSortAlgorithm.cpp.
So, in main function of my program, I check if libBubbleSortAlgorithm.so exist. If not, then I must create this lib. This lib is created via popen. So I've ended up with file libBubbleSortAlgorithm.so. If I run command
nm libBubbleSortAlgorithm.so | c++filt
then I get something like this.
0000000000000ed0 T execute(int*, int)
U dyld_stub_binder
I presume this is ok. So, next in main program, I load this .so file in my program with dlopen and call this function like this
void *handle = dlopen(buff, RTLD_LAZY);
if (handle)
{
execute = dlsym(handle, "execute");
int tab[5] = { 5, 2, 4, 7, 1 };
int x = 5;
execute(tab, x);
}
But before main I've also wrote this
#ifdef __cplusplus
extern "C" {
#endif
void (*execute)(int*, int);
#ifdef __cplusplus
}
#endif
So, in Xcode7, I get this error:
/Users/Tadej/Documents/Development/ALGatorC_final/ALGatorC/ALGatorC/main.cpp:96:49: Assigning to 'void (*)(int *, int)' from incompatible type 'void *'
Thank you in advance for help.
Regards,
golobich
Edit: I've changed code like this:
#ifdef __cplusplus
extern "C" {
#endif
int* (*execute)(int*, int);
#ifdef __cplusplus
}
#endif
execute = (int*(*)(int*, int))dlsym(handle, "execute");
int tab[5] = { 5, 2, 4, 7, 1 };
int x = 5;
int *xs = execute(tab, x);
for (int i = 0; i<5; i++)
{
std::cout << xs[i] << ", ";
}
So, now, I have problem at runtime. At execute(tab, x), Xcode complain and say this: EXC_BAD_ACCESS(code=1, address=0x0). So, problem is that execute is NULL. Any help? :)
You can safely cast the result.
dlsym just returns a (function) pointer, but does not know (nor it can) know the actual signature of your function. Only client code (your) can know that.
Cast can be done like this:
typedef int *(*execute_t)(int, int) ;
...
execute = (execute_t *)dlsym(handle, "execute");
And keep in mind what #molbdnilo says about function to be declared 'extern "C". This has to be done in libary code, not on client side
extern "C" int* execute(int tab[], int n)
{
for (int i = 0; i<n; i++)
{
....
The function in the library wasn't compiled with extern "C" linkage, so the name has C++ name-mangling in the library.
Because of this, dlsym can't find the name "execute" and returns a null pointer.
Either add extern "C" in the library, or dlsym the actual symbol as shown by nm without piping its output through c++filt.
Or build your library from C code.
I had same Problem but I did the following, without using the extern "C" keyword. Let say, we create a directory in Users/you/Desktop/FooProject and we write our shared library foo.cpp :
#ifndef FOO_H
#define FOO_H
int sum(int x, int y)
{
return x+y;
}
int subs( int x, int y)
{
return x-y;
}
#endif //FOO_H
We create the share library from foo.cpp:
g++ -dynamiclib foo.cpp -o libfoo.dylib
Now we would like to write a program that gets the function pointers to our library in the same directory /Users/You/FooProject/. For that we use dlopen(), dlsym() and dlclose() functions.
Because of the C++ name-mangling (used for function overloading ) our function names will differ from the ones that we have written on foo.cpp.
If we run objdump -t libfoo.dylib we get ( on my machine) this output:
libfoo.dylib: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000f80 g F __TEXT,__text __Z3sumii
0000000000000fa0 g F __TEXT,__text __Z4subsii
0000000000000000 *UND* dyld_stub_binder
Here is the tricky thing to take in count. Notice the two underscore lines before the names __Z3sumii and __Z4subsii. The actual names of the functions that we want to pull are just with one underscore instead of two. The names of the functions are _Z3sumii and _Z4subsii with only one underscore.
If you try to pull out the functions on dlsym() passing the name with the two underscores or the original names it will return NULL.
Wrong:
int (*sum)(int, int);
sum = dlsym(foo_lib_handle,"__Z3sumii");//two underscores and no casting
or
int (*sum)(int, int);
sum = dlsym(foo_lib_handle,"sum"); //the name demangled and no casting
Correct:
int (*sum)(int, int);
sum = ( int(*)(int, int) ) dlsym(foo_lib_handle,"_Z3sumii");
Because the dlsym returns a void pointer and the signatura expected is different we need to cast it appropriately.
Now that we know the names we need. We can write the code to pull out the function pointers for the dylib, called pullout.cpp:
#include <dlfcn.h>
#include <iostream>
int main( )
{
//function pointers for the pulled functions
int (*sum)(int, int);
int (*subs)(int, int);
// open the shared library
void* foo_lib_handle = dlopen("libfoo.dylib", RTLD_LAZY | RTLD_GLOBAL);
if(!foo_lib_handle)
{
std::cout << "problemo loading dylib" << std::endl;
return 1;
}
//notice the casting and the name "_Z3sumii" instead of "__Z3sumii" and the same for subs
sum = ( int(*)(int, int) ) dlsym(foo_lib_handle,"_Z3sumii");
subs = ( int(*)(int,int ) ) dlsym(foo_lib_handle,"_Z4subsii");
if( sum == NULL || subs == NULL )
{
std::cout << "functions pointers are null" << std::endl;
return 1;
}
std::cout << "calling sum(8,8) = " << sum(8,8) << '\n';
std::cout << "calling subs(18,8) = "<< subs(18,8) <<'\n';
//close the library
dlclose(foo_lib_handle);
return 0;
}
Compile pullout.cpp:
g++ -c pullout.cpp
To Link the pullout.o file generated, we can use several approaches :
We can use the -L to specify the path where to search the lib, and -l :
g++ pullout.o -L. -lfoo -o pulloutFoo
The -l option is expanded as -libfoo.dylib. Is important to notice that the default search path for gcc are:
/usr/local/lib
/usr/lib
Because of this, we need to use the -L option followed by the path. In our case we use the current directory.
Second option is to specify the full path and the name of the lib, so we do not have to use te -L, and -l options.
g++ pullout.o libfoo.dylib -o pullFoo
Third option, put the shared library into one of the common directories like /usr/local/lib . Then we would just do :
g++ pullout.o -lfoo -o pullFoo
If we run it:
$ ./pullFoo
calling sum(8,8) 16
calling subs(18,8) 10
Extra:
For runtime problems, see install names for mac os here: dynamic libraries and macOs and here stakoverflow.

How does SWIG wrap a map<string,string> in Python?

I'm using SWIG 2.0 to create a Python wrapper for a C++ library. One method has an argument of type "const std::map&". SWIG happily generates a wrapper for it, but I can't figure out how to invoke the method. If I pass, for example, {"a":"b"} for that argument, I get a "NotImplementedError: Wrong number or type of arguments for overloaded function" error.
I looked at the generated .cxx file in the hope it would clarify, but it didn't. Here's the code that processes that argument:
res4 = SWIG_ConvertPtr(obj3, &argp4, SWIGTYPE_p_std__mapT_std__string_std__string_t, 0 | 0);
if (!SWIG_IsOK(res4)) {
SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "new_Context" "', argument " "4"" of type '" "std::map< std::string,std::string > const &""'");
}
It clearly knows that argument exists, and that it's supposed to be something that gets converted to a map. But I can't figure out what it actually wants me to pass for it.
When you're using a C++ template (e.g. a std::map<string, string>) you need to create an alias for it in your .i file so you can use it in python:
namespace std {
%template(map_string_string) map<string, string>;
}
Now let's say you want to wrap a function that looks like this:
void foo(const std::map<string, string> &arg);
On the python side, you need to pass a map_string_string to foo, not a python dict. It turns out that you can easily convert a python dict to a map though by doing this:
map_string_string({ 'a' : 'b' })
so if you want to call foo, you need to do this:
foo(map_string_string({ 'a' : 'b' }))
Here's full example code that works.
// test.i
%module test
%include "std_string.i"
%include "std_map.i"
namespace std {
%template(map_string_string) map<string, string>;
}
void foo(const std::map<std::string, std::string> &val);
%{
#include <iostream>
#include <string>
#include <map>
using namespace std;
void
foo(const map<string, string> &val)
{
map<string, string>::const_iterator i = val.begin();
map<string, string>::const_iterator end = val.end();
while (i != end) {
cout << i->first << " : " << i->second << endl;
++i;
}
}
%}
And the python test code:
#run_test.py
import test
x = test.map_string_string({ 'a' : 'b', 'c' : 'd' })
test.foo(x)
And my command line:
% swig -python -c++ test.i
% g++ -fPIC -shared -I/usr/include/python2.7 -o _test.so test_wrap.cxx
% python run_test.py
a : b
c : d

separating interface and implemention with normal functions

this seems like it should be pretty simple, I'm probably leaving something simple out.
this is the code I'm trying to run. it is 3 files, 2*cpp and 1*header.
this wont run on code blocks, I'm trying to see what I'm missing!
these are the errors given:
obj\Debug\main.o||In function `main':|
|9|undefined reference to `generateArray(int*, int)'|
|11|undefined reference to `reverseOrder(int*, int*, int)'|
|13|undefined reference to `displayArray(int*, int*, int)'|
// lab6.h
#ifndef LAB6_H_INCLUDED
#define LAB6_H_INCLUDED
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
void generateArray(int[], int );
void displayArray(int[], int[], int );
void reverseOrder(int [],int [], int);
#endif // LAB6_H_INCLUDED
// lab6.cpp
#include "lab6.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using std::cout; using std::endl;
using std::rand; using std::srand;
using std::time;
using std::setw;
void generateArray(int array1[], int arraySize)
{
srand(time(0));
for (int i=0; i<10; i++)
{
array1[i]=(rand()%10);
}
}
void displayArray(int array1[], int array2[], int arraySize)
{
cout<<endl<<"Array 1"<<endl;
for (int i=0; i<arraySize; i++)
{
cout<<array1[i]<<", ";
}
cout<<endl<<"Array 2"<<endl;
for (int i=0; i<arraySize; i++)
{
cout<<array2[i]<<", ";
}
}
void reverseOrder(int array1[],int array2[], int arraySize)
{
for (int i=0, j=arraySize-1; i<arraySize;j--, i++)
{
array2[j] = array1[i];
}
}
// and finally main.cpp
#include "lab6.h"
int main()
{
generateArray(array1, arraySize);
reverseOrder(array1, array2, arraySize);
displayArray(array1, array2, arraySize);
return 0;
}
Concluding from the linker's error messages, it seems that you haven't given the linker both object files, and it cannot find what you defined in lab6.cpp. I don't know CodeBlocks, so I don't know how you would have to setup your project so that the linker gets passed all the object files.
Most compilers, however, would invoke the linker with all the object files they generate, so manually invoking the compiler
cc lab6.cpp main.cpp
(substituting your compiler for "cc") might do.
Anyway, once you managed that, you will still have linker errors, because your arrays are defined in the header, which makes them end up in two translation units. The linker will complain about duplicate symbols then.
Other than that, I'd criticize that
you use global variables instead of local ones (once you fixed that, they are also not defined in two translation units anymore),
the code would blow up if you changed arraySize (because you haven't used it everywhere),
you use int to specify the size of the arrays instead of std::size_t and
you use C arrays instead of C++' containers (which might be required, as this is homework).
Oh, and I would remove all the using declarations and prefix identifiers with std::, where needed. In your case it would even save typing. Also, it makes the code clearer (some would argue against this) and it is less error prone (hard to argue against that).
No, you haven't.
You have two cpp files, that contain
int array1[arraySize];
int array2[arraySize];
lib6.cpp and main.cpp compile normally but duranig linking of course there is an error: "multiple definition of array1 ..."
Firstly, take the following snippet of code out of your header file:
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
Move the code above inside your main function. If you put these in the header file, you are making them into global variables, which is a really bad idea. Moreover, since these are definitions, not declarations, they will be created multiple times (once for each compilation unit -- i.e., .cpp source file -- that includes the header), which will result in a multiple definition error if you were to link "lab6.o" and "main.o" together.
Secondly, it appears that you have compiled "main.cpp" to "main.o" but then you have forgotten to compile "lab6.cpp" to "lab6.o" and to link "lab6.o" with "main.o", together. I don't know how to do this with Code::Blocks, although I suspect it involves checking "lab6.cpp" so that it is included in the build. If you are willing to use the commandline to build and you have the g++ compiler, then you can use:
g++ main.cpp -c -o main.o
g++ lab6.cpp -c -o lab6.o
g++ main.o lab6.o -o lab6
With the above, you can then invoke ./lab6 to run your program. You may want to use a build system such as CMake or Make (I recommend CMake) to build your program instead of relying on Code::Blocks.
Also, assuming you are permitted to do so, it is highly advisable that you use std::vector instead of primitive arrays. Of course, your assignment might be requiring you to use regular arrays, in which case that wouldn't be possible. Also, it is generally better to use std::size_t instead of int as an indexing type, although int will work, and if you use std::size_t (which is unsigned) it might cause problems with some of your loops, so contrary to the suggestion of one of the other answerers, I'd advise you just stick with int at this point (though, in the future, you should probably use std::size_t as your array size/index type).
Don't use "using" directives when writing native C++ code as it pollutes the global namespace.
How do you tell the difference between constants with your naming convention? How about ARRAYSIZE instead of arraySize for constants and enums
Why are your arrays in the header file? your functions are for the "user" to use in main(). With this implementation the user cannot change ARRAYSIZE can he. In fact, is there even a need for ARRAYSIZE when the functions are designed to work with arrays of arbitrary size?
Pass arrays by pointer, passing by value is slower and more expensive
lab6.cpp
#include "lab6.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
//#include <iomanip>
void generateArray(int* array1, int arraySize)
{
// make implicit type conversions explicit
std::srand((unsigned)std::time(0));
// why the magic number here?
for (int i=0; i<10; i++)
{
array1[i]=(std::rand()%10);
}
}
void displayArray(int* array1, int* array2, int arraySize)
{
std::cout << std::endl << "Array 1" << std::endl;
for (int i=0; i<arraySize; i++)
{
std::cout<<array1[i]<<", ";
}
std::cout << std::endl << "Array 2" << std::endl;
for (int i=0; i<arraySize; i++)
{
std::cout<<array2[i]<<", ";
}
}
void reverseOrder(int* array1, int* array2, int arraySize)
{
// This is hard to read, and why do you need another integer anyway
// for (int i=0, j=arraySize-1; i<arraySize;j--, i++)
// {
// array2[j] = array1[i];
// }
for(int i=0;i<arraySize;i++)
{
array2[arraySize - i - 1] = array1[i];
}
}
lab6.h
#ifndef LAB6_H_INCLUDED
#define LAB6_H_INCLUDED
void generateArray(int* array1, int arraySize);
void displayArray(int* array1, int* array2, int arraySize);
void reverseOrder(int* array1, int* array2, int arraySize);
#endif // LAB6_H_INCLUDED
main.cpp
#include "lab6.h"
int main()
{
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
generateArray(array1, arraySize);
reverseOrder(array1, array2, arraySize);
displayArray(array1, array2, arraySize);
return 0;
}