@@ -180,10 +180,17 @@ async function prepareHermesArtifactsAsync(
180180 // enables the fallback to hermesCommitAtMergeBase() when no prebuilt artifacts exist.
181181 let allowBuildFromSource = false ;
182182 if ( ! process . env . HERMES_VERSION ) {
183- const packageJsonPath = path . resolve ( __dirname , '..' , '..' , 'package.json' ) ;
183+ const packageJsonPath = path . resolve (
184+ __dirname ,
185+ '..' ,
186+ '..' ,
187+ 'package.json' ,
188+ ) ;
184189 const mappedVersion = findMatchingHermesVersion ( packageJsonPath ) ;
185190 if ( mappedVersion != null ) {
186- hermesLog ( `Using mapped upstream version for Hermes lookup: ${ mappedVersion } ` ) ;
191+ hermesLog (
192+ `Using mapped upstream version for Hermes lookup: ${ mappedVersion } ` ,
193+ ) ;
187194 resolvedVersion = mappedVersion ;
188195 } else {
189196 allowBuildFromSource = true ;
@@ -209,7 +216,11 @@ async function prepareHermesArtifactsAsync(
209216 return artifactsPath ;
210217 }
211218
212- const sourceType = await hermesSourceType ( resolvedVersion , buildType , allowBuildFromSource ) ;
219+ const sourceType = await hermesSourceType (
220+ resolvedVersion ,
221+ buildType ,
222+ allowBuildFromSource ,
223+ ) ;
213224 localPath = await resolveSourceFromSourceType (
214225 sourceType ,
215226 resolvedVersion ,
@@ -552,12 +563,16 @@ function ensureMacOSSliceInXCFramework(artifactsPath /*: string */) {
552563 const universalDir = path . join ( frameworksDir , 'universal' ) ;
553564
554565 if ( ! fs . existsSync ( macosDir ) ) {
555- hermesLog ( 'No macOS framework found in tarball, skipping xcframework rebuild' ) ;
566+ hermesLog (
567+ 'No macOS framework found in tarball, skipping xcframework rebuild' ,
568+ ) ;
556569 return ;
557570 }
558571
559572 // Find the framework name (hermes.framework or hermesvm.framework)
560- const macosFrameworks = fs . readdirSync ( macosDir ) . filter ( f => f . endsWith ( '.framework' ) ) ;
573+ const macosFrameworks = fs
574+ . readdirSync ( macosDir )
575+ . filter ( f => f . endsWith ( '.framework' ) ) ;
561576 if ( macosFrameworks . length === 0 ) {
562577 hermesLog ( 'No .framework found in macosx directory, skipping' ) ;
563578 return ;
@@ -570,7 +585,9 @@ function ensureMacOSSliceInXCFramework(artifactsPath /*: string */) {
570585 : [ ] ;
571586
572587 if ( xcframeworks . length === 0 ) {
573- hermesLog ( 'No existing xcframework found, creating one from macOS framework only' ) ;
588+ hermesLog (
589+ 'No existing xcframework found, creating one from macOS framework only' ,
590+ ) ;
574591 fs . mkdirSync ( universalDir , { recursive : true } ) ;
575592 const xcframeworkName = frameworkName . replace ( '.framework' , '.xcframework' ) ;
576593 execSync (
@@ -587,7 +604,9 @@ function ensureMacOSSliceInXCFramework(artifactsPath /*: string */) {
587604 const xcframeworkPath = path . join ( universalDir , xcframeworkName ) ;
588605
589606 // Check if macOS slice already exists in the xcframework
590- const existingSlices = fs . readdirSync ( xcframeworkPath ) . filter ( d => d . startsWith ( 'macos-' ) ) ;
607+ const existingSlices = fs
608+ . readdirSync ( xcframeworkPath )
609+ . filter ( d => d . startsWith ( 'macos-' ) ) ;
591610 if ( existingSlices . length > 0 ) {
592611 hermesLog ( 'macOS slice already present in xcframework, skipping rebuild' ) ;
593612 return ;
@@ -602,14 +621,18 @@ function ensureMacOSSliceInXCFramework(artifactsPath /*: string */) {
602621 } ) ;
603622
604623 // Build the -framework arguments for xcodebuild -create-xcframework
605- const frameworkArgs = sliceDirs . map ( sliceDir => {
606- const slicePath = path . join ( xcframeworkPath , sliceDir ) ;
607- const frameworks = fs . readdirSync ( slicePath ) . filter ( f => f . endsWith ( '.framework' ) ) ;
608- if ( frameworks . length > 0 ) {
609- return `-framework "${ path . join ( slicePath , frameworks [ 0 ] ) } "` ;
610- }
611- return null ;
612- } ) . filter ( Boolean ) ;
624+ const frameworkArgs = sliceDirs
625+ . map ( sliceDir => {
626+ const slicePath = path . join ( xcframeworkPath , sliceDir ) ;
627+ const frameworks = fs
628+ . readdirSync ( slicePath )
629+ . filter ( f => f . endsWith ( '.framework' ) ) ;
630+ if ( frameworks . length > 0 ) {
631+ return `-framework "${ path . join ( slicePath , frameworks [ 0 ] ) } "` ;
632+ }
633+ return null ;
634+ } )
635+ . filter ( Boolean ) ;
613636
614637 // Add the macOS framework
615638 frameworkArgs . push ( `-framework "${ path . join ( macosDir , frameworkName ) } "` ) ;
@@ -651,15 +674,84 @@ async function buildFromHermesCommit(
651674 artifactsPath /*: string */ ,
652675) /*: Promise<string> */ {
653676 const { commit, timestamp} = hermesCommitAtMergeBase ( ) ;
654- abort (
655- `[Hermes] No prebuilt Hermes artifacts available for version "${ version } ".\n` +
656- `Hermes commit at merge base with facebook/react-native: ${ commit } (timestamp: ${ timestamp } )\n` +
657- `To resolve, either:\n` +
658- ` 1. Set HERMES_ENGINE_TARBALL_PATH to a local Hermes tarball path\n` +
659- ` 2. Set HERMES_VERSION to an upstream RN version with published artifacts (e.g., HERMES_VERSION=nightly)\n` +
660- ` 3. Build Hermes from commit ${ commit } and provide the tarball path via HERMES_ENGINE_TARBALL_PATH` ,
677+ hermesLog (
678+ `Building Hermes from source at commit ${ commit } (merge base timestamp: ${ timestamp } )` ,
661679 ) ;
662- return '' ; // unreachable
680+
681+ const HERMES_GITHUB_URL = 'https://github.com/facebook/hermes.git' ;
682+ const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'hermes-build-' ) ) ;
683+ const hermesDir = path . join ( tmpDir , 'hermes' ) ;
684+
685+ try {
686+ // Clone Hermes at the identified commit
687+ hermesLog ( `Cloning Hermes at commit ${ commit } ...` ) ;
688+ execSync ( `git clone --depth 1 ${ HERMES_GITHUB_URL } "${ hermesDir } "` , {
689+ stdio : 'inherit' ,
690+ timeout : 300000 ,
691+ } ) ;
692+ execSync ( `git -C "${ hermesDir } " fetch --depth 1 origin ${ commit } ` , {
693+ stdio : 'inherit' ,
694+ timeout : 120000 ,
695+ } ) ;
696+ execSync ( `git -C "${ hermesDir } " checkout ${ commit } ` , {
697+ stdio : 'inherit' ,
698+ } ) ;
699+
700+ // The build-ios-framework.sh script runs from the hermes directory.
701+ // It sources build-apple-framework.sh which sets HERMES_PATH relative to itself,
702+ // but we override it to point to the cloned Hermes repo.
703+ const reactNativeRoot = path . resolve ( __dirname , '..' , '..' ) ;
704+ const buildScript = path . join (
705+ reactNativeRoot ,
706+ 'sdks' ,
707+ 'hermes-engine' ,
708+ 'utils' ,
709+ 'build-ios-framework.sh' ,
710+ ) ;
711+
712+ hermesLog ( `Building Hermes frameworks (${ buildType } )...` ) ;
713+ execSync ( `bash "${ buildScript } "` , {
714+ cwd : hermesDir ,
715+ stdio : 'inherit' ,
716+ timeout : 3600000 , // 60 minutes
717+ env : {
718+ ...process . env ,
719+ BUILD_TYPE : buildType ,
720+ HERMES_PATH : hermesDir ,
721+ JSI_PATH : path . join ( hermesDir , 'API' , 'jsi' ) ,
722+ REACT_NATIVE_PATH : reactNativeRoot ,
723+ // Deployment targets matching react-native-macos minimums
724+ IOS_DEPLOYMENT_TARGET : '15.1' ,
725+ MAC_DEPLOYMENT_TARGET : '14.0' ,
726+ XROS_DEPLOYMENT_TARGET : '1.0' ,
727+ RELEASE_VERSION : version ,
728+ } ,
729+ } ) ;
730+
731+ // Create tarball from the destroot (same structure as Maven artifacts)
732+ const tarballName = `hermes-ios-${ buildType . toLowerCase ( ) } .tar.gz` ;
733+ const tarballPath = path . join ( artifactsPath , tarballName ) ;
734+ hermesLog ( 'Creating Hermes tarball from build output...' ) ;
735+ execSync ( `tar -czf "${ tarballPath } " -C "${ hermesDir } " destroot` , {
736+ stdio : 'inherit' ,
737+ } ) ;
738+
739+ hermesLog ( `Hermes built from source and packaged at ${ tarballPath } ` ) ;
740+ return tarballPath ;
741+ } catch ( e ) {
742+ abort (
743+ `[Hermes] Failed to build Hermes from source at commit ${ commit } .\n` +
744+ `Error: ${ e . message } \n` +
745+ `To resolve, either:\n` +
746+ ` 1. Set HERMES_ENGINE_TARBALL_PATH to a local Hermes tarball path\n` +
747+ ` 2. Set HERMES_VERSION to an upstream RN version with published artifacts\n` +
748+ ` 3. Build Hermes manually from commit ${ commit } and provide the tarball path via HERMES_ENGINE_TARBALL_PATH` ,
749+ ) ;
750+ return '' ; // unreachable
751+ } finally {
752+ // Clean up
753+ fs . rmSync ( tmpDir , { recursive : true , force : true } ) ;
754+ }
663755}
664756// macOS]
665757
0 commit comments