1# Copyright (c) Meta Platforms, Inc. and affiliates.
2#
3# This source code is licensed under the MIT license found in the
4# LICENSE file in the root directory of this source tree.
5
6require "json"
7require_relative "./hermes-utils.rb"
8
9react_native_path = File.join(__dir__, "..", "..")
10
11# Whether Hermes is built for Release or Debug is determined by the PRODUCTION envvar.
12build_type = ENV['PRODUCTION'] == "1" ? :release : :debug
13
14# package.json
15package = JSON.parse(File.read(File.join(react_native_path, "package.json")))
16version = package['version']
17
18# sdks/.hermesversion
19hermestag_file = File.join(react_native_path, "sdks", ".hermesversion")
20isInCI = ENV['REACT_NATIVE_CI'] === 'true'
21
22source = {}
23git = "https://github.com/facebook/hermes.git"
24
25isInMain = version.include?('1000.0.0')
26isNightly = version.start_with?('0.0.0-')
27
28if ENV.has_key?('HERMES_ENGINE_TARBALL_PATH')
29  if !File.exist?(ENV['HERMES_ENGINE_TARBALL_PATH'])
30    abort "[Hermes] HERMES_ENGINE_TARBALL_PATH is set, but points to a non-existing file: \"#{ENV['HERMES_ENGINE_TARBALL_PATH']}\"\nIf you don't want to use tarball, run `unset HERMES_ENGINE_TARBALL_PATH`"
31  end
32end
33
34if ENV.has_key?('HERMES_ENGINE_TARBALL_PATH')
35  Pod::UI.puts "[Hermes] Using pre-built Hermes binaries from local path: #{ENV['HERMES_ENGINE_TARBALL_PATH']}".yellow if Object.const_defined?("Pod::UI")
36  source[:http] = "file://#{ENV['HERMES_ENGINE_TARBALL_PATH']}"
37elsif isInMain
38  Pod::UI.puts '[Hermes] Installing hermes-engine may take slightly longer, building Hermes compiler from source...'.yellow if Object.const_defined?("Pod::UI")
39  source[:git] = git
40  source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip
41elsif isNightly
42  Pod::UI.puts '[Hermes] Nightly version, download pre-built for Hermes'.yellow if Object.const_defined?("Pod::UI")
43  destination_path = download_nightly_hermes(react_native_path, version)
44  # set tarball as hermes engine
45  source[:http] = "file://#{destination_path}"
46elsif File.exist?(hermestag_file) && isInCI
47  Pod::UI.puts '[Hermes] Detected that you are on a React Native release branch, building Hermes from source but fetched from tag...'.yellow if Object.const_defined?("Pod::UI")
48  hermestag = File.read(hermestag_file).strip
49  source[:git] = git
50  source[:tag] = hermestag
51else
52  # Sample url from Maven:
53  # https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.71.0/react-native-artifacts-0.71.0-hermes-ios-debug.tar.gz
54  if File.exist?(File.join(__dir__, "destroot"))
55    source[:path] = '.'
56  else
57    source[:http] = 'https://github.com/expo/react-native/releases/download/sdk-48.0.0/ABI48_0_0hermes.tar.gz'
58  end
59end
60
61Pod::Spec.new do |spec|
62  spec.name        = "ABI48_0_0hermes-engine"
63  spec.version     = version
64  spec.summary     = "Hermes is a small and lightweight JavaScript engine optimized for running React Native."
65  spec.description = "Hermes is a JavaScript engine optimized for fast start-up of React Native apps. It features ahead-of-time static optimization and compact bytecode."
66  spec.homepage    = "https://hermesengine.dev"
67  spec.license     = package['license']
68  spec.author      = "Facebook"
69  spec.source      = source
70  spec.platforms   = { :osx => "10.13", :ios => "12.4" }
71
72  spec.preserve_paths      = '**/*.*'
73  spec.source_files        = ''
74
75  spec.xcconfig = {
76                    "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
77                    "CLANG_CXX_LIBRARY" => "compiler-default"
78                  }.merge!(build_type == :debug ? { "GCC_PREPROCESSOR_DEFINITIONS" => "HERMES_ENABLE_DEBUGGER=1" } : {})
79
80  if source[:http] then
81
82    spec.subspec 'Pre-built' do |ss|
83      ss.preserve_paths = ["destroot/bin/*"].concat(build_type == :debug ? ["**/*.{h,c,cpp}"] : [])
84      ss.source_files = "destroot/include/**/*.h"
85      ss.exclude_files = ["destroot/include/jsi/jsi/JSIDynamic.{h,cpp}", "destroot/include/jsi/jsi/jsilib-*.{h,cpp}"]
86      ss.header_mappings_dir = "destroot/include"
87      ss.ios.vendored_frameworks = "destroot/Library/Frameworks/universal/ABI48_0_0hermes.xcframework"
88      ss.osx.vendored_frameworks = "destroot/Library/Frameworks/macosx/hermes.framework"
89    end
90
91  elsif source[:git] then
92
93    spec.subspec 'Hermes' do |ss|
94      ss.source_files = ''
95      ss.public_header_files = 'API/hermes/*.h'
96      ss.header_dir = 'ABI48_0_0hermes'
97    end
98
99    spec.subspec 'JSI' do |ss|
100      ss.source_files = ''
101      ss.public_header_files = 'API/jsi/jsi/*.h'
102      ss.header_dir = 'ABI48_0_0jsi'
103    end
104
105    spec.subspec 'Public' do |ss|
106      ss.source_files = ''
107      ss.public_header_files = 'public/hermes/Public/*.h'
108      ss.header_dir = 'ABI48_0_0hermes/Public'
109    end
110
111    hermesc_path = ""
112
113    if ENV.has_key?('HERMES_OVERRIDE_HERMESC_PATH') && File.exist?(ENV['HERMES_OVERRIDE_HERMESC_PATH']) then
114      hermesc_path = ENV['HERMES_OVERRIDE_HERMESC_PATH']
115    else
116      # Keep hermesc_path synchronized with .gitignore entry.
117      ENV['REACT_NATIVE_PATH'] = react_native_path
118      hermesc_path = "${REACT_NATIVE_PATH}/sdks/hermes-engine/build_host_hermesc"
119      # NOTE: Prepare command is not run  if the pod is not downloaded.
120      spec.prepare_command = ". #{react_native_path}/sdks/hermes-engine/utils/build-hermesc-xcode.sh #{hermesc_path}"
121    end
122
123    spec.user_target_xcconfig = {
124      'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/hermes-engine/destroot/Library/Frameworks/iphoneos" ' +
125                                  '"$(PODS_ROOT)/hermes-engine/destroot/Library/Frameworks/iphonesimulator" ' +
126                                  '"$(PODS_ROOT)/hermes-engine/destroot/Library/Frameworks/macosx" ' +
127                                  '"$(PODS_ROOT)/hermes-engine/destroot/Library/Frameworks/catalyst"',
128      'OTHER_LDFLAGS' => '-framework "hermes"',
129      'HERMES_CLI_PATH' => "#{hermesc_path}/bin/hermesc"
130    }
131
132    spec.script_phases = [
133      {
134        :name => 'Build Hermes',
135        :script => <<-EOS
136        . ${PODS_ROOT}/../.xcode.env
137        export CMAKE_BINARY=${CMAKE_BINARY:-#{%x(command -v cmake | tr -d '\n')}}
138        . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermes-xcode.sh #{version} #{hermesc_path}/ImportHermesc.cmake
139        EOS
140      },
141      {
142        :name => 'Copy Hermes Framework',
143        :script => ". ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/copy-hermes-xcode.sh"
144      }
145    ]
146  end
147end
148