FSharp.Charting
FSharp.Charting copied to clipboard
On OSX you need explicit DLL references (instead of using the script in the nuget package)
Referencing the FSharp.Charting.Gtk.fsx script in the nuget package doesn't work because of a bug in F# Interactive's resolution of DLLs w.r.t. relative directory #I paths when executing on Mono (or when executing on OSX/Linux).
This means you have to reference the DLLs explicitly, e.g. like this, and you have to remove the references in the script.
#r "../gtk-sharp-2.0/gtk-sharp.dll"
#r "../gtk-sharp-2.0/gdk-sharp.dll"
#r "../gtk-sharp-2.0/atk-sharp.dll"
#r "../gtk-sharp-2.0/glib-sharp.dll"
#r "FSharp.Charting.Gtk.0.90.5/lib/net40/OxyPlot.dll"
#r "FSharp.Charting.Gtk.0.90.5/lib/net40/OxyPlot.GtkSharp.dll"
#r "FSharp.Charting.Gtk.0.90.5/lib/net40/FSharp.Charting.Gtk.dll"
#load "FSharp.Charting.Gtk.0.90.5/FSharp.Charting.Gtk.fsx"
This is external, and fixed in F# 3.0 tag 3.0.31. Leaving this open until we verify it.
I'm experiencing the same issue on OSX. gist shows my output and system information. I run F# 3.0 but have no idea how to check its tag.
PS: @dsyme solution worked but I have to admit this took me hours to arrive at this issue. Somehow I feel that starting F# programming on OSX is not very n00b friendly. If you can think of a decent tutorial that would take me through the basic scaffolding I'd be very grateful, preferably without the Visual Studio friendly magic that Xamarin does. All I want for now is to be able to write scripts from your Expert F#, reference external libraries and run them.
Trying to run http://fsharp.github.io/FSharp.Charting/ReferencingTheLibrary.html now throws an exception
System.TypeInitializationException: An exception was thrown by the type initializer for Gtk.Widget ---> System.DllNotFoundException: gtksharpglue-2
at (wrapper managed-to-native) Gtk.Widget:gtksharp_gtk_widget_get_requisition_offset ()
at Gtk.Widget..cctor () [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
which FSharp.Charting.Gtk.0.90.5/FSharp.Charting.Gtk.fsx is trying to fix by
// Workaround bug http://stackoverflow.com/questions/13885454/mono-on-osx-couldnt-find-gtksharpglue-2-dll
if Environment.OSVersion.Platform = System.PlatformID.MacOSX then
let prevDynLoadPath = Environment.GetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH")
let newDynLoadPath = "/Library/Frameworks/Mono.framework/Versions/Current/lib" + (match prevDynLoadPath with null -> "" | s -> ":" + s) + ":/usr/lib"
System.Environment.SetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH", newDynLoadPath)
which unfortunately doesn't seem to work for me
I think this means I have gtk# installed (using mono that ships with Xamarin):
vkz-air:~ vkz$ locate gtksharpglue
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.la
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM/Contents
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM/Contents/Info.plist
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM/Contents/Resources
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM/Contents/Resources/DWARF
/Library/Frameworks/Mono.framework/Versions/3.2.6/lib/libgtksharpglue-2.so.dSYM/Contents/Resources/DWARF/libgtksharpglue-2.so
Does anyone know who distributes the NuGet package? It currently is out of date (and on OSX not functional), compared to what is on github.
What is the status of this ("This is external, and fixed in F# 3.0 tag 3.0.31. Leaving this open until we verify it.") now in, mono 3.8?
@jmchapman BTW - I think FSharp.Charting is not very good as a cross-platform library. We're trying to fix that with Foogle Charts, but it is still in its early days: http://github.com/fsprojects/Foogle.Charts/ (but I hope there will be a lot more in 2-6 months).
@tpetricek is this issue related to these missing references?
I'm actually not sure what is the status of the FSharp.Charting.Gtk project. @dsyme contributed to it, so perhaps he can comment? (But I'm afraid it might not build at all on Windows.)
I confirm the issue on OS X 10.10.4
The basic example in the docs:
#load "packages/FSharp.Charting.Gtk/FSharp.Charting.Gtk.fsx"
open FSharp.Charting
Chart.Line([ for x in 0 .. 10 -> x, x*x ])
crashes with
Error: An exception was thrown by the type initializer for Gtk.Widget
Actually, sending the lines to F# interactive, it seems it crashes at the 2nd line:
> #load "packages/FSharp.Charting.Gtk/FSharp.Charting.Gtk.fsx";;
[Loading /Users/adrian/Dropbox/Projects/_learning_/_fs_/packages/FSharp.Charting.Gtk/FSharp.Charting.Gtk.fsx]
namespace FSI_0002.FSharp.Charting
val verifyMac : unit -> bool
val isMac : bool
module FsiAutoShow = begin
end
> open FSharp.Charting;;
* Assertion at mini-exceptions.c:540, condition `class' not met
Looks like it can't open FSharp.Charting since anything there will yield the same result.
> open FSharp.Chartingggg;;
* Assertion at mini-exceptions.c:540, condition `class' not met
@essenciary Can you try editing FSharp.Charting.Gtk.fsx to change these lines:
member x.Invoke f =
let res = ref None
let evt = new System.Threading.AutoResetEvent(false)
Gtk.Application.Invoke(new System.EventHandler(fun _ _ ->
res := Some(f())
evt.Set() |> ignore ))
evt.WaitOne() |> ignore
res.Value.Value
Into this:
member x.Invoke f =
f()
And seeing if it will then work?
@evolvedmicrobe Thanks a lot, making progress but still failing.
#load "packages/FSharp.Charting.Gtk/FSharp.Charting.Gtk.fsx";;
[Loading /Users/adrian/Dropbox/Projects/_learning_/_fs_/packages/FSharp.Charting.Gtk/FSharp.Charting.Gtk.fsx]
namespace FSI_0002.FSharp.Charting
val verifyMac : unit -> bool
val isMac : bool
module FsiAutoShow = begin
end
> open FSharp.Charting;;
> Chart.Line([ for x in 0 .. 10 -> x, x*x ]);;
Binding session to '/Users/adrian/Dropbox/Projects/_learning_/_fs_/OxyPlot.dll'...
Binding session to '/Users/adrian/Dropbox/Projects/_learning_/_fs_/OxyPlot.GtkSharp.dll'...
val it : ChartTypes.GenericChart =
Error: An exception was thrown by the type initializer for Gtk.Widget
>
Eck, GTK. The joys of unmanaged code.
So I can't reproduce that error here, do you have any more information from the stack trace?
One theory is that you might have a System.DllNotFoundException. FSharp.Charting needs to load a lot of unmanaged libraries in order to render the plot with gtk, these can normally be found in the locations set by this environmental variable:
export DYLD_FALLBACK_LIBRARY_PATH=/LIBRARY/Frameworks/Mono.framework/Versions/Current/lib:/lib:/usr/lib
However, there are some major gotchas with setting this variable.
Gotcha #1 - This variable has to be set before you try and load ANY unmanaged library. Unmanaged libraries are loaded with a call to "dlopen" but depending on versions and reasons I cannot divine, this function appears to only load the environmental variables once. That is, if you try to set this after loading any library, as is done in F# charting with the code below, it may be useless. dlopen may have already read the variable once and then keeps its copy.
// Workaround bug http://stackoverflow.com/questions/13885454/mono-on-osx-couldnt-find-gtksharpglue-2-dll
if Environment.OSVersion.Platform = System.PlatformID.MacOSX then
let prevDynLoadPath = Environment.GetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH")
let newDynLoadPath = "/Library/Frameworks/Mono.framework/Versions/Current/lib" + (match prevDynLoadPath with null -> "" | s -> ":" + s) + ":/usr/lib"
System.Environment.SetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH", newDynLoadPath)
So the F# code above can fail if the environmental variable has already been read by dlopen (again, this is undefined and may vary from OS versions per my current understanding)
Gotcha #2 - Environmental variables you set in your .bash_profile will not be set when apps are opened. This was a recent Mac change, it didn't use to be this way. However, now from terminal you must explicitly set the variable if you want it to be set in any process started from a .app GUI, a la
launchctl setenv DYLD_FALLBACK_LIBRARY_PATH $DYLD_FALLBACK_LIBRARY_PATH
open -n open -n /Applications/Xamarin\ Studio.app/
I would try to see if you can figure out what the problem is, if it's the dll load issue, setting the relevant environmental variables before loading fsharpi may help. If you have Xamarin studio installed, I might also try just creating an empty C# GTK project so that you can run it and verify a window pops up (this will confirm the GTK installation). With a stack trace, the environmental variable problem ruled out and a confirmation of a working GTK installation, it should narrow it down quite a bit.
@evolvedmicrobe
Per your comment, I gave Xamarin a try. Till now I've been running the code via Atom or directly in the terminal (cause Xamarin crashes when trying to create a new FSharp Script file - but that's for another day).
Opening the script file in Xamarin with the NuGet dependencies already installed, using the modified x.Invoke and running it in F# Interactive just worked (™).
Running it in Xamarin with the original x.Invoke does break.
So then:
- changing x.Invoke was key - thanks a million
- looks like I'm stuck in the middle of a dependency hell. I've spent over 10 hours in the last week trying to get this example to work mapping DLLs and building GTK. I'd love a stack that just works 100% but since I'm into web dev, I don't mind running GTK dependent scripts in Xamarin once in a blue moon.
If this issue is relevant in regards to refactoring x.Invoke I'm happy to dig into it and provide any additional information.
Thanks again for your support, much appreciated!
@essenciary Glad you got it working! It looks like your problem has identified two key issues.
Issue #1 - The environmental variables cannot always be set at runtime to load static libraries
Because dlopen may read the DY/LD_LIBRARY_PATH environmental variables before they are modified by the F# code to point to the appropriate path (by System.Environment.SetEnvironmentVariable), attempting to set these variables in F# is not a robust solution as it may fail if the variable has already been read by the library loading functions. As we cannot alter the environmental variables of the parent process before the child F# process is called, perhaps it would be better to simply check for the correct environmental variable and fail with a useful error message if it is not set. That is, we implement a consistent and useful failure rather than an occasionally successful and confusing work around.
Issue #2 - GTK SIGSEGV on Gtk.Application.Invoke function call
Calling Gtk.Application.Invoke to alter the state of a GUI rather than running it on the current thread is supposed to be hygenic and reflect best practices. However, clearly in this case the call to Gtk.Application.Invoke causes havoc and a low-level error that shuts down the runtime. I am not sure what caused this, but when you mentioned digging in is this something you might be able to investigate? (This never used to be a problem, so I suspect something has changed)
@evolvedmicrobe Nigel, thanks. Sorry for my late reply, holidays.
I'll take a look but to be honest, I don't think I'm ready for such a task. I'm pretty new to F# and have no knowledge of Mono/GTK/etc. Coming from a PHP/Ruby/Elixir type of stack.