mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Use app path in output
This commit is contained in:
parent
a78434fd48
commit
eb6a7b51ff
3 changed files with 74 additions and 22 deletions
|
@ -85,6 +85,9 @@ pub fn build_file(
|
||||||
buf
|
buf
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cwd = app_o_file.parent().unwrap();
|
||||||
|
let binary_path = cwd.join(&*loaded.output_path); // TODO should join ".exe" on Windows
|
||||||
|
|
||||||
program::gen_from_mono_module(
|
program::gen_from_mono_module(
|
||||||
&arena,
|
&arena,
|
||||||
loaded,
|
loaded,
|
||||||
|
@ -106,11 +109,8 @@ pub fn build_file(
|
||||||
size,
|
size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cwd = app_o_file.parent().unwrap();
|
|
||||||
|
|
||||||
// Step 2: link the precompiled host and compiled app
|
// Step 2: link the precompiled host and compiled app
|
||||||
let host_input_path = cwd.join("platform").join("host.o");
|
let host_input_path = cwd.join("platform").join("host.o");
|
||||||
let binary_path = cwd.join("app"); // TODO should be app.exe on Windows
|
|
||||||
|
|
||||||
// TODO we should no longer need to do this once we have platforms on
|
// TODO we should no longer need to do this once we have platforms on
|
||||||
// a package repository, as we can then get precompiled hosts from there.
|
// a package repository, as we can then get precompiled hosts from there.
|
||||||
|
|
|
@ -19,7 +19,7 @@ use roc_mono::ir::{
|
||||||
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache};
|
use roc_mono::layout::{Layout, LayoutCache};
|
||||||
use roc_parse::ast::{self, Attempting, TypeAnnotation};
|
use roc_parse::ast::{self, Attempting, StrLiteral, TypeAnnotation};
|
||||||
use roc_parse::header::{ExposesEntry, ImportsEntry, PlatformHeader, TypedIdent};
|
use roc_parse::header::{ExposesEntry, ImportsEntry, PlatformHeader, TypedIdent};
|
||||||
use roc_parse::module::module_defs;
|
use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{self, Fail, Parser};
|
use roc_parse::parser::{self, Fail, Parser};
|
||||||
|
@ -39,6 +39,9 @@ use std::str::from_utf8_unchecked;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
/// Default name for the binary generated for an app, if an invalid one was specified.
|
||||||
|
const DEFAULT_APP_OUTPUT_PATH: &str = "app";
|
||||||
|
|
||||||
/// Filename extension for normal Roc modules
|
/// Filename extension for normal Roc modules
|
||||||
const ROC_FILE_EXTENSION: &str = "roc";
|
const ROC_FILE_EXTENSION: &str = "roc";
|
||||||
|
|
||||||
|
@ -533,7 +536,7 @@ pub enum BuildProblem<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ModuleHeader<'a> {
|
struct ModuleHeader<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleName,
|
module_name: AppOrInterfaceName<'a>,
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
deps_by_name: MutMap<ModuleName, ModuleId>,
|
deps_by_name: MutMap<ModuleName, ModuleId>,
|
||||||
|
@ -580,6 +583,7 @@ pub struct MonomorphizedModule<'a> {
|
||||||
pub module_id: ModuleId,
|
pub module_id: ModuleId,
|
||||||
pub interns: Interns,
|
pub interns: Interns,
|
||||||
pub subs: Subs,
|
pub subs: Subs,
|
||||||
|
pub output_path: Box<str>,
|
||||||
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
||||||
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
||||||
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
||||||
|
@ -598,7 +602,7 @@ pub struct VariablySizedLayouts<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParsedModule<'a> {
|
struct ParsedModule<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleName,
|
module_name: AppOrInterfaceName<'a>,
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
@ -617,7 +621,7 @@ enum Msg<'a> {
|
||||||
CanonicalizedAndConstrained {
|
CanonicalizedAndConstrained {
|
||||||
constrained_module: ConstrainedModule,
|
constrained_module: ConstrainedModule,
|
||||||
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
||||||
module_docs: ModuleDocumentation,
|
module_docs: Option<ModuleDocumentation>,
|
||||||
},
|
},
|
||||||
MadeEffectModule {
|
MadeEffectModule {
|
||||||
constrained_module: ConstrainedModule,
|
constrained_module: ConstrainedModule,
|
||||||
|
@ -671,6 +675,7 @@ struct State<'a> {
|
||||||
pub goal_phase: Phase,
|
pub goal_phase: Phase,
|
||||||
pub stdlib: StdLib,
|
pub stdlib: StdLib,
|
||||||
pub exposed_types: SubsByModule,
|
pub exposed_types: SubsByModule,
|
||||||
|
pub output_path: Option<&'a str>,
|
||||||
|
|
||||||
pub headers_parsed: MutSet<ModuleId>,
|
pub headers_parsed: MutSet<ModuleId>,
|
||||||
|
|
||||||
|
@ -1242,6 +1247,7 @@ where
|
||||||
root_id,
|
root_id,
|
||||||
goal_phase,
|
goal_phase,
|
||||||
stdlib,
|
stdlib,
|
||||||
|
output_path: None,
|
||||||
module_cache: ModuleCache::default(),
|
module_cache: ModuleCache::default(),
|
||||||
dependencies: Dependencies::default(),
|
dependencies: Dependencies::default(),
|
||||||
procedures: MutMap::default(),
|
procedures: MutMap::default(),
|
||||||
|
@ -1426,6 +1432,22 @@ fn update<'a>(
|
||||||
.sources
|
.sources
|
||||||
.insert(parsed.module_id, (parsed.module_path.clone(), parsed.src));
|
.insert(parsed.module_id, (parsed.module_path.clone(), parsed.src));
|
||||||
|
|
||||||
|
// If this was an app module, set the output path to be
|
||||||
|
// the module's declared "name".
|
||||||
|
//
|
||||||
|
// e.g. for `app "blah"` we should generate an output file named "blah"
|
||||||
|
match &parsed.module_name {
|
||||||
|
AppOrInterfaceName::App(output_str) => match output_str {
|
||||||
|
StrLiteral::PlainLine(path) => {
|
||||||
|
state.output_path = Some(path);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!("TODO gracefully handle a malformed string literal after `app` keyword.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AppOrInterfaceName::Interface(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
let module_id = parsed.module_id;
|
let module_id = parsed.module_id;
|
||||||
|
|
||||||
state.module_cache.parsed.insert(parsed.module_id, parsed);
|
state.module_cache.parsed.insert(parsed.module_id, parsed);
|
||||||
|
@ -1449,10 +1471,9 @@ fn update<'a>(
|
||||||
.can_problems
|
.can_problems
|
||||||
.insert(module_id, canonicalization_problems);
|
.insert(module_id, canonicalization_problems);
|
||||||
|
|
||||||
state
|
if let Some(docs) = module_docs {
|
||||||
.module_cache
|
state.module_cache.documentation.insert(module_id, docs);
|
||||||
.documentation
|
}
|
||||||
.insert(module_id, module_docs);
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.module_cache
|
.module_cache
|
||||||
|
@ -1750,6 +1771,7 @@ fn finish_specialization<'a>(
|
||||||
let State {
|
let State {
|
||||||
procedures,
|
procedures,
|
||||||
module_cache,
|
module_cache,
|
||||||
|
output_path,
|
||||||
..
|
..
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
|
@ -1770,6 +1792,7 @@ fn finish_specialization<'a>(
|
||||||
can_problems,
|
can_problems,
|
||||||
mono_problems,
|
mono_problems,
|
||||||
type_problems,
|
type_problems,
|
||||||
|
output_path: output_path.unwrap_or(DEFAULT_APP_OUTPUT_PATH).into(),
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
module_id: state.root_id,
|
module_id: state.root_id,
|
||||||
subs,
|
subs,
|
||||||
|
@ -1966,7 +1989,10 @@ fn parse_header<'a>(
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
|
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
|
||||||
header.name,
|
Located {
|
||||||
|
region: header.name.region,
|
||||||
|
value: AppOrInterfaceName::Interface(header.name.value),
|
||||||
|
},
|
||||||
filename,
|
filename,
|
||||||
header.exposes.into_bump_slice(),
|
header.exposes.into_bump_slice(),
|
||||||
header.imports.into_bump_slice(),
|
header.imports.into_bump_slice(),
|
||||||
|
@ -1980,7 +2006,10 @@ fn parse_header<'a>(
|
||||||
pkg_config_dir.pop();
|
pkg_config_dir.pop();
|
||||||
|
|
||||||
let (module_id, app_module_header_msg) = send_header(
|
let (module_id, app_module_header_msg) = send_header(
|
||||||
header.name,
|
Located {
|
||||||
|
region: header.name.region,
|
||||||
|
value: AppOrInterfaceName::App(header.name.value),
|
||||||
|
},
|
||||||
filename,
|
filename,
|
||||||
header.provides.into_bump_slice(),
|
header.provides.into_bump_slice(),
|
||||||
header.imports.into_bump_slice(),
|
header.imports.into_bump_slice(),
|
||||||
|
@ -2082,9 +2111,16 @@ fn load_from_str<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum AppOrInterfaceName<'a> {
|
||||||
|
/// A filename
|
||||||
|
App(StrLiteral<'a>),
|
||||||
|
Interface(roc_parse::header::ModuleName<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn send_header<'a>(
|
fn send_header<'a>(
|
||||||
name: Located<roc_parse::header::ModuleName<'a>>,
|
loc_name: Located<AppOrInterfaceName<'a>>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
|
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
|
||||||
imports: &'a [Located<ImportsEntry<'a>>],
|
imports: &'a [Located<ImportsEntry<'a>>],
|
||||||
|
@ -2093,10 +2129,17 @@ fn send_header<'a>(
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
) -> (ModuleId, Msg<'a>) {
|
) -> (ModuleId, Msg<'a>) {
|
||||||
let declared_name: ModuleName = name.value.as_str().into();
|
use AppOrInterfaceName::*;
|
||||||
|
|
||||||
// TODO check to see if declared_name is consistent with filename.
|
let declared_name: ModuleName = match &loc_name.value {
|
||||||
// If it isn't, report a problem!
|
App(_) => ModuleName::APP.into(),
|
||||||
|
Interface(module_name) => {
|
||||||
|
// TODO check to see if module_name is consistent with filename.
|
||||||
|
// If it isn't, report a problem!
|
||||||
|
|
||||||
|
module_name.as_str().into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut imported: Vec<(ModuleName, Vec<Ident>, Region)> = Vec::with_capacity(imports.len());
|
let mut imported: Vec<(ModuleName, Vec<Ident>, Region)> = Vec::with_capacity(imports.len());
|
||||||
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
||||||
|
@ -2199,15 +2242,13 @@ fn send_header<'a>(
|
||||||
// We always need to send these, even if deps is empty,
|
// We always need to send these, even if deps is empty,
|
||||||
// because the coordinator thread needs to receive this message
|
// because the coordinator thread needs to receive this message
|
||||||
// to decrement its "pending" count.
|
// to decrement its "pending" count.
|
||||||
|
|
||||||
// Send the header the main thread for processing,
|
|
||||||
(
|
(
|
||||||
home,
|
home,
|
||||||
Msg::Header(ModuleHeader {
|
Msg::Header(ModuleHeader {
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
exposed_ident_ids: ident_ids,
|
exposed_ident_ids: ident_ids,
|
||||||
module_name: declared_name,
|
module_name: loc_name.value,
|
||||||
imported_modules,
|
imported_modules,
|
||||||
deps_by_name,
|
deps_by_name,
|
||||||
exposes: exposed,
|
exposes: exposed,
|
||||||
|
@ -2618,8 +2659,14 @@ fn canonicalize_and_constrain<'a>(
|
||||||
|
|
||||||
// Generate documentation information
|
// Generate documentation information
|
||||||
// TODO: store timing information?
|
// TODO: store timing information?
|
||||||
let module_docs =
|
let module_docs = match module_name {
|
||||||
crate::docs::generate_module_docs(module_name, &exposed_ident_ids, &parsed_defs);
|
AppOrInterfaceName::App(_) => None,
|
||||||
|
AppOrInterfaceName::Interface(name) => Some(crate::docs::generate_module_docs(
|
||||||
|
name.as_str().into(),
|
||||||
|
&exposed_ident_ids,
|
||||||
|
&parsed_defs,
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
let mut var_store = VarStore::default();
|
let mut var_store = VarStore::default();
|
||||||
let canonicalized = canonicalize_module_defs(
|
let canonicalized = canonicalize_module_defs(
|
||||||
|
@ -2749,6 +2796,10 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
|
||||||
(module_name.as_str().into(), exposed)
|
(module_name.as_str().into(), exposed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Package(_package_name, _exposes) => {
|
||||||
|
todo!("TODO support exposing package-qualified module names.");
|
||||||
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
|
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
|
||||||
// Ignore spaces.
|
// Ignore spaces.
|
||||||
exposed_from_import(*sub_entry)
|
exposed_from_import(*sub_entry)
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl TagName {
|
||||||
impl ModuleName {
|
impl ModuleName {
|
||||||
// NOTE: After adding one of these, go to `impl ModuleId` and
|
// NOTE: After adding one of these, go to `impl ModuleId` and
|
||||||
// add a corresponding ModuleId to there!
|
// add a corresponding ModuleId to there!
|
||||||
|
pub const APP: &'static str = ""; // app modules have no module name
|
||||||
pub const BOOL: &'static str = "Bool";
|
pub const BOOL: &'static str = "Bool";
|
||||||
pub const STR: &'static str = "Str";
|
pub const STR: &'static str = "Str";
|
||||||
pub const NUM: &'static str = "Num";
|
pub const NUM: &'static str = "Num";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue