Use app path in output

This commit is contained in:
Richard Feldman 2020-11-18 00:28:47 -05:00
parent a78434fd48
commit eb6a7b51ff
3 changed files with 74 additions and 22 deletions

View File

@ -85,6 +85,9 @@ pub fn build_file(
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(
&arena,
loaded,
@ -106,11 +109,8 @@ pub fn build_file(
size,
);
let cwd = app_o_file.parent().unwrap();
// Step 2: link the precompiled host and compiled app
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
// a package repository, as we can then get precompiled hosts from there.

View File

@ -19,7 +19,7 @@ use roc_mono::ir::{
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
};
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::module::module_defs;
use roc_parse::parser::{self, Fail, Parser};
@ -39,6 +39,9 @@ use std::str::from_utf8_unchecked;
use std::sync::Arc;
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
const ROC_FILE_EXTENSION: &str = "roc";
@ -533,7 +536,7 @@ pub enum BuildProblem<'a> {
#[derive(Debug)]
struct ModuleHeader<'a> {
module_id: ModuleId,
module_name: ModuleName,
module_name: AppOrInterfaceName<'a>,
module_path: PathBuf,
exposed_ident_ids: IdentIds,
deps_by_name: MutMap<ModuleName, ModuleId>,
@ -580,6 +583,7 @@ pub struct MonomorphizedModule<'a> {
pub module_id: ModuleId,
pub interns: Interns,
pub subs: Subs,
pub output_path: Box<str>,
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
@ -598,7 +602,7 @@ pub struct VariablySizedLayouts<'a> {
#[derive(Debug)]
struct ParsedModule<'a> {
module_id: ModuleId,
module_name: ModuleName,
module_name: AppOrInterfaceName<'a>,
module_path: PathBuf,
src: &'a str,
module_timing: ModuleTiming,
@ -617,7 +621,7 @@ enum Msg<'a> {
CanonicalizedAndConstrained {
constrained_module: ConstrainedModule,
canonicalization_problems: Vec<roc_problem::can::Problem>,
module_docs: ModuleDocumentation,
module_docs: Option<ModuleDocumentation>,
},
MadeEffectModule {
constrained_module: ConstrainedModule,
@ -671,6 +675,7 @@ struct State<'a> {
pub goal_phase: Phase,
pub stdlib: StdLib,
pub exposed_types: SubsByModule,
pub output_path: Option<&'a str>,
pub headers_parsed: MutSet<ModuleId>,
@ -1242,6 +1247,7 @@ where
root_id,
goal_phase,
stdlib,
output_path: None,
module_cache: ModuleCache::default(),
dependencies: Dependencies::default(),
procedures: MutMap::default(),
@ -1426,6 +1432,22 @@ fn update<'a>(
.sources
.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;
state.module_cache.parsed.insert(parsed.module_id, parsed);
@ -1449,10 +1471,9 @@ fn update<'a>(
.can_problems
.insert(module_id, canonicalization_problems);
state
.module_cache
.documentation
.insert(module_id, module_docs);
if let Some(docs) = module_docs {
state.module_cache.documentation.insert(module_id, docs);
}
state
.module_cache
@ -1750,6 +1771,7 @@ fn finish_specialization<'a>(
let State {
procedures,
module_cache,
output_path,
..
} = state;
@ -1770,6 +1792,7 @@ fn finish_specialization<'a>(
can_problems,
mono_problems,
type_problems,
output_path: output_path.unwrap_or(DEFAULT_APP_OUTPUT_PATH).into(),
exposed_to_host,
module_id: state.root_id,
subs,
@ -1966,7 +1989,10 @@ fn parse_header<'a>(
match parsed {
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
header.name,
Located {
region: header.name.region,
value: AppOrInterfaceName::Interface(header.name.value),
},
filename,
header.exposes.into_bump_slice(),
header.imports.into_bump_slice(),
@ -1980,7 +2006,10 @@ fn parse_header<'a>(
pkg_config_dir.pop();
let (module_id, app_module_header_msg) = send_header(
header.name,
Located {
region: header.name.region,
value: AppOrInterfaceName::App(header.name.value),
},
filename,
header.provides.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)]
fn send_header<'a>(
name: Located<roc_parse::header::ModuleName<'a>>,
loc_name: Located<AppOrInterfaceName<'a>>,
filename: PathBuf,
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
imports: &'a [Located<ImportsEntry<'a>>],
@ -2093,10 +2129,17 @@ fn send_header<'a>(
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_timing: ModuleTiming,
) -> (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.
// If it isn't, report a problem!
let declared_name: ModuleName = match &loc_name.value {
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_modules: MutSet<ModuleId> = MutSet::default();
@ -2199,15 +2242,13 @@ fn send_header<'a>(
// We always need to send these, even if deps is empty,
// because the coordinator thread needs to receive this message
// to decrement its "pending" count.
// Send the header the main thread for processing,
(
home,
Msg::Header(ModuleHeader {
module_id: home,
module_path: filename,
exposed_ident_ids: ident_ids,
module_name: declared_name,
module_name: loc_name.value,
imported_modules,
deps_by_name,
exposes: exposed,
@ -2618,8 +2659,14 @@ fn canonicalize_and_constrain<'a>(
// Generate documentation information
// TODO: store timing information?
let module_docs =
crate::docs::generate_module_docs(module_name, &exposed_ident_ids, &parsed_defs);
let module_docs = match module_name {
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 canonicalized = canonicalize_module_defs(
@ -2749,6 +2796,10 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
(module_name.as_str().into(), exposed)
}
Package(_package_name, _exposes) => {
todo!("TODO support exposing package-qualified module names.");
}
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
// Ignore spaces.
exposed_from_import(*sub_entry)

View File

@ -59,6 +59,7 @@ impl TagName {
impl ModuleName {
// NOTE: After adding one of these, go to `impl ModuleId` and
// 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 STR: &'static str = "Str";
pub const NUM: &'static str = "Num";