People are probably getting fed up with the barrage of new questions I’m asking but I’m trying to get a feel for how to use this product having moved from 15 years of using Xojo.
I’m porting a bytecode VM for a toy language I wrote. Therefore I need to write a console application. It needs to run on macOS, Win 10 and Ubuntu. There is no GUI component.
What I want is to use the fastest language possible that manages memory for me. If I wanted ultimate performance I’d use C but I hate messing with pointers, malloc, etc.
I’m a little confused about runtime library support cross platform. Say I choose to use C# to write the application in. I see that I can use Elements RTL to get access to some of the common things I’d need (file access, dictionaries), etc which is great. What dependencies does this add to my compiled application? Would I have to make sure, for instance that a particular .NET runtime is installed on the users computer or are the required libraries somehow bundled into the final compiled .EXE? If I build a C# console app for macOS do I need to worry about whether or not the end user has Mono installed, etc?
(*and/or which language you think will be the best fit for your existing mental model for the code you’re porting. For example, one of the reasons Fire is written in mostly C# (not Oxygene, my personal favorite), is that way way back I had started writing the basics of it in Objective-C (because I wanted a side project to work open my laptop on, and we didn’t have an IDE that ran on Mac ;). When the time came to convert it to native Elements, I figured C# more closely preserved the code base I already was familiar with. That, and our C# front-end was new at the time, and I wanted to dog-food it).
Separate from the language, you can pick what platform(s) you want to build for. One option is to build a single executable using .NET. That could then run on Windows via .NET (no real reason to worry about dependencies there, really, if you target .NET 4.0 pretty much every Windows PC thats not bene left unattended since 2005 will run your app out of the box. On Mac, you would need Mono to be installed, yes.
Another option is to, as in your test project, to build separate executables with shared code. That can give you a Mac native app (no Mono or other dependencies needed), and for Windows you can decide to also build a CPU native app, or use .NET there. There’s upsides to both.
For more background, let’s look again at two of the big cross-platform projects we hare here internally: Fire./Water, and EBuild (our build chain around the compiler).
Fire and Water are essentially the same code base; Fire is built as a native Cocoa app for Mac, and Water is build as a .NET app, for Windows. Of course the scenario here is more complex as it is for you, as there’s GUI involved too (which actually purposely is not shared, in Fire/Water). It’s mainly the GUI that made us chose .NET instead of native for Water, as it meant that we could use WPF. Also, the compiler itself is .NET based, making that integration easier. But aside form that, the parts Fire and Water share could just as easily be built as a CPU-native Windows (or Linux) app, rather than .NET.
I gather from you other messages that (like me) you mostly work on Mac, so one advantage of using .NET for your Widows binary is that you can not just build but also run both your native Mac version and your .NET version (via Mono) on Mac, without having to go to Windows too often.
I’m in the same boat with EBuild. It builds for .NET (and that version is always used when you compile projects, even from Fire, as the compiler runs on .NET/Mono, and its also integrated in Water and VS) but also as Cocoa native (that version is linked into Fire itself to drive a lot of things in the IDE). Except for corner case Windows-specific bugs, I almost never have to leave the comfort of my Mac to work on EBuild, because both versions of in can run, test and debug on Mac. If instead the Windows version of the library was “native” Windows, i’d have to use Windows all the time ;).
Now, on the flip side, there are arguments that can be made for using native code in Windows, as well (especially if you’re basically building a VM yourself, you might prefer the more free and direct memory access that not being constrained by .NET will give you.
You could also do all three (Mac, native Windows, and .NET), and heck, why not add native Linux too ;).
Regardless of your choices, Elements RTL provides the same common set of functionality you need, across all platforms. Is Elements RTL all-comprehensive? No. There’ll be places where you might need to shell out to a Cocoa, .NET or Win32 API manually, with some #ifdef's (Elements makes tis really easy too, for example with if defined()). But it’ll be less than you think.
To put things in perspective: for EBuild, pretty much any code I write, I find I just write it without really thinking about the platform, and it will end up just compiling everywhere. Fire/Water are more complicated, so when we ported to Water, I spend a good deal of time putting in abstractions on my own, for OS-level (and UI-level) things that differ between Mac/Windows or Cocoa/.NET — but these days, with that out of the way, even there i find when I implement new stuff in Fire, it usually “just works” in Water as well, without me giving it such thought.
Of course we’re also always interested in feedback for what else to abstract in Elements RTL that currently isn’t, so if you come cross anything where you find writing separate code for Mac vs Windows, or for Cocoa vs. .NET where it seems that should not be necessary — please let us know.
So to sum up:
your choice of language has no effect on your deployment requirements. Pick the one you like best.
building for .NET/Mono would require .NET or Mono to be installed; the former can be assumed to be pretty much almost there, on Windows, but for Mac requiring Mono is a bigger inconvenience.
Same would go for targeting the JVM, but that’s probably going to be limited for your needs anyways, and since you didn’t bring the option up yourself…
building a native macOS, Windows or Linux app will have no deployment requirements (except any you add yourself, of course)
My suggestion would be: native Cocoa based version for Mac, and either .NET or native version for Windows (depending on whether the .NET runtime is too restrictive for your needs or not; if not, i’d go for .NET to target Windows).
hth, (and sorry for this turning into an essay ;).
That is the answer to end all answers! Thank you so much for taking the time to explain.
I guess I’ve just been struggling to comprehend how revolutionary Elements is compared to Xojo when it comes to being language agnostic.
One final question on this point. If I target .NET for the Windows application, does Elements compile it my code down to CIL to run on the CLR? Presumably this means the resultant application is likely to be less performant than if I use Island to compile down to machine code? I suspect RTL will provide must of the functionality that my parser, compiler and VM will need so I’m thinking that Island is the way to go?
That depends. In .NET code has his unwarranted mysticism about it as running “not native”, but what does that really mean? the CLR does not “interpret” IL code; it gets just-in-time compiled to native Cpu code on the fly, and that code runs as fast and native is code created by a “native” compiler. In fact, you could argue it can run more native and more effectively, because when you’re building a native exe, your basically compile for “x86_64” — but what does that mean, exactly? Intel and AMD have been creating CPUs that run “x86_86” code for a span of two decades now, and this CPUs aren’t all the same — they have evolved and newer CPUs have new features you’re potentially ignoring with “native” code, while the CLR knows exactly what CPU your code will be running omg when JITting, and can optimize it even better.
For general purpose code (assuming its well-written to play nice with the frameworks, not fight them), .NET code in my experience runs as fast as so called “native code”, in all areas that matter.
In fact, for any case but your specific scenario, my recommendation would have been «do a native Mac version (for convenience of not needing Mono, more so than for speed), and a .NET version “for Windows” unless you really have super good reasons to not want .NET.»
In your case, the fact that you’re building a VM yourself, and might need to benefit from more flexible direct memory access (not to mention maybe wanting to even do your own JIT, maybe, which the CLR probably won’t allow at all, even in “unsafe” mode) might be such a “super good reason” to consider native (I might also be wring and it maybe is not :). But even there probably not for speed reasons but for more for other restrictions that a "managed’ runtime that tried to be safe is putting in place.
I would hope so, yes. On the native platform you’ll have three levels of APIs (if we ignore the Swift library):
Elements RTL (thats shared with all platforms)
Island RTL (that’s shared with all Island platforms (Island/Windows, Island/Darwin)
Platform APIs: Cocoa, Foundation, CoreFoundation & Co on Mac, Win32 API on Windows.
Ideally Elements RTL will cover the majority of what you need, and you can fall back to Island RTL or the platform APIs (with #ifdefs), only when needed.
If you go native on both sides, I suggest using the newer Island/Darwin backend for MacOS rather than the original Cocoa/Toffee backend, because that means you also have Island RTL as a common layer on both sides.
This really needs a diagram… Let me fire up Illustrator.