- Rust For Macbook
- Rust Ide For Mac
- Rust For Mac System Requirements
- Rust For Mac Free
- Rust Download For Windows 10
38 Games Like Rust for Mac. The list of games like Rust that is displayed below has been generated by the Game Cupid game discovery engine. The games like Rust that are listed here have all been selected by an advanced algorithm that compares and evaluates features in Rust and then matches it with games that share similar features.
I’ve recently been working on a Rust project at work which requires compiling for Linux (GNU), Linux (musl - for Alpine Linux) and macOS. I use Linux Mint nearly all the time, so building for macOS targets has required asking very nicely to borrow a spare Macbook Air. This is naturally a bit crap, so I set out to find a Linux-only solution to cross compile for macOS using osxcross. A weekend of pain later, and I have the following post. Hopefully it spares you a weekend of your own pain.
- I think Rust is well on the way, and we might be able to enjoy the game properly on Mac soon, but they still need to do some work. This is a huge step in the correct direction, because a few months ago, I was not able to hit over 15 fps on the lowest settings with the same Mac.
- Rust for Mac, free and safe download. Rust latest version: An online survival game inspired by Minecraft and DayZ. Rust is a title that blends many of gamings most popular genres: first-person action, survival, a.
Environment
This process should work in any modern-ish Debian-based environment. This is the setup I used:
- Linux Mint 19.1, Dell XPS1 15, Intel i9 x64
- Rust 1.32.0 (with Rustup)
- Clang 6.0.0
I’ve also tested this process in CircleCI and it seems to be working fine.
The only device I have to test on at time of writing is a Macbook Air with macOS Mojave on it. This process should work for other macOS versions, but is untested.
Requirements
There are a few system dependencies required to work with osxcross. I don’t think the version requirements are too strict for the packages listed below. You may want to check the osxcross requirements as well if you’re having problems.
Building osxcross
The following process is based on this tutorial on Reddit and some trial and error. I’m using the macOS 10.10 SDK as I had the least problems getting up and running with it.
Add the following to a script called osxcross_setup.sh
and make it executable.
Not a lot to it, thanks to the hard work put in by the osxcross developers. Running ./osxcross_setup.sh
should create a folder named osxcross
with everything you need in it to cross compile to macOS with Clang. This doesn’t modify $PATH
or install any system files, so is useful for CI as well.
Append ./build_gcc.sh
to osxcross_setup.sh
if you want to use GCC to cross compile.
Configuring Cargo
Cargo needs to be told to use the correct linker for the x86_64-apple-darwin
target, so add the following to your project’s .cargo/config
file:
If you’ve used a different macOS SDK version, you might need to replace darwin14
with darwin15
. To check what binary to use, look in osxcross/target/bin
.
Building the project
Because I chose not to install osxcross at the system level, the $PATH
variable must be modified for Cargo to pick up the linker binaries specified previously. The build command changes to:
This adds [pwd]/osxcross/target/bin
to $PATH
, which means the linker binaries should get picked up. The path must be absolute to work properly, hence $(pwd)
.
Now you should have a binary in target/x86_64-apple-darwin/[debug|release]
which works on macOS!
Building *-sys
crates
You can stop here if none of your crates require any C bindings to function. Quite a few of them do, so read on if you run into compilation or linking errors.
The project I’m cross compiling uses the git2 crate which has libz-sys in its dependency tree. Unfortunately this means digging out a C compiler. The build uses the host system compiler by default, so the architectures for the final binary (target arch) and these linked libraries (host arch) don’t match up.
The solution to this is to set the CC
and CXX
environment variables in our build command:
This uses o64-clang
and o64-clang++
in osxcross/target/bin
.
Now git2 compiles, but fails to link! This is due to the fact that libz-sys attempts to link to the host system zlib
library. Because I’m building on a Linux machine, this is a Linux-native library which won’t work on macOS.
Luckily, libz-sys supports building its own statically linked version of zlib. According to libz-sys’ build.rs
, if LIBZ_SYS_STATIC=1
is set in the environment a bundled version of zlib will be built. Because we set CC
and CXX
, this statically linked code will be compiled for a macOS target. The full build command ends up looking like this:
CI
I got the above process working in CircleCI, but it should be pretty easy to get any Debian-based CI service to work.
It should be possible to cache the osxcross
folder so it doesn’t have to be built for every job. The cache should be invalidated when your build script(s) change. For example, I use the cache checksum project-v1-
to ensure the osxcross
folder is regenerated correctly.
Wrapping up
The final build command is pretty long, so I’d suggest putting it in a script. In my case, I have a build script containing the following snippet:
Now you can just run ./osxcross_setup.sh
and ./build_macos.sh
in your CI.
Rust is a systems programming language focused on speed and safe concurrency, and which I’ve been using for personal projects heavily since the 1.0 release last year. Most of these projects have been replacements for existing scripts in my workflows or new command line tools, but I wanted to create a Mac application and determine if it would benefit from Rust’s memory efficiency, safety, and robust library ecosystem.
I’ve done iOS and Mac application development for many years and it's worth noting that the hardest part of Cocoa development has always been learning the frameworks rather than the languages. This experiment is about applying Cocoa and Rust knowledge to create something safe and yet easy to work with.
Rust For Macbook
Getting started with Cocoa crates
There are already crates for working with the Objective-C runtime, such as the [CODE]objc[/CODE] and [CODE]block[/CODE] crates, which are for using the runtime directly and interfacing with Apple’s block extensions respectively. The [CODE]objc[/CODE] crate in particular provides the [CODE]msg_send![/CODE] macro, which is a basic interface to messaging Objective-C objects. Here’s an example of creating an [CODE]NSObject[/CODE]:
-- CODE language-rust --
unsafe {
let cls = Class::get('NSObject').unwrap();
let obj: *mut Object = msg_send![cls, new];
}
The [CODE]cocoa[/CODE] crate builds on this to provide an interface to using frameworks including AppKit for drawing windows and views onscreen. It also has an interesting take on implementing Objective-C classes in that translates them to traits which are implemented by a generic [CODE]NSObject[/CODE] type. This snippet creates an app and a window, and presents it on screen:
-- CODE language-rust --
unsafe {
let _pool = NSAutoreleasePool::new(nil);
let app = NSApp();
app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
NSRect::new(NSPoint::new(0., 0.), NSSize::new(200., 200.)),
NSTitledWindowMask as NSUInteger,
NSBackingStoreBuffered,
NO
).autorelease();
let title = NSString::alloc(nil).init_str('Hello World!');
window.setTitle_(title);
window.makeKeyAndOrderFront_(nil);
app.run();
}
Pretty cool, though as is, the entire interface is unsafe, missing the hopeful goal of the experiment. This approach could still be interesting when writing the application core code in Rust, and then packaging it using Cocoa bindings.
Wrapping Cocoa APIs in “safety”
Given those caveats, couldn’t we create Rust wrappers for Objective-C classes? Of course! After some trial and error, I had a base trait to use for wrapping and interacting with Objective-C objects:
Rust Ide For Mac
-- CODE language-rust --
use objc::runtime::Object;
pub type Id = *mut Object;
pub trait ObjCClass: Sized {
/// Returns pointer to underlying objc object
fn ptr(&self) -> Id;
/// Creates an instance from an objc object pointer, failing
/// if the pointer is not an instance of the wrapped class
fn from_ptr(ptr: Id) -> Option<self>;</self>
/// The printed name of the class
fn class_name() -> &'static str;
/// Type-safe reference to an instance with a nil pointer
fn nil() -> Self;
/// Performs an `isKindOfClass` check to whether a particular
/// pointer is an instance of the wrapped class
fn ptr_is_class(ptr: Id) -> bool;
/// Change an instance of one class into another, failing if
/// the pointer is not an instance of the preferred class.
/// Useful for converting between inherited classes e.g.
/// NSDictionary to NSMutableDictionary.
fn coerce<t: objcclass='>(&self) -> Option<t> {</t></t:>
T::from_ptr(self.ptr())
}
/// Designate this instance as suitable for being released
/// once it is out of scope
fn autorelease(&self) -> Self;
/// Drop the Objective-C reference. The object is then invalid
fn release(&mut self);
}
Rust For Mac System Requirements
Note that this creates a Rust object with a reference to an Objective-C object, but the overall effect is minimal as most interaction still happens in Objective-C runtime land.
Using this trait was most easily done creating a handy macro named [CODE]impl_objc_class[/CODE], and then wrapping the average class became easy! Here’s an example which wraps a few methods on [CODE]NSString[/CODE].
Rust For Mac Free
-- CODE language-rust --
const UTF8_ENCODING: NSUInteger = 4;
impl_objc_class!(NSString);
impl NSString {
/// Creates an `NSString` from a `str`.
pub fn from(content: &str) -> Self {
let ptr: *mut Object = unsafe {
let string: *mut Object = msg_send![class!('NSString'), alloc];
msg_send![string, initWithBytes:content.as_ptr()
length:content.len()
encoding:UTF8_ENCODING]
};
NSString { ptr: ptr }
}
/// The length of the string as measured in UTF-8 code points
pub fn len(&self) -> usize {
unsafe { msg_send![self.ptr, lengthOfBytesUsingEncoding:UTF8_ENCODING] }
}
}
The class can now be used directly, and without [CODE]unsafe[/CODE]:
-- CODE language-rust --
let greeting = NSString::from('hello');
assert_eq!(greeting.len(), 5);
Resources still need to be released (or auto-released, if applicable) when they are no longer needed, but classes became much easier to use. I explored some options such as implementing a [CODE]Drop[/CODE] trait to automatically discard Objective-C objects once the Rust reference goes out of scope, but this behavior is not always desirable, especially when working with references to applications and windows which are expected to stay for the life time of the application, or at least longer than the current scope.
Packaging Rust into an app
While we can use the snippets of the cocoa crate to run an executable, the executable is not packaged as an app bundle, which would be suitable for having an app icon, putting an app in the dock, or being registered as a default application (like being the mail client used for [CODE]mailto:[/CODE] links, for example). For that, we’d need to package the executable into an app bundle.
An easy way to create an app bundle which launches Rust code is to create a Cocoa app with a Rust and dependent app target. This requires a few steps in Xcode:
- Create a new app using the Cocoa app template
- Add a second “External build system” target to the application which creates the Rust binary
- Add the second target to the default app target as a dependency
- Add the rust executable as a bundled resource of the app target
- Replace the default AppDelegate with a script to launch the Rust binary, something like this bit of Swift:
-- CODE language-rust --
let task = Process()
task.launchPath = Bundle.main.path(forResource: 'my-rust-program', ofType: nil)
task.launch()
task.waitUntilExit()
I’ve created an example which shows all of these parts in action, adds an app icon, and pipes output from the Rust executable to the system console.
Conclusions
The initial results were less than ergonomic when using the existing Cocoa crate since the interface did not add additional safety, and perhaps removed some because the generic object type conformed to every Cocoa class trait. I could (and did) call the wrong methods on Cocoa class instances.
Writing my own layer of classes on top of [CODE]objc[/CODE] improved the latter, though it was more initial overhead to write wrappers before using classes, and still felt clumsy when converting between values in class clusters for example. There is potential for a “Rustier” crate for interfacing with Objective-C, or a generator which makes ergonomic method names. Despite this, I mapped a number of Objective-C classes by hand, and while my stylistic choices probably aren’t suitable for a general use library, Rust+Cocoa became very fast to use and iterate on ideas. The approach could be worth a try if you have reusable components in Rust to share with a Cocoa application, and have constructs unsuitable for use with the foreign function interface.
There’s more I could cover here about the experience, like how to declare your own Objective-C classes in Rust and implementing protocols, but that should be the topic of a later post.
I’ve made some longer examples demonstrating the snippets in this post as well as a general template usable for packaging a mac app, which is available on GitHub.
Rust Download For Windows 10
Thanks for reading!