diff --git a/Cargo.lock b/Cargo.lock index aea2803c01..e9d2be3060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,7 @@ dependencies = [ "bincode", "fmm", "fmm-llvm", + "fnv", "hir", "hir_mir", "interface", diff --git a/cmd/pen/src/application_configuration.rs b/cmd/pen/src/application_configuration.rs index 3900b49892..50f8c6d1b6 100644 --- a/cmd/pen/src/application_configuration.rs +++ b/cmd/pen/src/application_configuration.rs @@ -9,8 +9,9 @@ pub static APPLICATION_CONFIGURATION: Lazy> = main_module: app::MainModuleConfiguration { source_main_function_name: "main".into(), object_main_function_name: "_pen_main".into(), - context_type_name: "Context".into(), - new_context_function_name: "UnsafeNew".into(), + main_context_type_name: "context".into(), + system_context_type_name: "Context".into(), + new_system_context_function_name: "UnsafeNew".into(), }, } .into() diff --git a/cmd/pen/src/main.rs b/cmd/pen/src/main.rs index 4cfc8e238b..320137174a 100644 --- a/cmd/pen/src/main.rs +++ b/cmd/pen/src/main.rs @@ -71,11 +71,11 @@ fn run() -> Result<(), Box> { .setting(clap::AppSettings::Hidden) .about("Compiles a main module") .arg( - clap::Arg::new("main function interface file") - .short('f') - .long("main-function-interface-file") + clap::Arg::new("context interface file") + .short('c') + .long("context-interface-file") .required(true) - .takes_value(true), + .number_of_values(2), ) .arg(clap::Arg::new("source file").required(true)) .arg(clap::Arg::new("dependency file").required(true)) @@ -186,13 +186,25 @@ fn run() -> Result<(), Box> { matches.value_of("interface file").unwrap(), matches.value_of("target"), ), - ("compile-main", matches) => main_module_compiler::compile( - matches.value_of("source file").unwrap(), - matches.value_of("dependency file").unwrap(), - matches.value_of("object file").unwrap(), - matches.value_of("main function interface file").unwrap(), - matches.value_of("target"), - ), + ("compile-main", matches) => { + let context_options = matches + .values_of("context interface file") + .unwrap() + .collect::>(); + + main_module_compiler::compile( + matches.value_of("source file").unwrap(), + matches.value_of("dependency file").unwrap(), + matches.value_of("object file").unwrap(), + &context_options + .iter() + .step_by(2) + .cloned() + .zip(context_options.iter().skip(1).step_by(2).cloned()) + .collect(), + matches.value_of("target"), + ) + } ("compile-prelude", matches) => prelude_module_compiler::compile( matches.value_of("source file").unwrap(), matches.value_of("object file").unwrap(), diff --git a/cmd/pen/src/main_module_compiler.rs b/cmd/pen/src/main_module_compiler.rs index 53e955a07a..489a5e7c33 100644 --- a/cmd/pen/src/main_module_compiler.rs +++ b/cmd/pen/src/main_module_compiler.rs @@ -1,12 +1,12 @@ use super::{compile_configuration::COMPILE_CONFIGURATION, main_package_directory_finder}; use crate::{application_configuration::APPLICATION_CONFIGURATION, infrastructure}; -use std::sync::Arc; +use std::{collections::BTreeMap, error::Error, sync::Arc}; pub fn compile( source_file: &str, dependency_file: &str, object_file: &str, - context_interface_file: &str, + context_interface_files: &BTreeMap<&str, &str>, target_triple: Option<&str>, ) -> Result<(), Box> { let main_package_directory = main_package_directory_finder::find()?; @@ -17,7 +17,10 @@ pub fn compile( &file_path_converter.convert_to_file_path(source_file)?, &file_path_converter.convert_to_file_path(dependency_file)?, &file_path_converter.convert_to_file_path(object_file)?, - &file_path_converter.convert_to_file_path(context_interface_file)?, + &context_interface_files + .iter() + .map(|(&key, path)| Ok((key.into(), file_path_converter.convert_to_file_path(path)?))) + .collect::, Box>>()?, target_triple, &COMPILE_CONFIGURATION, &APPLICATION_CONFIGURATION, diff --git a/cmd/pen/src/package_creator.rs b/cmd/pen/src/package_creator.rs index 7cbda5ae5a..62f3ccd196 100644 --- a/cmd/pen/src/package_creator.rs +++ b/cmd/pen/src/package_creator.rs @@ -32,11 +32,10 @@ pub fn create(package_directory: &str, library: bool) -> Result<(), Box { write!(formatter, "system package not found") } - Self::TooManySystemPackages => { - write!(formatter, "too many system package") - } Self::Test => write!(formatter, "test failed"), } } diff --git a/lib/app/src/external_package_configuration_reader.rs b/lib/app/src/external_package_configuration_reader.rs index 6b838b7d83..c20546c64e 100644 --- a/lib/app/src/external_package_configuration_reader.rs +++ b/lib/app/src/external_package_configuration_reader.rs @@ -5,19 +5,17 @@ use crate::{ }; use std::{collections::BTreeMap, error::Error}; -pub fn read_main( +pub fn read( infrastructure: &Infrastructure, - package_directory: &FilePath, + configuration: &PackageConfiguration, output_directory: &FilePath, -) -> Result, Box> { - infrastructure - .package_configuration_reader - .read(package_directory)? +) -> Result, Box> { + configuration .dependencies() - .values() - .map(|url| -> Result<_, Box> { + .iter() + .map(|(key, url)| -> Result<_, Box> { Ok(( - url.clone(), + key.clone(), infrastructure.package_configuration_reader.read( &file_path_resolver::resolve_package_directory(output_directory, url), )?, diff --git a/lib/app/src/infra/build_script_compiler.rs b/lib/app/src/infra/build_script_compiler.rs index 7bdea81b99..8d0a3d996b 100644 --- a/lib/app/src/infra/build_script_compiler.rs +++ b/lib/app/src/infra/build_script_compiler.rs @@ -28,7 +28,7 @@ pub trait BuildScriptCompiler { fn compile_application( &self, - system_package_directory: &FilePath, + system_package_directories: &[FilePath], archive_files: &[FilePath], application_file: &FilePath, ) -> Result>; diff --git a/lib/app/src/infra/main_module_target.rs b/lib/app/src/infra/main_module_target.rs index bfbd687320..b176a1a07f 100644 --- a/lib/app/src/infra/main_module_target.rs +++ b/lib/app/src/infra/main_module_target.rs @@ -1,21 +1,22 @@ use crate::infra::FilePath; +use std::collections::BTreeMap; pub struct MainModuleTarget { source_file: FilePath, object_file: FilePath, - main_function_interface_file: FilePath, + context_interface_files: BTreeMap, } impl MainModuleTarget { pub fn new( source_file: FilePath, object_file: FilePath, - main_function_interface_file: FilePath, + context_interface_files: BTreeMap, ) -> Self { Self { source_file, object_file, - main_function_interface_file, + context_interface_files, } } @@ -27,7 +28,7 @@ impl MainModuleTarget { &self.object_file } - pub fn main_function_interface_file(&self) -> &FilePath { - &self.main_function_interface_file + pub fn context_interface_files(&self) -> &BTreeMap { + &self.context_interface_files } } diff --git a/lib/app/src/module_compiler.rs b/lib/app/src/module_compiler.rs index 7abcaf7a95..5f56955e66 100644 --- a/lib/app/src/module_compiler.rs +++ b/lib/app/src/module_compiler.rs @@ -12,7 +12,8 @@ pub use compile_configuration::{ CompileConfiguration, ConcurrencyConfiguration, ErrorTypeConfiguration, FmmConfiguration, HirConfiguration, ListTypeConfiguration, StringTypeConfiguration, }; -use std::error::Error; +use fnv::FnvHashMap; +use std::{collections::BTreeMap, error::Error}; const PRELUDE_PREFIX: &str = "prelude:"; @@ -26,7 +27,7 @@ pub fn compile( compile_configuration: &CompileConfiguration, ) -> Result<(), Box> { let (module, module_interface) = hir_mir::compile( - &compile_to_hir(infrastructure, source_file, dependency_file, None)?, + &compile_to_hir(infrastructure, source_file, dependency_file, &[])?, &prelude_type_configuration_qualifier::qualify(&compile_configuration.hir, PRELUDE_PREFIX), )?; @@ -51,16 +52,20 @@ pub fn compile_main( source_file: &FilePath, dependency_file: &FilePath, object_file: &FilePath, - context_interface_file: &FilePath, + context_interface_files: &BTreeMap, target_triple: Option<&str>, compile_configuration: &CompileConfiguration, application_configuration: &ApplicationConfiguration, ) -> Result<(), Box> { - let context_interface = interface_serializer::deserialize( - &infrastructure - .file_system - .read_to_vec(context_interface_file)?, - )?; + let context_interfaces = context_interface_files + .iter() + .map(|(key, file)| { + Ok(( + key.clone(), + interface_serializer::deserialize(&infrastructure.file_system.read_to_vec(file)?)?, + )) + }) + .collect::, Box>>()?; compile_mir_module( infrastructure, @@ -69,7 +74,7 @@ pub fn compile_main( infrastructure, source_file, dependency_file, - Some(&context_interface), + &context_interfaces.values().cloned().collect::>(), )?, &prelude_type_configuration_qualifier::qualify( &compile_configuration.hir, @@ -77,7 +82,7 @@ pub fn compile_main( ), &main_module_configuration_qualifier::qualify( &application_configuration.main_module, - &context_interface, + &context_interfaces, )?, )?, object_file, @@ -100,7 +105,7 @@ pub fn compile_test( test_module_configuration: &TestModuleConfiguration, ) -> Result<(), Box> { let (module, test_information) = hir_mir::compile_test( - &compile_to_hir(infrastructure, source_file, dependency_file, None)?, + &compile_to_hir(infrastructure, source_file, dependency_file, &[])?, &prelude_type_configuration_qualifier::qualify(&compile_configuration.hir, PRELUDE_PREFIX), test_module_configuration, )?; @@ -125,7 +130,7 @@ fn compile_to_hir( infrastructure: &Infrastructure, source_file: &FilePath, dependency_file: &FilePath, - context_interface: Option<&interface::Module>, + extra_prelude_interfaces: &[interface::Module], ) -> Result> { let (interface_files, prelude_interface_files) = dependency_serializer::deserialize( &infrastructure.file_system.read_to_vec(dependency_file)?, @@ -158,7 +163,7 @@ fn compile_to_hir( .map(|file| { interface_serializer::deserialize(&infrastructure.file_system.read_to_vec(file)?) }) - .chain(context_interface.cloned().map(Ok)) + .chain(extra_prelude_interfaces.iter().cloned().map(Ok)) .collect::, _>>()?, )?) } diff --git a/lib/app/src/module_compiler/main_module_configuration_qualifier.rs b/lib/app/src/module_compiler/main_module_configuration_qualifier.rs index f40068fd30..e0b7110e92 100644 --- a/lib/app/src/module_compiler/main_module_configuration_qualifier.rs +++ b/lib/app/src/module_compiler/main_module_configuration_qualifier.rs @@ -1,19 +1,33 @@ use crate::{application_configuration::MainModuleConfiguration, error::ApplicationError}; +use fnv::FnvHashMap; use std::error::Error; pub fn qualify( configuration: &MainModuleConfiguration, - context_interface: &interface::Module, -) -> Result> { - Ok(MainModuleConfiguration { + context_interfaces: &FnvHashMap, +) -> Result> { + Ok(hir_mir::MainModuleConfiguration { source_main_function_name: configuration.source_main_function_name.clone(), object_main_function_name: configuration.object_main_function_name.clone(), + context_type_name: configuration.main_context_type_name.clone(), + contexts: context_interfaces + .iter() + .map(|(key, interface)| Ok((key.clone(), qualify_context(interface, configuration)?))) + .collect::>>()?, + }) +} + +fn qualify_context( + context_interface: &interface::Module, + configuration: &MainModuleConfiguration, +) -> Result> { + Ok(hir_mir::ContextConfiguration { // TODO Support type aliases too. context_type_name: context_interface .type_definitions() .iter() .find(|definition| { - definition.original_name() == configuration.context_type_name + definition.original_name() == configuration.system_context_type_name && definition.is_public() }) .ok_or(ApplicationError::ContextTypeNotFound)? @@ -23,7 +37,7 @@ pub fn qualify( .declarations() .iter() .find(|definition| { - definition.original_name() == configuration.new_context_function_name + definition.original_name() == configuration.new_system_context_function_name }) .ok_or(ApplicationError::NewContextFunctionNotFound)? .name() diff --git a/lib/app/src/package_build_script_compiler.rs b/lib/app/src/package_build_script_compiler.rs index b200353441..337804b68a 100644 --- a/lib/app/src/package_build_script_compiler.rs +++ b/lib/app/src/package_build_script_compiler.rs @@ -82,22 +82,32 @@ pub fn compile_modules( Ok(MainModuleTarget::new( target.source_file().clone(), target.object_file().clone(), - file_path_resolver::resolve_interface_file( + system_package_finder::find( + infrastructure, + package_directory, output_directory, - &file_path_resolver::resolve_source_file( - &file_path_resolver::resolve_package_directory( + )? + .into_iter() + .map(|(key, url)| { + ( + key, + file_path_resolver::resolve_interface_file( output_directory, - &system_package_finder::find( - infrastructure, - package_directory, - output_directory, - )?, + &file_path_resolver::resolve_source_file( + &file_path_resolver::resolve_package_directory( + output_directory, + &url, + ), + &[application_configuration + .context_module_basename + .clone()], + &infrastructure.file_path_configuration, + ), + &infrastructure.file_path_configuration, ), - &[application_configuration.context_module_basename.clone()], - &infrastructure.file_path_configuration, - ), - &infrastructure.file_path_configuration, - ), + ) + }) + .collect(), )) }) .transpose()? @@ -174,14 +184,14 @@ pub fn compile_application( infrastructure .build_script_compiler .compile_application( - &file_path_resolver::resolve_package_directory( + &system_package_finder::find( + infrastructure, + main_package_directory, output_directory, - &system_package_finder::find( - infrastructure, - main_package_directory, - output_directory, - )?, - ), + )? + .values() + .map(|url| file_path_resolver::resolve_package_directory(output_directory, url)) + .collect::>(), &[file_path_resolver::resolve_main_package_archive_file( output_directory, &infrastructure.file_path_configuration, diff --git a/lib/app/src/system_package_finder.rs b/lib/app/src/system_package_finder.rs index dd4ebda26f..440b0c166a 100644 --- a/lib/app/src/system_package_finder.rs +++ b/lib/app/src/system_package_finder.rs @@ -3,6 +3,7 @@ use crate::{ external_package_configuration_reader, infra::{FilePath, Infrastructure}, }; +use fnv::FnvHashMap; use std::error::Error; // TODO Use a package type field. @@ -10,25 +11,31 @@ pub fn find( infrastructure: &Infrastructure, package_directory: &FilePath, output_directory: &FilePath, -) -> Result> { - let urls = external_package_configuration_reader::read_main( +) -> Result, Box> { + let package_configuration = infrastructure + .package_configuration_reader + .read(package_directory)?; + let system_packages = external_package_configuration_reader::read( infrastructure, - package_directory, + &package_configuration, output_directory, )? .into_iter() - .filter_map(|(url, configuration)| { + .filter_map(|(key, configuration)| { if configuration.is_system() { - Some(url) + Some(( + key.clone(), + package_configuration.dependencies()[&key].clone(), + )) } else { None } }) - .collect::>(); + .collect::>(); - match urls.as_slice() { - [] => Err(ApplicationError::SystemPackageNotFound.into()), - [url] => Ok(url.clone()), - _ => Err(ApplicationError::TooManySystemPackages.into()), + if system_packages.is_empty() { + Err(ApplicationError::SystemPackageNotFound.into()) + } else { + Ok(system_packages) } } diff --git a/lib/hir-mir/src/lib.rs b/lib/hir-mir/src/lib.rs index 039599444d..100c5eb668 100644 --- a/lib/hir-mir/src/lib.rs +++ b/lib/hir-mir/src/lib.rs @@ -34,7 +34,7 @@ pub use error::CompileError; pub use error_type_configuration::ErrorTypeConfiguration; use hir::{analysis::types::type_existence_validator, ir::*}; pub use list_type_configuration::ListTypeConfiguration; -pub use main_module_configuration::MainModuleConfiguration; +pub use main_module_configuration::*; pub use string_type_configuration::StringTypeConfiguration; pub use test_module_configuration::TestModuleConfiguration; @@ -46,7 +46,10 @@ pub fn compile_main( let context = CompileContext::new(module, compile_configuration.clone().into()); let module = main_function_compiler::compile(module, context.types(), main_module_configuration)?; - let (module, _) = compile_module(&module, &context)?; + let (module, _) = compile_module( + &module, + &CompileContext::new(&module, compile_configuration.clone().into()), + )?; Ok(module) } diff --git a/lib/hir-mir/src/main_function_compiler.rs b/lib/hir-mir/src/main_function_compiler.rs index 539af90d13..7f02b5f8fa 100644 --- a/lib/hir-mir/src/main_function_compiler.rs +++ b/lib/hir-mir/src/main_function_compiler.rs @@ -6,7 +6,7 @@ use hir::{ types::{self, Type}, }; -const MAIN_FUNCTION_WRAPPER_SUFFIX: &str = "__wrapper"; +const MAIN_FUNCTION_WRAPPER_SUFFIX: &str = ":wrapper"; pub fn compile( module: &Module, @@ -22,26 +22,58 @@ pub fn compile( .ok_or_else(|| CompileError::MainFunctionNotFound(module.position().clone()))?; let position = main_function_definition.position(); - let context_type = type_resolver::resolve( - &types::Reference::new( - &main_module_configuration.context_type_name, - position.clone(), - ), - types, - )?; + // TODO Mangle a context type name. + let context_type_definition = TypeDefinition::new( + &main_module_configuration.context_type_name, + &main_module_configuration.context_type_name, + main_module_configuration + .contexts + .iter() + .map(|(key, configuration)| { + Ok(types::RecordField::new( + key, + type_resolver::resolve( + &types::Reference::new(&configuration.context_type_name, position.clone()), + types, + )?, + )) + }) + .collect::, CompileError>>()?, + true, + false, + false, + position.clone(), + ); + let context_type = types::Record::new(context_type_definition.name(), position.clone()); + let new_context_function_declarations = main_module_configuration + .contexts + .iter() + .map(|(key, configuration)| { + Ok(( + key.clone(), + module + .declarations() + .iter() + .find(|definition| definition.name() == configuration.new_context_function_name) + .ok_or_else(|| { + CompileError::NewContextFunctionNotFound(module.position().clone()) + })?, + )) + }) + .collect::, CompileError>>()?; let function_type = types::Function::new( - vec![context_type], + vec![context_type.clone().into()], types::None::new(position.clone()), position.clone(), ); - let new_context_function_definition = module - .declarations() - .iter() - .find(|definition| definition.name() == main_module_configuration.new_context_function_name) - .ok_or_else(|| CompileError::NewContextFunctionNotFound(module.position().clone()))?; Ok(Module::new( - module.type_definitions().to_vec(), + module + .type_definitions() + .iter() + .cloned() + .chain([context_type_definition]) + .collect(), module.type_aliases().to_vec(), module.foreign_declarations().to_vec(), module.declarations().to_vec(), @@ -61,13 +93,26 @@ pub fn compile( Call::new( None, Variable::new(main_function_definition.name(), position.clone()), - vec![Call::new( - None, - Variable::new( - new_context_function_definition.name(), - new_context_function_definition.position().clone(), - ), - vec![], + vec![RecordConstruction::new( + context_type, + new_context_function_declarations + .iter() + .map(|(key, definition)| { + RecordField::new( + key, + Call::new( + None, + Variable::new( + definition.name(), + definition.position().clone(), + ), + vec![], + position.clone(), + ), + position.clone(), + ) + }) + .collect(), position.clone(), ) .into()], diff --git a/lib/hir-mir/src/main_module_configuration.rs b/lib/hir-mir/src/main_module_configuration.rs index fe804175a6..d3dd009ceb 100644 --- a/lib/hir-mir/src/main_module_configuration.rs +++ b/lib/hir-mir/src/main_module_configuration.rs @@ -1,6 +1,13 @@ +use std::collections::BTreeMap; + pub struct MainModuleConfiguration { pub source_main_function_name: String, pub object_main_function_name: String, + pub context_type_name: String, + pub contexts: BTreeMap, +} + +pub struct ContextConfiguration { pub context_type_name: String, pub new_context_function_name: String, } diff --git a/lib/infra/src/error.rs b/lib/infra/src/error.rs index 86e28c007f..1ab315281f 100644 --- a/lib/infra/src/error.rs +++ b/lib/infra/src/error.rs @@ -6,11 +6,12 @@ pub enum InfrastructureError { CommandNotFound(String), CreateDirectory { path: PathBuf, source: io::Error }, EnvironmentVariableNotFound(String), - LinkScriptNotFound(PathBuf), + LinkScriptNotFound, PackageUrlSchemeNotSupported(url::Url), ReadDirectory { path: PathBuf, source: io::Error }, ReadFile { path: PathBuf, source: io::Error }, - TooManyFfiBuildScripts(PathBuf), + MultipleFfiBuildScripts(PathBuf), + MultipleLinkScripts(Vec), WriteFile { path: PathBuf, source: io::Error }, } @@ -21,11 +22,12 @@ impl Error for InfrastructureError { Self::CommandNotFound(_) => None, Self::CreateDirectory { path: _, source } => Some(source), Self::EnvironmentVariableNotFound(_) => None, - Self::LinkScriptNotFound(_) => None, + Self::LinkScriptNotFound => None, Self::PackageUrlSchemeNotSupported(_) => None, Self::ReadDirectory { path: _, source } => Some(source), Self::ReadFile { path: _, source } => Some(source), - Self::TooManyFfiBuildScripts(_) => None, + Self::MultipleFfiBuildScripts(_) => None, + Self::MultipleLinkScripts(_) => None, Self::WriteFile { path: _, source } => Some(source), } } @@ -51,11 +53,9 @@ impl Display for InfrastructureError { Self::EnvironmentVariableNotFound(name) => { write!(formatter, "environment variable \"{}\" not found", name) } - Self::LinkScriptNotFound(directory) => write!( - formatter, - "link script not found in system package \"{}\"", - directory.display() - ), + Self::LinkScriptNotFound => { + write!(formatter, "link script not found in any system packages") + } Self::PackageUrlSchemeNotSupported(url) => { write!(formatter, "package URL scheme not supported {}", url) } @@ -67,13 +67,24 @@ impl Display for InfrastructureError { Self::ReadFile { path, source: _ } => { write!(formatter, "failed to read file {}", path.to_string_lossy()) } - Self::TooManyFfiBuildScripts(path) => { + Self::MultipleFfiBuildScripts(path) => { write!( formatter, - "too many FFI build scripts in package directory \"{}\"", + "multiple FFI build scripts found in package directory \"{}\"", path.display() ) } + Self::MultipleLinkScripts(paths) => { + write!( + formatter, + "multiple link scripts found in system packages {}", + paths + .iter() + .map(|path| format!("\"{}\"", path.display())) + .collect::>() + .join(", ") + ) + } Self::WriteFile { path, source: _ } => { write!(formatter, "failed to write file {}", path.to_string_lossy()) } diff --git a/lib/infra/src/ninja_build_script_compiler.rs b/lib/infra/src/ninja_build_script_compiler.rs index b18be26bc0..5c4a6a1b2f 100644 --- a/lib/infra/src/ninja_build_script_compiler.rs +++ b/lib/infra/src/ninja_build_script_compiler.rs @@ -3,7 +3,7 @@ use crate::{ default_target_finder, llvm_command_finder, package_script_finder, InfrastructureError, }; use app::infra::FilePath; -use std::{error::Error, sync::Arc}; +use std::{collections::BTreeMap, error::Error, path::PathBuf, sync::Arc}; const FFI_ARCHIVE_DIRECTORY: &str = "ffi"; const AR_DESCRIPTION: &str = " description = archiving package of $package_directory"; @@ -72,7 +72,7 @@ impl NinjaBuildScriptCompiler { " description = compiling module of $source_file", "rule compile_main", " command = pen compile-main --target $target \ - -f $main_function_interface_file $in $out", + $context_options $in $out", " description = compiling module of $source_file", "rule compile_prelude", " command = pen compile-prelude --target $target $in $out", @@ -242,9 +242,16 @@ impl NinjaBuildScriptCompiler { let ninja_dependency_file = object_file.with_extension(self.ninja_dynamic_dependency_file_extension); let bit_code_file = object_file.with_extension(self.bit_code_file_extension); - let main_function_interface_file = self - .file_path_converter - .convert_to_os_path(target.main_function_interface_file()); + let context_interface_files = target + .context_interface_files() + .iter() + .map(|(key, path)| { + ( + key.clone(), + self.file_path_converter.convert_to_os_path(path), + ) + }) + .collect::>(); Ok([ format!( @@ -252,12 +259,20 @@ impl NinjaBuildScriptCompiler { bit_code_file.display(), source_file.display(), dependency_file.display(), - main_function_interface_file.display(), + context_interface_files + .values() + .map(|path| path.display().to_string()) + .collect::>() + .join(" "), ninja_dependency_file.display(), ), format!( - " main_function_interface_file = {}", - main_function_interface_file.display() + " context_options = {}", + context_interface_files + .iter() + .map(|(key, path)| format!("-c {} {}", key, path.display())) + .collect::>() + .join(" ") ), format!(" dyndep = {}", ninja_dependency_file.display()), format!(" source_file = {}", target.source_file()), @@ -406,6 +421,24 @@ impl NinjaBuildScriptCompiler { .collect::>() .join(" ") } + + fn find_link_script( + &self, + system_package_directories: &[PathBuf], + ) -> Result> { + let scripts = system_package_directories + .iter() + .flat_map(|directory| { + package_script_finder::find(directory, self.link_script_basename).transpose() + }) + .collect::, _>>()?; + + match scripts.as_slice() { + [] => Err(InfrastructureError::LinkScriptNotFound.into()), + [script] => Ok(script.into()), + _ => Err(InfrastructureError::MultipleLinkScripts(scripts).into()), + } + } } impl app::infra::BuildScriptCompiler for NinjaBuildScriptCompiler { @@ -532,13 +565,10 @@ impl app::infra::BuildScriptCompiler for NinjaBuildScriptCompiler { fn compile_application( &self, - system_package_directory: &FilePath, + system_package_directories: &[FilePath], archive_files: &[FilePath], application_file: &FilePath, ) -> Result> { - let system_package_directory = self - .file_path_converter - .convert_to_os_path(system_package_directory); let application_file = self .file_path_converter .convert_to_os_path(application_file); @@ -547,11 +577,13 @@ impl app::infra::BuildScriptCompiler for NinjaBuildScriptCompiler { "rule link".into(), format!( " command = {} -t $target -o $out $in", - package_script_finder::find(&system_package_directory, self.link_script_basename)? - .ok_or(InfrastructureError::LinkScriptNotFound( - system_package_directory, - ))? - .display(), + self.find_link_script( + &system_package_directories + .iter() + .map(|directory| self.file_path_converter.convert_to_os_path(directory)) + .collect::>() + )? + .display(), ), " description = linking application".into(), format!( diff --git a/lib/infra/src/package_script_finder.rs b/lib/infra/src/package_script_finder.rs index 31c6a10807..0ac5058cdf 100644 --- a/lib/infra/src/package_script_finder.rs +++ b/lib/infra/src/package_script_finder.rs @@ -17,7 +17,7 @@ pub fn find( [script] => Some(script.into()), _ => { return Err( - InfrastructureError::TooManyFfiBuildScripts(package_directory.into()).into(), + InfrastructureError::MultipleFfiBuildScripts(package_directory.into()).into(), ) } })