From 735bd91037717c17f18c30453194f0a6c9ece35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Wed, 2 Dec 2020 14:25:46 -0800 Subject: [PATCH] Integrate Native Module codegen into Xcode build pipeline (#30449) Summary: Move the codegen invocation out of Podfiles and into the FBReactNativeSpec Pod itself. With this change, developers do not need to modify their existing project's Podfiles, and yet the codegen will be integrated into their projects automatically by way of the FBReactNativeSpec Pod. This is accomplished in part by injecting a script build phase into the Pods Xcode project that is generated by CocoaPods. The build phase will save the output of the codegen script to a log in the derived files directory. The codegen will be executed if the codegen log file is not present, or if the contents of the Libraries directory has changed. The codegen will thus be invoked in these situations: **RNTester:** * When `packages/rn-tester/RNTesterPods.xcworkspace` is built, if the codegen output logfile is not present or if the input files have changed. **OSS React Native apps:** * When `ios/AwesomeProject.xcworkspace` is built, if the codegen output file is not present or if the input files have changed. Normally, this should not happen, as we do not expect folks to update the contents of `node_modules/react-native/Libraries`. Pull Request resolved: https://github.com/facebook/react-native/pull/30449 Changelog: [Internal] - Moved codegen invocation out of Podfile and into FBReactNativeSpec Pod Reviewed By: fkgozali Differential Revision: D25138896 fbshipit-source-id: 4779f822459cea2c30fd544eee19a49e8d80153d --- .gitignore | 1 - .../FBReactNativeSpec.podspec | 18 ++++- package.json | 1 + packages/rn-tester/Podfile | 10 --- packages/rn-tester/Podfile.lock | 72 ++++++++--------- scripts/generate-native-modules-specs.sh | 80 +++++++++++++------ scripts/react_native_pods.rb | 62 -------------- template/ios/Podfile | 4 - 8 files changed, 111 insertions(+), 137 deletions(-) diff --git a/.gitignore b/.gitignore index ddb36db5831400..c9ad5eacf11c52 100644 --- a/.gitignore +++ b/.gitignore @@ -112,7 +112,6 @@ package-lock.json /Libraries/FBReactNativeSpec/FBReactNativeSpec /packages/react-native-codegen/lib /ReactCommon/fabric/components/rncore/ -/schema-native-modules.json /schema-rncore.json # Visual studio diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec.podspec b/Libraries/FBReactNativeSpec/FBReactNativeSpec.podspec index 89d480eb0f42d3..949365c323ef4c 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec.podspec +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec.podspec @@ -10,13 +10,22 @@ package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) version = package['version'] source = { :git => 'https://github.com/facebook/react-native.git' } +codegen_path_prefix = ".." if version == '1000.0.0' # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. source[:commit] = `git rev-parse HEAD`.strip + codegen_path_prefix = "packages" else source[:tag] = "v#{version}" end +react_native_path = File.join(__dir__, "..", "..") +srcs_dir = File.join(__dir__, "..") +codegen_script_path = File.join(react_native_path, "scripts", "generate-native-modules-specs.sh") +codegen_path = File.join(react_native_path, codegen_path_prefix, "react-native-codegen") +generated_files = [File.join(__dir__, "FBReactNativeSpec", "FBReactNativeSpec.h"), File.join(__dir__, "FBReactNativeSpec", "FBReactNativeSpec-generated.mm")] +codegen_command = "CODEGEN_PATH=#{codegen_path} sh '#{codegen_script_path}' | tee \"${SCRIPT_OUTPUT_FILE_0}\"" + folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' folly_version = '2020.01.13.00' @@ -46,5 +55,12 @@ Pod::Spec.new do |s| s.dependency "React-jsi", version s.dependency "ReactCommon/turbomodule/core", version - use_react_native_codegen! (s) + s.prepare_command = "touch #{generated_files.reduce() { |str, file| str + " " + file }}" + s.script_phase = { + :name => 'Generate Native Modules Code', + :input_files => [srcs_dir], + :output_files => ["$(DERIVED_FILE_DIR)/FBReactNativeSpec-codegen.log"], + :script => codegen_command, + :execution_position => :before_compile + } end diff --git a/package.json b/package.json index 8d175291d2482e..4116abcca8fa1c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "rn-get-polyfills.js", "scripts/compose-source-maps.js", "scripts/fixmacscripts.sh", + "scripts/generate-native-modules-specs.sh", "scripts/generate-native-modules-specs-cli.js", "scripts/ios-configure-glog.sh", "scripts/launchPackager.bat", diff --git a/packages/rn-tester/Podfile b/packages/rn-tester/Podfile index c4d3bbbdd8f207..56fedf74cba92f 100644 --- a/packages/rn-tester/Podfile +++ b/packages/rn-tester/Podfile @@ -101,16 +101,6 @@ def frameworks_pre_install(installer) end end -pre_install do |installer| - frameworks_pre_install(installer) if ENV['USE_FRAMEWORKS'] == '1' - if ENV['USE_CODEGEN'] != '0' - prefix_path = "../.." - codegen_path = "../../packages/react-native-codegen" - system("(cd #{codegen_path} && yarn install && yarn run build)") - codegen_pre_install(installer, {path:prefix_path, codegen_path:codegen_path}) - end -end - post_install do |installer| flipper_post_install(installer) end diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 24fc91418ab2b5..ac0c47f7705218 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -15,12 +15,12 @@ PODS: - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.2.0): + - Flipper-Folly (2.3.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.19) + - OpenSSL-Universal (= 1.0.2.20) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): @@ -58,9 +58,9 @@ PODS: - FlipperKit/Core - FlipperKit/FlipperKitNetworkPlugin - glog (0.3.5) - - OpenSSL-Universal (1.0.2.19): - - OpenSSL-Universal/Static (= 1.0.2.19) - - OpenSSL-Universal/Static (1.0.2.19) + - OpenSSL-Universal (1.0.2.20): + - OpenSSL-Universal/Static (= 1.0.2.20) + - OpenSSL-Universal/Static (1.0.2.20) - RCT-Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion @@ -510,47 +510,47 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 0ea4559a49682230337df966e735d6cc7760108e - FBLazyVector: b44bc80ae11c8740f6224d6f30812405501b4211 - FBReactNativeSpec: 320f0fef68a24fd095fef59b2de4341fdf5be6a1 + FBLazyVector: a9ade8db1e01f3b89d9e22a47719772e4a36213c + FBReactNativeSpec: f7baff2aa46514535cf951ff27ca4d638e488b51 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 + Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d glog: 0dc7efada961c0793012970b60faebbd58b0decb - OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 + OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: b3998425a8ee9f695f57a204dc494534246f0fe9 - RCTRequired: 97e9e58f6455e79079415f8385836b2ef72d4e02 - RCTTypeSafety: c5333e4103a98acd15accfe49bb53c84f6e2a2e6 - React: 177260f7dcff672e54b9b688ce8086875aca1c78 - React-callinvoker: 460276eea0afbe0fa542eb0caafef9e3b57ef5b3 - React-Core: e3d3e43edf16521c700c6c6b23f4d3c402d934a1 - React-CoreModules: 607d4712ba894a5657534b8e8afada4729292c2f - React-cxxreact: a7e10cdf2ccf2555fe759f676bf11e04f9a74788 - React-jsi: d9e6609ca4aab2a89557f0560c896f2b197ccc0e - React-jsiexecutor: c3320e14214539a2a9127c4d3698367a7b9418d4 - React-jsinspector: baaeb2b57b3e79166dbe8c64fff01d420b51ee47 - React-perflogger: 92b04aa5da0c5c750dab7d40d783ccacbc6d1e58 - React-RCTActionSheet: 3f69d888ac5c3efd5ca78b3d6551ad8d87b568a3 - React-RCTAnimation: 9e359fb72c9542bde35b95ee0a1a622e0efd39c5 - React-RCTBlob: 49ddb39defb45db21f4425b96b7cd4e658d31a0f - React-RCTImage: 1b3276c1c6b7ea4cac9cb4504d2bc36ef194b703 - React-RCTLinking: deca7e1cf77253b9a8171aa950b90cdbbe9db94b - React-RCTNetwork: 23e3b4e85b5b47fe58e2a70f42a78df0e54b3689 - React-RCTPushNotification: cf58e2c5bc0eec6ea6af647170bf88b6099ccb4c - React-RCTSettings: 516049436a9b14714ab4a038ed5934baea77a621 - React-RCTTest: 587e397665a04a83353f1756c99dbc74a200ef82 - React-RCTText: f9a18da593677c71effbc0810ab70a991946ee79 - React-RCTVibration: 8e5e94c2bb1473959e6ba239350903bb9a2415c5 - React-runtimeexecutor: 9b2b71497a9b0d21972fb28ba069a964b0ab8683 + RCTRequired: 48327ba0b69b69e3cc2cebc13f56b9a3eb3f281d + RCTTypeSafety: a4c23878c48fdfd36bfac1bee0d0f91afe310452 + React: 51d1f9e616d16e8b92bc053391616003e2cf3886 + React-callinvoker: c097b9b5625f8cbbaffadf3c66b6f1df00fba58a + React-Core: b28f0b2baeef682d767956960a03bb58289b92a1 + React-CoreModules: ae29062afda1351a564852e7be362f9452872a31 + React-cxxreact: 77ee98786d476a952fc39866966b51f1372ac3c5 + React-jsi: 87b35f13705cf3b7c47400f06aeff6c40b643eaa + React-jsiexecutor: 6d22b636933ff96e50ebf0d47cb848caeecf07af + React-jsinspector: add92a0175a56529199638b9f1ac8d7813a4392b + React-perflogger: 8ac93e334eff901640cb121c7428c61c82e9ac4d + React-RCTActionSheet: 1f4f2a85b3034ad179bd3c25508e2479a0a905c0 + React-RCTAnimation: e4ea1e8136bb8e05998c64d0248a541b9c1af367 + React-RCTBlob: db17953d43e1aa37552ea02deaff7dc1dea7d5a6 + React-RCTImage: 471dc72765530155105bb8604fbd3dd54dc33f5b + React-RCTLinking: c787e9c43a34d708bd875f869f2af644b1753e4f + React-RCTNetwork: c1502990e987183e2aeefa9b6cf144f00773e2c2 + React-RCTPushNotification: 926ce4da579702f9f0251a2893c4ec1e2c759df8 + React-RCTSettings: 9c15af07456b7feb164cd0471c03fa48bf4a2550 + React-RCTTest: f9a7eab7f54a93ea93a4af45b614d174b8b4dde3 + React-RCTText: 8c6e3dae3e92acdb3ba4d1fb3b00303b65a5cbd7 + React-RCTVibration: 6731e3a4db76e3aaa9975c41b2e6089042013667 + React-runtimeexecutor: 0d7718336b29ba8fcb8339c69081fdf556660dbf React-TurboModuleCxx-RNW: 12172bdbaaf052406ec571465243fad4b2eb2702 - React-TurboModuleCxx-WinRTPort: 0799e9908aa43f37f7d6791512f593ba60a7cdfc - ReactCommon: 8a60219a59638aaf77c3b00d8f7b4e155d3efc0c - Yoga: 168e8ee8910abaa7e7dd507046845ea2ee1b12cd + React-TurboModuleCxx-WinRTPort: e409b4465cfd72e1d1b4067106f0cf29aa8cbc46 + ReactCommon: 94c0373b8c85c713e41149d947479b0f6ced890e + Yoga: d689cee4cb7b695bad8c4dc802b01cd3fd5d3c7d YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 8f04bb9d219d2191a23c2c17a1e9816fa6aea5a8 +PODFILE CHECKSUM: 096cbc796e89167c003b0c49186597432f0fb5e8 COCOAPODS: 1.10.1 diff --git a/scripts/generate-native-modules-specs.sh b/scripts/generate-native-modules-specs.sh index e72916bc138da1..d667c46901fe99 100755 --- a/scripts/generate-native-modules-specs.sh +++ b/scripts/generate-native-modules-specs.sh @@ -4,54 +4,88 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -# This script collects the JavaScript spec definitions for native -# modules, then uses react-native-codegen to generate native code. -# The script will copy the generated code to the final location by -# default. Optionally, call the script with a path to the desired -# output location. +# This script collects the JavaScript spec definitions for core +# native modules, then uses react-native-codegen to generate +# native code. +# The script will use the local react-native-codegen package by +# default. Optionally, set the CODEGEN_PATH to point to the +# desired codegen library (e.g. when using react-native-codegen +# from npm). # # Usage: -# ./scripts/generate-native-modules-specs.sh [output-dir] +# ./scripts/generate-native-modules-specs.sh # # Example: -# ./scripts/generate-native-modules-specs.sh ./codegen-out +# CODEGEN_PATH=.. ./scripts/generate-native-modules-specs.sh # shellcheck disable=SC2038 set -e THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) +TEMP_DIR=$(mktemp -d /tmp/react-native-codegen-XXXXXXXX) RN_DIR=$(cd "$THIS_DIR/.." && pwd) -CODEGEN_DIR=$(cd "$RN_DIR/packages/react-native-codegen" && pwd) -OUTPUT_DIR="${1:-$RN_DIR/Libraries/FBReactNativeSpec/FBReactNativeSpec}" -SCHEMA_FILE="$RN_DIR/schema-native-modules.json" -YARN_BINARY="${YARN_BINARY:-yarn}" +CODEGEN_PATH="${CODEGEN_PATH:-$(cd "$RN_DIR/packages" && pwd)}" +CODEGEN_DIR="$CODEGEN_PATH/react-native-codegen" + +YARN_BINARY="${YARN_BINARY:-$(command -v yarn)}" + +cleanup () { + set +e + rm -rf "$TEMP_DIR" + set -e +} describe () { printf "\\n\\n>>>>> %s\\n\\n\\n" "$1" } step_build_codegen () { - describe "Building react-native-codegen package" - pushd "$CODEGEN_DIR" >/dev/null || exit - "$YARN_BINARY" - "$YARN_BINARY" build - popd >/dev/null || exit + if [ ! -d "$CODEGEN_DIR/lib" ]; then + describe "Building react-native-codegen package" + pushd "$CODEGEN_DIR" >/dev/null || exit + "$YARN_BINARY" + "$YARN_BINARY" build + popd >/dev/null || exit + fi } -step_gen_schema () { +run_codegen () { + SRCS_DIR=$1 + LIBRARY_NAME=$2 + OUTPUT_DIR=$3 + + SCHEMA_FILE="$TEMP_DIR/schema-$LIBRARY_NAME.json" + + if [ ! -d "$CODEGEN_DIR/lib" ]; then + describe "Building react-native-codegen package" + pushd "$CODEGEN_DIR" >/dev/null || exit + "$YARN_BINARY" + "$YARN_BINARY" build + popd >/dev/null || exit + fi + describe "Generating schema from flow types" - SRCS_DIR=$(cd "$RN_DIR/Libraries" && pwd) "$YARN_BINARY" node "$CODEGEN_DIR/lib/cli/combine/combine-js-to-schema-cli.js" "$SCHEMA_FILE" "$SRCS_DIR" -} -step_gen_specs () { describe "Generating native code from schema (iOS)" pushd "$RN_DIR" >/dev/null || exit "$YARN_BINARY" --silent node scripts/generate-native-modules-specs-cli.js ios "$SCHEMA_FILE" "$OUTPUT_DIR" popd >/dev/null || exit } -step_build_codegen -step_gen_schema -step_gen_specs +# Handle Core Modules +run_codegen_core_modules () { + LIBRARY_NAME="FBReactNativeSpec" + SRCS_DIR=$(cd "$RN_DIR/Libraries" && pwd) + OUTPUT_DIR="$SRCS_DIR/$LIBRARY_NAME/$LIBRARY_NAME" + + run_codegen "$SRCS_DIR" "$LIBRARY_NAME" "$OUTPUT_DIR" +} + +main() { + run_codegen_core_modules +} + +trap cleanup EXIT +main "$@" diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 8c2e09dc54329f..97dc46ca16425b 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -111,65 +111,3 @@ def flipper_post_install(installer) end end end - -# Pre Install processing for Native Modules -def codegen_pre_install(installer, options={}) - prefix = options[:path] ||= "../node_modules/react-native" - codegen_path = options[:codegen_path] ||= "../node_modules/react-native-codegen" - - Dir.mktmpdir do |dir| - native_module_spec_name = "FBReactNativeSpec" - schema_file = dir + "/schema-#{native_module_spec_name}.json" - srcs_dir = "#{prefix}/Libraries" - schema_generated = system("node #{codegen_path}/lib/cli/combine/combine-js-to-schema-cli.js #{schema_file} #{srcs_dir}") - specs_generated = system("node #{prefix}/scripts/generate-native-modules-specs-cli.js ios #{schema_file} #{srcs_dir}/#{native_module_spec_name}/#{native_module_spec_name}") - end -end - -def use_react_native_codegen!(spec, options={}) - # The path to react-native (e.g. react_native_path) - prefix = options[:path] ||= File.join(__dir__, "..") - - # The path to JavaScript files - srcs_dir = options[:srcs_dir] ||= File.join(prefix, "Libraries") - - # Library name (e.g. FBReactNativeSpec) - library_name = spec.name - modules_output_dir = File.join(prefix, "Libraries/#{library_name}/#{library_name}") - - # Run the codegen as part of the Xcode build pipeline. - spec.script_phase = { - :name => 'Generate Specs', - :input_files => [srcs_dir], - :output_files => ["$(DERIVED_FILE_DIR)/codegen.log"], - :script => "sh '#{File.join(__dir__, "generate-native-modules-specs.sh")}' | tee \"${SCRIPT_OUTPUT_FILE_0}\"", - :execution_position => :before_compile - } - - # Since the generated files are not guaranteed to exist when CocoaPods is run, we need to create - # empty files to ensure the references are included in the resulting Pods Xcode project. - mkdir_command = "mkdir -p #{modules_output_dir}" - generated_filenames = [ "#{library_name}.h", "#{library_name}-generated.mm" ] - generated_files = generated_filenames.map { |filename| File.join(modules_output_dir, filename) } - - if ENV['USE_FABRIC'] == '1' - # We use a different library name for components, as well as an additional set of files. - # Eventually, we want these to be part of the same library as #{library_name} above. - components_library_name = "rncore" - components_output_dir = File.join(prefix, "ReactCommon/react/renderer/components/#{components_library_name}") - mkdir_command += " #{components_output_dir}" - components_generated_filenames = [ - "ComponentDescriptors.h", - "EventEmitters.cpp", - "EventEmitters.h", - "Props.cpp", - "Props.h", - "RCTComponentViewHelpers.h", - "ShadowNodes.cpp", - "ShadowNodes.h" - ] - generated_files = generated_files.concat(components_generated_filenames.map { |filename| File.join(components_output_dir, filename) }) - end - - spec.prepare_command = "#{mkdir_command} && touch #{generated_files.reduce() { |str, file| str + " " + file }}" -end diff --git a/template/ios/Podfile b/template/ios/Podfile index 04f68e5431fb93..6701249e83ac20 100644 --- a/template/ios/Podfile +++ b/template/ios/Podfile @@ -13,10 +13,6 @@ target 'HelloWorld' do # Pods for testing end - pre_install do |installer| - codegen_pre_install(installer) - end - # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and