Skip to content

Commit

Permalink
plugin: patch node-pre-gyp module path variables
Browse files Browse the repository at this point in the history
Patches node-pre-gyp's binary module_path substitutable variables
with fixed values in the native modules' package.json, so that cross
compiled native modules will be built in the same path where they
are expected to be found at runtime by node-pre-gyp.
Creates a temporary build directory in Android's build steps for this
patching to take place.
  • Loading branch information
jaimecbernardo committed Feb 12, 2018
1 parent 62c2670 commit d933954
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 5 deletions.
41 changes: 36 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,31 @@ dependencies {
compile 'com.facebook.react:react-native:+'
}


task CleanNodeProjectTempAssetsFolder (type: Delete) {
description "Delete the temporary Node Project build folder."
delete "${rootProject.buildDir}/nodejs-assets/"
}

task CopyNodeProjectAssetsFolder (type:Copy) {
dependsOn "CleanNodeProjectTempAssetsFolder"
description "Copies the Node Project to a build folder for manipulation."
from "${rootProject.projectDir}/../nodejs-assets/nodejs-project"
into "${rootProject.buildDir}/nodejs-assets/nodejs-project/"
exclude '**/*~' // temporary files
exclude '**/.*' // files and dirs starting with .
exclude '**/*.gz' // gzip files will cause errors on aapt when merging assets.
}

task GenerateNodeProjectAssetsLists {
dependsOn "CopyNodeProjectAssetsFolder"
description "Generates a list for runtime copying"

doLast{
String file_list = "";
String dir_list = "";

def assets_tree = fileTree(dir: "${rootProject.projectDir}/../nodejs-assets/")
def assets_tree = fileTree(dir: "${rootProject.buildDir}/nodejs-assets/")
assets_tree.include('nodejs-project/**') // Include the node project.
assets_tree.exclude('**/.*') // Exclude files and dirs starting with .
assets_tree.exclude('**/*~') // Exclude temporary files.
Expand All @@ -75,20 +92,27 @@ task GenerateNodeProjectAssetsLists {
file_list += "${assetFile.relativePath}\n"
}
}
def file_list_path = new File( "${rootProject.projectDir}/../nodejs-assets/file.list")
def file_list_path = new File( "${rootProject.buildDir}/nodejs-assets/file.list")
file_list_path.write file_list
def dir_list_path = new File( "${rootProject.projectDir}/../nodejs-assets/dir.list")
def dir_list_path = new File( "${rootProject.buildDir}/nodejs-assets/dir.list")
dir_list_path.write dir_list
}

project.android.sourceSets.main.assets.srcDirs+="${rootProject.projectDir}/../nodejs-assets/"
project.android.sourceSets.main.assets.srcDirs+="${rootProject.buildDir}/nodejs-assets/"
}

tasks.getByPath(":${project.name}:preBuild").dependsOn GenerateNodeProjectAssetsLists

import org.gradle.internal.os.OperatingSystem;

if ("1".equals(System.getenv('NODEJS_MOBILE_BUILD_NATIVE_MODULES'))) {
task ApplyPatchScriptToModules (type:Exec) {
dependsOn "CopyNodeProjectAssetsFolder"
description "Apply patches to modules to improve compatibility."
commandLine 'node', "${project.projectDir}/../scripts/patch-package.js", "${rootProject.buildDir}/nodejs-assets/nodejs-project/node_modules/"
}
GenerateNodeProjectAssetsLists.dependsOn "ApplyPatchScriptToModules"

task CleanNPMTempBuildDir (type: Delete) {
delete "${rootProject.buildDir}/nodejs-native-assets-temp-build/"
}
Expand Down Expand Up @@ -174,11 +198,18 @@ if ("1".equals(System.getenv('NODEJS_MOBILE_BUILD_NATIVE_MODULES'))) {
dependsOn "CopyNodeProjectAssets${abi_name}"
description = "Building a native toolchain to compile nodejs-mobile native modules for ${abi_name}."
executable = "${ndk_bundle_path}/build/tools/make-standalone-toolchain.sh"
args "--toolchain=${temp_toolchain_name}-${temp_cc_ver}", "--arch=${temp_arch}", "--install-dir=${standalone_toolchain}", "--stl=libc++", "--force", "--platform=android-21"
args "--toolchain=${temp_toolchain_name}-${temp_cc_ver}", "--arch=${temp_arch}", "--install-dir=${standalone_toolchain}", "--stl=libc++", "--force", "--platform=android-22"
}

task "ApplyPatchScriptToModules${abi_name}" (type:Exec) {
dependsOn "CopyNodeProjectAssets${abi_name}"
description "Apply patches to modules to improve compatibility for ${abi_name}."
commandLine 'node', "${project.projectDir}/../scripts/patch-package.js", "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/nodejs-project/node_modules/"
}

task "BuildNpmModules${abi_name}" (type:Exec) {
dependsOn "MakeToolchain${abi_name}"
dependsOn "ApplyPatchScriptToModules${abi_name}"
description = "Building native modules for ${abi_name}."
workingDir "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/nodejs-project/"
commandLine 'npm', '--verbose', 'rebuild', '--build-from-source'
Expand Down
5 changes: 5 additions & 0 deletions scripts/module-postlink.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ if ( detectedConfigs && detectedConfigs.ios && detectedConfigs.ios.pbxprojPath)
var rebuildNativeModulesBuildPhaseScript = `
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
set -e
# Apply patches to the modules package.json
PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native/scripts/ && pwd )"
NODEJS_PROJECT_MODULES_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd nodejs-project/node_modules/ && pwd )"
node "$PATCH_SCRIPT_DIR"/patch-package.js $NODEJS_PROJECT_MODULES_DIR
# Rebuild modules with right environment
NODEJS_HEADERS_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native/ios/libnode/ && pwd )"
pushd $CODESIGNING_FOLDER_PATH/nodejs-project/
if [ "$PLATFORM_NAME" == "iphoneos" ]
Expand Down
60 changes: 60 additions & 0 deletions scripts/patch-package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const fs = require('fs');
const path = require('path');

// Patches a package.json in case it has variable substitution for
// the module's binary at runtime. Since we are cross-compiling
// for mobile, this substitution will have different values at
// build time and runtime, so we pre-substitute them with fixed
// values.
function patchPackageJSON_preNodeGyp_modulePath(filePath)
{
let packageReadData = fs.readFileSync(filePath);
let packageJSON = JSON.parse(packageReadData);
if ( packageJSON && packageJSON.binary && packageJSON.binary.module_path ) {
let binaryPathConfiguration = packageJSON.binary.module_path;
binaryPathConfiguration = binaryPathConfiguration.replace(/\{node_abi\}/g, "node_abi");
binaryPathConfiguration = binaryPathConfiguration.replace(/\{platform\}/g, "platform");
binaryPathConfiguration = binaryPathConfiguration.replace(/\{arch\}/g, "arch");
binaryPathConfiguration = binaryPathConfiguration.replace(/\{target_arch\}/g, "target_arch");
packageJSON.binary.module_path = binaryPathConfiguration;
let packageWriteData = JSON.stringify(packageJSON, null, 2);
fs.writeFileSync(filePath, packageWriteData);
}
}

// Visits every package.json to apply patches.
function visitPackageJSON(folderPath)
{
let files = fs.readdirSync(folderPath);
for (var i in files) {
let name = files[i];
let filePath = path.join(folderPath, files[i]);
if(fs.statSync(filePath).isDirectory()) {
visitPackageJSON(filePath);
} else {
if (name === 'package.json') {
try {
patchPackageJSON_preNodeGyp_modulePath(filePath);
} catch (e) {
console.warn(
'Failed to patch the file : "' +
filePath +
'". The following error was thrown: ' +
JSON.stringify(e)
);
}
}
}
}
}

if (process.argv.length >=3)
{
if (fs.existsSync(process.argv[2])) {
visitPackageJSON(process.argv[2]);
}
process.exit(0);
} else {
console.error("A path is expected as an argument.");
process.exit(1);
}

0 comments on commit d933954

Please sign in to comment.