Skip to content

Commit

Permalink
Merge branch 'master' into TIMOB-26966
Browse files Browse the repository at this point in the history
  • Loading branch information
garymathews committed Apr 12, 2019
2 parents 1676b20 + bfd53e3 commit da04a2f
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ android/.idea/modules.xml
android/.idea/scopes/scope_settings.xml
android/.idea/vcs.xml
*.iml

/iphone/TitaniumKit/Carthage
/iphone/TitaniumKit/docs
/iphone/TitaniumKit/build
/iphone/lib/libTiCore.a

.vscode/
android/runtime/v8/src/native/V8Snapshots.h
6 changes: 1 addition & 5 deletions android/build.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<project name="titanium-mobile" default="build">
<property name="ti.android.root" location="${basedir}"/>

<import file="build/common.xml"/>

<target name="full.build" depends="clean,build">
</target>

<target name="full.build" depends="clean,build" />
<target name="clean" depends="clean.all" />

<target name="build" depends="build.all" />
</project>
17 changes: 15 additions & 2 deletions android/cli/commands/_cleanModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const __ = appc.i18n(__dirname).__;
exports.run = function run(logger, config, cli, finished) {
const projectDir = cli.argv['project-dir'];

const toDelete = [ 'build', 'dist', 'libs', 'java-sources.txt' ];
toDelete.forEach((f) => {
const toDelete = [ 'build', 'dist', 'java-sources.txt' ];
toDelete.forEach(f => {
const target = path.join(projectDir, f);
if (appc.fs.exists(target)) {
logger.debug(__('Deleting %s', target.cyan));
Expand All @@ -33,5 +33,18 @@ exports.run = function run(logger, config, cli, finished) {
}
});

// remove only the libraries we generate
const moduleid = cli.manifest.moduleid;
const arches = fs.readdirSync(path.join(projectDir, 'libs'));
arches.forEach(arch => {
const target = path.join(projectDir, 'libs', arch, `lib${moduleid}.so`);
if (appc.fs.exists(target)) {
logger.debug(__('Deleting %s', target.cyan));
fs.removeSync(target);
} else {
logger.debug(__('File does not exist %s', target.cyan));
}
});

finished();
};
2 changes: 1 addition & 1 deletion android/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
],
"architectures": ["arm64-v8a", "armeabi-v7a", "x86"],
"v8": {
"version": "7.0.276.42",
"version": "7.3.492.26",
"mode": "release"
},
"minSDKVersion": "19",
Expand Down
4 changes: 4 additions & 0 deletions android/runtime/v8/src/native/V8Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "V8Util.h"

#include "V8Runtime.h"
#include "V8Snapshots.h"

#define TAG "V8Runtime"

Expand Down Expand Up @@ -225,6 +226,9 @@ JNIEXPORT void JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeIn
// Create a new Isolate and make it the current one.
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
#ifdef V8_SNAPSHOT_H
create_params.snapshot_blob = &snapshot;
#endif
isolate = Isolate::New(create_params);
isolate->Enter();

Expand Down
1 change: 1 addition & 0 deletions android/runtime/v8/src/native/V8Snapshots.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// GENERATED AT BUILD TIME
24 changes: 24 additions & 0 deletions build/lib/android/V8Snapshots.h.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef V8_SNAPSHOT_H
#define V8_SNAPSHOT_H

#include <v8.h>

<% function DEFINE_SNAPSHOT (target, blob) { -%>
<% if (!blob) return -%>
#ifdef __<%- target -%>__
static const unsigned char snapshot_data[] = {
<% for (let i = 0; i < blob.length - 1; i++) { -%>
<%- blob.readUInt8(i) + ',' -%>
<% } -%>
<%- blob.readUInt8(blob.length - 1) %>
};
#endif
<% } -%>
<% DEFINE_SNAPSHOT('i386', x86) -%>
<% DEFINE_SNAPSHOT('arm', arm) -%>
<% DEFINE_SNAPSHOT('aarch64', arm64) -%>

static const int snapshot_size = sizeof(snapshot_data);
static v8::StartupData snapshot = { (const char*) snapshot_data, snapshot_size };

#endif
34 changes: 21 additions & 13 deletions build/lib/android/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const path = require('path');
const fs = require('fs-extra');
const AndroidSDK = require('./androidsdk');
const ant = require('./ant');
const utils = require('../utils');
const copyFile = utils.copyFile;
Expand All @@ -27,25 +28,32 @@ class Android {
this.apiLevel = options.apiLevel;
this.sdkVersion = options.sdkVersion;
this.gitHash = options.gitHash;
this.sdk = new AndroidSDK(this.androidSDK, this.apiLevel);
this.antProperties = {
'build.version': this.sdkVersion,
'build.githash': this.gitHash,
'android.sdk': this.sdk.getAndroidSDK(),
'android.platform': this.sdk.getPlatformDir(),
'google.apis': this.sdk.getGoogleApisDir(),
'kroll.v8.build.x86': 1,
'android.ndk': this.androidNDK
};
}

async clean() {
return ant.build(ANDROID_BUILD_XML, [ 'clean' ], {});
return ant.build(ANDROID_BUILD_XML, [ 'clean' ], this.antProperties);
}

async build() {
const AndroidSDK = require('./androidsdk');
const sdk = new AndroidSDK(this.androidSDK, this.apiLevel);
const properties = {
'build.version': this.sdkVersion,
'build.githash': this.gitHash,
'android.sdk': sdk.getAndroidSDK(),
'android.platform': sdk.getPlatformDir(),
'google.apis': sdk.getGoogleApisDir(),
'kroll.v8.build.x86': 1,
'android.ndk': this.androidNDK
};
return ant.build(ANDROID_BUILD_XML, [ 'full.build' ], properties);
// Clean build and download V8
await this.clean().catch(error => console.error(error));

// Generate snapshots
const snapshot = require('./snapshot');
await snapshot.build().catch(error => console.error(error));

// Build Titanium Android
return ant.build(ANDROID_BUILD_XML, [ 'build' ], this.antProperties);
}

async package(packager) {
Expand Down
110 changes: 110 additions & 0 deletions build/lib/android/snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use strict';

const spawn = require('child_process').spawn; // eslint-disable-line security/detect-child-process
const os = require('os');
const fs = require('fs-extra');
const path = require('path');
const ejs = require('ejs');

const ANDROID_DIR = path.resolve('..', 'android');
const ANDROID_PROPS = require(path.join(ANDROID_DIR, 'package.json')); // eslint-disable-line security/detect-non-literal-require
const V8_PROPS = ANDROID_PROPS.v8;
const V8_LIB_DIR = path.join('..', 'dist', 'android', 'libv8', V8_PROPS.version, V8_PROPS.mode, 'libs');

// Obtain target architectures
const TARGETS = [];
for (const target of ANDROID_PROPS.architectures) {
if (target === 'arm64-v8a') {
TARGETS.push('arm64');
} else if (target === 'armeabi-v7a') {
TARGETS.push('arm');
} else {
TARGETS.push(target);
}
}

/**
* Runs mksnapshot to generate snapshots for each architecture
* @param {string} target targets to generate blob
* @returns {Promise<void>}
*/
async function generateBlob(target) {
const V8_LIB_TARGET_DIR = path.resolve(V8_LIB_DIR, target);
const MKSNAPSHOT_PATH = path.join(V8_LIB_TARGET_DIR, 'mksnapshot');
const BLOB_PATH = path.join(V8_LIB_TARGET_DIR, 'blob.bin');
const args = [
'--startup_blob=' + BLOB_PATH
];

// Set correct permissions for 'mksnapshot'
fs.chmodSync(MKSNAPSHOT_PATH, 0o755);

return new Promise((resolve, reject) => {

// Snapshot already exists, skip...
if (fs.existsSync(BLOB_PATH)) {
resolve();
}

// Generate snapshot
const p = spawn(MKSNAPSHOT_PATH, args);
p.on('close', code => {
if (code !== 0) {
return reject(`"mksnapshot ${args.join(' ')}" failed with exit code: ${code}`);
}
resolve();
});
});
}

/**
* Generates V8Snapshots.h header from architecture blobs
* @returns {Promise<void>}
*/
async function generateHeader() {
const blobs = {};

// Load snapshots for each architecture
for (const target of TARGETS) {
const V8_LIB_TARGET_DIR = path.resolve(V8_LIB_DIR, target);
const BLOB_PATH = path.join(V8_LIB_TARGET_DIR, 'blob.bin');

if (fs.existsSync(BLOB_PATH)) {
blobs[target] = Buffer.from(fs.readFileSync(BLOB_PATH, 'binary'), 'binary');
}
}

return new Promise(async (resolve, reject) => {

// Generate 'V8Snapshots.h' from template
ejs.renderFile(path.join(__dirname, 'V8Snapshots.h.ejs'), blobs, {}, (error, output) => {
if (error) {
return reject(error);
}
fs.writeFileSync(path.join(ANDROID_DIR, 'runtime', 'v8', 'src', 'native', 'V8Snapshots.h'), output);
resolve();
});
});
}

/**
* Generates empty snapshot blobs for each supported architecture
* and creates a header to include the snapshots at build time.
* NOTE: SNAPSHOT GENERATION IS ONLY SUPPORTED ON macOS
* @returns {Promise<void>}
*/
async function build() {
return new Promise(async (resolve, reject) => {

// Only macOS is supports creating snapshots
if (os.platform() === 'darwin') {
for (const target of TARGETS) {
await generateBlob(target).catch(error => reject(error));
}
await generateHeader().catch(error => reject(error));
}
resolve();
});
}

module.exports = { build };
89 changes: 63 additions & 26 deletions build/lib/ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
const path = require('path');
const fs = require('fs-extra');
const utils = require('./utils');
const promisify = require('util').promisify;
const glob = promisify(require('glob'));
const spawn = require('child_process').spawn; // eslint-disable-line security/detect-child-process
const copyFiles = utils.copyFiles;
const copyAndModifyFile = utils.copyAndModifyFile;
const globCopy = utils.globCopy;
const globCopyFlat = utils.globCopyFlat;

const ROOT_DIR = path.join(__dirname, '../..');
const IOS_ROOT = path.join(ROOT_DIR, 'iphone');
Expand Down Expand Up @@ -53,40 +53,77 @@ class IOS {
});
}

/**
* This generates "redirecting" headers in built SDK's iphone/include directory that points to the "real" headers
* whether they are in TitaniumKit's framework, or the iphone/Classes directory
* This should retain backwards compatibility for module builds and allow iphone/include to be a sort of single header path that can be used
*
* @param {string} DEST_IOS destination directory to copy files to
*/
async copyLegacyHeaders(DEST_IOS) {
// Gather all the *.h files in TitaniumKit, create "redirecting" headers in iphone/include that point to the TitaniumKit ones
await fs.ensureDir(path.join(DEST_IOS, 'include'));
const subdirs = await fs.readdir(path.join(IOS_ROOT, 'TitaniumKit/build/Release-iphoneuniversal/TitaniumKit.framework/Headers'));
// create them all in parallel
await Promise.all(subdirs.map(file => {
// TODO: Inject a deprecation warning if used and remove in SDK 9.0.0?
return fs.writeFile(path.join(DEST_IOS, 'include', file), `#import <TitaniumKit/${file}>\n`);
}));

// re-arrange redirecting headers for iphone/TitaniumKit/TitankumKit/Libraries/*/*.h files
const libDirs = await fs.readdir(path.join(IOS_ROOT, 'TitaniumKit/TitaniumKit/Libraries'));
for (const libDir of libDirs) {
await fs.ensureDir(path.join(DEST_IOS, 'include', libDir));
const libFiles = await fs.readdir(path.join(IOS_ROOT, 'TitaniumKit/TitaniumKit/Libraries', libDir));
for (const libFile of libFiles) {
if (libFile.endsWith('.h') && libFile !== 'APSUtility.h') { // for whatever reason APSUtility.h seems not to get copied as part of framework?
await fs.move(path.join(DEST_IOS, 'include', libFile), path.join(DEST_IOS, 'include', libDir, libFile));
}
}
}

// Create redirecting headers in iphone/include/ pointing to iphone/Classes/ headers
// TODO: Use map and Promise.all to run these in parallel
const classesHeaders = await glob('**/*.h', { cwd: path.join(IOS_ROOT, 'Classes') });
for (const classHeader of classesHeaders) {
let depth = 1;
if (classHeader.includes(path.sep)) { // there's a sub-directory
await fs.ensureDir(path.join(DEST_IOS, 'include', path.dirname(classHeader))); // make sure we create destination
depth = classHeader.split(path.sep).length;
}
// TODO: Inject a deprecation warning if used and remove in SDK 9.0.0?
await fs.writeFile(path.join(DEST_IOS, 'include', classHeader), `#import "${'../'.repeat(depth)}Classes/${classHeader}"\n`);
}
}

async package(packager) {
// FIXME This is a hot mess. Why can't we place artifacts in their proper location already like Windows?
// FIXME: This is a hot mess. Why can't we place artifacts in their proper location already like Windows?
console.log('Packaging iOS platform...');
const DEST_IOS = path.join(packager.zipSDKDir, 'iphone');

// Copy legacy copies of TiBase.h, TiApp.h etc into 'include/' to retain backwards compatibility in SDK 8.0.0
// TODO: Inject a deprecation warning if used and remove in SDK 9.0.0
await globCopyFlat('**/*.h', path.join(IOS_ROOT, 'TitaniumKit/TitaniumKit/Sources'), path.join(DEST_IOS, 'include'));

// Copy legacy copies of APSAnalytics.h and APSHTTPClient.h into 'include/' to retain backwards compatibility in SDK 8.0.0
// TODO: Inject a deprecation warning if used and remove in SDK 9.0.0
await globCopy('**/*.h', path.join(IOS_ROOT, 'TitaniumKit/TitaniumKit/Libraries'), path.join(DEST_IOS, 'include'));

// Copy meta files and directories
await copyFiles(IOS_ROOT, DEST_IOS, [ 'AppledocSettings.plist', 'Classes', 'cli', 'iphone', 'templates' ]);
return Promise.all([
this.copyLegacyHeaders(DEST_IOS),

// Copy TitaniumKit
await copyFiles(path.join(IOS_ROOT, 'TitaniumKit/build/Release-iphoneuniversal'), path.join(DEST_IOS, 'Frameworks'), [ 'TitaniumKit.framework' ]);
// Copy meta files and directories
// Copy module templates (Swift & Obj-C)
copyFiles(IOS_ROOT, DEST_IOS, [ 'AppledocSettings.plist', 'Classes', 'cli', 'iphone', 'templates' ]),

// Copy module templates (Swift & Obj-C)
await copyFiles(IOS_ROOT, DEST_IOS, [ 'AppledocSettings.plist', 'Classes', 'cli', 'iphone', 'templates' ]);
// Copy TitaniumKit
copyFiles(path.join(IOS_ROOT, 'TitaniumKit/build/Release-iphoneuniversal'), path.join(DEST_IOS, 'Frameworks'), [ 'TitaniumKit.framework' ]),

// Copy and inject values for special source files
await this.injectSDKConstants(path.join(DEST_IOS, 'main.m'));
// Copy and inject values for special source files
this.injectSDKConstants(path.join(DEST_IOS, 'main.m')),

// Copy Ti.Verify
await copyFiles(IOS_LIB, DEST_IOS, [ 'libtiverify.a' ]);
// Copy Ti.Verify
copyFiles(IOS_LIB, DEST_IOS, [ 'libtiverify.a' ]),

// Copy iphone/package.json, but replace __VERSION__ with our version!
await copyAndModifyFile(IOS_ROOT, DEST_IOS, 'package.json', { __VERSION__: this.sdkVersion });
// Copy iphone/package.json, but replace __VERSION__ with our version!
copyAndModifyFile(IOS_ROOT, DEST_IOS, 'package.json', { __VERSION__: this.sdkVersion }),

// Copy iphone/Resources/modules/<name>/* to this.zipSDKDir/iphone/modules/<name>/images
// TODO: Pretty sure these can be removed nowadays
return fs.copy(path.join(IOS_ROOT, 'Resources/modules'), path.join(DEST_IOS, 'modules'));
// Copy iphone/Resources/modules/<name>/* to this.zipSDKDir/iphone/modules/<name>/images
// TODO: Pretty sure these can be removed nowadays
fs.copy(path.join(IOS_ROOT, 'Resources/modules'), path.join(DEST_IOS, 'modules'))
]);
}

async injectSDKConstants(dest) {
Expand Down

0 comments on commit da04a2f

Please sign in to comment.