@@ -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 ,
@@ -536,15 +547,84 @@ async function buildFromHermesCommit(
536547 artifactsPath /*: string */ ,
537548) /*: Promise<string> */ {
538549 const { commit, timestamp} = hermesCommitAtMergeBase ( ) ;
539- abort (
540- `[Hermes] No prebuilt Hermes artifacts available for version "${ version } ".\n` +
541- `Hermes commit at merge base with facebook/react-native: ${ commit } (timestamp: ${ timestamp } )\n` +
542- `To resolve, either:\n` +
543- ` 1. Set HERMES_ENGINE_TARBALL_PATH to a local Hermes tarball path\n` +
544- ` 2. Set HERMES_VERSION to an upstream RN version with published artifacts (e.g., HERMES_VERSION=nightly)\n` +
545- ` 3. Build Hermes from commit ${ commit } and provide the tarball path via HERMES_ENGINE_TARBALL_PATH` ,
550+ hermesLog (
551+ `Building Hermes from source at commit ${ commit } (merge base timestamp: ${ timestamp } )` ,
546552 ) ;
547- return '' ; // unreachable
553+
554+ const HERMES_GITHUB_URL = 'https://github.com/facebook/hermes.git' ;
555+ const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'hermes-build-' ) ) ;
556+ const hermesDir = path . join ( tmpDir , 'hermes' ) ;
557+
558+ try {
559+ // Clone Hermes at the identified commit
560+ hermesLog ( `Cloning Hermes at commit ${ commit } ...` ) ;
561+ execSync ( `git clone --depth 1 ${ HERMES_GITHUB_URL } "${ hermesDir } "` , {
562+ stdio : 'inherit' ,
563+ timeout : 300000 ,
564+ } ) ;
565+ execSync ( `git -C "${ hermesDir } " fetch --depth 1 origin ${ commit } ` , {
566+ stdio : 'inherit' ,
567+ timeout : 120000 ,
568+ } ) ;
569+ execSync ( `git -C "${ hermesDir } " checkout ${ commit } ` , {
570+ stdio : 'inherit' ,
571+ } ) ;
572+
573+ // The build-ios-framework.sh script runs from the hermes directory.
574+ // It sources build-apple-framework.sh which sets HERMES_PATH relative to itself,
575+ // but we override it to point to the cloned Hermes repo.
576+ const reactNativeRoot = path . resolve ( __dirname , '..' , '..' ) ;
577+ const buildScript = path . join (
578+ reactNativeRoot ,
579+ 'sdks' ,
580+ 'hermes-engine' ,
581+ 'utils' ,
582+ 'build-ios-framework.sh' ,
583+ ) ;
584+
585+ hermesLog ( `Building Hermes frameworks (${ buildType } )...` ) ;
586+ execSync ( `bash "${ buildScript } "` , {
587+ cwd : hermesDir ,
588+ stdio : 'inherit' ,
589+ timeout : 3600000 , // 60 minutes
590+ env : {
591+ ...process . env ,
592+ BUILD_TYPE : buildType ,
593+ HERMES_PATH : hermesDir ,
594+ JSI_PATH : path . join ( hermesDir , 'API' , 'jsi' ) ,
595+ REACT_NATIVE_PATH : reactNativeRoot ,
596+ // Deployment targets matching react-native-macos minimums
597+ IOS_DEPLOYMENT_TARGET : '15.1' ,
598+ MAC_DEPLOYMENT_TARGET : '14.0' ,
599+ XROS_DEPLOYMENT_TARGET : '1.0' ,
600+ RELEASE_VERSION : version ,
601+ } ,
602+ } ) ;
603+
604+ // Create tarball from the destroot (same structure as Maven artifacts)
605+ const tarballName = `hermes-ios-${ buildType . toLowerCase ( ) } .tar.gz` ;
606+ const tarballPath = path . join ( artifactsPath , tarballName ) ;
607+ hermesLog ( 'Creating Hermes tarball from build output...' ) ;
608+ execSync ( `tar -czf "${ tarballPath } " -C "${ hermesDir } " destroot` , {
609+ stdio : 'inherit' ,
610+ } ) ;
611+
612+ hermesLog ( `Hermes built from source and packaged at ${ tarballPath } ` ) ;
613+ return tarballPath ;
614+ } catch ( e ) {
615+ abort (
616+ `[Hermes] Failed to build Hermes from source at commit ${ commit } .\n` +
617+ `Error: ${ e . message } \n` +
618+ `To resolve, either:\n` +
619+ ` 1. Set HERMES_ENGINE_TARBALL_PATH to a local Hermes tarball path\n` +
620+ ` 2. Set HERMES_VERSION to an upstream RN version with published artifacts\n` +
621+ ` 3. Build Hermes manually from commit ${ commit } and provide the tarball path via HERMES_ENGINE_TARBALL_PATH` ,
622+ ) ;
623+ return '' ; // unreachable
624+ } finally {
625+ // Clean up
626+ fs . rmSync ( tmpDir , { recursive : true , force : true } ) ;
627+ }
548628}
549629// macOS]
550630
0 commit comments