Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More than one file was found with OS independent path 'lib/x86/libnode.so' #19

Open
wants to merge 2 commits into
base: unstable
Choose a base branch
from
Open
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
53 changes: 42 additions & 11 deletions ios/RNNodeJsMobile.m
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,54 @@ - (id)init

-(void)callStartNodeWithScript:(NSString *)script
{
NSArray* nodeArguments = [NSArray arrayWithObjects:
@"node",
@"-e",
script,
nil
];
NSArray* nodeArguments = nil;

NSString* dlopenoverridePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/override-dlopen-paths-preload.js", NODEJS_PROJECT_RESOURCE_PATH] ofType:@""];
// Check if the file to override dlopen lookup exists, for loading native modules from the Frameworks.
if(!dlopenoverridePath)
{
nodeArguments = [NSArray arrayWithObjects:
@"node",
@"-e",
script,
nil
];
} else {
nodeArguments = [NSArray arrayWithObjects:
@"node",
@"-r",
dlopenoverridePath,
@"-e",
script,
nil
];
}
[[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath];
}

-(void)callStartNodeProject:(NSString *)mainFileName
{
NSString* srcPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, mainFileName] ofType:@""];
NSArray* nodeArguments = [NSArray arrayWithObjects:
@"node",
srcPath,
nil
];
NSArray* nodeArguments = nil;

NSString* dlopenoverridePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/override-dlopen-paths-preload.js", NODEJS_PROJECT_RESOURCE_PATH] ofType:@""];
// Check if the file to override dlopen lookup exists, for loading native modules from the Frameworks.
if(!dlopenoverridePath)
{
nodeArguments = [NSArray arrayWithObjects:
@"node",
srcPath,
nil
];
} else {
nodeArguments = [NSArray arrayWithObjects:
@"node",
@"-r",
dlopenoverridePath,
srcPath,
nil
];
}
[[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath];
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"react-native": ">=0.52.0"
},
"dependencies": {
"nodejs-mobile-gyp": "^0.1.0",
"nodejs-mobile-gyp": "^0.2.0",
"ncp": "^2.0.0",
"mkdirp": "^0.5.1",
"xcode": "^0.9.3"
Expand Down
128 changes: 128 additions & 0 deletions scripts/ios-create-plists-and-dlopen-override.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { spawnSync } = require('child_process');

function visitEveryFramework(projectPath) {
var foundFrameworks = [];
function recursivelyFindFrameworks(currentPath) {
let currentFiles = fs.readdirSync(currentPath);
for (let i = 0; i < currentFiles.length; i++) {
let currentFilename = path.normalize(path.join(currentPath,currentFiles[i]));
if (fs.lstatSync(currentFilename).isDirectory()) {
if (currentFilename.endsWith(".node")) {
let frameworkContents = fs.readdirSync(currentFilename);
// Frameworks output by nodejs-mobile-gyp are expected to have only one file inside, corresponding to the proper shared library.
if (frameworkContents.length != 1) {
console.log('Skipping a ".node". Expected to find only one file inside this path: ' + currentFilename);
} else {
let currentBinaryName = frameworkContents[0];
let checkFileType = spawnSync('file', [path.join(currentFilename,currentBinaryName)]);
// File inside a .framework should be a dynamically linked shared library.
if(checkFileType.stdout.toString().indexOf('dynamically linked shared library') > -1)
{
let newFrameworkObject = {
originalFileName: currentFilename,
originalRelativePath: '',
originalBinaryName: currentBinaryName,
newFrameworkName: '',
newFrameworkFileName: ''
};
foundFrameworks.push(newFrameworkObject);
} else {
console.log('Skipping a ".node". Couldn\'t find a dynamically linked shared library inside ' + currentFilename);
}
}
}
recursivelyFindFrameworks(currentFilename);
}
}
}
recursivelyFindFrameworks(projectPath);

if (foundFrameworks.length<1) {
console.log("No valid framework native modules were found. Skipping integrating them into the App.");
return;
}

for (let i = 0; i < foundFrameworks.length; i++) {
// Fill the helper fields for each framework.
let currentFramework = foundFrameworks[i];
currentFramework.originalRelativePath = path.relative(projectPath,currentFramework.originalFileName);

// To make each framework name unique while embedding, use a digest of the relative path.
let hash = crypto.createHash('sha1');
hash.update(currentFramework.originalRelativePath);
currentFramework.newFrameworkName = 'node' + hash.digest('hex');
currentFramework.newFrameworkFileName = path.join(path.dirname(currentFramework.originalFileName),currentFramework.newFrameworkName+'.framework');
}

for (let i = 0; i < foundFrameworks.length; i++) {
// Rename the binaries to the new framework structure and add a .plist
let currentFramework = foundFrameworks[i];
fs.renameSync(currentFramework.originalFileName, currentFramework.newFrameworkFileName);
fs.renameSync(
path.join(currentFramework.newFrameworkFileName,currentFramework.originalBinaryName),
path.join(currentFramework.newFrameworkFileName,currentFramework.newFrameworkName)
);

// Read template Info.plist
let plistXmlContents = fs.readFileSync(path.join(__dirname,'plisttemplate.xml')).toString();

// Replace values with the new bundle name and XCode environment variables.
plistXmlContents = plistXmlContents
.replace(/\{ENV_MAC_OS_X_PRODUCT_BUILD_VERSION\}/g, process.env.MAC_OS_X_PRODUCT_BUILD_VERSION)
.replace(/\{VAR_BINARY_NAME\}/g, currentFramework.newFrameworkName)
.replace(/\{ENV_DEFAULT_COMPILER\}/g, process.env.DEFAULT_COMPILER)
.replace(/\{ENV_PLATFORM_PRODUCT_BUILD_VERSION\}/g, process.env.PLATFORM_PRODUCT_BUILD_VERSION)
.replace(/\{ENV_SDK_VERSION\}/g, process.env.SDK_VERSION)
.replace(/\{ENV_SDK_PRODUCT_BUILD_VERSION\}/g, process.env.SDK_PRODUCT_BUILD_VERSION)
.replace(/\{ENV_SDK_NAME\}/g, process.env.SDK_NAME)
.replace(/\{ENV_XCODE_VERSION_ACTUAL\}/g, process.env.XCODE_VERSION_ACTUAL)
.replace(/\{ENV_XCODE_PRODUCT_BUILD_VERSION\}/g, process.env.XCODE_PRODUCT_BUILD_VERSION);

// Use plutil to generate the plist in the binary format.
let plistGeneration = spawnSync('plutil',[
'-convert',
'binary1', // Will convert the xml plist to binary.
'-o',
path.join(currentFramework.newFrameworkFileName,'Info.plist'), // target Info.plist path.
'-' // read the input from the process stdin.
], {
input: plistXmlContents
});
}

var frameworkOverrideContents = []
for (let i = 0; i < foundFrameworks.length; i++) {
// Generate the contents of a JSON file for overriding dlopen calls at runtime.
let currentFramework = foundFrameworks[i];
frameworkOverrideContents.push(
{
originalpath: currentFramework.originalRelativePath.split(path.sep),
newpath: ['..', 'Frameworks', currentFramework.newFrameworkName+'.framework', currentFramework.newFrameworkName]
}
);
}
fs.writeFileSync(path.join(projectPath, 'override-dlopen-paths-data.json'), JSON.stringify(frameworkOverrideContents));

// Copy runtime script that will override dlopen paths.
fs.copyFileSync(path.join(__dirname,'override-dlopen-paths-preload.js'),path.join(projectPath,'override-dlopen-paths-preload.js'));

for (let i = 0; i < foundFrameworks.length; i++) {
// Put an empty file in each of the .node original locations, since some modules check their existence.
fs.closeSync(fs.openSync(foundFrameworks[i].originalFileName, 'w'));
}

}


if (process.argv.length >=3) {
if (fs.existsSync(process.argv[2])) {
visitEveryFramework(path.normalize(process.argv[2]));
}
process.exit(0);
} else {
console.error("A path is expected as an argument.");
process.exit(1);
}
46 changes: 40 additions & 6 deletions scripts/module-postlink.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,21 @@ else
fi
fi
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
# Delete object files that may already come from within the npm package.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.o" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.a" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type f -delete
# Delete bundle contents that may be there from previous builds.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.node/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type d -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.framework/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d -delete
# 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
if [ -d "$CODESIGNING_FOLDER_PATH"/nodejs-project/node_modules/ ]; then
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
fi
# Get the nodejs-mobile-gyp location
NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-gyp/ && pwd )"
NODEJS_MOBILE_GYP_BIN_FILE="$NODEJS_MOBILE_GYP_DIR"/bin/node-gyp.js
Expand All @@ -205,9 +216,9 @@ NODEJS_HEADERS_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-rea
pushd $CODESIGNING_FOLDER_PATH/nodejs-project/
if [ "$PLATFORM_NAME" == "iphoneos" ]
then
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_node_engine="chakracore" npm_config_arch="arm64" npm --verbose rebuild --build-from-source
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="arm64" npm --verbose rebuild --build-from-source
else
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_node_engine="chakracore" npm_config_arch="x64" npm --verbose rebuild --build-from-source
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="x64" npm --verbose rebuild --build-from-source
fi
popd
`
Expand Down Expand Up @@ -239,7 +250,30 @@ else
fi
fi
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
/usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none $(find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -type f -name "*.node")
# Delete object files
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.o" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.a" -type f -delete
# Create Info.plist for each framework built and loader override.
PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native/scripts/ && pwd )"
NODEJS_PROJECT_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd nodejs-project/ && pwd )"
node "$PATCH_SCRIPT_DIR"/ios-create-plists-and-dlopen-override.js $NODEJS_PROJECT_DIR
# Embed every resulting .framework in the application and delete them afterwards.
embed_framework()
{
FRAMEWORK_NAME="$(basename "$1")"
cp -r "$1" "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"

/usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/$FRAMEWORK_NAME"
}
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d | while read frmwrk_path; do embed_framework "$frmwrk_path"; done

#Delete gyp temporary .deps dependency folders from the project structure.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/.deps/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name ".deps" -type d -delete

#Delete frameworks from their build paths
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.framework/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d -delete
`
var signNativeModulesBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', signNativeModulesBuildPhaseName, firstTargetUUID);
if (signNativeModulesBuildPhase) {
Expand Down
27 changes: 27 additions & 0 deletions scripts/override-dlopen-paths-preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
var fs = require('fs');
var path = require('path');

var substitutionDataFile = path.join(__dirname,'override-dlopen-paths-data.json');
// If the json file exists, override dlopen to load the specified framework paths instead.
if (fs.existsSync(substitutionDataFile)) {
var pathSubstitutionData = JSON.parse(fs.readFileSync(substitutionDataFile, 'utf8'));

var pathSubstitutionDictionary = {};
// Build a dictionary to convert paths at runtime, taking current sandboxed paths into account.
for (let i = 0; i < pathSubstitutionData.length; i++) {
pathSubstitutionDictionary[
path.normalize(path.join.apply(null, [__dirname].concat(pathSubstitutionData[i].originalpath)))
] = path.normalize(path.join.apply(null, [__dirname].concat(pathSubstitutionData[i].newpath)));
}

var old_dlopen = process.dlopen;
// Override process.dlopen
process.dlopen = function(_module, _filename) {
if( pathSubstitutionDictionary[path.normalize(_filename)] ) {
_filename = pathSubstitutionDictionary[path.normalize(_filename)];
}
old_dlopen(_module,_filename);
}
}


57 changes: 57 additions & 0 deletions scripts/plisttemplate.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>{ENV_MAC_OS_X_PRODUCT_BUILD_VERSION}</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>{VAR_BINARY_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.janeasystems.{VAR_BINARY_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>{VAR_BINARY_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>{ENV_DEFAULT_COMPILER}</string>
<key>DTPlatformBuild</key>
<string>{ENV_PLATFORM_PRODUCT_BUILD_VERSION}</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>{ENV_SDK_VERSION}</string>
<key>DTSDKBuild</key>
<string>{ENV_SDK_PRODUCT_BUILD_VERSION}</string>
<key>DTSDKName</key>
<string>{ENV_SDK_NAME}</string>
<key>DTXcode</key>
<string>{ENV_XCODE_VERSION_ACTUAL}</string>
<key>DTXcodeBuild</key>
<string>{ENV_XCODE_PRODUCT_BUILD_VERSION}</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>