How to generate GIR files from the Vala compiler? - introspection

I am trying to create python bindings to a vala library using pygi with gobject introspection. However, I am having trouble generating the GIR files (that I am planning to compile to typelib files subsequently). According to the documentation valac should support generating GIR files.
Compiling the following
helloworld.vala
public struct Point {
public double x;
public double y;
}
public class Person {
public int age = 32;
public Person(int age) {
this.age = age;
}
}
public int main() {
var p = Point() { x=0.0, y=0.1 };
stdout.printf("%f %f\n", p.x, p.y);
var per = new Person(22);
stdout.printf("%d\n", per.age);
return 0;
}
with the command
valac helloworld.vala --gir=Hello-1.0.gir
doesn't create the Hello-1.0.gir file as one would expect. How can I generate the gir file?

To generate the GIR one has to put the functions to be exported under the same namespace
hello.vala
namespace Hello {
public struct Point {
public double x;
public double y;
}
public class Person {
public int age = 32;
public Person(int age) {
this.age = age;
}
}
}
public int main() {
var p = Hello.Point() { x=0.0, y=0.1 };
stdout.printf("%f %f\n", p.x, p.y);
var per = new Hello.Person(22);
stdout.printf("%d\n", per.age);
return 0;
}
and then run the following command.
valac hello.vala --gir=Hello-1.0.gir --library Hello-1.0
This will generate a gir and a vapi file in the current directory.
Then to generate the typelib file, one needs to run
g-ir-compiler --shared-library=hello Hello-1.0.gir -o Hello-1.0.typelib
assuming the shared library has been compiled to libhello.so

Related

How are assemblies located and loaded in .NET 5+?

I am currently elaborating which content I should use in the different version numbers, so I read What are differences between AssemblyVersion, AssemblyFileVersion and AssemblyInformationalVersion? and many other posts and articles.
Based on SemVer, I would increase the minor version number if I make backwards compatible changes. I understand and like this concept, and I want to use it.
This answer on the above linked post has good explanations on the different version numbers, but it also says that changing AssemblyVersion would require recompiling all dependent assemblies and executables.
I did a quick test:
testVersionLib.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>abc.snk</AssemblyOriginatorKeyFile>
<AssemblyVersion>3.4.5.6</AssemblyVersion>
</PropertyGroup>
</Project>
project testVersionLib: class1.cs
using System;
namespace testVersionLib
{
public class Class1
{
public string m_versionText = "3.4.5.6";
}
}
project testVersionExe: program.cs
using System;
using System.Diagnostics;
namespace testVersionExe
{
class Program
{
static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
PrintFileVersion ();
PrintAssemblyFullName ();
}
private static void PrintAssemblyFullName ()
{
Console.WriteLine ("m_versionText: " + new testVersionLib.Class1 ().m_versionText);
Console.WriteLine ("DLL Assembly FullName: " + System.Reflection.Assembly.GetAssembly (typeof (testVersionLib.Class1)).FullName);
}
private static void PrintFileVersion ()
{
Console.WriteLine ("DLL FileVersion: " + FileVersionInfo.GetVersionInfo ("testVersionLib.dll").FileVersion);
}
}
}
and found that this may apply to .Net Framework, but it obviously does not apply to .NET 5 (and most likely .NET 6 and above as well, and maybe previous versions of .NET Core): I created a .NET 5 C# console app with AssemblyVersion 1.2.3.4 and strong name. This EXE references a DLL with AssemblyVersion 3.4.5.6 and strong name. The DLL compiled with different versions and is placed in the EXE's folder without compiling that one again.
The results:
The EXE fails to start if the DLL version is below 3.4.5.6 (e.g. 3.4.5.5, 3.4.4.6, 3.3.5.6), which makes sense.
The EXE successfully runs if the DLL version is equal to or above the version that was used to created the app (equal: 3.4.5.6; above: 3.4.5.7, 3.4.6.6, 3.5.5.6, 4.4.5.6).
This answer only says that
[...] .Net 5+ does not (by default) require that the assembly version used at runtime match the assembly version used at build time.
but it does not explain why and how.
How are assemblies located, resolved and loaded in .NET 5?
If someone wants to repeat my test with the compiled files, here's the 7z archive, encoded as PNG:
To decode the image, save it as PNG and use this code:
static void Main (string[] args)
{
string dataPath = #"c:\temp\net5ver.7z";
string imagePath = #"c:\temp\net5ver.7z.png";
string decodedDataPath = #"c:\temp\net5ver.out.7z";
int imageWidth = 1024;
Encode (dataPath, imagePath, imageWidth);
Decode (imagePath, decodedDataPath);
}
public static void Decode (string i_imagePath, string i_dataPath)
{
var bitmap = new Bitmap (i_imagePath);
var bitmapData = bitmap.LockBits (new Rectangle (Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
byte[] dataLengthBytes = new byte[4];
Marshal.Copy (bitmapData.Scan0, dataLengthBytes, 0, 4);
int dataLength = BitConverter.ToInt32 (dataLengthBytes);
int imageWidth = bitmap.Width;
int dataLines = (int)Math.Ceiling (dataLength / (double)imageWidth);
if (bitmap.Height != dataLines + 1)
throw new Exception ();
byte[] row = new byte[imageWidth];
List<byte> data = new();
for (int copyIndex = 0; copyIndex < dataLines; copyIndex++)
{
int rowStartIndex = imageWidth * (copyIndex + 1);
Marshal.Copy (IntPtr.Add (bitmapData.Scan0, rowStartIndex), row, 0, row.Length);
data.AddRange (row.Take (dataLength - data.Count));
}
bitmap.UnlockBits (bitmapData);
System.IO.File.WriteAllBytes (i_dataPath, data.ToArray ());
}
public static void Encode (string i_dataPath,
string i_imagePath,
int i_imageWidth)
{
byte[] data = System.IO.File.ReadAllBytes (i_dataPath);
int dataLines = (int)Math.Ceiling (data.Length / (double)i_imageWidth);
int imageHeight = dataLines + 1;
var bitmap = new Bitmap (i_imageWidth, imageHeight, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var palette = bitmap.Palette;
for (int index = 0; index < byte.MaxValue; index++)
palette.Entries[index] = Color.FromArgb (index, index, index);
bitmap.Palette = palette;
var bitmapData = bitmap.LockBits (new Rectangle (Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
Marshal.Copy (BitConverter.GetBytes (data.Length), 0, bitmapData.Scan0, 4);
for (int copyIndex = 0; copyIndex < dataLines; copyIndex++)
{
int dataStartIndex = i_imageWidth * copyIndex;
int rowStartIndex = i_imageWidth * (copyIndex + 1);
byte[] row = data.Skip (dataStartIndex).Take (i_imageWidth).ToArray ();
Marshal.Copy (row, 0, IntPtr.Add (bitmapData.Scan0, rowStartIndex), row.Length);
}
bitmap.UnlockBits (bitmapData);
bitmap.Save (i_imagePath);
}

unordered_map insertion is creating bottleneck

So here I am trying to create a Graph data structure in which i have to keep track of edges according to their ids. So I am creating edge ids in string data structure as eid: sourceid_destinationid
using namespace std;
class Edge{
public:
bool operator==(const Edge* &obj) const
{
return eid==obj->eid;
}
std::string eid;
set<int> rrids;
int sourceid;
int destid;
int strength;
public:
Edge(std::string eid,int from,int to);
std::string getId();
void addRRid(int rrid);
void removeRRid(int rrid);
void setRRid(set<int> rrids);
void setId(std::string eid);
};
This is another class which I am using for adding and removing the edges.
hpp-file
using namespace std;
class RRassociatedGraph{
public:
unordered_map<int,vertex*> vertexMap;
std::unordered_map<std::string,Edge*> EdgeMap;
int noOfEdges;
public:
RRassociatedGraph();
unordered_set<vertex> getVertices();
int getNumberOfVertices();
void addVertex(vertex v);
vertex* find(int id);
Edge* findedge(std::string id);
void addEdge(int from, int to, int label);
void removeEdge(int from, int to,int rrSetID);
};
When I debugged the code I found out that in the function add edge here the place where I am doing EdgeMap.insert the execution doesn't go to next line. It remains in hashtable for loop of some bucket entry. I can't debug this code frequently because I have to wait for 3 hours to get this issue. The code is working perfectly with small graphs. But for larger graphs where edgeMap has to store 800k edges. It goes in this hashtable infinite loop. I don't get this hashtable code. But is there something wrong with my data structure of creating Edgemap?
#include "RRassociatedGraph.hpp"
RRassociatedGraph::RRassociatedGraph() {
noOfEdges=0;
}
void RRassociatedGraph::addVertex(vertex v) {
vertexMap.insert(pair<int,vertex*>(v.getId(), &v));
}
vertex* RRassociatedGraph::find(int id) {
unordered_map<int,vertex*>::const_iterator got=vertexMap.find(id);
if(got != vertexMap.end() )
return got->second;
return nullptr;
}
Edge* RRassociatedGraph::findedge(std::string id){
unordered_map<std::string,Edge*>::const_iterator got=EdgeMap.find(id);
if(got != EdgeMap.end() )
return got->second;
return nullptr;
}
void RRassociatedGraph::addEdge(int from, int to, int label) {
vertex* fromVertex = find(from);
if (fromVertex == nullptr) {
fromVertex = new vertex(from);
vertexMap.insert(pair<int,vertex*>(fromVertex->getId(), fromVertex));
}
vertex* toVertex = find(to);
if (toVertex == nullptr) {
toVertex = new vertex(to);
vertexMap.insert(pair<int,vertex*>(toVertex->getId(), toVertex));
}
if(fromVertex==toVertex){
// fromVertex->outDegree++;
//cout<<fromVertex->getId()<<" "<<toVertex->getId()<<"\n";
return;
}
std::string eid=std::to_string(from);
eid+="_"+std::to_string(to);
Edge* edge=findedge(eid);
if(edge==nullptr){
edge=new Edge(eid,from,to);
edge->addRRid(label);
fromVertex->addOutGoingEdges(edge);
EdgeMap.insert(pair<std::string,Edge*>(edge->getId(), edge));
noOfEdges++;
}
else{
edge->addRRid(label);
fromVertex->outDegree++;
}
}
void RRassociatedGraph::removeEdge(int from, int to,int rrSetID) {
vertex* fromVertex = find(from);
std::string eid=std::to_string(from);
eid+="_"+std::to_string(to);
if(EdgeMap.count(eid)==1){
Edge* e=EdgeMap.find(eid)->second;
if(fromVertex->removeOutgoingEdge(e,rrSetID)){
EdgeMap.erase(eid);
delete e;
}
}
}
this is the place where it keeps going into this for loop. The insertion time of map should be very less but this is creating bottleneck in my code.
template <class _Tp, class _Hash, class _Equal, class _Alloc>
void
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__invalidate_all(this);
#endif // _LIBCPP_DEBUG_LEVEL >= 2
__pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
__bucket_list_.reset(__nbc > 0 ?
__pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
__bucket_list_.get_deleter().size() = __nbc;
if (__nbc > 0)
{
for (size_type __i = 0; __i < __nbc; ++__i)
__bucket_list_[__i] = nullptr;
__next_pointer __pp = __p1_.first().__ptr();
__next_pointer __cp = __pp->__next_;
if (__cp != nullptr)
{
size_type __chash = __constrain_hash(__cp->__hash(), __nbc);
__bucket_list_[__chash] = __pp;
size_type __phash = __chash;
for (__pp = __cp, __cp = __cp->__next_; __cp != nullptr;
__cp = __pp->__next_)
{
__chash = __constrain_hash(__cp->__hash(), __nbc);
if (__chash == __phash)
__pp = __cp;
else
{
if (__bucket_list_[__chash] == nullptr)
{
__bucket_list_[__chash] = __pp;
__pp = __cp;
__phash = __chash;
}
else
{
__next_pointer __np = __cp;
for (; __np->__next_ != nullptr &&
key_eq()(__cp->__upcast()->__value_,
__np->__next_->__upcast()->__value_);
__np = __np->__next_)
;
__pp->__next_ = __np->__next_;
__np->__next_ = __bucket_list_[__chash]->__next_;
__bucket_list_[__chash]->__next_ = __cp;
}
}
}
}
}
}
I have many files so I can't put the whole code. I am not that good in c++. Please let me know if I have to implement it some other way. I have to use hashMap because I also need faster search.
You are probably experiencing re-hash at insert. Unordered_map has number of buckets. When they are filled worst case insert time is O(size()).
http://en.cppreference.com/w/cpp/container/unordered_map/insert
Rehashing occurs only if the new number of elements is greater than max_load_factor()*bucket_count().
What you may do with your current setup is:
1. Growth map at the init of the program, as usually number of buckets doesn't shrink.
2. Change from std::unordered_map to Boost::intrusive_map, where you can manager number of buckets manually.

Haxe – Proper way to implement Map with Int64 keys that can be serialized (native target)

I need to know, what would be proper way to implement Maps with 64 bit keys. There will not be so many items in them, I just need to use various bits of the key for various things with large enough address space and I need it to be very fast, so String keys would probably be too slow. So far I tried:
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = 1 << 63 | 0x00000001;
var omap:Map<Int64, String> = new Map<Int64, String>();
omap.set(key, "test");
var smap:Map<Int64, String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = 1 << 63 | 0x00000001;
trace(key+" "+smap.get(key2));
}
}
http://try.haxe.org/#7CDb2
which obviously doesn't work, because haxe.Int64 creates an object instance. Using cpp.Int64 works, because it for some reason falls back to 32 bit integer in my cpp code and I don't know what am I doing wrong. How can I force it to "stay" 64 bit, or should I do it some other way?
EDIT: This is currently not working on native targets due to bug / current implementation in hxcpp: https://github.com/HaxeFoundation/hxcpp/issues/523
I figured out this workaround / wrapper, which may not be the most efficient solution possible, but it seems to work.
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = Int64.make(1000,1);
var omap:Int64Map<String> = new Int64Map();
omap.set(key, "test");
var smap:Int64Map<String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = Int64.make(1000,1);
trace(key+" "+smap.get(key2));
}
}
class Int64Map<V> {
private var map:Map<Int64,V>;
public function new() : Void {
this.map = new Map<Int64,V>();
}
public function set(key:Int64, value:V):Void {
this.map.set(key, value);
}
public inline function get(key:Int64):Null<V> {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.get(skey);
return null;
}
public inline function exists(key:Int64):Bool {
return (getMapKey(key) != null);
}
public function remove( key : Int64 ) : Bool {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.remove(skey);
return false;
}
public function keys() : Iterator<Int64> {
return this.map.keys();
}
public function toString() : String {
return this.map.toString();
}
public function iterator() : Iterator<V> {
return this.map.iterator();
}
private function getMapKey(key:Int64):Null<Int64> {
for (ikey in this.map.keys()){
if (Int64.eq(key, ikey)){
return ikey;
}
}
return null;
}
}
http://try.haxe.org/#57686

How to declare fields?

I write a GUI program in Vala. When I compile it, compiler produces this error:
The name e1 does not exist in the context of Subtract.minus
The code is:
using Gtk;
class Subtract:Window{
public Subtract(){
this.title="Subtract program";
this.destroy.connect(Gtk.main_quit);
var e1=new Entry();
var e2=new Entry();
var lbl=new Label("Result");
var btn=new Button.with_label("Subtract");
var box=new Box(Gtk.Orientation.VERTICAL,5);
box.add(e1);
box.add(e2);
box.add(lbl);
box.add(btn);
this.add(box);
btn.clicked.connect(minus);
}
public void minus(){
int a=int.parse(e1.get_text());
int b=int.parse(e2.get_text());
int result=a-b;
lbl.set_label(result.to_string());
}
public static int main(string[]args){
Gtk.init(ref args);
var win=new Subtract();
win.show_all();
Gtk.main();
return 0;
}
}
How can I make the variables accessible from the minus method.
You have to declare the variables for your widgets (at least e1, e2 and lbl) as fields:
using Gtk;
class Subtract: Window {
// Fields (sometimes also called "attributes")
private Entry e1;
private Entry e2;
private Label lbl;
private Button btn;
private Box box;
public Subtract () {
title = "Subtract program";
destroy.connect (Gtk.main_quit);
// You don't have to use "this." to access fields in Vala
// I.e. "this.e1" is equivalent to "e1" in the code below
e1 = new Entry ();
e2 = new Entry ();
lbl = new Label ("Result");
btn = new Button.with_label ("Subtract");
box = new Box (Gtk.Orientation.VERTICAL, 5);
box.add (e1);
box.add (e2);
box.add (lbl);
box.add (btn);
add (box);
btn.clicked.connect (minus);
}
public void minus () {
// The compiler happily accepts "e1" (etc.) here now
// since I have declared them as fields
int a = int.parse (e1.get_text ());
int b = int.parse (e2.get_text ());
int result = a - b;
lbl.set_label (result.to_string ());
}
public static int main (string[] args) {
Gtk.init (ref args);
var win = new Subtract ();
win.show_all ();
Gtk.main ();
return 0;
}
}
PS: The correct technical term is "scope" here. Your code had the variables at the scope of the constructor, my code as the variables as class scoped fields which makes them visible across all the methods of the class.
The Vala compiler calls it "context", which is roughly the same in this case.

How to create a method at runtime using Reflection.emit

I'm creating an object at runtime using reflection emit. I successfully created the fields, properties and get set methods.
Now I want to add a method. For the sake of simplicity let's say the method just returns a random number. How do I define the method body?
EDIT:
Yes, I've been looking at the msdn documentation along with other references and I'm starting to get my head wrapped around this stuff.
I see how the example above is adding and/or multplying, but what if my method is doing other stuff. How do I define that "stuff"
Suppose I was generating the class below dynamically, how would I create the body of GetDetails() method?
class TestClass
{
public string Name { get; set; }
public int Size { get; set; }
public TestClass()
{
}
public TestClass(string Name, int Size)
{
this.Name = Name;
this.Size = Size;
}
public string GetDetails()
{
string Details = "Name = " + this.Name + ", Size = " + this.Size.ToString();
return Details;
}
}
You use a MethodBuilder to define methods. To define the method body, you call GetILGenerator() to get an ILGenerator, and then call the Emit methods to emit individual IL instructions. There is an example on the MSDN documentation for MethodBuilder, and you can find other examples of how to use reflection emit on the Using Reflection Emit page:
public static void AddMethodDynamically(TypeBuilder myTypeBld,
string mthdName,
Type[] mthdParams,
Type returnType,
string mthdAction)
{
MethodBuilder myMthdBld = myTypeBld.DefineMethod(
mthdName,
MethodAttributes.Public |
MethodAttributes.Static,
returnType,
mthdParams);
ILGenerator ILout = myMthdBld.GetILGenerator();
int numParams = mthdParams.Length;
for (byte x = 0; x < numParams; x++)
{
ILout.Emit(OpCodes.Ldarg_S, x);
}
if (numParams > 1)
{
for (int y = 0; y < (numParams - 1); y++)
{
switch (mthdAction)
{
case "A": ILout.Emit(OpCodes.Add);
break;
case "M": ILout.Emit(OpCodes.Mul);
break;
default: ILout.Emit(OpCodes.Add);
break;
}
}
}
ILout.Emit(OpCodes.Ret);
}
It sounds like you're looking for resources on writing MSIL. One important resource is the OpCodes class, which has a member for every IL instruction. The documentation describes how each instruction works. Another important resource is either Ildasm or Reflector. These will let you see the IL for compiled code, which will help you understand what IL you want to write. Running your GetDetailsMethod through Reflector and setting the language to IL yields:
.method public hidebysig instance string GetDetails() cil managed
{
.maxstack 4
.locals init (
[0] string Details,
[1] string CS$1$0000,
[2] int32 CS$0$0001)
L_0000: nop
L_0001: ldstr "Name = "
L_0006: ldarg.0
L_0007: call instance string ConsoleApplication1.TestClass::get_Name()
L_000c: ldstr ", Size = "
L_0011: ldarg.0
L_0012: call instance int32 ConsoleApplication1.TestClass::get_Size()
L_0017: stloc.2
L_0018: ldloca.s CS$0$0001
L_001a: call instance string [mscorlib]System.Int32::ToString()
L_001f: call string [mscorlib]System.String::Concat(string, string, string, string)
L_0024: stloc.0
L_0025: ldloc.0
L_0026: stloc.1
L_0027: br.s L_0029
L_0029: ldloc.1
L_002a: ret
}
To generate a method like that dynamically, you will need to call ILGenerator.Emit for each instruction:
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldstr, "Name = ");
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Call, nameProperty.GetGetMethod());
// etc..
You may also want to look for introductions to MSIL, such as this one: Introduction to IL Assembly Language.

Resources