Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/react-native-reanimated/android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project(Reanimated)
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.16)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down Expand Up @@ -50,6 +50,9 @@ find_package(react-native-worklets REQUIRED CONFIG)
add_library(reanimated SHARED ${REANIMATED_COMMON_CPP_SOURCES}
${REANIMATED_ANDROID_CPP_SOURCES})

target_precompile_headers(reanimated PRIVATE
"${ANDROID_CPP_DIR}/ReanimatedPCH.h")

if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
include(
"${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-reanimated/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ if (project == rootProject) {
apply plugin: "com.android.library"
apply plugin: "maven-publish"

apply from: "./generate-stub-pch.gradle.kts"

android {
compileSdkVersion safeExtGet("compileSdkVersion", 36)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import groovy.json.JsonSlurper

// Workaround for Android Studio's C++ analyzer surfacing errors during Gradle
// Sync when CMake's precompiled header binary (`cmake_pch.hxx.pch`, generated
// from `ReanimatedPCH.h`) hasn't been built yet. The project compiles fine,
// but on a clean sync the IDE can't index sources without the PCH binary. See
// the underlying issue: https://issuetracker.google.com/issues/187448826

// Generates minimal stub `.pch` files from an empty header so the IDE's C++
// engine doesn't fail during sync. The actual build regenerates the real PCH
// files via ninja because we set each stub PCH's mtime older than its source
// (`cmake_pch.hxx.cxx`).

// Adapted from Expo's PR: https://github.com/expo/expo/pull/45921

val cxxDir = project.file(".cxx")

val generateStubPCHTask = tasks.register("generateStubPCH") {
dependsOn("configureCMakeDebug")
doLast {
if (!cxxDir.exists()) {
return@doLast
}
cxxDir.walkTopDown().forEach { file ->
if (file.name != "compile_commands.json") {
return@forEach
}
@Suppress("UNCHECKED_CAST")
val entries = JsonSlurper().parseText(file.readText()) as List<Map<String, Any>>
entries.forEach entry@{ entry ->
val entryFile = entry["file"] as String
if (!entryFile.endsWith("cmake_pch.hxx.cxx")) {
return@entry
}
val pchFile = File(entryFile.substring(0, entryFile.length - ".cxx".length) + ".pch")
if (!pchFile.exists() || pchFile.length() == 0L) {
pchFile.parentFile.mkdirs()

val command = entry["command"] as String
val compiler = command.split(" ").first()
val target = Regex("""--target=\S+""").find(command)!!.value
val sysroot = Regex("""--sysroot=\S+""").find(command)!!.value

val stubHeader = File(pchFile.parentFile, "stub_pch.hxx")
stubHeader.writeText("")

val process = ProcessBuilder(
compiler,
target,
sysroot,
"-x", "c++-header",
"-o", pchFile.absolutePath,
stubHeader.absolutePath,
)
.directory(File(entry["directory"] as String))
.redirectErrorStream(true)
.start()
process.outputStream.close()
if (process.waitFor() != 0) {
throw GradleException(
"Stub PCH generation failed: ${process.inputStream.bufferedReader().readText()}",
)
}
}
// Ensure PCH is older than source so ninja rebuilds the real one during build
pchFile.setLastModified(File(entryFile).lastModified() - 1)
}
}
}
}

// Register `prepareKotlinBuildScriptModel` if absent (Android Studio sync needs it
// to exist so the stub PCH generation runs) or configure it if some other plugin
// already registered it (e.g. on CI, where re-registering throws `Cannot add task
// 'prepareKotlinBuildScriptModel' as a task with that name already exists.`).
if (tasks.findByName("prepareKotlinBuildScriptModel") == null) {
tasks.register("prepareKotlinBuildScriptModel") {
dependsOn(generateStubPCHTask)
}
} else {
tasks.named("prepareKotlinBuildScriptModel") {
dependsOn(generateStubPCHTask)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

// IWYU pragma: begin_keep

// C++ standard library
#include <algorithm>
#include <atomic>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

// fbjni
#include <fbjni/fbjni.h>

// folly
#include <folly/Conv.h>
#include <folly/Expected.h>
#include <folly/Format.h>
#include <folly/dynamic.h>
#include <folly/json/dynamic.h>

// jsi
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>

// react-native renderer (Fabric)
#include <react/renderer/components/root/RootProps.h>
#include <react/renderer/components/root/RootShadowNode.h>
#include <react/renderer/components/view/BaseViewProps.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/core/EventDispatcher.h>
#include <react/renderer/core/ShadowNode.h>
#include <react/renderer/mounting/ShadowTree.h>
#include <react/renderer/uimanager/UIManager.h>

// IWYU pragma: end_keep
5 changes: 4 additions & 1 deletion packages/react-native-worklets/android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project(Worklets)
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.16)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down Expand Up @@ -68,6 +68,9 @@ endif()
add_library(worklets SHARED ${WORKLETS_COMMON_CPP_SOURCES}
${WORKLETS_ANDROID_CPP_SOURCES})

target_precompile_headers(worklets PRIVATE
"${ANDROID_CPP_DIR}/WorkletsPCH.h")

if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
include(
"${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-worklets/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ if (project == rootProject) {
}

apply from: "./fix-prefab.gradle"
apply from: "./generate-stub-pch.gradle.kts"


android {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import groovy.json.JsonSlurper

// Workaround for Android Studio's C++ analyzer surfacing errors during Gradle
// Sync when CMake's precompiled header binary (`cmake_pch.hxx.pch`, generated
// from `WorkletsPCH.h`) hasn't been built yet. The project compiles fine,
// but on a clean sync the IDE can't index sources without the PCH binary. See
// the underlying issue: https://issuetracker.google.com/issues/187448826

// Generates minimal stub `.pch` files from an empty header so the IDE's C++
// engine doesn't fail during sync. The actual build regenerates the real PCH
// files via ninja because we set each stub PCH's mtime older than its source
// (`cmake_pch.hxx.cxx`).

// Adapted from Expo's PR: https://github.com/expo/expo/pull/45921

val cxxDir = project.file(".cxx")

val generateStubPCHTask = tasks.register("generateStubPCH") {
dependsOn("configureCMakeDebug")
doLast {
if (!cxxDir.exists()) {
return@doLast
}
cxxDir.walkTopDown().forEach { file ->
if (file.name != "compile_commands.json") {
return@forEach
}
@Suppress("UNCHECKED_CAST")
val entries = JsonSlurper().parseText(file.readText()) as List<Map<String, Any>>
entries.forEach entry@{ entry ->
val entryFile = entry["file"] as String
if (!entryFile.endsWith("cmake_pch.hxx.cxx")) {
return@entry
}
val pchFile = File(entryFile.substring(0, entryFile.length - ".cxx".length) + ".pch")
if (!pchFile.exists() || pchFile.length() == 0L) {
pchFile.parentFile.mkdirs()

val command = entry["command"] as String
val compiler = command.split(" ").first()
val target = Regex("""--target=\S+""").find(command)!!.value
val sysroot = Regex("""--sysroot=\S+""").find(command)!!.value

val stubHeader = File(pchFile.parentFile, "stub_pch.hxx")
stubHeader.writeText("")

val process = ProcessBuilder(
compiler,
target,
sysroot,
"-x", "c++-header",
"-o", pchFile.absolutePath,
stubHeader.absolutePath,
)
.directory(File(entry["directory"] as String))
.redirectErrorStream(true)
.start()
process.outputStream.close()
if (process.waitFor() != 0) {
throw GradleException(
"Stub PCH generation failed: ${process.inputStream.bufferedReader().readText()}",
)
}
}
// Ensure PCH is older than source so ninja rebuilds the real one during build
pchFile.setLastModified(File(entryFile).lastModified() - 1)
}
}
}
}

// Register `prepareKotlinBuildScriptModel` if absent (Android Studio sync needs it
// to exist so the stub PCH generation runs) or configure it if some other plugin
// already registered it (e.g. on CI, where re-registering throws `Cannot add task
// 'prepareKotlinBuildScriptModel' as a task with that name already exists.`).
if (tasks.findByName("prepareKotlinBuildScriptModel") == null) {
tasks.register("prepareKotlinBuildScriptModel") {
dependsOn(generateStubPCHTask)
}
} else {
tasks.named("prepareKotlinBuildScriptModel") {
dependsOn(generateStubPCHTask)
}
}
26 changes: 26 additions & 0 deletions packages/react-native-worklets/android/src/main/cpp/WorkletsPCH.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

// IWYU pragma: begin_keep

// C++ standard library
#include <algorithm>
#include <atomic>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

// fbjni
#include <fbjni/fbjni.h>

// jsi
#include <jsi/jsi.h>

// IWYU pragma: end_keep
5 changes: 4 additions & 1 deletion scripts/clang-tidy-lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ if [ ! -f "compile_commands.json" ]; then
)
fi

run-clang-tidy -quiet -p . -header-filter="^.*/$1/.*\.h$" "$1"
ndk_bin="$(grep -oE '/[^ "]+/clang\+\+' compile_commands.json | head -1 | xargs dirname)"

run-clang-tidy -quiet -p . -clang-tidy-binary "$ndk_bin/clang-tidy" \
-header-filter="^.*/$1/.*\.h$" "$1"
Loading