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

Add alternative build opportunity for bevy projects #165

Open
wants to merge 9 commits into
base: main
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
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crossbow"
version = "0.2.3"
version = "0.2.4"
edition = "2021"
authors = ["DodoRare Team <support@dodorare.com>"]
description = "Cross-Platform build tools and toolkit for games"
Expand All @@ -21,10 +21,10 @@ apple-bundle = { version = "0.1.4", optional = true }

[target.'cfg(target_os = "android")'.dependencies]
ndk-glue = "0.7.0"
crossbow-android = { path = "platform/android", version = "0.2.3", optional = true }
crossbow-android = { path = "platform/android", version = "0.2.4", optional = true }

[target.'cfg(target_os = "ios")'.dependencies]
crossbow-ios = { path = "platform/ios", version = "0.2.3", optional = true }
crossbow-ios = { path = "platform/ios", version = "0.2.4", optional = true }

[patch.crates-io]
bevy = { git = "https://github.com/dodorare/bevy", rev = "732fc8c585ebd3a622153771a8c51ace93024a04" }
Expand Down
6 changes: 3 additions & 3 deletions crossbundle/cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crossbundle"
version = "0.2.3"
version = "0.2.4"
edition = "2021"
authors = ["DodoRare Team <support@dodorare.com>"]
description = "Build and publish apps for Android/iOS"
Expand All @@ -18,8 +18,8 @@ name = "crossbundle"
path = "src/main.rs"

[dependencies]
crossbow = { path = "../../", version = "0.2.3", default-features = false, features = ["update-manifest"] }
crossbundle-tools = { path = "../tools", version = "0.2.3", default-features = false }
crossbow = { path = "../../", version = "0.2.4", default-features = false, features = ["update-manifest"] }
crossbundle-tools = { path = "../tools", version = "0.2.4", default-features = false }
android-tools = { version = "0.2.11", optional = true }
clap = { version = "3.2", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
Expand Down
51 changes: 30 additions & 21 deletions crossbundle/cli/src/commands/build/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{error::*, types::CrossbowMetadata};
use android_manifest::AndroidManifest;
use android_tools::java_tools::{JarSigner, Key};
use clap::Parser;

use crossbundle_tools::{
commands::{android::*, combine_folders},
error::CommandExt,
Expand All @@ -21,24 +22,27 @@ pub struct AndroidBuildCommand {
#[clap(long, short, multiple_values = true)]
pub target: Vec<AndroidTarget>,
/// Build strategy specifies what and how to build Android application: with help of
/// Gradle, or with our native approach.
/// Gradle, or with our native approach
#[clap(long, short, default_value = "gradle-apk")]
pub strategy: AndroidStrategy,
/// Only compile rust code as a dynamic library. By default: "crossbow-android"
#[clap(long, default_missing_value = "crossbow_android")]
pub lib: Option<String>,
/// Path to export Gradle project. By default exports to `target/android/` folder.
/// Path to export Gradle project. By default exports to `target/android/` folder
#[clap(long)]
pub export_path: Option<PathBuf>,
/// Path to the signing key.
/// Path to the signing key
#[clap(long, requires_all = &["sign-key-pass", "sign-key-alias"])]
pub sign_key_path: Option<PathBuf>,
/// Signing key password.
/// Signing key password
#[clap(long)]
pub sign_key_pass: Option<String>,
/// Signing key alias.
/// Signing key alias
#[clap(long)]
pub sign_key_alias: Option<String>,
/// Native compile for bevy projects without cargo Executor trait invocations
#[clap(long, short)]
pub bevy_compile: bool,
}

impl AndroidBuildCommand {
Expand Down Expand Up @@ -182,7 +186,7 @@ impl AndroidBuildCommand {
std::fs::create_dir_all(&out_dir)?;
}
let file_name = compiled_lib.file_name().unwrap().to_owned();
std::fs::copy(compiled_lib, &out_dir.join(&file_name))?;
std::fs::copy(compiled_lib, out_dir.join(file_name))?;
}
Ok(())
}
Expand All @@ -197,6 +201,7 @@ impl AndroidBuildCommand {
let example = self.shared.example.as_ref();
let (project_path, target_dir, package_name) = Self::needed_project_dirs(example, context)?;
config.status_message("Starting apk build process", &package_name)?;

let (sdk, ndk) = Self::android_toolchain()?;

let android_build_dir = target_dir.join("android").join(&package_name);
Expand Down Expand Up @@ -401,7 +406,7 @@ impl AndroidBuildCommand {
let aab_output_path = outputs_build_dir.join(output_aab);
let mut options = fs_extra::file::CopyOptions::new();
options.overwrite = true;
fs_extra::file::move_file(&signed_aab, &outputs_build_dir.join(output_aab), &options)?;
fs_extra::file::move_file(&signed_aab, outputs_build_dir.join(output_aab), &options)?;
config.status("Build finished successfully")?;
Ok((manifest, sdk, aab_output_path, package_name, key))
}
Expand All @@ -413,7 +418,7 @@ impl AndroidBuildCommand {
) -> Result<(PathBuf, PathBuf, String)> {
let project_path: PathBuf = context.project_path.clone();
let target_dir: PathBuf = context.target_dir.clone();
let (_target, package_name) = if let Some(example) = example {
let (_, package_name) = if let Some(example) = example {
(Target::Example(example.clone()), example.clone())
} else {
(Target::Lib, context.package_name())
Expand Down Expand Up @@ -483,19 +488,23 @@ impl AndroidBuildCommand {
let rust_triple = build_target.rust_triple();

config.status_message("Compiling for architecture", rust_triple)?;
// Compile rust code for android depending on application wrapper
rust_compile(
ndk,
build_target,
project_path,
profile,
self.shared.features.clone(),
self.shared.all_features,
self.shared.no_default_features,
target_sdk_version,
&lib_name,
context.config.android.app_wrapper,
)?;
// Compile rust code for android depending on application wrapper and `--bevy-compile`
// flag
match self.bevy_compile {
true => bevy_native_compile(build_target, target_dir, target_sdk_version, ndk)?,
false => rust_compile(
ndk,
build_target,
project_path,
profile,
self.shared.features.clone(),
self.shared.all_features,
self.shared.no_default_features,
target_sdk_version,
&lib_name,
context.config.android.app_wrapper,
)?,
}

let out_dir = target_dir.join(build_target.rust_triple()).join(profile);
let compiled_lib = out_dir.join(lib_name);
Expand Down
2 changes: 1 addition & 1 deletion crossbundle/cli/src/commands/build/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl IosBuildCommand {

let app_path = apple::gen_apple_app_folder(apple_target_dir, name, assets, resources)?;
config.status("Copying binary to app folder")?;
std::fs::copy(&bin_path, &app_path.join(name)).unwrap();
std::fs::copy(bin_path, app_path.join(name)).unwrap();
config.status_message("Generating", "Info.plist")?;
apple::save_info_plist(&app_path, properties, false).unwrap();

Expand Down
2 changes: 1 addition & 1 deletion crossbundle/cli/tests/cargo_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn test_cargo_metadata() {
let example = android_build_command.shared.example.as_ref();
let (_, _, package_name) = AndroidBuildCommand::needed_project_dirs(example, &context).unwrap();
config
.status_message("Starting apk build process", &package_name)
.status_message("Starting apk build process", package_name)
.unwrap();

let android_manifest =
Expand Down
18 changes: 18 additions & 0 deletions crossbundle/derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "crossbundle-derive"
version = "0.2.4"
edition = "2021"
authors = ["DodoRare Team <support@dodorare.com>"]
description = "Cross-Platform Rust Toolkit for Games 🏹"
repository = "https://github.com/dodorare/crossbow"
license = "Apache-2.0"
keywords = ["derive", "android", "ios"]
readme = "README.md"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full"] }
36 changes: 36 additions & 0 deletions crossbundle/derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};

fn crossbundle_main_logic(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
if input.sig.ident != "main" {
panic!("crossbundle_main can only be used on a function called 'main'")
}
TokenStream::from(quote! {
#[no_mangle]
#[cfg(target_os = "android")]
unsafe extern "C" fn ANativeActivity_onCreate(
activity: *mut std::os::raw::c_void,
saved_state: *mut std::os::raw::c_void,
saved_state_size: usize,
) {
crossbow::ndk_glue::init(
activity as _,
saved_state as _,
saved_state_size as _,
main,
);
}

#[allow(unused)]
#input
})
}

#[proc_macro_attribute]
pub fn crossbundle_main(attr: TokenStream, item: TokenStream) -> TokenStream {
crossbundle_main_logic(attr, item)
}
4 changes: 2 additions & 2 deletions crossbundle/tools/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crossbundle-tools"
version = "0.2.3"
version = "0.2.4"
edition = "2021"
authors = ["DodoRare Team <support@dodorare.com>"]
description = "Build and publish apps for Android/iOS"
Expand All @@ -10,7 +10,7 @@ keywords = ["android", "ios"]
readme = "README.md"

[dependencies]
crossbow-android = { version = "0.2.3", path = "../../platform/android", default-features = false, features = ["embed"] }
crossbow-android = { version = "0.2.4", path = "../../platform/android", default-features = false, features = ["embed"] }
# Apple crates
apple-bundle = { version = "0.1.4", optional = true }
simctl = { version = "0.1.1", package = "creator-simctl", optional = true }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use crate::{commands::android::cargo_env_target_cfg, error::*, types::*};
use std::path::Path;

/// Use cargo inner features to build bevy project to avoid cargo Executor trait using.
/// Required to add `[lib]` section in `Cargo.toml` with cdylib crate-type. For correct
/// app working in runtime use crossbundle derive macro. For more information see
/// crossbundle build command docs.
pub fn bevy_native_compile(
build_target: AndroidTarget,
target_dir: &Path,
target_sdk_version: u32,
ndk: &AndroidNdk,
) -> Result<()> {
let mut cargo = std::process::Command::new("cargo");
let triple = build_target.rust_triple();
let clang_target = format!(
"--target={}{}",
build_target.ndk_llvm_triple(),
target_sdk_version
);
let ar = ndk.toolchain_bin("ar", build_target)?;

cargo.env(format!("AR_{}", triple), &ar);
cargo.env(cargo_env_target_cfg("AR", triple), &ar);

// Read initial RUSTFLAGS
let mut rustflags = match std::env::var("CARGO_ENCODED_RUSTFLAGS") {
Ok(val) => val,
Err(std::env::VarError::NotPresent) => "".to_string(),
Err(std::env::VarError::NotUnicode(_)) => {
panic!("RUSTFLAGS environment variable contains non-unicode characters")
}
};

let (clang, clang_pp) = ndk.clang(build_target, target_sdk_version)?;

// Configure cross-compiler for `cc` crate
// https://github.com/rust-lang/cc-rs#external-configuration-via-environment-variables
cargo.env(format!("CC_{}", triple), &clang);
cargo.env(format!("CFLAGS_{}", triple), &clang_target);
cargo.env(format!("CXX_{}", triple), &clang_pp);
cargo.env(format!("CXXFLAGS_{}", triple), &clang_target);

// Configure LINKER for `rustc`
// https://doc.rust-lang.org/beta/cargo/reference/environment-variables.html#configuration-environment-variables
cargo.env(cargo_env_target_cfg("LINKER", triple), &clang);
if !rustflags.is_empty() {
rustflags.push('\x1f');
}

rustflags.push_str("-Clink-arg=");
rustflags.push_str(&clang_target);

let ar = ndk.toolchain_bin("ar", build_target)?;
cargo.env(format!("AR_{}", triple), &ar);
cargo.env(cargo_env_target_cfg("AR", triple), &ar);

// Workaround for https://github.com/rust-windowing/android-ndk-rs/issues/149:
// Rust (1.56 as of writing) still requires libgcc during linking, but this does
// not ship with the NDK anymore since NDK r23 beta 3.
// See https://github.com/rust-lang/rust/pull/85806 for a discussion on why libgcc
// is still required even after replacing it with libunwind in the source.
// XXX: Add an upper-bound on the Rust version whenever this is not necessary anymore.
if ndk.build_tag() > 7272597 {
let link_dir = target_dir.join("link-libraries");
std::fs::create_dir_all(&link_dir).map_err(|_| Error::PathNotFound(link_dir.clone()))?;
let libgcc = link_dir.join("libgcc.a");
std::fs::write(libgcc, "INPUT(-lunwind)")
.map_err(|_| Error::PathNotFound(link_dir.clone()))?;

// cdylibs in transitive dependencies still get built and also need this
// workaround linker flag, yet arguments passed to `cargo rustc` are only
// forwarded to the final compiler invocation rendering our workaround ineffective.
// The cargo page documenting this discrepancy (https://doc.rust-lang.org/cargo/commands/cargo-rustc.html)
// suggests to resort to RUSTFLAGS.
// Note that `rustflags` will never be empty because of an unconditional `.push_str`
// above, so we can safely start with appending \x1f here.
rustflags.push_str("\x1f-L\x1f");
rustflags.push_str(link_dir.to_str().expect("Target dir must be valid UTF-8"));
}
cargo.env("CARGO_ENCODED_RUSTFLAGS", rustflags);

cargo.arg("rustc");
cargo.arg("--lib");
cargo.arg("--target").arg(triple);

cargo.output_err(true)?;

Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod bevy_native_compiler;
mod cmake_toolchain;
mod compile_options;
mod consts;
mod gen_tmp_lib_file;
mod rust_compiler;
mod set_linker_args;

pub use bevy_native_compiler::*;
pub use cmake_toolchain::*;
pub use rust_compiler::*;
pub use set_linker_args::*;
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ pub fn rust_compile(
// Set environment variables needed for use with the cc crate
let (clang, clang_pp) = ndk.clang(build_target, target_sdk_version)?;
std::env::set_var(format!("CC_{}", rust_triple), &clang);
std::env::set_var(format!("CXX_{}", rust_triple), &clang_pp);
std::env::set_var(format!("CXX_{}", rust_triple), clang_pp);
std::env::set_var(cargo_env_target_cfg("LINKER", rust_triple), &clang);
let ar = ndk.toolchain_bin("ar", build_target)?;
std::env::set_var(format!("AR_{}", rust_triple), &ar);
std::env::set_var(format!("AR_{}", rust_triple), ar);

let cargo_config = cargo::util::Config::default()?;
let workspace = cargo::core::Workspace::new(&project_path.join("Cargo.toml"), &cargo_config)?;
Expand Down Expand Up @@ -164,7 +164,7 @@ impl cargo::core::compiler::Executor for SharedLibraryExecutor {
// XXX: Add an upper-bound on the Rust version whenever this is not necessary anymore.
if self.ndk.build_tag() > 7272597 {
let mut args = search_for_libgcc_and_libunwind(
&self.build_target,
self.build_target,
build_path,
&self.ndk,
self.target_sdk_version,
Expand Down Expand Up @@ -210,10 +210,3 @@ impl cargo::core::compiler::Executor for SharedLibraryExecutor {
Ok(())
}
}

/// Helper function that allows to return environment argument with specified tool
pub fn cargo_env_target_cfg(tool: &str, target: &str) -> String {
let utarget = target.replace('-', "_");
let env = format!("CARGO_TARGET_{}_{}", &utarget, tool);
env.to_uppercase()
}
Loading