Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for tvOS (Apple TV) #1000

Closed
wants to merge 11 commits into from

Conversation

douglowder
Copy link

Summary

Add support for tvOS, so that Hermes will work with React Native for Apple TV.

Test Plan

New test target ApplePlatformsIntegrationTVTests in the integration test app for Apple platforms, similar to the existing ones for iOS and MacOS.

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label May 18, 2023
@tmikov
Copy link
Contributor

tmikov commented May 18, 2023

Thank you! We will review this PR in the next few days. Please keep in mind that even if we merge it, we won't be able to provide actual support (answer questions, provide fixes, etc) for Hermes on tvOS, we will have to rely on the community.

@tmikov tmikov mentioned this pull request May 18, 2023
@douglowder
Copy link
Author

Thanks for reviewing this, @tmikov and the rest of the team :)

I would very much appreciate you merging this so that I can use the Hermes engine as is in the React Native TV repo, and not have to create a fork.

Needless to say, if there are issues, they will probably be coming from people using the React Native TV repo, so I will definitely be available to help with such issues if they arise.

@douglowder
Copy link
Author

Hmm it seems like there is something weird going on in Circle CI -- the same xcodebuild test invocation that works fine on my desktop can't find an Apple TV simulator in the Circle CI environment.

@neildhar
Copy link
Contributor

Thank you for contributing this, looking at the PR, some high level comments and questions:

  1. The iOS build for Hermes has actually been migrated to RN. So changes to Hermes source and our CMake files should be made here, but things like build-ios-framework and build-apple-framework are now maintained by RN (we will delete them from Hermes in the near future). Correspondingly, these should live wherever React Native TV is.
  2. It looks like many of the changes here are to build tools like the hermes CLI, and node-hermes. In general, building these should not be necessary to use Hermes in RN on tvOS, you should just need to build the libhermes target. Is there a reason your PR addresses these other targets?

I also have some questions about specific lines, but these can wait since the above two points may significantly reduce the scope of necessary changes.

@douglowder
Copy link
Author

douglowder commented May 19, 2023

The iOS build for Hermes has actually been migrated to RN. So changes to Hermes source and our CMake files should be made here, but things like build-ios-framework and build-apple-framework are now maintained by RN (we will delete them from Hermes in the near future). Correspondingly, these should live wherever React Native TV is.

@neildhar thanks very much for letting me know about the above, and I will make the corresponding changes to those files in the React Native TV repo. I am curious: if you are removing those from Hermes, how will you build and test for any Apple targets in this repo, and therefore prevent regressions that would otherwise only be detected downstream in the React Native repo? Is it possibly your plan to move Hermes into the React Native monorepo as just another package?

It looks like many of the changes here are to build tools like the hermes CLI, and node-hermes. In general, building these should not be necessary to use Hermes in RN on tvOS, you should just need to build the libhermes target. Is there a reason your PR addresses these other targets?

It appeared to me that all these changes were needed in order for build-ios-framework.sh to complete successfully for tvOS. If you could identify which changes are specifically for building the CLI and node-hermes, I'll try removing them from the PR and see if everything is still ok. The difficulty with tvOS is that it is almost iOS but not quite -- certain APIs (even fundamental ones like fork()) are removed and will not compile if they are left in the source by the preprocessor.

@neildhar
Copy link
Contributor

prevent regressions that would otherwise only be detected downstream in the React Native repo?

This is a great question. Empirically, this setup has been much more reliable. In the past, we've had problems at the point of producing the Hermes CocoaPod, and consuming it on the RN side. Having that process subsumed into the RN build has eliminated that class of problems entirely.
But to make sure that we don't break the RN build, we need to add a simple end-to-end test in our CI that clones the RN repo and builds RNTester against Hermes source from our repo. We already have such a test for Android, and it's a matter of setting up something similar for iOS. Once we have that, we can eliminate the existing iOS testing, and the build scripts in the Hermes repo, in favour of the end-to-end approach.

which changes are specifically for building the CLI and node-hermes

At the very least, the changes in the node-hermes directory should not be needed. I tried tinkering with some of your changes locally and I do see it complaining about certain system calls. I'd like to give some more thought to how best to address these.

@douglowder
Copy link
Author

@neildhar I think you absolutely need the changes I put in node-hermes directory. They are to exclude code from Apple TV builds (!TARGET_OS_TV), in the same way that the existing preprocessor directives are excluding code from iOS builds (!TARGET_OS_IPHONE)

Copy link
Contributor

@neildhar neildhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@douglowder nothing in the node-hermes directory gets built when preparing the Apple frameworks. The library you modified is a third-party library, and had those iOS ifdefs to begin with, but we don't actually build it for iOS in Hermes.

To verify, I checked out your changes and was able to complete a successful build without any of the changes in that directory.

@@ -57,6 +57,14 @@ if(HERMES_APPLE_TARGET_PLATFORM MATCHES "catalyst")
set(THREADS_PREFER_PTHREAD_FLAG ON)
endif()

if(HERMES_APPLE_TARGET_PLATFORM MATCHES "appletvos")
add_definitions(-DTARGET_OS_TV=1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to define this ourselves, that is, why doesn't it defined automatically as it is for iOS?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the answer to that question..... I just found that it was needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll back out the node-hermes changes and see if CI succeeds and has the tvOS artifacts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great to understand what's going on with this. Based on some cursory searches, it looks like the tvOS define should be in TargetConditionals.h just like the iOS one. This may suggest something is wrong with how the build is set up, or warrant a comment to avoid confusion in the future.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have a look at TargetConditionals.h

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not able to determine why the build is not picking up the tvOS version of TargetConditionals.h. I will add a comment here and hopefully we can figure that out in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologise for the back and forth on this. But we can't merge changes that we don't really understand. In this instance, it may suggest a subtle issue in the build setup that could break in the future, or add overhead when managing the integration of our Apple builds with upstream RN.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally understand. I'll close this for now, and once the React Native TV 0.71 release is out, will come back to this and see what is going on with TargetConditionals. My guess is that somewhere in the Hermes build, the Apple CMake configuration is picking up iPhone includes instead of Apple TV includes.

@douglowder douglowder requested a review from neildhar May 22, 2023 23:27
Copy link
Contributor

@neildhar neildhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for making the changes to the node-hermes directory. I've done a pass over the individual ifdefs to get your input.

external/icu_decls/unicode/platform.h Outdated Show resolved Hide resolved
@@ -200,7 +200,11 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
// If this OS has posix_spawn and there is no memory limit being implied, use
// posix_spawn. It is more efficient than fork/exec.
#ifdef HAVE_POSIX_SPAWN
#if defined(TARGET_OS_TV) && TARGET_OS_TV
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue being worked around here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apple TV needs to use posix_spawn (does not have fork()) but MemoryLimit did not exist for Apple TV (at least at the time I was working on this patch).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? MemoryLimit is a parameter to this function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I didn't say that correctly. Apple TV needs to use this path even if MemoryLimit is not 0.

lib/Support/OSCompatPosix.cpp Outdated Show resolved Hide resolved
external/llvh/lib/Support/Unix/Program.inc Outdated Show resolved Hide resolved
@@ -57,6 +57,14 @@ if(HERMES_APPLE_TARGET_PLATFORM MATCHES "catalyst")
set(THREADS_PREFER_PTHREAD_FLAG ON)
endif()

if(HERMES_APPLE_TARGET_PLATFORM MATCHES "appletvos")
add_definitions(-DTARGET_OS_TV=1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great to understand what's going on with this. Based on some cursory searches, it looks like the tvOS define should be in TargetConditionals.h just like the iOS one. This may suggest something is wrong with how the build is set up, or warrant a comment to avoid confusion in the future.

@douglowder douglowder requested a review from neildhar May 24, 2023 01:07
@@ -57,6 +57,14 @@ if(HERMES_APPLE_TARGET_PLATFORM MATCHES "catalyst")
set(THREADS_PREFER_PTHREAD_FLAG ON)
endif()

if(HERMES_APPLE_TARGET_PLATFORM MATCHES "appletvos")
add_definitions(-DTARGET_OS_TV=1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologise for the back and forth on this. But we can't merge changes that we don't really understand. In this instance, it may suggest a subtle issue in the build setup that could break in the future, or add overhead when managing the integration of our Apple builds with upstream RN.

@@ -778,10 +778,12 @@ bool unset_env(const char *name) {
void *SigAltStackLeakSuppressor::stackRoot_{nullptr};

SigAltStackLeakSuppressor::~SigAltStackLeakSuppressor() {
#if defined(__APPLE__) && !(defined(TARGET_OS_TV) && TARGET_OS_TV)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion was to use just defined(__APPLE__) && !TARGET_OS_TV. As noted in my previous comment, doing this correctly also ensures that TargetConditionals.h is properly imported.

In addition to the suggested change above, we should also add a comment that this is not supported on tvOS.

@@ -200,7 +200,11 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
// If this OS has posix_spawn and there is no memory limit being implied, use
// posix_spawn. It is more efficient than fork/exec.
#ifdef HAVE_POSIX_SPAWN
#if defined(__APPLE__) && defined(TARGET_OS_TV) && TARGET_OS_TV
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for explaining what was going on with MemoryLimit here. I think the right thing to do here would be to restrict the ifdef to just the region below with the fork, and then use ErrMsg to report an error if we're on tvOS and a MemoryLimit is specified. I suspect something similar would happen on iOS anyway, since I don't think we're allowed to actually call fork.

@douglowder douglowder closed this May 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Do not delete this pull request or issue due to inactivity.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants