Technical Guide, Part 1: Compiling Hermes for Apple Platforms

Mike Grabowski
May 31 · 7 min read
Technical Guide, Part 1: Compiling Hermes for Apple Platforms

Months of our intense work with teams at Facebook and Microsoft resulted in bringing Hermes to iOS. We are happy to share the details of the process in a series of articles. This article is the third in the series and the first to focus on the technical journey:

You are going to find out how we brought Hermes to iOS and how you can implement it yourself. We provide a detailed guide to Hermes implementation based on the actual work done. So, if you want to learn more about how different core pieces play together, keep reading!

Technical Guide, Part 1: Compiling Hermes for Apple Platforms
Technical Guide, Part 1: Compiling Hermes for Apple Platforms

Compiling Hermes for Apple platforms

Just to be on the safe side, let me explain that C++ is one of these cross-platform languages that can run literally everywhere. For example, you can write native modules in C++ for Android and on iOS (hey, the Objective-C is not just similar in its name). Thanks to that, seeing a task of compiling Hermes on Apple devices didn’t sound that scary when I first started playing around that topic.

Thankfully, I didn’t have to start from the middle of nowhere (but I have to admit that playing around with cmake in general was quite an experience!). Folks at Microsoft have been working on bringing Hermes to Mac for their React Native macOS project. The work was done primarily by Eloy Durán (@alloy), who sent a PR to Hermes with the base for my work.

On a high level, this PR enables cmake to package Hermes in a dynamic library so that it can be used on a macOS platform. To make the integration with Apple ecosystem smoother, the PR adds a special Podspec so that you don’t have to manually import a framework file to your project. You can let CocoaPods do that magic for you instead.

At this point, I was amazed by the comprehensiveness of cmake and the number of out-of-the-box features it provides. If you look at the changes in the aforementioned PR, they’re all related to the build system. It’s mind blowing to see that such an advanced project like a JavaScript engine can be run on macOS by just flipping a few flags, i.e. without changing the business logic of the engine itself.

That’s good for me and all of you planning to work on C++ bits in the future! With that in mind, let’s move onto the iOS part.

On the way to iOS

#1

1 set(CMAKE_OSX_SYSROOT ${HERMES_APPLE_TARGET_PLATFORM})

I ended up going straight with a variable. We will need to build Hermes for every platform and architecture separately, which means building it a couple of times. Having a variable definitely helps — we can change its value depending on what we are targeting.

The list of all platforms and architectures should be aligned with what React Native supports right now — otherwise, developers may run into issues on certain devices.

Here’s a breakdown of the platforms together with their architectures.

Here’s a breakdown of the platforms together with their architectures.
Here’s a breakdown of the platforms together with their architectures.

#2

By default, the library would be placed under a Library/Frameworks/hermes.framework path within a build folder. Unfortunately, that would result in one build process overwriting the artifacts from the previous one.

Since I wanted to keep the artifacts for every platform, I ended up tweaking the location where the files are placed:

1 install(DIRECTORY ${DSYM_PATH} DESTINATION

2 Library/Frameworks/${HERMES_APPLE_TARGET_PLATFORM})

As a result, the files would be now placed under Library/Frameworks/iphonesimulator or Library/Frameworks/iphoneos, depending on whether we’re building for a device or a simulator.

#3

To do so, for each invocation of cmake, I ended up setting CMAKE_OSX_ARCHITECTURES with the right value for every platform. Looking at the table I have shared just a few paragraphs earlier, that would be “armv7;armv7s;arm64” for iPhone and “x86_64;i386” for iPhone Simulator.

Since that variable can be passed as a command line argument straight to cmake, there is no custom code that I had to do to make it work.

#4

The value of CMAKE_OSX_DEPLOYMENT_TARGET was set equally to “10.0” for both simulator and the device.

build_apple_framework

1 build_apple_framework “iphoneos” “armv7;armv7s;arm64” “10.0”

2 build_apple_framework “iphonesimulator” “x86_64;i386” “10.0”

Thanks to that, it becomes trivial to control what platforms and architectures Hermes supports on iOS.

Bonus points: it can be used to build macOS version too, so I went ahead and updated @alloy part too:

1 build_apple_framework “macosx” “x86_64” “10.0”

hermes.framework files

It would be a poor developer experience if you had to change a hermes.framework in your project depending on whether you run on a device or a simulator. It would definitely hinder your work if you had to manually replace the library in your project.

Thankfully, there are universal frameworks, in other words — frameworks that support more than a single platform. Simply put — it’s a way to combine two hermes.framework into a single one!

You can create one programmatically with a lipo — a tool to create multi-architectural files. To generate a universal framework file, the invocation would look as follows:

lipo -create -output

1 Library/Frameworks/iphoneos/hermes.framework/hermes

2 Library/Frameworks/iphoneos/hermes.framework/hermes

3 Library/Frameworks/iphonesimulator/hermes.framework/hermes

To speed things up, I decided to merge all additional architectures into the iPhone binary. The first argument to lipo is the destination, the following ones are input binaries that should be combined together.

Just like before, I moved the logic into a Bash function, called create_universal_framework:

1 create_universal_framework “iphoneos” “iphonesimulator”

Again, such an approach allows us to easily control the contents of the final hermes.framework file.

Last but not least

That required changing spec.vendored_frameworks to spec.osx.vendored_frameworks and spec.ios.vendored_frameworks to tell CocoaPods that this package contains frameworks for both macOS as well as iOS (note that macOS and iOS binaries can’t be merged into a single universal framework — they are separate).

In other words, replacing this:

1 spec.vendored_frameworks = “destroot/Library/Frameworks/hermes.framework”

with:

1 spec.ios.vendored_frameworks = “destroot/Library/Frameworks/iphoneos/hermes.framework”

2 spec.osx.vendored_frameworks = “destroot/Library/Frameworks/macosx/hermes.framework”

Try Hermes yourself

You should definitely clone Hermes and play around with it. Follow our Hermes implementation guide and test it yourself. It’s quite easy to get started and working on a JavaScript engine can get really rewarding!

If you want to learn more about Hermes, check our podcast: React Native 0.64 with Hermes for iOS. My guests, Microsoft and Facebook engineers, discuss the engine in detail!

What’s next?

Callstack Engineers

We are React Native community-trusted, extremely skilled…

Callstack Engineers

We are React Native community-trusted, extremely skilled Javascript developers ready for hire for your next React Native and React project, now.

Mike Grabowski

Written by

CTO at Callstack.com, React Native developer. Dealing with timezone differences between Europe and USA. Writing with ❤ from Poland.

Callstack Engineers

We are React Native community-trusted, extremely skilled Javascript developers ready for hire for your next React Native and React project, now.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store