diff --git a/React/FBReactNativeSpec/FBReactNativeSpec.podspec b/React/FBReactNativeSpec/FBReactNativeSpec.podspec index 32a4bf8cb41..bdbf1023319 100644 --- a/React/FBReactNativeSpec/FBReactNativeSpec.podspec +++ b/React/FBReactNativeSpec/FBReactNativeSpec.podspec @@ -4,7 +4,9 @@ # LICENSE file in the root directory of this source tree. require "json" -require_relative "../../scripts/react_native_pods.rb" + +react_native_path = "../.." +require_relative "#{react_native_path}/scripts/react_native_pods.rb" package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) version = package['version'] @@ -46,5 +48,13 @@ Pod::Spec.new do |s| s.dependency "React-jsi", version s.dependency "ReactCommon/turbomodule/core", version - use_react_native_codegen! (s) + use_react_native_codegen!(s, { + :react_native_path => react_native_path, + :js_srcs_dir => "#{react_native_path}/Libraries", + :library_name => "FBReactNativeSpec", + :output_dir => "#{react_native_path}/React/FBReactNativeSpec", + :component_library_name => "rncore", + # TODO: component_output_dir should be programmatically specified, and may change with use_frameworks! support. + :component_output_dir => "#{react_native_path}/ReactCommon/react/renderer/components/" + }) end diff --git a/scripts/codegen.js b/scripts/codegen.js deleted file mode 100644 index 12ff0917dd6..00000000000 --- a/scripts/codegen.js +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -require('shelljs/global'); -const yargs = require('yargs'); -const execSync = require('child_process').execSync; - -let argv = yargs.option('srcs', { - alias: 'srcs_dir', - type: 'string', - description: 'Path to JavaScript sources', -}).option('modules_library_name', { - type: 'string', - description: 'Native modules interfaces library name', -}).option('modules_output_dir', { - type: 'string', - description: 'Native modules interfaces output dir', -}).option('components_library_name', { - type: 'string', - description: 'Native components interfaces library name', -}).option('components_output_dir', { - type: 'string', - description: 'Native components interfaces output dir', -}).argv; - -let env_vars = []; -const { srcs_dir, modules_library_name, modules_output_dir, components_library_name, components_output_dir } = argv; - -if (srcs_dir) { - env_vars.push(`SRCS_DIR=${srcs_dir}`); -} -if (modules_library_name) { - env_vars.push(`MODULES_LIBRARY_NAME=${modules_library_name}`); -} -if (modules_output_dir) { - env_vars.push(`MODULES_OUTPUT_DIR=${modules_output_dir}`); -} -if (components_library_name) { - env_vars.push(`COMPONENTS_LIBRARY_NAME=${components_library_name}`); -} -if (components_output_dir) { - env_vars.push(`COMPONENTS_OUTPUT_DIR=${components_output_dir}`); -} - -execSync(`${env_vars.join(' ')} ./generate-specs.sh`); diff --git a/scripts/generate-specs.sh b/scripts/generate-specs.sh index 4456557dfbb..d3ea448e175 100755 --- a/scripts/generate-specs.sh +++ b/scripts/generate-specs.sh @@ -4,20 +4,12 @@ # 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 core +# This script collects the JavaScript spec definitions for # native modules and components, then uses react-native-codegen # to generate native code. # -# Optionally, set these envvars to override defaults: -# - SRCS_DIR: Path to JavaScript sources -# - MODULES_LIBRARY_NAME: Defaults to FBReactNativeSpec -# - MODULES_OUTPUT_DIR: Defaults to React/$MODULES_LIBRARY_NAME/$MODULES_LIBRARY_NAME -# - COMPONENTS_LIBRARY_NAME: Defaults to rncore -# - COMPONENTS_OUTPUT_DIR: Defaults to ReactCommon/react/renderer/components/$COMPONENTS_LIBRARY_NAME -# # Usage: # ./scripts/generate-specs.sh -# SRCS_DIR=myapp/js MODULES_LIBRARY_NAME=MySpecs MODULES_OUTPUT_DIR=myapp/MySpecs ./scripts/generate-specs.sh # # shellcheck disable=SC2038 @@ -44,27 +36,45 @@ describe () { printf "\\n\\n>>>>> %s\\n\\n\\n" "$1" >&2 } +print_usage () { + printf "\\nNAME\\n\\t%s -- generate specs\\n" "$1" >&2 + printf "\\nSYNOPSIS\\n" >&2 + printf "\\t%s javascript_sources_directory specs_library_name output_directory\\n" "$1" >&2 + printf "\\t%s javascript_sources_directory specs_library_name output_directory component_library_name [component_output_directory]\\n" "$1" >&2 + printf "\\n\\nDESCRIPTION\\n\\tIn the first synopsis form, this script collects native module and native component JavaScript spec definitions in javascript_sources_directory, then uses react-native-codegen to generate the native interface code into a library named specs_library_name, which is copied to the destination output_directory.\\n" >&2 + printf "\\n\\tIn the second synopsis form, the component_library_name will be used as the name of the component native interface code library. If provided, the component output will be copied to the component_output_directory, otherwise it will be copied to the output_directory.\\n" >&2 +} + main() { - SRCS_DIR=${SRCS_DIR:-$(cd "$RN_DIR/Libraries" && pwd)} - MODULES_LIBRARY_NAME=${MODULES_LIBRARY_NAME:-FBReactNativeSpec} - - COMPONENTS_LIBRARY_NAME=${COMPONENTS_LIBRARY_NAME:-rncore} - MODULES_OUTPUT_DIR=${MODULES_OUTPUT_DIR:-"$RN_DIR/React/$MODULES_LIBRARY_NAME/$MODULES_LIBRARY_NAME"} - # TODO: $COMPONENTS_PATH should be programmatically specified, and may change with use_frameworks! support. - COMPONENTS_PATH="ReactCommon/react/renderer/components" - COMPONENTS_OUTPUT_DIR=${COMPONENTS_OUTPUT_DIR:-"$RN_DIR/$COMPONENTS_PATH/$COMPONENTS_LIBRARY_NAME"} - - TEMP_OUTPUT_DIR="$TEMP_DIR/out" - SCHEMA_FILE="$TEMP_DIR/schema.json" - - CODEGEN_REPO_PATH="$RN_DIR/packages/react-native-codegen" - CODEGEN_NPM_PATH="$RN_DIR/../react-native-codegen" + MIN_ARG_NUM=3 + if [ "$#" -eq 0 ]; then + print_usage "$0" + exit 1 + fi if [ -z "$NODE_BINARY" ]; then echo "Error: Could not find node. Make sure it is in bash PATH or set the NODE_BINARY environment variable." 1>&2 exit 1 fi + if [ "$#" -lt "$MIN_ARG_NUM" ]; then + echo "Error: Expected $MIN_ARG_NUM arguments, got $# instead. Run $0 with no arguments to learn more." 1>&2 + exit 1 + fi + + SRCS_DIR=$1 + LIBRARY_NAME=$2 + OUTPUT_DIR=$3 + COMPONENT_LIBRARY_NAME_OVERRIDE=$4 + COMPONENT_OUTPUT_DIR_OVERRIDE=$5 + + PLATFORM="ios" + TEMP_OUTPUT_DIR="$TEMP_DIR/out" + SCHEMA_FILE="$TEMP_DIR/schema.json" + + CODEGEN_REPO_PATH="$RN_DIR/packages/react-native-codegen" + CODEGEN_NPM_PATH="$RN_DIR/../react-native-codegen" + if [ -d "$CODEGEN_REPO_PATH" ]; then CODEGEN_PATH=$(cd "$CODEGEN_REPO_PATH" && pwd) elif [ -d "$CODEGEN_NPM_PATH" ]; then @@ -82,15 +92,38 @@ main() { describe "Generating schema from Flow types" "$NODE_BINARY" "$CODEGEN_PATH/lib/cli/combine/combine-js-to-schema-cli.js" "$SCHEMA_FILE" "$SRCS_DIR" - describe "Generating native code from schema (iOS)" - pushd "$RN_DIR" >/dev/null || exit 1 - "$NODE_BINARY" scripts/generate-specs-cli.js ios "$SCHEMA_FILE" "$TEMP_OUTPUT_DIR" "$MODULES_LIBRARY_NAME" - popd >/dev/null || exit 1 + describe "Generating native code from schema ($PLATFORM)" + pushd "$RN_DIR" >/dev/null + "$NODE_BINARY" scripts/generate-specs-cli.js "$PLATFORM" "$SCHEMA_FILE" "$TEMP_OUTPUT_DIR" "$LIBRARY_NAME" + popd >/dev/null - mkdir -p "$COMPONENTS_OUTPUT_DIR" "$MODULES_OUTPUT_DIR" - cp -R "$TEMP_OUTPUT_DIR/$MODULES_LIBRARY_NAME.h" "$TEMP_OUTPUT_DIR/$MODULES_LIBRARY_NAME-generated.mm" "$MODULES_OUTPUT_DIR" || exit 1 - find "$TEMP_OUTPUT_DIR" -type f | xargs sed -i.bak "s/$MODULES_LIBRARY_NAME/$COMPONENTS_LIBRARY_NAME/g" || exit 1 - find "$TEMP_OUTPUT_DIR" -type f -not -iname "$MODULES_LIBRARY_NAME*" -exec cp '{}' "$COMPONENTS_OUTPUT_DIR/" ';' || exit 1 + + mkdir -p "$OUTPUT_DIR" + + if [ -z "$COMPONENT_LIBRARY_NAME_OVERRIDE" ]; then + # Copy all output to output_dir + cp -R "$TEMP_OUTPUT_DIR/" "$OUTPUT_DIR" + echo >&2 "$LIBRARY_NAME output has been written to $OUTPUT_DIR:" + ls -1 "$OUTPUT_DIR" 2>&1 + else + # Copy modules output to output_dir + cp "$TEMP_OUTPUT_DIR/$LIBRARY_NAME.h" "$TEMP_OUTPUT_DIR/$LIBRARY_NAME-generated.mm" "$OUTPUT_DIR" + echo >&2 "$LIBRARY_NAME output has been written to $OUTPUT_DIR:" + ls -1 "$OUTPUT_DIR" 2>&1 + + # Rename library name used in components output files + find "$TEMP_OUTPUT_DIR" -type f | xargs sed -i.bak "s/$LIBRARY_NAME/$COMPONENT_LIBRARY_NAME_OVERRIDE/g" + + if [ -n "$COMPONENT_OUTPUT_DIR_OVERRIDE" ]; then + # Components codegen output to be moved to separate directory + mkdir -p "$COMPONENT_OUTPUT_DIR_OVERRIDE" + OUTPUT_DIR="$COMPONENT_OUTPUT_DIR_OVERRIDE" + fi + + find "$TEMP_OUTPUT_DIR" -type f -not -iname "$LIBRARY_NAME.h" -not -iname "$LIBRARY_NAME-generated.mm" -not -iname "*.bak" -exec cp '{}' "$OUTPUT_DIR/" ';' + echo >&2 "$COMPONENT_LIBRARY_NAME_OVERRIDE output has been written to $OUTPUT_DIR:" + ls -1 "$OUTPUT_DIR" 2>&1 + fi echo >&2 'Done.' } diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index a4131f3ec29..02b04e1e4f7 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -161,38 +161,38 @@ def use_react_native_codegen!(spec, options={}) js_srcs = options[:js_srcs_dir] ||= "#{prefix}/Libraries" # Library name (e.g. FBReactNativeSpec) - modules_library_name = options[:library_name] ||= spec.name + library_name = options[:library_name] ||= "#{spec.name}Spec" # Output dir, relative to podspec that invoked this method - modules_output_dir = options[:modules_output_dir] ||= "#{prefix}/React/#{modules_library_name}/#{modules_library_name}" + output_dir = options[:output_dir] ||= "#{prefix}/React/#{library_name}" - generated_dirs = [ modules_output_dir ] - generated_filenames = [ "#{modules_library_name}.h", "#{modules_library_name}-generated.mm" ] - generated_files = generated_filenames.map { |filename| "#{modules_output_dir}/#{filename}" } + generated_dirs = [ "#{output_dir}/#{library_name}" ] + generated_filenames = [ "#{library_name}.h", "#{library_name}-generated.mm" ] + generated_files = generated_filenames.map { |filename| "#{output_dir}/#{library_name}/#{filename}" } # Run the codegen as part of the Xcode build pipeline. - env_vars = "SRCS_DIR='${PODS_TARGET_SRCROOT}/#{js_srcs}'" - env_vars += " MODULES_OUTPUT_DIR='${PODS_TARGET_SRCROOT}/#{modules_output_dir}'" - env_vars += " MODULES_LIBRARY_NAME='#{modules_library_name}'" + codegen_script_args = [ "'${PODS_TARGET_SRCROOT}/#{js_srcs}'" ] + codegen_script_args.push "'#{library_name}'" + codegen_script_args.push "'${PODS_TARGET_SRCROOT}/#{output_dir}/#{library_name}'" - 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 #{modules_library_name} above. - components_output_dir = options[:components_output_dir] ||= "#{prefix}/ReactCommon/react/renderer/components/rncore/" - generated_dirs.push components_output_dir - env_vars += " COMPONENTS_OUTPUT_DIR='${PODS_TARGET_SRCROOT}/#{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| "#{components_output_dir}/#{filename}" }) - end + # 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. + component_library_name = options[:component_library_name] ||= library_name + component_output_dir = options[:component_output_dir] ||= output_dir + generated_dirs.push "#{component_output_dir}/#{component_library_name}" + codegen_script_args.push "'#{component_library_name}'" + codegen_script_args.push "'${PODS_TARGET_SRCROOT}/#{component_output_dir}/#{component_library_name}'" + 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| "#{component_output_dir}/#{component_library_name}/#{filename}" }) # Prepare filesystem by creating empty files that will be picked up as references by CocoaPods. prepare_command = "mkdir -p #{generated_dirs.join(" ")} && touch -a #{generated_files.join(" ")}" @@ -202,11 +202,11 @@ def use_react_native_codegen!(spec, options={}) spec.script_phase = { :name => 'Generate Specs', :input_files => [ "${PODS_TARGET_SRCROOT}/#{js_srcs}" ], # This also needs to be relative to Xcode - :output_files => ["${DERIVED_FILE_DIR}/codegen-#{modules_library_name}.log"].concat(generated_files.map { |filename| " ${PODS_TARGET_SRCROOT}/#{filename}"} ), + :output_files => ["${DERIVED_FILE_DIR}/codegen-#{library_name}.log"].concat(generated_files.map { |filename| " ${PODS_TARGET_SRCROOT}/#{filename}"} ), # The final generated files will be created when this script is invoked at Xcode build time. :script => %{set -o pipefail -bash -l -c '#{env_vars} $\{PODS_TARGET_SRCROOT\}/#{prefix}/scripts/generate-specs.sh' 2>&1 | tee "${SCRIPT_OUTPUT_FILE_0}" +bash -l -c '$\{PODS_TARGET_SRCROOT\}/#{prefix}/scripts/generate-specs.sh #{codegen_script_args.join(" ")}' 2>&1 | tee "${SCRIPT_OUTPUT_FILE_0}" }, :execution_position => :before_compile, :show_env_vars_in_log => true