global variables in a shared library? - vala

I'm trying to add global variables to a shared library. Consider this example, in library libutils, globals.vala contains
namespace Libutils {
public static GLib.Object yorgi_obj;
public static int yorgi_int;
}
I see externs are properly generated in .c & .h files
libutils:globals.c
extern GObject* libutils_yorgi_obj;
GObject* libutils_yorgi_obj = NULL;
extern gint libutils_yorgi_int;
gint libutils_yorgi_int = 0;
libutils:globals.h
extern GObject* libutils_yorgi_obj;
extern gint libutils_yorgi_int;
My test program, tester.vala
int main(string[] args) {
Libutils.yorgi_int = 1;
All is well in compiling tester.vala. But linking to Libutils.so I get
...tester.vala:614: undefined reference to `libutils_yorgi_int'
Do I have to specify some special vala attributes or pass something to the linker?

Related

How can I hide some parameters from C DLL function on JNA Wrapper side?

I've successfully wrapped a C DLL library using JNA.
As I'm not the owner of the C development part, I would like to hide
some parameters of a C function that I've wrapped on java side.
To be more precise my java code is as follows :
public interface IJNALibrary extends Library {
// INIT FUNCTION
public int initFunction(int firstValue, int secondValue, int thirdValue);
}
On the C side I have in the *.h file :
extern "C" CSAMPLE_API int initFunction (
unsigned firstValue,
unsigned secondValue,
unsigned thirdValue);
My purpose is to directly set secondValue and thirdValue parameters to 1 and thus hide those parameters to the java API user.
I don't want the user to know that he could change the values of those parameters.
In fact I would like to have something like :
public interface IJNALibrary extends Library {
// INIT FUNCTION
public int initFunction(int firstValue);
}
and initFunction(int firstValue) calls initFunction(int firstValue, int secondValue, int thirdValue) from the C DLL part.
But this has to be done inside the java Wrapper and not from the code which calls the java Wrapper.
I'm afraid that It cannot be possible, is it?
Unless I create another C DLL (with public int initFunction(int firstValue) function) which calls the first C DLL(which embed initFunction(int firstValue, int secondValue, int thirdValue).But I would rather do it on the java side in order not to have manage 2 C DLLs.
See also below the Sample.java file which calls the mapped method defined in IJNALibrary interface.
public class Sample {
static IJNALibrary IJNAFunctions;
public static void main(String[] args) throws IOException {
System.setProperty("jna.library.path", "./librayPath");
// LOADING LIBRARY
IJNAFunctions = (IJNALibrary) Native.load("c", IJNALibrary.class);
int firstValue = 1;
int secondValue = 2;
int thirdValue = 3;
int initReturn = IJNAFunctions.initFunction(firstValue, secondValue, thirdValue);
}
}
Thanx for your help.
It depends on what you want to archive. If you want to make it easier for users to call the init, this is an option (demonstrated using gethostname from libc), which uses a Java 8 feature, which allows adding default methods to interfaces:
public class TestDefaultMethod {
public static interface LibC extends Library {
LibC INSTANCE = Native.load("c", LibC.class);
// Original binding of method
int gethostname(byte[] name, int len);
// Helper method to make it easier to call gethostname
default String gethostname() {
byte[] result = new byte[255];
LibC.INSTANCE.gethostname(result, result.length);
return Native.toString(result);
}
}
public static void main(String[] args) {
// Usage
System.out.println(LibC.INSTANCE.gethostname());
}
}
Java developers normally don't arrays to functions, which fill them and a java developer would never pass the length of the array in a separate parameter. These are artifacts of the C nature of the function. In the wrapped function an array is allocated, the native call done and the array then unwrapped. All the ugly C specialties are hidden in the default method.
If you don't want to expose the method on java at all (be warned, if your users can access the JNA library, they can circumvent your protections!), you can use a function pointer directly:
public class TestDefaultMethod {
public static interface LibC extends Library {
NativeLibrary libc = NativeLibrary.getInstance("c");
LibC INSTANCE = Native.load("c", LibC.class);
default String gethostname() {
byte[] result = new byte[255];
libc.getFunction("gethostname").invokeInt(new Object[] {result, result.length});
return Native.toString(result);
}
}
public static void main(String[] args) {
System.out.println(LibC.INSTANCE.gethostname());
}
}
Same idea as above, the default method will hide the ugly parts. In this case though the function is not accessed through the managed INSTANCE, but access through the function pointer directly.

JNA to Go DLL - How do I get String returned from Go Func?

I have a Java program that is using JNA to call a Go Func. Here's the Interface to the Go func in Java:
public interface GPG extends Library {
// GoString class maps to: C type struct { const char *p; GoInt n; }
public class GoString extends Structure {
public static class ByValue extends GoString implements Structure.ByValue {}
public String p;
public long n;
protected List getFieldOrder(){
return Arrays.asList(new String[]{"p","n"});
}
}
// Foreign functions
public GoString.ByValue decrypt(GoString.ByValue encString, GoString.ByValue secretKeyring, GoString.ByValue passphrase);
}
The func signature in Go is:
func decrypt(encString string, secretKeyring string, passphrase string) string
The Go generated C header has:
/* Created by "go tool cgo" - DO NOT EDIT. */
/* package command-line-arguments */
#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t below */
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
#endif
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
typedef _GoString_ GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern GoString decrypt(GoString p0, GoString p1, GoString p2);
#ifdef __cplusplus
}
#endif
I call the Go Func from Java using this code:
GPG gpg = (GPG) Native.loadLibrary("C:/lib/gpg.dll", GPG.class);
GPG.GoString.ByValue encString = new GPG.GoString.ByValue();
encString.p = value;
encString.n = encString.p.length();
GPG.GoString.ByValue secretKeyring = new GPG.GoString.ByValue();
secretKeyring.p = "c:/gnupg/secring.gpg";
secretKeyring.n = secretKeyring.p.length();
GPG.GoString.ByValue passphrase = new GPG.GoString.ByValue();
passphrase.p = "SecretPassPhrase";
passphrase.n = passphrase.p.length();
GPG.GoString.ByValue decValue = gpg.decrypt(encString, secretKeyring, passphrase);
Clearly the func is being called and processes up to the return of the result string. But it then produces: "panic: runtime error: cgo result has Go pointer"
How do I get a String result back from Go?
Using go version go1.10 windows/amd64, JNA 4.5.1, Java 1.8.0_152
Your GO function should looks like this:
//export decrypt
func decrypt(encString string, secretKeyring string, passphrase string) *C.char {
//... your code here
var str string = "returning string"
return C.CString(str)
}
Java Interface:
public String decrypt(GoString.ByValue encString, GoString.ByValue secretKeyring, GoString.ByValue passphrase);
Your const char * in _GoString_ should use a Pointer instead, then use Pointer.getString() with the provided offset to obtain the actual string.
If Go itself is rejecting a string return value, you'll likely have to instead populate a buffer provided by the caller.

DllImport in FSI

Need to port following C# code to F#:
[DllImport("libc", SetLastError = true)]
private static extern int chmod(string pathname, int mode);
What is wrong in following code? Tried it in FSI on Mac and getting error FS0193: internal error: Method 'FSI_0020+Libc.chmod' does not have a method body.
module Libc =
open System.Runtime.InteropServices
[<DllImport("libc", SetLastError = true)>]
extern int chmod(string pathname, int mode)
[<DllImport ("libc", EntryPoint = "chmod", SetLastError = true)>]
extern int sys_chmod (string _path, uint32 _mode)
let chmodCarry mode path = sys_chmod(path, mode)
And what to do with private and static in this case? I would make sys_chmod private and expose the carried chmod function only.
Or is there any other more portable way to make a file executable?

How to create and using vapi files?

I want to make a custom vapi file, I have the basic stuff but I obviously miss something and I can't find anywhere how to do this properly. My main goal is to create a torent app, using libtorrent, and create the GUI (the frontend?) with vala and gtk.
I have a c_func_head.h:
#ifndef WHATEVER_H_INCLUDED
#define WHATEVER_H_INCLUDED
int add(int a, int b);
#endif
c_functions.c:
#include <stdio.h>
#include <stdlib.h>
#include "c_func_head.h"
int add(int a, int b){
printf("Adding numbers in c...\n");
return a+b;
}
vala_p.vapi:
[CCode (cheader_filename = "c_func_head.h")]
namespace MyFunc {
[CCode (cname = "add")]
public int add (int a, int b);
}
and finally vala_program.vala:
//extern int add(int a, int b);
using MyFunc;
void main(){
stdout.printf("Calling a c function...\n");
//stdout.printf("The sum is: %d\n", add2number(2, 2));
int sum = add(2, 2);
stdout.printf("The sum is: %d\n", sum);
}
As you can see I used an extern too, it worked with it but I want to use vapi files.
I compiled with (everything is in the same folder):
valac vala_program.vala --vapidir=vala_p.vapi -o mustrun
and the error is:
The namespace name `MyFunc' could not be found using MyFunc;
One more thing. Is it possible to make bindings for libtorrent? It uses c++ and I gues I have to use c++ too.
You can't make Vala bindings of C++ code. Only C. There a a guide to writing legacy bindings and a binding for Transmission, which is C-based.
As for the specific error you have, you want to call valac vala_program.vala vala_p.vapi if the library (i.e., header files) are the the same directory or valac vala_program.vala --pkg vala_p --vapidir=/path/to/directory/containing/vapi.

How to write void pointer typedefs in vapi files?

I'm trying to write a VAPI file to use unixODBC, one of the functions is called SQLAllocHandle:
// From <sqltypes.h>
#define SQL_API
typedef signed short int SQLSMALLINT;
typedef SQLSMALLINT SQLRETURN;
typedef void * SQLHANDLE;
// From <sql.h>
#define SQL_SUCCESS 0
#define SQL_SUCCESS_WITH_INFO 1
#define SQL_ERROR (-1)
#define SQL_INVALID_HANDLE (-2)
#define SQL_HANDLE_ENV 1
#define SQL_HANDLE_DBC 2
#define SQL_HANDLE_STMT 3
#define SQL_HANDLE_DESC 4
#define SQL_NULL_HANDLE 0
SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle);
It's my first try to write a vapi file, but the documentation is scarce at the moment (Vala vapi files documentation).
The calling code should look similiar to this:
using UnixOdbc;
int main(string[] args) {
Handle h;
if (AllocHandle (HandleType.ENV, NullHandle, out h) == Return.SUCCESS)
...
}
In particular I'd like to know how to convert the SQLHANDLE type which is really just a void * (opaque void pointer).
In other words, what would the UnixOdbc.Handle type look like in the vapi file?
My current approach is to pretend that it is a long:
[CCode (cheader_filename = "sql.h, sqltypes.h")]
namespace UnixOdbc {
[CCode (cname = "SQLRETURN", cprefix = "SQL_")]
public enum Return {
SUCCESS,
SUCCESS_WITH_INFO,
ERROR,
INVALID_HANDLE
}
[CCode (cname = "SQLSMALLINT", cprefix = "SQL_HANDLE_")]
public enum HandleType {
ENV,
DBC,
STMT,
DESC
}
[CCode (cname = "SQLHANDLE")]
public struct Handle: long {}
[CCode (cname = "SQL_NULL_HANDLE")]
public const Handle NULL_HANDLE;
[CCode (cname = "SQLAllocHandle")]
public static Return AllocHandle (HandleType handle_type, Handle input_handle, out Handle output_handle);
}
You can trying reading the guide for legacy VAPI files. I would make:
[CCode(cname = "void")]
[Compact]
public class Handle {
[CCode(cname = "SQLAllocHandle")]
public static Return alocate_handle(HandleType type, Handle? input_handle, out Handle? output_handle);
...
}
Simply disregard the binding of SQL_NULL_HANDLE; it doesn't do anything useful.

Resources