diff --git a/.github/workflows/pr-realm-js.yml b/.github/workflows/pr-realm-js.yml index 7a9c3cf1f8..23d89af221 100644 --- a/.github/workflows/pr-realm-js.yml +++ b/.github/workflows/pr-realm-js.yml @@ -21,16 +21,45 @@ concurrency: cancel-in-progress: true jobs: - bundle: - name: Bundle TypeScript + generate-jsi: + name: Generate JSI runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Setup node version - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - name: Install dependencies + # Ignoring scripts to prevent a prebuilt from getting fetched / built + run: npm ci --ignore-scripts + - name: Generate JSI + run: | + npm run bindgen:generate:jsi --workspace realm + # Due to a limitation in upload-artifact a redundant file is needed to force + # preserving paths (https://github.com/actions/upload-artifact/issues/174) + - name: Upload dist artifacts + uses: actions/upload-artifact@v3 + with: + name: realm-js-jsi + path: | + README.md + packages/realm/binding/jsi/jsi_init.cpp + + generate-ts: + name: Generate TS Bundle + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: "recursive" + - name: Setup node version + uses: actions/setup-node@v4 with: node-version: 20 cache: npm @@ -44,7 +73,7 @@ jobs: - name: Upload dist artifacts uses: actions/upload-artifact@v3 with: - name: realm-js-bundles + name: realm-js-ts path: | README.md packages/*/dist @@ -52,9 +81,9 @@ jobs: build: name: Build for ${{ matrix.variant.os }} ${{ matrix.variant.arch }} runs-on: ${{ matrix.variant.runner }} + needs: [generate-ts] env: REALM_DISABLE_ANALYTICS: 1 - NDK_VERSION: 25.1.8937393 strategy: fail-fast: false matrix: @@ -64,23 +93,16 @@ jobs: - { os: linux, runner: ubuntu-latest, arch: arm64, artifact-path: packages/realm/prebuilds } - { os: windows, runner: windows-latest, arch: x64, artifact-path: packages/realm/prebuilds, test-node: true, test-electron: true } - { os: windows, runner: windows-2019, arch: ia32, artifact-path: packages/realm/prebuilds } - - { os: android, runner: ubuntu-latest, arch: x86_64, artifact-path: packages/realm/react-native/android/src/main/jniLibs } - - { os: android, runner: ubuntu-latest, arch: armeabi-v7a, artifact-path: packages/realm/react-native/android/src/main/jniLibs } - - { os: android, runner: ubuntu-latest, arch: arm64-v8a, artifact-path: packages/realm/react-native/android/src/main/jniLibs } - - { os: android, runner: ubuntu-latest, arch: x86, artifact-path: packages/realm/react-native/android/src/main/jniLibs } - { os: darwin, runner: macos-latest, arch: x64, artifact-path: packages/realm/prebuilds, test-node: true, test-electron: true } - { os: darwin, runner: macos-latest, arch: arm64, artifact-path: packages/realm/prebuilds, test-node: true, test-electron: true } - - { os: ios, runner: macos-latest-xlarge, arch: simulator, artifact-path: packages/realm/react-native/ios/realm-js-ios.xcframework } - - { os: ios, runner: macos-latest-xlarge, arch: catalyst, artifact-path: packages/realm/react-native/ios/realm-js-ios.xcframework } - - { os: ios, runner: macos-latest-xlarge, arch: ios, artifact-path: packages/realm/react-native/ios/realm-js-ios.xcframework } steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Setup node version - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 cache: npm @@ -92,13 +114,18 @@ jobs: - name: Restore NPM cache id: npm-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.npm-cache-dir.outputs.dir }} key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} restore-keys: | ${{ runner.os }}-node- + - name: Download TS Bundle + uses: actions/download-artifact@v3 + with: + name: realm-js-ts + - name: Setup Wireit cache uses: google/wireit@setup-github-actions-caching/v1 @@ -113,20 +140,6 @@ jobs: if: ${{ (matrix.variant.runner == 'ubuntu-latest') }} run: sudo apt-get install ccache ninja-build - - name: Setup Java - if: ${{ matrix.variant.os == 'android' }} - uses: actions/setup-java@v3 - with: - distribution: 'zulu' # See 'Supported distributions' for available options - java-version: '11' - - - name: Setup Android SDK - if: ${{ matrix.variant.os == 'android' }} - uses: android-actions/setup-android@v2 - - - name: Install NDK - if: ${{ matrix.variant.os == 'android' }} - run: sdkmanager --install "ndk;${{ env.NDK_VERSION }}" # The ccache installed by github doesn't want to be moved around. Let the ccache action download a new one. - name: Remove pre-installed ccache @@ -187,21 +200,6 @@ jobs: if: ${{ (matrix.variant.os != 'ios') && (matrix.variant.os != 'android') }} run: npm run build:node:prebuild:${{matrix.variant.arch}} --workspace realm - # build the c++ library for IOS - # the Info.plist needs to be regenerated with all libraries in place - - name: Build iOS - if: ${{ (matrix.variant.os == 'ios') }} - run: | - npm run build:ios --workspace realm - rm -vf ${{ matrix.variant.artifact-path }}/Info.plist - env: - PLATFORMS: ${{ matrix.variant.arch }} - - # build the c++ library for Android - - name: Build Android - if: ${{ (matrix.variant.os == 'android') }} - run: npm run build:android --workspace realm -- --arch=${{matrix.variant.arch}} - # Due to a limitation in upload-artifact a redundant file is needed to force # preserving paths (https://github.com/actions/upload-artifact/issues/174) - name: Upload prebuild artifact @@ -212,41 +210,14 @@ jobs: README.md ${{ matrix.variant.artifact-path }} - ios-xcframework: - name: Generate Info.plist with all frameworks in place - needs: [build] - if: ${{ success() || failure() }} - runs-on: macos-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - submodules: "recursive" - - - name: Download prebuilds - uses: actions/download-artifact@v3 - with: - name: realm-js-prebuilds - - - name: Regenerate Info.plist - run: scripts/regen-info-plist.sh packages/realm/react-native/ios/realm-js-ios.xcframework - - # Due to a limitation in upload-artifact a redundant file is needed to force - # preserving paths (https://github.com/actions/upload-artifact/issues/174) - - name: Upload prebuild artifact - uses: actions/upload-artifact@v3 - with: - name: realm-js-prebuilds - path: | - README.md - packages/realm/react-native/ios/realm-js-ios.xcframework/Info.plist - integration-tests: name: Test ${{ matrix.variant.environment }} on ${{ matrix.variant.os }} (${{matrix.variant.target}}) - needs: [bundle, build, ios-xcframework] + needs: [generate-jsi, generate-ts, build] if: ${{ success() || failure() }} env: REALM_DISABLE_ANALYTICS: 1 + NDK_VERSION: 25.1.8937393 + JAVA_VERSION: 17 MOCHA_REMOTE_TIMEOUT: 60000 LONG_TIMEOUT: 300000 # 5 minutes MOCHA_REMOTE_REPORTER: mocha-github-actions-reporter @@ -254,7 +225,7 @@ jobs: SPAWN_LOGCAT: true BAAS_BRANCH: master # Pin the Xcode version - DEVELOPER_DIR: /Applications/Xcode_14.3.1.app + DEVELOPER_DIR: /Applications/Xcode_14.2.app IOS_DEVICE_NAME: iPhone 14 runs-on: ${{ matrix.variant.runner }} strategy: @@ -264,9 +235,9 @@ jobs: - { os: linux, target: "test:ci", runner: ubuntu-latest, environment: node } - { os: linux, target: "test:ci:main", runner: ubuntu-latest, environment: electron } - { os: linux, target: "test:ci:renderer", runner: ubuntu-latest, environment: electron } - #- { os: windows, target: "test:ci", runner: windows-latest, environment: node} - #- { os: windows, target: "test:ci:main", runner: windows-latest, environment: electron } - #- { os: windows, target: "test:ci:renderer", runner: windows-latest, environment: electron } + # - { os: windows, target: "test:ci", runner: windows-latest, environment: node} + # - { os: windows, target: "test:ci:main", runner: windows-latest, environment: electron } + # - { os: windows, target: "test:ci:renderer", runner: windows-latest, environment: electron } - { os: darwin, target: "test:ci:main", runner: macos-latest, environment: electron } - { os: darwin, target: "test:ci:renderer", runner: macos-latest, environment: electron } - { os: darwin, target: "test:ci", runner: macos-latest, environment: node } @@ -276,12 +247,12 @@ jobs: timeout-minutes: 60 steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Setup node version - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 cache: npm @@ -293,7 +264,7 @@ jobs: - name: Restore NPM cache id: npm-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.npm-cache-dir.outputs.dir }} key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} @@ -303,14 +274,20 @@ jobs: - name: Restore Wireit cache uses: google/wireit@setup-github-actions-caching/v1 - - name: Restore React Native cache - if: ${{ matrix.variant.environment == 'react-native' }} - uses: actions/cache@v3 + - name: Setup Java + if: ${{ matrix.variant.os == 'android' }} + uses: actions/setup-java@v3 with: - path: '**/Pods' - key: ${{ runner.os }}-${{matrix.variant.environment}}-${{ hashFiles('**/Podfile.lock', './src/**', './vendor/**') }} - restore-keys: | - ${{ runner.os }}-${{matrix.variant.environment}}- + distribution: 'zulu' # See 'Supported distributions' for available options + java-version: '${{env.JAVA_VERSION }}' + + - name: Setup Android SDK + if: ${{ matrix.variant.os == 'android' }} + uses: android-actions/setup-android@v2 + + - name: Install NDK + if: ${{ matrix.variant.os == 'android' }} + run: sdkmanager --install "ndk;${{ env.NDK_VERSION }}" - name: MSVC Setup if: ${{ runner.os == 'Windows' }} @@ -340,10 +317,16 @@ jobs: sudo apt-get install xvfb echo "wrapper=xvfb-run" >> $GITHUB_ENV - - name: Download bundles + - name: Download JSI uses: actions/download-artifact@v3 + if: ${{ matrix.variant.environment == 'react-native' }} with: - name: realm-js-bundles + name: realm-js-jsi + + - name: Download TS Bundle + uses: actions/download-artifact@v3 + with: + name: realm-js-ts - name: Download prebuilds uses: actions/download-artifact@v3 @@ -394,7 +377,7 @@ jobs: - name: Setup Java Gradle cache for android test app if: ${{ (matrix.variant.os == 'android') }} - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.gradle/caches @@ -405,7 +388,7 @@ jobs: - name: Setup Android Emulator cache if: ${{ (matrix.variant.os == 'android') }} - uses: actions/cache@v3 + uses: actions/cache@v4 id: avd-cache with: path: | @@ -413,12 +396,6 @@ jobs: ~/.android/adb* key: avd-29 - - uses: actions/setup-java@v3 - if: ${{ (matrix.variant.os == 'android') }} - with: - distribution: 'zulu' # See 'Supported distributions' for available options - java-version: '17' - - name: Run ${{matrix.variant.target}} (${{ matrix.variant.os}} / ${{ matrix.variant.environment }}) if: ${{ (matrix.variant.os == 'android') }} env: diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 478b9a6200..cdcb7f0433 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -59,7 +59,7 @@ jobs: github_token: ${{ secrets.REALM_CI_PAT }} name: realm-js-prebuilds - - name: Download bundle artifacts from PR + - name: Download ts bundle artifacts from PR uses: dawidd6/action-download-artifact@d0f291cf39bd21965ea9c4c6e210fc355c3844ed with: workflow: pr-realm-js.yml @@ -67,7 +67,17 @@ jobs: path: ${{ github.workspace }} workflow_conclusion: "" # Ignores workflow conclusion github_token: ${{ secrets.REALM_CI_PAT }} - name: realm-js-bundles + name: realm-js-ts + + - name: Download jsi artifacts from PR + uses: dawidd6/action-download-artifact@d0f291cf39bd21965ea9c4c6e210fc355c3844ed + with: + workflow: pr-realm-js.yml + commit: ${{ inputs.commit || github.sha }} + path: ${{ github.workspace }} + workflow_conclusion: "" # Ignores workflow conclusion + github_token: ${{ secrets.REALM_CI_PAT }} + name: realm-js-jsi - name: Read version id: get-version diff --git a/.gitignore b/.gitignore index 5b91ac900c..4deb08c1c6 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,6 @@ yarn.lock /android /packages/realm/react-native/android/src/main/jni/core /packages/realm/react-native/android/.cxx/ -/packages/realm/build-android/ .idea .gradle local.properties @@ -96,15 +95,9 @@ coverage/ **/imported-apps/ **/realm-config -#Ignore symlinked directories (otherwise on Windows they are shown as untracked files) -/react-native/android/src/main/jni/vendor/ -/react-native/android/src/main/jni/src/ /build-tmp*/ /cmakebuild/ -/react-native/android/src/main/java/io/realm/react/Version.java -/react-native/android/src/main/jniLibs/ /realm*.tgz -/react-native/ios/realm-js-ios.xcframework/ # Ignore template package-lock.json files /templates/*/package-lock.json @@ -113,13 +106,15 @@ coverage/ # Generated artifacts /packages/realm/bindgen/vendor/bindgen-lib/generated/ /packages/realm/generated/ +/packages/realm/binding/jsi/jsi_init.cpp # Build artifacts /packages/realm/dist/ /packages/realm/prebuilds/ /packages/realm/react-native/android/src/main/java/io/realm/react/Version.java /packages/realm/react-native/android/src/main/jniLibs/ -/packages/realm/react-native/ios/realm-js-ios.xcframework/ +/packages/realm/react-native/ios/lib/ +/packages/realm/react-native/ios/input-files.xcfilelist # Wireit repo caches .wireit diff --git a/CHANGELOG.md b/CHANGELOG.md index 95b3cd3f20..6a3514fd80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ * None ### Enhancements -* None +* Building for iOS and Android has been optimized for compatibility with future React Native versions. + * Android builds now compile on the consumers machine rather than through prebuilds. + * iOS builds also compile on the consumers machine and can opt-in to compile Realm Core from source with the `REALM_BUILD_CORE` flag when running `pod install`. + * Package size has decreased since prebuilds have been removed. ### Fixed * Fixed `User#callFunction` to correctly pass arguments to the server. Previously they would be sent as an array, so if your server-side function used to handle the unwrapping of arguments, it would need an update too. The "functions factory" pattern of calling `user.functions.sum(1, 2, 3)` wasn't affected by this bug. Thanks to @deckyfx for finding this and suggesting the fix! ([#6447](https://github.com/realm/realm-js/issues/6447), since v12.0.0) diff --git a/contrib/building.md b/contrib/building.md index 072294fba6..3c40c16fb5 100644 --- a/contrib/building.md +++ b/contrib/building.md @@ -22,8 +22,8 @@ - [Building for Node.js](#building-for-nodejs) - [Additional steps for Windows](#additional-steps-for-windows) - [Building for ARM/Linux](#building-for-armlinux) - - [Building the documentation](#building-the-documentation) - [Cleaning up build files](#cleaning-up-build-files) + - [Building the documentation](#building-the-documentation) - [Running the tests](#running-the-tests) - [Linting the source code](#linting-the-source-code) - [JS/TS](#jsts) @@ -201,15 +201,22 @@ Other editors should also be able to be configured to use the `compile_commands. You can build and bundle for iOS by running the following command from the root directory: ```sh -npm run build:ios --workspace realm +npm run bindgen:generate:jsi --workspace realm npm run bundle --workspace realm ``` +In the consuming project, be sure to enable building core from source by setting the environment variable `REALM_BUILD_CORE`. +This can either be set globally or locally before running `pod install`: +``` +REALM_BUILD_CORE=1 pod install +``` + ### Building for Android You can build and bundle for Android by running the following command from the root directory: ```sh +npm run bindgen:generate:jsi --workspace realm npm run build:android --workspace realm npm run bundle --workspace realm ``` diff --git a/contrib/debug-rn-examples.md b/contrib/debug-rn-examples.md index 85083123f0..b926d0135d 100644 --- a/contrib/debug-rn-examples.md +++ b/contrib/debug-rn-examples.md @@ -99,14 +99,9 @@ Since we want to keep the simplicity for our users, changes made in order to deb ## Common Issues -### Android or iOS doesn't find Realm. +### Android doesn't find Realm. -Make sure to build binaries for Android and iOS in packages/realm by running: - -``` -npm run build:ios --workspace=realm -``` -or +Make sure to build binaries for Android in packages/realm by running: ``` npm run build:android --workspace=realm diff --git a/contrib/debugging-react-native.md b/contrib/debugging-react-native.md index a54c8d6304..8c6bfe23f9 100644 --- a/contrib/debugging-react-native.md +++ b/contrib/debugging-react-native.md @@ -11,12 +11,15 @@ It is assumed the developer has their machine prepared to build realm and react- The instructions below also assume that the developer is working on a MacOS system and have Xcode installed. In your realm-js project, run the following commands to prepare for debug mode: -``` +```sh # install js dependencies, but skip building the node binaries -$ npm install --ignore-scripts +npm install --ignore-scripts +``` -# build the xcframework -$ ./scripts/build-ios.sh -c Debug -s +When running `pod install` for iOS, be sure to set the environment variable `REALM_BUILD_CORE=1`. This will flag core to be built from source with the Debug configuration. + +```sh +REALM_BUILD_CORE=1 npx pod-install ``` You are now prepared to either use the [ReactTestApp](#setup-reacttestapp) or [prepare a custom project](#setup-custom-react-native-project) @@ -25,24 +28,24 @@ You are now prepared to either use the [ReactTestApp](#setup-reacttestapp) or [p There is a test application in `tests/ReactTestApp` which will run all the unit tests living in `tests/js`. This is a good place to start. It is already setup to debug the JS code and the C++ source is included by reference in the Xcode project. However this will require some steps before it is ready to run. -``` +```sh # install the js test dependencies -$ cd tests -$ npm install +cd tests +npm install -# install the test app dependencies and copy realm and realm tests into node_modules using `install-local` -$ cd ReactTestApp -$ npm install -$ npx install-local -$ npx pod-install +# install the test app dependencies and copy realm and realm tests into node_modules using `install-local` +cd ReactTestApp +npm install +npx install-local +npx pod-install # open the project in xcode -$ open ios/ReactTestApp.xcworkspace +open ios/ReactTestApp.xcworkspace ``` You should now be able to move onto -- [Debugging Javascript](#debugging-javascript) -- [Debugging C++](#debugging-c++) +- [Debugging Javascript](#debugging-javascript) +- [Debugging C++](#debugging-c++) ## Setup Custom React Native Project diff --git a/integration-tests/environments/react-native/README.md b/integration-tests/environments/react-native/README.md index ef8bad6644..962ed1cd81 100644 --- a/integration-tests/environments/react-native/README.md +++ b/integration-tests/environments/react-native/README.md @@ -18,14 +18,20 @@ To install this environment, run the following command from the root directory o npx lerna bootstrap --scope @realm/react-native-tests --include-dependencies ``` -For iOS environments run +For iOS environments run ```bash -npx pod-install +npx pod-install ``` within the `integration-tests/environments/react-native` directory. +To build iOS with debug symbols, run `pod install` with the environment variable `REALM_BUILD_CORE`. + +```bash +REALM_BUILD_CORE=1 npx pod-install +``` + ## Running the tests To run tests on Android, start an emulator and run: @@ -216,5 +222,5 @@ Open the `package.json` of both `react-native` and `react-native-backup`: Install dependencies again to run the `prepare` script (from the root of the repository): ```bash -npx lerna bootstrap +npm install ``` diff --git a/integration-tests/environments/react-native/ios/Podfile b/integration-tests/environments/react-native/ios/Podfile index 8f7c6de1aa..f5a82f5024 100644 --- a/integration-tests/environments/react-native/ios/Podfile +++ b/integration-tests/environments/react-native/ios/Podfile @@ -58,7 +58,7 @@ target 'RealmReactNativeTests' do installer.pods_project.targets.each do |target| if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle" target.build_configurations.each do |config| - config.build_settings['CODE_SIGN_IDENTITY[sdk=macosx*]'] = '-' + config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' end end target.build_configurations.each do |config| diff --git a/integration-tests/environments/react-native/package.json b/integration-tests/environments/react-native/package.json index ae3f7c9fe0..3453223358 100644 --- a/integration-tests/environments/react-native/package.json +++ b/integration-tests/environments/react-native/package.json @@ -29,18 +29,16 @@ "test": { "command": "npm run test:android && npm run test:ios" }, - "pod-install:simulator": { + "pod-install": { "command": "pod-install || (cd ios && bundle install && bundle exec pod install)", "dependencies": [ - { - "script": "../../../packages/realm:build:ios:debug:simulator", - "cascade": false - } + "../../../packages/realm:prepare:ios", + "../../../packages/realm:bindgen:generate:jsi" ], - "clean": "if-file-deleted", "files": [ "ios/Podfile", - "../../../packages/realm/react-native/ios/realm-js-ios.xcframework" + "../../../packages/realm/RealmJS.podspec", + "../../../packages/realm/scripts/*" ], "output": [ "ios/Pods", @@ -55,49 +53,13 @@ } } }, - "pod-install:catalyst": { - "command": "pod-install || (cd ios && bundle install && bundle exec pod install)", - "dependencies": [ - { - "script": "../../../packages/realm:build:ios:debug:catalyst", - "cascade": false - } - ], - "files": [ - "ios/Podfile", - "../../../packages/realm/react-native/ios/realm-js-ios.xcframework" - ], - "output": [ - "ios/Pods", - "ios/Podfile.lock" - ], - "env": { - "USE_HERMES": { - "external": true - }, - "RCT_NEW_ARCH_ENABLED": { - "external": true - } - } - }, - "pod-install:ci": { - "command": "pod-install", - "env": { - "USE_HERMES": { - "external": true - }, - "RCT_NEW_ARCH_ENABLED": { - "external": true - } - } - }, "common": { "command": "mocha-remote --reporter @realm/mocha-reporter --watch $WATCH -- concurrently --kill-others-on-fail npm:metro npm:runner" }, "test:android": { "command": "npm run common", "dependencies": [ - "../../../packages/realm:build:android", + "../../../packages/realm:bindgen:generate:jsi", "../../../packages/realm:bundle", "../../../packages/mocha-reporter:bundle" ], @@ -115,7 +77,7 @@ "test:ios": { "command": "npm run common", "dependencies": [ - "pod-install:simulator", + "pod-install", "../../../packages/realm:bundle", "../../../packages/mocha-reporter:bundle" ], @@ -127,7 +89,7 @@ "test:catalyst": { "command": "npm run common", "dependencies": [ - "pod-install:catalyst", + "pod-install", "../../../packages/realm:bundle", "../../../packages/mocha-reporter:bundle" ], @@ -145,7 +107,7 @@ "test:ci:ios": { "command": "npm run common:ci", "dependencies": [ - "pod-install:ci" + "pod-install" ], "env": { "PLATFORM": "ios" @@ -167,7 +129,6 @@ "command": "npm run common", "dependencies": [ "pod-install:simulator", - "../../../packages/realm:build:ios:debug:simulator", "../../../packages/realm:bundle", "../../../packages/mocha-reporter:bundle" ], @@ -180,7 +141,6 @@ "command": "npm run common", "dependencies": [ "pod-install:catalyst", - "../../../packages/realm:build:ios:debug:catalyst", "../../../packages/realm:bundle", "../../../packages/mocha-reporter:bundle" ], diff --git a/packages/realm/README.md b/packages/realm/README.md index 637c79d59f..91e9680768 100644 --- a/packages/realm/README.md +++ b/packages/realm/README.md @@ -140,7 +140,7 @@ rm -rf ios/Pods rm ios/Podfile.lock rm -rf ~/Library/Developer/Xcode/DerivedData ``` -Afterwards, reinstall pods and try again. If this still doesn't work, ensure that `node_modules/realm/react-native/ios/realm-js-ios.xcframework` exists and contains a binary for your architecture. If this is missing, try reinstalling the `realm`` npm package. +Afterwards, reinstall pods and try again. If this still doesn't work, ensure that `node_modules/realm/react-native/ios/lib` directory exists and contains libraries (`.a` files). If this is missing, try reinstalling the `realm` npm package and as well as cocoapods. #### Android This can occur when installing `realm` and not performing a clean build. The following commands can be used to clear your cache: diff --git a/packages/realm/RealmJS.podspec b/packages/realm/RealmJS.podspec index c12bf2ba16..c916119940 100644 --- a/packages/realm/RealmJS.podspec +++ b/packages/realm/RealmJS.podspec @@ -5,6 +5,8 @@ package = JSON.parse(File.read(File.expand_path('package.json', __dir__))) app_path = File.expand_path('../..', __dir__) +cmake_path = Pod::Executable::which('cmake') + # There is no API to detect the use of "use_frameworks!" in the Podfile which depends on this Podspec. # The "React" framework is only available and should be used if the Podfile calls use_frameworks! # Therefore we make an assumption on the location of the Podfile and check if it contains "use_frameworks!" ... @@ -35,13 +37,16 @@ Pod::Spec.new do |s| s.homepage = package['homepage'] s.platform = :ios, '9.0' - # The source field is a required field in the podspec, but it is not ment to be used. - # This is because the Podspec is not ment to be published into a CocoaPod repository, instead React Native uses a :path style dependency when adding this to the users projects Podfile. + # The source field is a required field in the podspec, but it is not meant to be used. + # This is because the Podspec is not meant to be published into a CocoaPod repository, instead React Native uses a :path style dependency when adding this to the users projects Podfile. # @see https://guides.cocoapods.org/using/the-podfile.html#using-the-files-from-a-folder-local-to-the-machine # @see https://github.com/react-native-community/cli/blob/master/docs/autolinking.md#platform-ios s.source = { :http => 'https://github.com/realm/realm-js/blob/main/CONTRIBUTING.md#how-to-debug-react-native-podspec' } - s.source_files = 'react-native/ios/RealmReact/*.mm' + s.source_files = 'react-native/ios/RealmReact/*.mm', + 'binding/jsi/*.cpp', + 'binding/ios/platform.mm' + s.public_header_files = 'react-native/ios/RealmReact/*.h' s.frameworks = uses_frameworks ? ['React'] : [] @@ -50,21 +55,42 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { # Setting up clang - 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17', + 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20', 'CLANG_CXX_LIBRARY' => 'libc++', # Setting the current project version and versioning system to get a symbol for analytics 'CURRENT_PROJECT_VERSION' => s.version, + 'REALM_BUILD_CORE' => ENV["REALM_BUILD_CORE"] == "1", + 'CMAKE_PATH' => cmake_path, 'VERSIONING_SYSTEM' => 'apple-generic', + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) REALM_ENABLE_SYNC=1', + 'GCC_SYMBOLS_PRIVATE_EXTERN' => 'YES', # Header search paths are prefixes to the path specified in #include macros 'HEADER_SEARCH_PATHS' => [ '"$(PODS_TARGET_SRCROOT)/react-native/ios/RealmReact/"', - '"$(PODS_ROOT)/Headers/Public/React-Core/"' - #"'#{app_path}/ios/Pods/Headers/Public/React-Core'" # Use this line instead of 👆 while linting + '"$(PODS_TARGET_SRCROOT)/react-native/ios/build/include/"', + '"$(PODS_TARGET_SRCROOT)/binding/"', + '"$(PODS_TARGET_SRCROOT)/bindgen/src/"', + '"$(PODS_TARGET_SRCROOT)/bindgen/vendor/realm-core/bindgen/src/"' ].join(' ') } + # Create placeholders for vendored_libraries, so they are added to the xcode project + s.prepare_command = <<-EOS + source "#{__dir__}/scripts/generate-dummy-libs.sh" + source "#{__dir__}/scripts/generate-input-list.sh" + EOS - # TODO: Consider providing an option to build with the -dbg binaries instead - s.vendored_frameworks = 'react-native/ios/realm-js-ios.xcframework' + s.vendored_libraries = "react-native/ios/lib/*.a" s.dependency 'React' + + # Post install script + s.script_phase = { + :name => 'Retrieve libraries and headers', + :execution_position => :before_compile, + :input_file_lists => ["$(PODS_TARGET_SRCROOT)/react-native/ios/input-files.xcfilelist"], + :output_file_lists => ["$(PODS_TARGET_SRCROOT)/react-native/ios/output-files.xcfilelist"], + :script => <<-EOS + source "$PODS_TARGET_SRCROOT/scripts/download-or-build-ios.sh" + EOS + } end diff --git a/packages/realm/bindgen/CMakeLists.txt b/packages/realm/bindgen/CMakeLists.txt index b4c14d541e..f93147446d 100644 --- a/packages/realm/bindgen/CMakeLists.txt +++ b/packages/realm/bindgen/CMakeLists.txt @@ -119,7 +119,7 @@ endif() target_include_directories(realm-js PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") -set(SDK_DIR ${PACKAGE_ROOT_DIR}/packages/realm) +set(SDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) set(BINDING_DIR ${SDK_DIR}/binding) target_include_directories(realm-js PRIVATE "${BINDING_DIR}") @@ -183,22 +183,10 @@ if(DEFINED CMAKE_JS_VERSION) else() include(jsi.cmake) - bindgen( - TEMPLATE ${SDK_DIR}/bindgen/src/templates/jsi.ts - OUTPUTS jsi_init.cpp - OUTDIR ${CMAKE_CURRENT_BINARY_DIR} - SPECS ${JS_SPEC_FILE} - OPTIN ${JS_OPT_IN_FILE} - SOURCES ${SDK_TS_FILES} - ) - - target_sources(realm-js PRIVATE jsi_init.cpp ${CMAKE_JS_SRC}) - + target_sources(realm-js PRIVATE ${BINDING_DIR}/jsi/jsi_init.cpp ${CMAKE_JS_SRC}) + target_include_directories(realm-js PRIVATE vendor/realm-core/bindgen/src) if(ANDROID) add_subdirectory(${BINDING_DIR}/android android) - elseif(CMAKE_SYSTEM_NAME STREQUAL iOS) - add_subdirectory(${BINDING_DIR}/ios ios) - else() # disabling for now to simplify the bootstrapping process. # message(FATAL_ERROR "Only support JSI builds for Android and iOS") endif() diff --git a/packages/realm/bindgen/jsi.cmake b/packages/realm/bindgen/jsi.cmake index e904dfb39d..c1e6aa764e 100644 --- a/packages/realm/bindgen/jsi.cmake +++ b/packages/realm/bindgen/jsi.cmake @@ -4,8 +4,19 @@ # This enables building for iOS on the end-users machine, # where "react-native" is installed as a sibling to our package instead of being a dev-dependency of our package. +if(NOT DEFINED NODE_PATH) + set(NODE_PATH $ENV{NODE_PATH}) + if(NOT NODE_PATH) + find_program(NODE_PATH node) + endif() + # if node is still not defined after the above attempts, then stop everything + if(NOT DEFINED NODE_PATH) + message(FATAL_ERROR "Node.js not found") + endif() +endif() + execute_process( - COMMAND node --print "path.dirname(require.resolve('react-native/package.json'))" + COMMAND ${NODE_PATH} --print "path.dirname(require.resolve('react-native/package.json'))" OUTPUT_VARIABLE REACT_NATIVE_ROOT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY diff --git a/packages/realm/binding/CMakeLists.txt b/packages/realm/binding/CMakeLists.txt index 7bd329353d..f999716705 100644 --- a/packages/realm/binding/CMakeLists.txt +++ b/packages/realm/binding/CMakeLists.txt @@ -1,6 +1,5 @@ # temporary cache bust -add_library(realm-js-shared OBJECT - js_realm.cpp) +add_library(realm-js-shared OBJECT) target_link_libraries(realm-js-shared PUBLIC Realm::ObjectStore) target_include_directories(realm-js-shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/packages/realm/binding/android/CMakeLists.txt b/packages/realm/binding/android/CMakeLists.txt index bf27935f43..f93a51d120 100644 --- a/packages/realm/binding/android/CMakeLists.txt +++ b/packages/realm/binding/android/CMakeLists.txt @@ -1,25 +1,16 @@ cmake_minimum_required(VERSION 3.18.1) -set(REACT_NATIVE_ROOT_DIR "${PACKAGE_ROOT_DIR}/node_modules/react-native") -set(REACT_NATIVE_AAR_DIR "${CMAKE_BINARY_DIR}/../react-native-aar") # TODO: Could we use CMAKE_BINARY_DIR instead? -set(REACT_NATIVE_VERSION "0.71.0") - -set(JSI_HEADER_DIR "${REACT_NATIVE_ROOT_DIR}/ReactCommon/jsi") - add_library(realm-js-android SHARED - # $ hack.cpp platform.cpp jni_utils.cpp io_realm_react_RealmReactModule.cpp - ${REACT_NATIVE_ROOT_DIR}/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.cpp ) set_target_properties(realm-js-android PROPERTIES OUTPUT_NAME "realm" PREFIX "lib" SUFFIX ".so" - LIBRARY_OUTPUT_DIRECTORY "${PACKAGE_ROOT_DIR}/packages/realm/react-native/android/src/main/jniLibs/${ANDROID_ABI}" ) target_compile_definitions(realm-js-android PRIVATE @@ -28,57 +19,6 @@ target_compile_definitions(realm-js-android PRIVATE REALM_HAVE_CONFIG=1 ) -# Extract .so files from the React Native AAR -if(NOT EXISTS ${REACT_NATIVE_AAR_DIR}) - set(REACT_ANDROID_LIB_URL "https://repo1.maven.org/maven2/com/facebook/react/react-android/${REACT_NATIVE_VERSION}/react-android-${REACT_NATIVE_VERSION}-release.aar") - message(STATUS "Getting ${REACT_ANDROID_LIB_URL}") - file(DOWNLOAD "${REACT_ANDROID_LIB_URL}" "${REACT_NATIVE_AAR_DIR}/react-android-${REACT_NATIVE_VERSION}-release.aar" STATUS download_status) - - list(GET download_status 0 status_code) - if (NOT "${status_code}" STREQUAL "0") - message(FATAL_ERROR "Downloading ${url}... Failed. Status: ${download_status}") - endif() - - message(STATUS "Uncompressing ${REACT_NATIVE_AAR_DIR}/react-android-${REACT_NATIVE_VERSION}-release.aar") - execute_process( - COMMAND ${CMAKE_COMMAND} -E tar xfz "react-android-${REACT_NATIVE_VERSION}-release.aar" - WORKING_DIRECTORY "${REACT_NATIVE_AAR_DIR}" - ) -endif() - -set(REACT_NATIVE_SO_DIR "${REACT_NATIVE_AAR_DIR}/jni/${ANDROID_ABI}") - -target_link_directories(realm-js-android PRIVATE ${REACT_NATIVE_SO_DIR}) -target_include_directories(realm-js-android PRIVATE ${JSI_HEADER_DIR}) - -# FBJNI_ROOT_DIR allows sharing the same directory for all architectures and skip re-downloading -if(NOT FBJNI_ROOT_DIR) - # set FBJNI_ROOT_DIR to current dir - set(FBJNI_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}") -endif() - -set(FBJNI_LIB_DIR "${FBJNI_ROOT_DIR}/jni/${ANDROID_ABI}") -set(FBJNI_LIB_FILE "${JSC_LIB_DIR}/libfbjni.so") -set(FBJNI_INCLUDE_DIR "${FBJNI_ROOT_DIR}/prefab/modules/fbjni/include") - -if(NOT EXISTS ${FBJNI_LIB_DIR}) - set(FBJNI_LIB_URL "https://repo1.maven.org/maven2/com/facebook/fbjni/fbjni/0.2.2/fbjni-0.2.2.aar") - - message(STATUS "Getting ${FBJNI_LIB_URL}...") - file(DOWNLOAD "${FBJNI_LIB_URL}" "${FBJNI_ROOT_DIR}/fbjni-0.2.2.aar" STATUS download_status) - - list(GET download_status 0 status_code) - if (NOT "${status_code}" STREQUAL "0") - message(FATAL_ERROR "Downloading ${url}... Failed. Status: ${download_status}") - endif() - - message(STATUS "Uncompressing ${FBJNI_ROOT_DIR}/fbjni-0.2.2.aar") - execute_process( - COMMAND ${CMAKE_COMMAND} -E tar xfz "fbjni-0.2.2.aar" - WORKING_DIRECTORY "${FBJNI_ROOT_DIR}" - ) -endif() - if (ANDROID_ABI MATCHES "^armeabi") target_compile_definitions(realm-js-android PUBLIC REALM_WRAP_MEMMOVE=1) target_link_options(realm-js-android PUBLIC -Wl,--wrap=memmove -Wl,--wrap=memcpy) @@ -94,6 +34,7 @@ target_link_options(realm-js-android PUBLIC -fvisibility=hidden) if (CMAKE_BUILD_TYPE STREQUAL "Release") set(REALM_LINKER_FLAGS "${REALM_LINKER_FLAGS} -Wl,-gc-sections -Wl,--exclude-libs,ALL") endif() + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${REALM_LINKER_FLAGS}") if(REALM_JS_BUILD_CORE_FROM_SOURCE AND TARGET ObjectStore) @@ -104,21 +45,18 @@ if(REALM_JS_BUILD_CORE_FROM_SOURCE AND TARGET ObjectStore) ) endif() -# Setup fbjni library -find_library(FBJNI_LIBRARY fbjni PATHS ${FBJNI_LIB_DIR} NO_CMAKE_FIND_ROOT_PATH) -target_include_directories(realm-js-android PUBLIC - ${FBJNI_INCLUDE_DIR} - ${REACT_NATIVE_ROOT_DIR}/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/ - ${REACT_NATIVE_ROOT_DIR}/ReactAndroid/src/main/jni/react/turbomodule/ - ${REACT_NATIVE_ROOT_DIR}/ReactCommon/callinvoker/ +target_include_directories(realm-js-android PRIVATE + "${REACT_NATIVE_ROOT_DIR}/ReactCommon/callinvoker" ) +find_package(fbjni REQUIRED CONFIG) +find_package(ReactAndroid REQUIRED CONFIG) target_link_libraries(realm-js-android - ${FBJNI_LIBRARY} realm-js - #realm-js-jsi - #realm-js-shared - jsi + ReactAndroid::jsi + ReactAndroid::reactnativejni + ReactAndroid::turbomodulejsijni + fbjni::fbjni ) if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") diff --git a/packages/realm/binding/jsi/jsi_init.cpp b/packages/realm/binding/jsi/jsi_init.cpp deleted file mode 100644 index 73eef2ba55..0000000000 --- a/packages/realm/binding/jsi/jsi_init.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//////////////////////////////////////////////////////////////////////////// - - -#include "jsi_init.hpp" - -#if !REALM_ENABLE_SYNC -#pragma comment(lib, "ws2_32.lib") -#pragma comment(lib, "crypt32") -#endif - -#include "js_realm.hpp" -#include "js_notifications.hpp" - -#include -#include - -namespace realmjsi = realm::js::realmjsi; -namespace fbjsi = facebook::jsi; - -namespace realm { -namespace js { - -std::function flush_ui_queue; - -} // namespace js -} // namespace realm - -namespace realm::js::jsi { -extern "C" void realm_jsi_init(fbjsi::Runtime& rt, fbjsi::Object& exports, std::function flush_ui_queue) -{ - // Store the function used to flush React Native microtask queue - js::flush_ui_queue = flush_ui_queue; - - auto env = JsiEnv(rt); - fbjsi::Function realm_constructor = js::RealmClass::create_constructor(env); - auto name = realm_constructor.getProperty(env, "name").asString(env); - exports.setProperty(env, std::move(name), std::move(realm_constructor)); -} - -extern "C" void realm_jsi_invalidate_caches() -{ - // Close all cached Realms - realm::_impl::RealmCoordinator::clear_all_caches(); - // Clear the Object Store App cache, to prevent instances from using a context that was released - realm::app::App::clear_cached_apps(); - // Clear notifications - realm::js::notifications::NotificationBucket::clear(); - realm::js::notifications::NotificationBucket::Token>::clear(); - realm::js::notifications::NotificationBucket::Token>::clear(); - // Ensure all registered invalidators get notified that the runtime is going away. - realm::js::Context::invalidate(); -} - -// Note: This must be called before RJSInvalidateCaches, otherwise the app cache -// will have been cleared and so no sync sessions will be closed -extern "C" void realm_jsi_close_sync_sessions() -{ - // Force all sync sessions to close immediately. This prevents the new JS thread - // from opening a new sync session while the old one is still active when reloading - // in dev mode. - realm::app::App::close_all_sync_sessions(); -} -} // namespace realm::js::jsi - -// TODO hook up as TurboModule diff --git a/packages/realm/package.json b/packages/realm/package.json index 581bc731ef..7c32ad848d 100644 --- a/packages/realm/package.json +++ b/packages/realm/package.json @@ -53,12 +53,14 @@ "index.node.js", "index.react-native.js", "types.d.cts", - "react-native/android", - "react-native/ios/realm-js-ios.xcframework", - "react-native/ios/realm-js-ios.xcframework/**/*.a", + "react-native/android/**/*{.gradle,.java,.xml}", "react-native/ios/RealmReact", - "bindgen/vendor/realm-core/dependencies.list", - "scripts/submit-analytics.mjs", + "react-native/ios/output-files.xcfilelist", + "react-native/shared", + "binding", + "bindgen", + "!bindgen/vendor/realm-core/build-xcode-platforms", + "scripts", "react-native.config.js", "RealmJS.podspec", "binding.gyp" @@ -72,6 +74,7 @@ "bundle:coverage": "ENABLE_TEST_COVERAGE_INSTRUMENTATION=true npm run bundle", "bindgen:configure": "wireit", "bindgen:build:node": "wireit", + "bindgen:generate:jsi": "wireit", "bindgen:generate:typescript": "wireit", "bindgen:generate:wrappers": "wireit", "bindgen:generate:spec-schema": "wireit", @@ -81,11 +84,7 @@ "build:node:prebuild:arm64": "wireit", "build:node:prebuild:x64": "wireit", "build:node:prebuild:ia32": "wireit", - "build:android": "wireit", - "build:ios": "wireit", - "build:ios:debug:simulator": "wireit", - "build:ios:debug:ios": "wireit", - "build:ios:debug:catalyst": "wireit", + "prepare:ios": "wireit", "install": "prebuild-install --runtime napi || echo 'Failed to download prebuild for Realm'", "docs": "wireit", "postinstall": "node ./scripts/submit-analytics.mjs" @@ -131,6 +130,24 @@ "bindgen:configure" ] }, + "bindgen:generate:jsi": { + "command": "realm-bindgen --template bindgen/src/templates/jsi.ts --spec bindgen/vendor/realm-core/bindgen/spec.yml --spec bindgen/js_spec.yml --opt-in bindgen/js_opt_in_spec.yml --output ./binding/jsi", + "dependencies": [ + "bindgen:generate:spec-schema" + ], + "files": [ + "bindgen/vendor/realm-core/bindgen/spec.yml", + "bindgen/vendor/realm-core/bindgen/src", + "bindgen/js_spec.yml", + "bindgen/js_opt_in_spec.yml", + "bindgen/src", + "!bindgen/src/templates", + "bindgen/src/templates/jsi.ts" + ], + "output": [ + "binding/jsi/jsi_init.cpp" + ] + }, "bindgen:generate:typescript": { "command": "realm-bindgen --template bindgen/src/templates/typescript.ts --spec bindgen/vendor/realm-core/bindgen/spec.yml --spec bindgen/js_spec.yml --opt-in bindgen/js_opt_in_spec.yml --output ./generated/ts", "dependencies": [ @@ -219,54 +236,16 @@ "PREBUILD_ARCH": "ia32" } }, - "build:android": { - "command": "tsx ./scripts/build-android.ts", - "files": [ - "bindgen/android/**", - "bindgen/src/**/*.ts", - "bindgen/vendor/realm-core/bindgen/src/**/*.ts", - "bindgen/vendor/realm-core/bindgen/src/**/*.h", - "bindgen/src/**/*.h" - ] - }, - "build:ios": { - "command": "scripts/build-ios.sh -c ${CONFIGURATION:=Release} ${PLATFORMS}", + "prepare:ios": { + "command": "source ./scripts/generate-dummy-libs.sh && source ./scripts/generate-input-list.sh", "files": [ - "../../src/ios/**", - "bindgen/src/**/*.ts", - "bindgen/vendor/realm-core/bindgen/src/**/*.ts", - "bindgen/vendor/realm-core/bindgen/src/**/*.h", - "bindgen/src/**/*.h" + "scripts/generate-dummy-libs.sh", + "scripts/generate-input-list.sh" ], - "env": { - "PLATFORMS": { - "external": true - }, - "CONFIGURATION": { - "external": true - } - } - }, - "build:ios:debug:simulator": { - "command": "npm run build:ios", - "env": { - "PLATFORMS": "simulator", - "CONFIGURATION": "Debug" - } - }, - "build:ios:debug:ios": { - "command": "npm run build:ios", - "env": { - "PLATFORMS": "ios", - "CONFIGURATION": "Debug" - } - }, - "build:ios:debug:catalyst": { - "command": "npm run build:ios", - "env": { - "PLATFORMS": "catalyst", - "CONFIGURATION": "Debug" - } + "output": [ + "react-native/ios/input-files.xcfilelist", + "react-native/ios/lib" + ] }, "docs": { "command": "typedoc", diff --git a/packages/realm/react-native/android/.npmignore b/packages/realm/react-native/android/.npmignore index 67bcc2f727..a2ad8c8259 100644 --- a/packages/realm/react-native/android/.npmignore +++ b/packages/realm/react-native/android/.npmignore @@ -1,2 +1,3 @@ .gradle/ build/ +.cxx/ diff --git a/packages/realm/react-native/android/build.gradle b/packages/realm/react-native/android/build.gradle index 1cf1291f0b..00f9bfd0a9 100644 --- a/packages/realm/react-native/android/build.gradle +++ b/packages/realm/react-native/android/build.gradle @@ -1,63 +1,96 @@ +import org.apache.tools.ant.taskdefs.condition.Os +import java.nio.file.Paths + buildscript { repositories { google() mavenCentral() + mavenLocal() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:7.3.1' } } +apply plugin: 'com.android.library' -allprojects { - repositories { - mavenLocal() - mavenCentral() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$projectDir/../../react-native/android" - } +static def findReactNative(startDir) { + def curPath = startDir.toPath().normalize() + while (curPath) { + def nodeModules = Paths.get(curPath.toString(), "node_modules") + def reactNative = Paths.get(nodeModules.toString(), "react-native") + if (nodeModules.toFile().exists() && reactNative.toFile().exists()) { + return reactNative.toFile() } + curPath = curPath.getParent() + } + throw new GradleException("Unable to find the React Native directory") +} + + +def sanitizeFilePath(String filePath) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + filePath = filePath.replace(File.separatorChar, '/' as char) + } + return filePath +} + +def REACT_NATIVE_ROOT_DIR = sanitizeFilePath(findReactNative(rootProject.projectDir).path); + +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] } -apply plugin: 'com.android.library' android { namespace 'io.realm.react' compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : 28 buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : '28.0.3' - + buildFeatures { + prefab = true + } defaultConfig { minSdkVersion rootProject.hasProperty('minSdkVersion') ? rootProject.minSdkVersion : 16 targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : 28 - } - buildTypes { - debug { - jniDebuggable true + externalNativeBuild { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DREACT_NATIVE_ROOT_DIR=${REACT_NATIVE_ROOT_DIR}" + targets 'realm-js-android' + cppFlags '' + abiFilters (*reactNativeArchitectures()) + } } } - // Do not strip debug symbols from debug builds of Realm buildTypes { debug { + jniDebuggable true packagingOptions { - if (com.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION.compareTo("4.2") >= 0) { - jniLibs.keepDebugSymbols += "**/librealm.so" - } else { - doNotStrip "**/librealm.so" - } + doNotStrip "**/librealm.so" } } } -} -def dependencyType = 'implementation' -try { - project.getConfigurations().getByName('implementation') -} catch (UnknownConfigurationException e) { - dependencyType = 'compile' // Pre 3.0 Android Gradle Plugin + externalNativeBuild { + cmake { + path file('../../bindgen/CMakeLists.txt') + version '3.22.1' + } + } + packagingOptions { + excludes = [ + "META-INF", + "META-INF/**", + "**/libc++_shared.so", + "**/libfbjni.so", + "**/libjsi.so", + "**/libreactnativejni.so", + "**/libturbomodulejsijni.so", + ] + } } project.dependencies { - add(dependencyType, fileTree(dir: 'libs', include: ['*.jar'])) - add(dependencyType, 'com.facebook.react:react-native:+') + implementation "com.facebook.react:react-android" } diff --git a/packages/realm/react-native/ios/RealmReact/RealmReact.mm b/packages/realm/react-native/ios/RealmReact/RealmReact.mm index 55f97afb0c..fdbc748187 100644 --- a/packages/realm/react-native/ios/RealmReact/RealmReact.mm +++ b/packages/realm/react-native/ios/RealmReact/RealmReact.mm @@ -18,7 +18,7 @@ #import "RealmReact.h" -#import +#import #import #import diff --git a/packages/realm/react-native/ios/output-files.xcfilelist b/packages/realm/react-native/ios/output-files.xcfilelist new file mode 100644 index 0000000000..ec12ed985a --- /dev/null +++ b/packages/realm/react-native/ios/output-files.xcfilelist @@ -0,0 +1,8 @@ +$(SRCROOT)/react-native/ios/build/lib/librealm.a +$(SRCROOT)/react-native/ios/build/lib/librealm-sync.a +$(SRCROOT)/react-native/ios/build/lib/librealm-parser.a +$(SRCROOT)/react-native/ios/build/lib/librealm-object-store.a +$(SRCROOT)/react-native/ios/lib/librealm.a +$(SRCROOT)/react-native/ios/lib/librealm-sync.a +$(SRCROOT)/react-native/ios/lib/librealm-parser.a +$(SRCROOT)/react-native/ios/lib/librealm-object-store.a diff --git a/packages/realm/scripts/build-android.ts b/packages/realm/scripts/build-android.ts deleted file mode 100644 index 9dca2033cf..0000000000 --- a/packages/realm/scripts/build-android.ts +++ /dev/null @@ -1,148 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//////////////////////////////////////////////////////////////////////////// -/* eslint-disable no-console */ - -import commandLineArgs from "command-line-args"; -import fs from "node:fs"; -import path from "node:path"; -import { execFileSync as exec } from "node:child_process"; -import { version } from "../package.json"; - -const packageRoot = path.resolve(__dirname, ".."); - -const NDK_VERSION = "25.1.8937393"; - -const { ANDROID_HOME } = process.env; - -if (!ANDROID_HOME) { - console.error(`Missing env variable ANDROID_HOME`); - process.exit(1); -} - -if (!fs.existsSync(ANDROID_HOME)) { - console.error(`Missing the Android SDK ${ANDROID_HOME}`); - process.exit(1); -} - -const ndkPath = path.resolve(ANDROID_HOME, "ndk", NDK_VERSION); -if (!fs.existsSync(ndkPath)) { - const cmd = `sdkmanager --install "ndk;${NDK_VERSION}"`; - console.error(`Missing Android NDK v${NDK_VERSION} (${ndkPath}) - run: ${cmd}`); - process.exit(1); -} - -const buildTypes = ["Debug", "Release", "RelWithDebInfo", "MinSizeRel"]; -let architectures = ["x86", "armeabi-v7a", "arm64-v8a", "x86_64"]; -const optionDefinitions = [ - { name: "arch", type: validateArchitectures, multiple: false, description: "Build only for a single architecture" }, - { name: "clean", type: Boolean, defaultValue: false, multiple: false, description: "Rebuild from scratch" }, - { - name: "build-type", - type: validateBuildType, - defaultValue: "Release", - multiple: false, - description: "CMAKE_BUILD_TYPE: Debug, Release, RelWithDebInfo, MinSizeRel", - }, -]; -const options = commandLineArgs(optionDefinitions, { camelCase: true }); - -if (options.arch) { - architectures = [options.arch]; -} - -const buildType = options.buildType; - -const cmakePath = process.platform === "win32" ? "cmake.exe" : "cmake"; - -const buildPath = path.resolve(packageRoot, "build-android"); -if (options.clean) { - if (fs.existsSync(buildPath)) { - fs.rmSync(buildPath, { recursive: true, force: true }); - } -} - -fs.mkdirSync(buildPath, { recursive: true }); - -for (const arch of architectures) { - console.log(`\nBuilding Realm JS Android for ${arch} (${buildType})`); - console.log("======================================="); - //create a build dir per architecture - const archBuildDir = path.resolve(buildPath, arch); - if (!fs.existsSync(archBuildDir)) { - fs.mkdirSync(archBuildDir); - } - - let args = [ - "-GNinja", - `-DANDROID_NDK=${ndkPath}`, - `-DANDROID_ABI=${arch}`, - `-DCMAKE_MAKE_PROGRAM=ninja`, - `-DCMAKE_TOOLCHAIN_FILE=${ndkPath}/build/cmake/android.toolchain.cmake`, - "-DANDROID_TOOLCHAIN=clang", - "-DANDROID_NATIVE_API_LEVEL=16", - `-DCMAKE_BUILD_TYPE=${buildType}`, - "-DANDROID_STL=c++_shared", - path.resolve(packageRoot, "./bindgen"), - ]; - exec(cmakePath, args, { cwd: archBuildDir, stdio: "inherit" }); - - //cwd is the archBuildDir here, hence build the current dir with "--build ." - args = ["--build", "."]; - exec(cmakePath, args, { cwd: archBuildDir, stdio: "inherit" }); -} - -generateVersionFile(); - -function generateVersionFile() { - const targetFile = path.resolve( - packageRoot, - "react-native", - "android", - "src", - "main", - "java", - "io", - "realm", - "react", - "Version.java", - ); - const versionFileContents = `package io.realm.react; - -public class Version { - public static final String VERSION = "${version}"; -} -`; - - fs.writeFileSync(targetFile, versionFileContents); -} - -function validateBuildType(buildTypeOption) { - if (!buildTypes.includes(buildTypeOption)) { - throw new Error(`Invalid build type: ${buildTypeOption}. Supported architectures ${buildTypes}`); - } - - return buildTypeOption; -} - -function validateArchitectures(arch) { - if (!architectures.includes(arch)) { - throw new Error(`"Invalid architecture ${arch}. Supported architectures ${architectures}`); - } - - return arch; -} diff --git a/packages/realm/scripts/build-ios.sh b/packages/realm/scripts/build-ios.sh deleted file mode 100755 index 1773ffd30e..0000000000 --- a/packages/realm/scripts/build-ios.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -# Start in the root directory of the project. -cd "$(dirname "$0")/.." -PROJECT_ROOT=$(pwd) -SDK_PATH=$PROJECT_ROOT -BINDGEN_PATH=$PROJECT_ROOT/bindgen -BINDING_PATH=$PROJECT_ROOT/binding -SCRIPT=$(basename "${BASH_SOURCE[0]}") - -function usage { - echo "Usage: ${SCRIPT} [-c ] []" - echo "" - echo "Arguments:" - echo " -c : build configuration (Debug or Release)" - echo " : platforms to build for (catalyst, ios, or simulator)" - exit 1; -} - -CONFIGURATION=Release -SUPPORT_PLATFORMS=(catalyst ios simulator) - -function is_supported_platform(){ - for platform in "${SUPPORT_PLATFORMS[@]}"; do - [[ "${platform}" == $1 ]] && return 0 - done - return 1 -} - -# Parse the options -while getopts ":c:" opt; do - case "${opt}" in - c) CONFIGURATION=${OPTARG};; - *) usage;; - esac -done - -echo "Configuration: ${CONFIGURATION}" - -shift $((OPTIND-1)) -PLATFORMS=($@) - -if [ -z ${PLATFORMS} ]; then - echo "No platform given. building all platforms..."; - PLATFORMS=(ios catalyst simulator) -else - echo "Building for..."; - for check_platform in "${PLATFORMS[@]}"; do - if ! is_supported_platform $check_platform; then - echo "${check_platform} is not a supported platform" - usage - exit 1 - fi - echo ${check_platform}; - done -fi - -DESTINATIONS=() -LIBRARIES=() -BUILD_LIB_CMDS=() - -for platform in "${PLATFORMS[@]}"; do - case "$platform" in - ios) - DESTINATIONS+=(-destination 'generic/platform=iOS') - LIBRARIES+=(-library ./out/$CONFIGURATION-iphoneos/librealm-js-ios.a -headers ./_include) - BUILD_LIB_CMDS+=("xcrun libtool -static -D -o ./out/$CONFIGURATION-iphoneos/librealm-js-ios.a ./out/$CONFIGURATION-iphoneos/*.a") - ;; - catalyst) - DESTINATIONS+=(-destination 'platform=macOS,arch=x86_64,variant=Mac Catalyst') - LIBRARIES+=(-library ./out/$CONFIGURATION-maccatalyst/librealm-js-ios.a -headers ./_include) - BUILD_LIB_CMDS+=("xcrun libtool -static -D -o ./out/$CONFIGURATION-maccatalyst/librealm-js-ios.a ./out/$CONFIGURATION-maccatalyst/*.a") - ;; - simulator) - DESTINATIONS+=(-destination 'generic/platform=iOS Simulator') - LIBRARIES+=(-library ./out/$CONFIGURATION-iphonesimulator/librealm-js-ios.a -headers ./_include) - BUILD_LIB_CMDS+=("xcrun libtool -static -D -o ./out/$CONFIGURATION-iphonesimulator/librealm-js-ios.a ./out/$CONFIGURATION-iphonesimulator/*.a") - ;; - *) - echo "${platform} not supported" - usage - exit 1 - ;; - esac -done - -pushd $SDK_PATH/react-native/ios - -mkdir -p build -pushd build - -# If the developer directory is not set, use the default Xcode path -SELECTED_DEVELOPER_DIR="$(xcode-select -p)" -DEVELOPER_DIR="${DEVELOPER_DIR:-${SELECTED_DEVELOPER_DIR}}" - -# Configure CMake project -SDKROOT="$DEVELOPER_DIR/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/" cmake "$BINDGEN_PATH" -GXcode \ - -DCMAKE_TOOLCHAIN_FILE="$BINDGEN_PATH/vendor/realm-core/tools/cmake/xcode.toolchain.cmake" \ - -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)/out/$\$EFFECTIVE_PLATFORM_NAME" \ - -DEVELOPER_DIR="$DEVELOPER_DIR" xcodebuild build \ - -scheme realm-js-ios \ - "${DESTINATIONS[@]}" \ - -configuration $CONFIGURATION \ - CC="$PROJECT_ROOT/../../scripts/ccache-clang.sh" \ - CXX="$PROJECT_ROOT/../../scripts/ccache-clang++.sh" \ - ONLY_ACTIVE_ARCH=NO \ - BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ - SUPPORTS_MACCATALYST=YES - -for cmd in "${BUILD_LIB_CMDS[@]}"; do - eval "${cmd}" -done - -rm -rf _include -mkdir -p _include/realm-js-ios -cp "$BINDING_PATH"/jsi/jsi_init.h _include/realm-js-ios/ - -rm -rf ../realm-js-ios.xcframework -xcodebuild -create-xcframework \ - "${LIBRARIES[@]}" \ - -output ../realm-js-ios.xcframework diff --git a/packages/realm/scripts/download-or-build-ios.sh b/packages/realm/scripts/download-or-build-ios.sh new file mode 100755 index 0000000000..44cd62db7d --- /dev/null +++ b/packages/realm/scripts/download-or-build-ios.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -e +set -o pipefail + +# Start in the root directory of the project. +cd "$(dirname "$0")/.." + +REALM_BUILD_CORE=false +PROJECT_ROOT="$PODS_TARGET_SRCROOT" +BINDGEN_PATH="$PROJECT_ROOT/bindgen" + +pushd "$PROJECT_ROOT/react-native/ios" + +# Should we wipe this directory first? +mkdir -p build +pushd build + +# Get core version +CORE_VERSION=v$(grep "^VERSION=" "$BINDGEN_PATH/vendor/realm-core/dependencies.list" | cut -d '=' -f2) +TAR_FILE_NAME=realm-Release-$CORE_VERSION-$PLATFORM_NAME-devel.tar.gz + +# There are only Release builds available on the CDN +CDN_URL="https://static.realm.io/downloads/core/$CORE_VERSION/$PLATFORM_NAME/Release/$TAR_FILE_NAME" + +# Check if URL is valid and reachable +if ! curl --output /dev/null --silent --head --fail "$CDN_URL"; then + echo "URL $CDN_URL is not valid or reachable." + REALM_BUILD_CORE=true +fi + +if [ "$REALM_BUILD_CORE" == "true" ]; then + # Take homebrew installs as well + CMAKE_DIRECTORY=$(dirname "$CMAKE_PATH") + export PATH="$CMAKE_DIRECTORY:$PATH" + + echo "Building realm-core..." + pushd "$PROJECT_ROOT/bindgen/vendor/realm-core" + + # The `env` call here ensures the environment variables are correctly derived. Without this, the c/c++ compilers will not be found by cmake, when invoked from xcode + env -i PATH="$PATH" DEVELOPER_DIR="$DEVELOPER_DIR" ./tools/build-apple-device.sh -p "$PLATFORM_NAME" -c "$CONFIGURATION" -v "$CORE_VERSION" -f -DREALM_BUILD_LIB_ONLY=1 + cp -R "_CPack_Packages/$PLATFORM_NAME/TGZ/realm-$CONFIGURATION-$CORE_VERSION-$PLATFORM_NAME/devel/*" "$PROJECT_ROOT/react-native/ios/build" + popd +else + # Download core prebuild and extract + curl -o "$TAR_FILE_NAME" "$CDN_URL" + # Check if the download was successful + if [ -f "$TAR_FILE_NAME" ]; then + # Extract the contents + tar -xzf "$TAR_FILE_NAME" + rm "$TAR_FILE_NAME" + else + echo "Failed to find required Realm Core libraries." + fi +fi + +pushd lib + +# Debug builds add '-dbg' to the filename, but xcode has links created, so renaming is necessary +find . -type f -name "*-dbg*" | while read -r file; do + # Construct new filename by removing '-dbg' + newfile=$(echo "$file" | sed 's/-dbg//') + # Rename the file + mv "$file" "$newfile" +done + +# Overwite the linked vendored libraries +cp ./*.a ../../lib + +popd diff --git a/packages/realm/scripts/generate-dummy-libs.sh b/packages/realm/scripts/generate-dummy-libs.sh new file mode 100755 index 0000000000..b6f68d8227 --- /dev/null +++ b/packages/realm/scripts/generate-dummy-libs.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +LIB_DIR=react-native/ios/lib + +rm -rf $LIB_DIR +mkdir $LIB_DIR +pushd $LIB_DIR + +touch librealm.a librealm-sync.a librealm-parser.a librealm-object-store.a +popd diff --git a/packages/realm/scripts/generate-input-list.sh b/packages/realm/scripts/generate-input-list.sh new file mode 100755 index 0000000000..67edf2323a --- /dev/null +++ b/packages/realm/scripts/generate-input-list.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +REALM_CORE_SRC=bindgen/vendor/realm-core +INPUT_FILELIST=react-native/ios/input-files.xcfilelist + +# Clear the file list +> $INPUT_FILELIST + +find "$REALM_CORE_SRC" -type f \( -name "*.h" -o -name "*.cpp" -o -name "*.hpp" -o -name "CMakeLists.txt" -o -name "*.cmake" \) | while read -r file; do + echo "\$(SRCROOT)/$file" >> "$INPUT_FILELIST" +done + +echo "\$(SRCROOT)/bindgen/vendor/realm-core/dependencies.list" >> "$INPUT_FILELIST" +echo "\$(SRCROOT)/bindgen/vendor/realm-core/tools/build-apple-device.sh" >> "$INPUT_FILELIST"