Skip to content

Commit

Permalink
Merge pull request #11 from irondash/precompiled_binaries
Browse files Browse the repository at this point in the history
feat: add support for precompiling binaries
  • Loading branch information
knopp authored Aug 30, 2023
2 parents 72b0271 + b190fdf commit d72e38e
Show file tree
Hide file tree
Showing 42 changed files with 3,226 additions and 839 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/check_and_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
on:
pull_request:
push:
branches:
- main

name: Check and Lint

jobs:
Flutter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- name: Pub Get
run: dart pub get --no-precompile
working-directory: build_tool
- name: Dart Format
run: dart format . --output=none --set-exit-if-changed
working-directory: build_tool
- name: Analyze
run: dart analyze
working-directory: build_tool
- name: Test
run: dart test
working-directory: build_tool
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
target
target
.dart_tool
*.iml
36 changes: 28 additions & 8 deletions build_pod.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,36 @@ NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"

export PATH=${NEW_PATH%?} # remove trailing :

export CARGOKIT_PLATFORM_NAME=$PLATFORM_NAME
export CARGOKIT_ARCHS=$ARCHS
env

# Platform name (macosx, iphoneos, iphonesimulator)
export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME

# Arctive architectures (arm64, armv7, x86_64), space separated.
export CARGOKIT_DARWIN_ARCHS=$ARCHS

# Current build configuration (Debug, Release)
export CARGOKIT_CONFIGURATION=$CONFIGURATION
export CARGOKIT_SRCROOT=$PODS_TARGET_SRCROOT
export CARGOKIT_TEMP_DIR=$TARGET_TEMP_DIR
export CARGOKIT_PRODUCT_NAME=$PRODUCT_NAME
export CARGOKIT_TARGET_DIR=$PODS_CONFIGURATION_BUILD_DIR
export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/rust_tool

"$BASEDIR/run_rust_tool.sh" build_pod $@
# Path to directory containing Cargo.toml.
export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1

# Name of Rust library being built.
export CARGOKIT_LIB_NAME=$2

# Temporary directory for build artifacts.
export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR

# Output directory for final artifacts.
export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME

# Directory to store built tool artifacts.
export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool

# Directory inside root project. Not necessarily the top level directory of root project.
export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT

"$BASEDIR/run_build_tool.sh" build-pod $@

# Make a symlink from built framework to phony file, which will be used as input to
# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate
Expand Down
39 changes: 0 additions & 39 deletions build_tool/Cargo.lock

This file was deleted.

18 changes: 0 additions & 18 deletions build_tool/Cargo.toml

This file was deleted.

2 changes: 2 additions & 0 deletions build_tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
A sample command-line application with an entrypoint in `bin/`, library code
in `lib/`, and example unit test in `test/`.
31 changes: 31 additions & 0 deletions build_tool/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

linter:
rules:
- prefer_relative_imports
- directives_ordering

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
5 changes: 5 additions & 0 deletions build_tool/bin/build_tool.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:build_tool/build_tool.dart' as build_tool;

void main(List<String> arguments) {
build_tool.runMain(arguments);
}
5 changes: 5 additions & 0 deletions build_tool/lib/build_tool.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'src/build_tool.dart' as build_tool;

Future<void> runMain(List<String> args) async {
return build_tool.runMain(args);
}
189 changes: 189 additions & 0 deletions build_tool/lib/src/android_environment.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import 'dart:io';
import 'dart:isolate';
import 'dart:math' as math;

import 'package:collection/collection.dart';
import 'package:path/path.dart' as path;
import 'package:version/version.dart';

import 'target.dart';
import 'util.dart';

class AndroidEnvironment {
AndroidEnvironment({
required this.sdkPath,
required this.ndkVersion,
required this.minSdkVersion,
required this.targetTempDir,
required this.target,
});

static void clangLinkerWrapper(List<String> args) {
final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG'];
if (clang == null) {
throw Exception(
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var");
}
final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET'];
if (target == null) {
throw Exception(
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var");
}

runCommand(clang, [
target,
...args,
]);
}

/// Full path to Android SDK.
final String sdkPath;

/// Full version of Android NDK.
final String ndkVersion;

/// Minimum supported SDK version.
final int minSdkVersion;

/// Target directory for build artifacts.
final String targetTempDir;

/// Target being built.
final Target target;

bool ndkIsInstalled() {
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
final ndkPackageXml = File(path.join(ndkPath, 'package.xml'));
return ndkPackageXml.existsSync();
}

void installNdk({
required String javaHome,
}) {
final sdkManagerExtension = Platform.isWindows ? '.bat' : '';
final sdkManager = path.join(
sdkPath,
'cmdline-tools',
'latest',
'bin',
'sdkmanager$sdkManagerExtension',
);

runCommand(sdkManager, [
'--install',
'ndk;$ndkVersion',
], environment: {
'JAVA_HOME': javaHome,
});
}

Future<Map<String, String>> buildEnvironment() async {
final hostArch = Platform.isMacOS
? "darwin-x86_64"
: (Platform.isLinux ? "linux-x86_64" : "windows-x86_64");

final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
final toolchainPath = path.join(
ndkPath,
'toolchains',
'llvm',
'prebuilt',
hostArch,
'bin',
);

final minSdkVersion =
math.max(target.androidMinSdkVersion!, this.minSdkVersion);

final arKey = 'AR_${target.rust}';
final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe']
.map((e) => path.join(toolchainPath, e))
.firstWhereOrNull((element) => File(element).existsSync());
if (arValue == null) {
throw Exception('Failed to find ar for $target in $toolchainPath');
}

final targetArg = '--target=${target.rust}$minSdkVersion';

final ccKey = 'CC_${target.rust}';
final ccValue = path.join(toolchainPath, 'clang');
final cfFlagsKey = 'CFLAGS_${target.rust}';
final cFlagsValue = targetArg;

final cxxKey = 'CXX_${target.rust}';
final cxxValue = path.join(toolchainPath, 'clang++');
final cxxfFlagsKey = 'CXXFLAGS_${target.rust}';
final cxxFlagsValue = targetArg;

final linkerKey =
'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase();

final ranlibKey = 'RANLIB_${target.rust}';
final ranlibValue = path.join(toolchainPath, 'llvm-ranlib');

final ndkVersionParsed = Version.parse(ndkVersion);
final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS';
final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed);

final runRustTool =
Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh';

final packagePath = (await Isolate.resolvePackageUri(
Uri.parse('package:build_tool/buildtool.dart')))!
.toFilePath();
final selfPath = path.canonicalize(path.join(
packagePath,
'..',
'..',
'..',
runRustTool,
));

// Make sure that run_build_tool is working properly even initially launched directly
// through dart run.
final toolTempDir =
Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir;

return {
arKey: arValue,
ccKey: ccValue,
cfFlagsKey: cFlagsValue,
cxxKey: cxxValue,
cxxfFlagsKey: cxxFlagsValue,
ranlibKey: ranlibValue,
rustFlagsKey: rustFlagsValue,
linkerKey: selfPath,
// Recognized by main() so we know when we're acting as a wrapper
'_CARGOKIT_NDK_LINK_TARGET': targetArg,
'_CARGOKIT_NDK_LINK_CLANG': ccValue,
'CARGOKIT_TOOL_TEMP_DIR': toolTempDir,
};
}

// Workaround for libgcc missing in NDK23, inspired by cargo-ndk
String _libGccWorkaround(String buildDir, Version ndkVersion) {
final workaroundDir = path.join(
buildDir,
'cargokit',
'libgcc_workaround',
'${ndkVersion.major}',
);
Directory(workaroundDir).createSync(recursive: true);
if (ndkVersion.major >= 23) {
File(path.join(workaroundDir, 'libgcc.a'))
.writeAsStringSync('INPUT(-lunwind)');
} else {
// Other way around, untested, forward libgcc.a from libunwind once Rust
// gets updated for NDK23+.
File(path.join(workaroundDir, 'libunwind.a'))
.writeAsStringSync('INPUT(-lgcc)');
}

var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? '';
if (rustFlags.isNotEmpty) {
rustFlags = '$rustFlags\x1f';
}
rustFlags = '$rustFlags-L\x1f$workaroundDir';
return rustFlags;
}
}
Loading

0 comments on commit d72e38e

Please sign in to comment.