I have finally had some time to start playing with Haxe, i find it a great concept but i am having trouble trying to deduce how i would go about getting the current system user's name or "special folder" locations.
In my case, the User's home folder, documents folder or update folder. My target language is Java, and perhaps later C#... But i have found no real way to query the system for this information directly. All i have found so far is how to query environment variables... Which have a ton of variability.
The Haxe std lib does not provide such specific function. However, it doesn't prevent us to use target-specific APIs.
#if java
import java.lang.System;
#elseif cs
import cs.system.Environment;
import cs.system.Environment.Environment_SpecialFolder;
#end
class Test {
static function main() {
#if java
//http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#getProperties%28%29
trace(System.getProperty("user.home")); //Test.hx:11: C:\Users\Andy
#elseif cs
//https://msdn.microsoft.com/en-us/library/system.environment.specialfolder
trace(Environment.GetFolderPath(Environment_SpecialFolder.UserProfile)); //Test.hx:14: C:\Users\Andy
#end
}
}
build.hxml:
-main Test
-java bin
-cmd java -jar bin/Test.jar
--next
-main Test
-cs bin
# Environment_SpecialFolder.UserProfile is available since .net 4.0
-D net-ver=40
-cmd bin\bin\Test.exe
Related
I am trying to call a shared library created with MathWorks MATLAB Compiler SDK from C# (.NET Core) running on a Linux container.
I have a matlab .m file that I've compiled into a .dll using the MATLAB R2018b compiler SDK. Because the final execution environment is .NET Core 2.2 running on a Linux container I chose the "C Shared Library" option. I call that shared library using the DLLImport mechanism of .NET.
Here is some code from my project. This code is KISS-level because I need to understand how to integrate MATLAB and C# on Linux before I start on the main project.
haveSomePi.m
function hal = haveSomePi()
hal = 3.1415;
end
MyMath.h
extern LIB_MyMath_C_API bool MW_CALL_CONV mlfHaveSomePi(int nargout, mxArray** hal);
MyMathWrapper.cs
[DllImport("MyMath.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mlfHaveSomePi(int nargout, ref IntPtr hal);
MyMathWrapperTests.cs
[TestMethod]
public void ShouldReturnPi()
{
var hal = IntPtr.Zero;
MyMathWrapper.mlfHaveSomePi(1, ref hal);
double result = (double)hal;
Assert.AreEqual(3.1415, result, 1e-5);
}
The expected result is that the assert in the test method passes. It fails because trying to cast an IntPtr to a double doesn't make sense in this context. I'm sure there is a way to de-reference the IntPtr to get at the underlying double, I just haven't found that particular nugget of information.
I have been successful when compiling the .m file into a .NET library and into a COM object. I don't think I can use either of those libraries on Linux because of differences in the binary load/link format for each OS. When calling the method in the COM object I was able to directly cast the IntPtr to a double, there must be some marshaling magic going on in the background.
Is the method signature for the DLLImport statement correct? Do I map mxArray** to IntPtr?
How do I get the double from the IntPtr? Copy a block of memory into a managed byte array and cast?
My ultimate goal is to access a large signal processing library of matlab code from dotnet. The matlab code uses a lot of vectors and arrays so getting those into and out of the unmangaged library is my next hurdle.
Best regards.
I'm not a mathlab user, so I might be wrong, very wrong!
Getting Linux .dll equivalent
What you need, is the correct shared library/object for the run-time OS to be exported from mathlab.
Windows: .dll = Dynamic Link Library
Linux: .so = shared object [.net core butter and bread for Linux]
Instruction to get .so exported lib from mathlab
Compile your MATLAB files into a shared library (on UNIX)
mcc -t -L C -W MyMath-T link:lib haveSomePi.m libmmfile.mlib
Resulting MyMath.so, MyMath.exports, MyMath.h and MyMath.mlib, more details here
Binding Assembly
Make sure you have MyMath.so file next to MyMath.dll file, (bin, app data or where is needed)
Custom "NativeLibraryLoader" can be used to load different shared lib files based on OS, written by a GIT user because .net core din't had any (link). I would say is a bit over-complicated, but is your choice.
[DllImport] can be used instead!
DllImport without extension, supported on Windows and Linux and MAC will import the appropriate library for the target platform.
[DllImport("MyMath")]
Use <dllmap/> to map an import library name to the target platform library name. For MyMath.dll the corresponding Linux .so should be MyMath.so (more here)
[DllImport("MyMath.dll")]
Config map in csproj
<configuration>
<dllmap dll="MyMath.dll" target="MyMath.so" />
</configuration>
I think the main concern here is that you are doing
C Shared Library
Which is NOT C#...
Instead you should be doing
.NET Assembly
https://in.mathworks.com/help/compiler_sdk/gs/create-a-dotnet-application-with-matlab-code.html
It's important to note that .NET Core is not supported either, and you will have to change your project to a "classic" .NET Framework (If I recall correctly, at least 4.x)
I have downloaded Jasmin JVM for my assembly language course at university. I am currently having some difficulties.
How do I write .j files:
- I have tried writing the files in textedit and eclipse and saving it as a .j file and then moving it into the directory but it wont let me run it from the terminal.
if anyone can help me out, or lead me in the right direction, that would be greatly appreciated.
Jasmin is not a JVM, it is a Java bytecode assembler.
Since it is deployed as a JAR you need the JRE1 to use it, however installing the whole JDK2 may be a better choice since you are going to develop with Java anyway.
To run it, assuming java is in your PATH environment var you can:
Move to the directory where jasmin.jar is located and run
java -jar jasmin.jar <input>
Edit your CLASSPATH environment var to include the jasmin.jar filename and then run the command above anywhere.
In order to fully understand the directives of Jasmin you are better of reading something about the Java class file format3, particularly about the various sections: header, constant pools, attributes, methods4, fields.
Finally you need to learn the byte code instructions.
Be careful that Jasmin is not a simple, low level, assembler.
For example it completely abstracts the constant pool from instructions like getXXX and invokeXXX.
Also some instructions have different names (e.g. invokenonvirtual <-> invokespecial), see here for a full listing.
Finally a solid knowledge of the JLS and CLASS file format is necessary, specifically of how generics and inner classes are implemented.
A simple helloworld.j
.bytecode 51.0 ;Java 7
.class public helloworld
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
.limit stack 2 ;Max stack depth
.limit locals 1 ;Locals + args = 0 + 1 = 1
getstatic java/lang/System/out Ljava/io/PrintStream;
;Stack: System.out object
ldc "Hello world!"
;Stack: System.out object, string
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
;Stack: /
return
.end method
Note that this class has no constructor.
You can assemble and run this program with
java -jar jasmin.jar helloworld.j
java helloworld
1 The set of binaries to execute Java applications.
2 The set of binaries to develop Java applications, this includes the JRE.
3 An overview on Wikipedia.
4 The code of a method is actually an attribute of the former.
I am trying to write some cross-language code with Haxe/OpenFL and compile it using FalshDevelop. But I get an error as soon as I use the basic Sys.print function. A minimal example is as follows:
package;
import flash.display.Sprite;
class Graphic extends Sprite {
public function new () {
super ();
}
static function main() { //used in standalone swf project
Sys.print("Hi");
}
}
It turns out that the default compile command of FlashDevelop is something like:
haxelib run openfl build project.xml flash
,which gives an error on Sys.print:
Graphic.hx:xx: characters 2-11 : Accessing this field requires a system platform
(php,neko,cpp,etc.)
My guess is that Sys.print isn't available in the flash target or flash isn't a system platform (strange). I was wondering if there is way to work around this, and configure FlashDevelop so that the compile command is:
haxelib run openfl build project.xml neko
Thanks
There are actually 2 questions.
For the first one, Sys.print is available only on some platforms because it wouldn't make sense in others(what would it do in flash?), what you probably want is trace, which is used to print things for debug purposes.
For the second question there is a drop down menu at the top of flashdevelop if you created a openfl project that looks like this and does exactly that:
I plan to write Haxe libraries in a subset of Haxe that will compile to every Haxe target language. Is there any way to verify that a Haxe program will compile to all target languages, and is it possible to do this without manually testing the compiled code on each target platform?
For example, is there a way to ensure that the following code is valid on every target platform, without testing it manually on every single platform?
class Test {
static function main(){
trace("How can I check to see which platforms this program will run on?");
}
}
EDIT: I have written a compile.hxml file that compiles the class Test.hx to various target languages. All the necessary haxelib libraries will need to be installed first in order for it to work properly.
-js test.js
-main Test
--next
-php www
-main Test
--next
-cpp cpp
-debug
-main Test
--next
-main Test
-java java
--next
-cs test
-main Test
-D haxe3
I have done some similar things with a few of my libraries (mdown and detox), and I was able to test several of the platforms using MUnit / MassiveUnit:
https://github.com/massiveinteractive/MassiveUnit
This is a unit testing platform that you can use to check your behaviour across multiple targets. There is also utest, and possibly others.
Currently munit can automatically run tests for your code on the following targets:
Neko
Flash 8
Flash 9+
Javascript
CPP
There are instructions for adding support for other targets here
(If you don't know much about unit testing - it's a way to write lots of small tests to make sure your library/code behaves as expected, and is perfect for checking that things function across platforms, as well as making sure you don't break things when you change your code.)
Has anyone actually managed to accomplish this?
I tried the approach suggested here, but no matter how i generate the precompiled serializer, mtouch fails to copy it to the app bundle, thus resulting in a runtime exception. I think this happens because the resulting binary may not be compatible with MonoTouch.
I have tried the following:
1) I used the provided iOs and Mono binaries included in the latest (r450 as this time) build in order to generate the precompiled serializer.
2) I used the source code to produce two different assemblies, built for MonoTouch. The first assembly is built using the symbols FEAT_SAFE;MONOTOUCH;NO_RUNTIME and the second is built using the symbols FEAT_SAFE;MONOTOUCH;FEAT_COMPILER. I have defined the symbol MONOTOUCH and used it the same as MONODROID symbol is used (see file CallbackAttribute.cs and Helpers.cs in the protobuf-net source).
I the used this two assemblies and tried to generate the precompiled serializer from a MonoTouch application in the simulator.
But no matter which version of the precompiled serializer i use, the assembly is still not included in the app bundle, with mtouch issuing: "Warning: Library 'MyLibrary.dll' missing in app bundle, cannot extract content", despite the fact that i do reference it in my code.
I finally got it. It seems that when the actual assembly name is different from the file name that contains it mtouch will not include it in the application bundle. And that was happening in my case. I am generating the assembly like this:
model.Compile("Taxi.ProtoBufSerializers.MQTTContractsSerializer", "MQTTContractsSerializer.dll");
So, given that Protobuf-Net sets the assembly name to the first parameter of this method and saves it in the file name given by the second parameter, mtouch will fail to include it in the application bundle.
However, i wanted to keep my namespace so i fiddled with Protobuf-Net's source code to generate the assembly like this:
File path: Given as the second parameter;
Assembly name: Path.GetFileNameWithoutExtension(path);
Module name: Path.GetFileName(path).
I am not performing any validations on the path at this time, but i don't need to do this just yet.
And voila: The sample works both on the simulator and the device.
Last but not least, i don't know if this is the way mtouch is supposed to behave or if it is a bug. I will however file a bug report against it.
I have only gotten it to work on the simulator. I created the custom serialization assembly on VS.NET 2010. One issue I had was that the IL/DLL that gets created had the wrong namespace. I did something like this:
model.Compile("X.Y.Serializer.MySerializer", "X.Y.Serializer.dll")
But the IL was something like:
.assembly X.Y.Serializer.MySerializer
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module X.Y.Serializer.MySerializer
I.e. the class name was in the assembly name.
So I wrote a perl program to:
Decompile DLL -> IL
Fix IL
Compile IL -> DLL
Here is the script:
#!/usr/bin/perl
# Usage: fix-protobuf-assembly assembly bad-namespace
#
# Example: fix-protobuf-assembly X.Y.Serializer.dll X.Y.Serializer.MySerializer
# X.Y.Serializer.MySerializer gets converted to X.Y.Serializer
use strict;
use File::Slurp;
use Cwd;
print "Current directory is " . getcwd() . "\n";
my $asm_file = shift || die "missing assembly file";
my $bad_ns = shift || die "missing namespace";
die "no such file '$asm_file'" if (! -f $asm_file);
my $il_file = $asm_file;
$il_file =~ s#dll$#il#;
Run("ildasm /out=$il_file $asm_file");
my $il = read_file($il_file) || die "error reading $il_file: $!";
my $ns = $bad_ns;
$ns =~ s#\.[^.]+$##;
if (($il =~ s#(\.assembly|module) $bad_ns#$1 $ns#g) == 0)
{
die "$bad_ns not found in input dll; aborting";
}
write_file($il_file, $il);
Run("ilasm /dll $il_file");
sub Run
{
my($command) = #_;
warn "Running $command ...\n";
system($command) && die "error running last command; bailing out";
}
Maybe I just missed the proper way to call Compile() and my hack is unnecessary.
The assembly worked fine on Windows and iOS simulator. But it then gave a runtime JIT compile violation error on the device. I just created a SO question:
JIT compile error with protobuf-net on MonoTouch/iOS device (iPhone/iPad)
I did try using MonoDevelop on Mac w/ standard console project to first create the serialization assembly. I had some issues, but to be honest I was sleepy and grumpy and it could have been user error, and quickly decided to jump over to Windows since my project has other components that I develop there.
I used .NET 4.0 projects on Windows and everything worked OK. I just had to create a lightweight version of two MT-only libraries so that I could access the classes that would be serialized.
Yes, we have been using it on a project since 2012 to improve performance over XML serialization. Mostly because the RESTFul services we had at the time could not do JSON over 1MB in size for some of the files. At this point in 2017, it would be a lot easier for us to use JSON now, instead of the extra hassle of building the custom serializers for each object.