React Native 本体をローカルでビルドする
JavaScript何かとつらいことで定評のある React Native は、コントリビュートもつらい。
実機テストするために「ローカル環境でのビルド」をする必要があったので、備忘録。
注意
- macOS Big Sur
- React Native 0.64-rc 本体
- Android のみ
- RNTester からのビルドではなく React Native 本体をサンドボックス内でビルドする
手順について
Android の場合は公式に Building from source という手順書がある。
ざっくり説明すると、node_modules
に React Native の fork をインストールし、 com.facebook.react:react-native:+
ではなく、'../node_modules/react-native/ReactAndroid'
でビルドしようというもの。
つまり、この手順通りにすればローカルでビルドできる。
そんなわけがなかった。
引っ掛かりポイント
0.63 -> 0.64 問題
node_modules
に React Native 0.64 が入ることになるが、実際は package.json
だけではなく ~/Android
など npm の管轄外でも 0.64 相応にアップデートしないといけない。
さらに 0.64 では React が 17.0 になったし、react-native-codegen に変更があったりする。
つまりupgrade-helper の出番となる。
これを使って、やっていき精神で関連部分を手動アップデート。
今回は Android のみでテストするので、iOS 部分に手をつけていない。
権限問題
手順書の通りに、ビルドに必要な NDK をダウンロードし、パスを設定した。
しかし、macOS Big Sur で実行するとお馴染み「権限がなくて実行できません」アラートが出る。
1つ1つのモジュールに出てきてしまいつらいので、1回ゲートキーパーの設定を切った。
shell
# 無効化する
sudo spctl --master-disable
# 元に戻すときは忘れずに
sudo spctl --master-enable
参考: macOS Gatekeeper周りのまとめ - zenn.dev
wrapNoInt エラー
NDK の問題が解消し、無事にビルドできる…はずなかった。
Folly がタダでは起き上がらせてくれないことをよく知っている(react-native-wind◯ws の愚痴)。
エラーを見ると wrapNoInt
がコケている。
/path/react-native/ReactAndroid/build/third-party-ndk/folly/folly/FileUtil.cpp:37:14: error: no matching function for call to 'wrapNoInt'
return int(wrapNoInt(open, name, flags, mode));
引数に取る open
に起因するらしく、標準の open
と Folly の open
バージョンが一致しないため。
Issue ではワークアラウンド的な対策が載っていたので、そちらを参考にして書き換えることに。
[Android][Linux] Building master RNTester on Linux fails while building Folly · Issue #28298 · facebook/react-native のコメント
node_modules/react-native/ReactAndroid/build.gradle
の task prepareFolly
辺りを以下のように変更。
node_modules/react-native/ReactAndroid/build.gradle
def follyReplaceContent = '''
ssize_t r;
do {
r = open(name, flags, mode);
} while (r == -1 && errno == EINTR);
return r;
'''
task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy) {
from(dependenciesPath ?: tarTree(downloadFolly.dest))
from("src/main/jni/third-party/folly/Android.mk")
include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk")
eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") }
// Fixes problem with Folly failing to build on certain systems. See
// https://github.com/facebook/react-native/issues/28298
filter { line -> line.replaceAll('return int\\(wrapNoInt\\(open, name, flags, mode\\)\\);', follyReplaceContent) }
includeEmptyDirs = false
into("$thirdPartyNdkDir/folly")
}
オチ
なんとか動いたのでなし。
wrapNoInt
問題について Folly 側で修正があるかはまだ追えてない。