diff --git a/pyoxidizer/src/project_building.rs b/pyoxidizer/src/project_building.rs index 57a04fb6c..59bdd1ef1 100644 --- a/pyoxidizer/src/project_building.rs +++ b/pyoxidizer/src/project_building.rs @@ -427,6 +427,27 @@ pub fn build_python_executable<'a>( .context("resolving Rust toolchain")? .cargo_exe; + build_python_executable_temp( + env, + bin_name, + exe, + target_triple, + opt_level, + release, + cargo_exe, + ) + +} + +fn build_python_executable_temp<'a>( + env: &Environment, + bin_name: &str, + exe: &'a (dyn PythonBinaryBuilder + 'a), + target_triple: &str, + opt_level: &str, + release: bool, + cargo_exe: PathBuf, +)->Result>{ let temp_dir = env.temporary_directory("pyoxidizer")?; // Directory needs to have name of project. @@ -467,8 +488,66 @@ pub fn build_python_executable<'a>( build.exe_path = None; temp_dir.close().context("closing temporary directory")?; + Ok(build) +} +/// Build a Python executable with local or init Rust project. +/// +/// Returns the binary data constituting the built executable. +pub fn build_python_executable_local<'a>( + env: &Environment, + bin_name: &str, + exe: &'a (dyn PythonBinaryBuilder + 'a), + target_triple: &str, + opt_level: &str, + release: bool, + cwd: PathBuf, +) -> Result> { + let cargo_exe = env + .ensure_rust_toolchain(Some(target_triple)) + .context("resolving Rust toolchain")? + .cargo_exe; - Ok(build) + let toml = cwd.join("Cargo.toml"); + + if toml.exists() { + let project_path = cwd.clone(); + let build_path = cwd.join("build"); + let artifacts_path = cwd.join("artifacts"); + let mut build = build_executable_with_rust_project( + env, + &project_path, + bin_name, + exe, + &build_path, + &artifacts_path, + target_triple, + opt_level, + release, + // Always build with locked because we crated a Cargo.lock with the + // Rust project we just created. + true, + // Don't include license for self because the Rust project is temporary and its + // licensing isn't material. + false, + ) + .context("building executable with Rust project")?; + + // Blank out the path since it is in the temporary directory. + build.exe_path = None; + + Ok(build) + } else { + build_python_executable_temp( + env, + bin_name, + exe, + target_triple, + opt_level, + release, + cargo_exe, + ) + } + } /// Build artifacts needed by the pyembed crate. diff --git a/pyoxidizer/src/starlark/file_resource.rs b/pyoxidizer/src/starlark/file_resource.rs index 9da0cf32e..21e2a1aba 100644 --- a/pyoxidizer/src/starlark/file_resource.rs +++ b/pyoxidizer/src/starlark/file_resource.rs @@ -11,7 +11,7 @@ use { python_package_resource::PythonPackageResourceValue, }, crate::{ - project_building::build_python_executable, + project_building::build_python_executable_local, py_packaging::{binary::PythonBinaryBuilder, resource::AddToFileManifest}, }, anyhow::{anyhow, Context, Result}, @@ -29,7 +29,7 @@ use { starlark_signature_extraction, starlark_signatures, }, }, - std::{ops::DerefMut, path::Path}, + std::{ops::DerefMut, path::{Path,PathBuf}}, tugger::starlark::file_manifest::FileManifestValue, }; @@ -42,10 +42,11 @@ pub fn file_manifest_add_python_executable( target: &str, release: bool, opt_level: &str, + cwd: PathBuf, ) -> Result<()> { const LABEL: &str = "FileManifest.add_python_executable()"; - let build = build_python_executable(env, &exe.name(), exe, target, opt_level, release) + let build = build_python_executable_local(env, &exe.name(), exe, target, opt_level, release,cwd) .context("building Python executable")?; let content = FileEntry::new_from_data(build.exe_data.clone(), true); diff --git a/pyoxidizer/src/starlark/python_executable.rs b/pyoxidizer/src/starlark/python_executable.rs index b68bbdf35..8e2dfcc3f 100644 --- a/pyoxidizer/src/starlark/python_executable.rs +++ b/pyoxidizer/src/starlark/python_executable.rs @@ -18,7 +18,7 @@ use { }, crate::{ licensing::licenses_from_cargo_manifest, - project_building::build_python_executable, + project_building::build_python_executable_local, py_packaging::binary::PythonBinaryBuilder, py_packaging::binary::{PackedResourcesLoadMode, WindowsRuntimeDllsMode}, }, @@ -82,15 +82,16 @@ pub fn build_internal( target: &str, context: &PyOxidizerEnvironmentContext, ) -> Result<(ResolvedTarget, PathBuf)> { - // Build an executable by writing out a temporary Rust project - // and building it. - let build = build_python_executable( + // Build an executable if can't find local toml file + // will writing out a temporary Rust project and building it. + let build = build_python_executable_local( context.env(), &exe.name(), &**exe, &context.build_target_triple, &context.build_opt_level, context.build_release, + context.cwd.clone(), ) .context("building Python executable")?; @@ -827,7 +828,7 @@ impl PythonExecutableValue { /// PythonExecutable.to_file_manifest(prefix) pub fn to_file_manifest(&self, type_values: &TypeValues, prefix: String) -> ValueResult { const LABEL: &str = "PythonExecutable.to_file_manifest()"; - + let pyoxidizer_context_value = get_context(type_values)?; let pyoxidizer_context = pyoxidizer_context_value .downcast_ref::() @@ -850,6 +851,7 @@ impl PythonExecutableValue { &pyoxidizer_context.build_target_triple, pyoxidizer_context.build_release, &pyoxidizer_context.build_opt_level, + pyoxidizer_context.cwd.clone(), ) .context("adding PythonExecutable to FileManifest") })?;