From 37fe6c926e1752e514de619542c6f0e9a4169444 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Wed, 14 Apr 2021 18:39:58 -0600 Subject: make include/export/unexport their own line types & implement export+assign --- src/makefile/input.rs | 196 ++++++++++++++++++++++++++++---------------------- 1 file changed, 112 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/makefile/input.rs b/src/makefile/input.rs index e2add0c..c9810ab 100644 --- a/src/makefile/input.rs +++ b/src/makefile/input.rs @@ -20,12 +20,17 @@ use super::inference_rules::InferenceRule; use super::r#macro::ExportConfig; use super::r#macro::{Macro, Set as MacroSet}; use super::target::{StaticTargetSet, Target}; -use super::token::{tokenize, Token, TokenString}; +use super::token::{Token, TokenString}; use super::ItemSource; enum LineType { Rule, Macro, + Include, + #[cfg(feature = "full")] + Export, + #[cfg(feature = "full")] + Unexport, Unknown, } @@ -35,6 +40,17 @@ impl LineType { if line_tokens.starts_with("define ") { return Self::Macro; } + if line_tokens.starts_with("include ") || line_tokens.starts_with("-include ") { + return Self::Include; + } + #[cfg(feature = "full")] + if line_tokens.starts_with("export") { + return Self::Export; + } + #[cfg(feature = "full")] + if line_tokens.starts_with("unexport") { + return Self::Unexport; + } for token in line_tokens.tokens() { if let Token::Text(text) = token { let colon_idx = text.find(':'); @@ -262,50 +278,6 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { while let Some((line_number, line)) = self.next_line(topmost) { let line = line?; - // handle include lines - let original_line = &line; - if let Some(line) = line - .strip_prefix("include ") - .or(line.strip_prefix("-include ")) - { - // remove extra leading space - let line = line.trim_start(); - let line = self.expand_macros(&tokenize(line)?)?; - let fields = line.split_whitespace(); - // POSIX says we only have to handle a single filename, but GNU make - // handles arbitrarily many filenames, and it's not like that's more work - for field in fields { - let child_macros = self.macros.with_overlay(); - let child = MakefileReader::read_file(self.args, child_macros, field) - .with_context(|| format!("while including {}", field)); - match child { - Ok(child) => { - let child = child.finish(); - self.extend(child); - } - Err(err) => { - if !original_line.starts_with('-') { - match err.downcast_ref::() { - Some(err) if err.kind() == IoErrorKind::NotFound => { - log::error!( - "{}:{}: included makefile {} not found", - &self.file_name, - line_number, - field, - ); - self.failed_includes.push(field.to_owned()); - } - _ => { - return Err(err); - } - } - } - } - } - } - continue; - } - if line.trim().is_empty() { // handle blank lines continue; @@ -352,13 +324,12 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { match line_type { LineType::Rule => { - self.read_rule(&line_tokens, line_number) - .wrap_err_with(|| { - format!( - "while parsing rule definition starting on line {}", - line_number - ) - })? + self.read_rule(line_tokens, line_number).wrap_err_with(|| { + format!( + "while parsing rule definition starting on line {}", + line_number + ) + })?; } LineType::Macro => { self.read_macro(line_tokens, line_number) @@ -367,33 +338,44 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { "while parsing macro definition starting on line {}", line_number ) - })? + })?; + } + LineType::Include => { + self.read_include(line_tokens, line_number) + .wrap_err_with(|| { + format!("while parsing include starting on line {}", line_number) + })?; + } + #[cfg(feature = "full")] + LineType::Export => { + let mut line_tokens = line_tokens; + line_tokens.strip_prefix("export"); + if line_tokens.is_empty() { + self.macros.exported = ExportConfig::all_but(); + } else { + let exported = if line_tokens.contains_text("=") { + // that's an assignment! + let new_macro = self.read_macro(line_tokens, line_number)?; + new_macro + } else { + self.expand_macros(&line_tokens)? + }; + self.macros.exported.add_all(exported.split_whitespace()); + } + } + #[cfg(feature = "full")] + LineType::Unexport => { + let mut line_tokens = line_tokens; + line_tokens.strip_prefix("unexport"); + if line_tokens.is_empty() { + self.macros.exported = ExportConfig::only(); + } else { + let exported = self.expand_macros(&line_tokens)?; + self.macros.exported.remove_all(exported.split_whitespace()); + } } LineType::Unknown => { if !line_tokens.is_empty() { - // TODO handle assignments here - #[cfg(feature = "full")] - if line_tokens.starts_with("export") { - let mut line_tokens = line_tokens; - line_tokens.strip_prefix("export"); - if line_tokens.is_empty() { - self.macros.exported = ExportConfig::all_but(); - } else { - let exported = self.expand_macros(&line_tokens)?; - self.macros.exported.add_all(exported.split_whitespace()); - } - continue; - } else if line_tokens.starts_with("unexport") { - let mut line_tokens = line_tokens; - line_tokens.strip_prefix("unexport"); - if line_tokens.is_empty() { - self.macros.exported = ExportConfig::only(); - } else { - let exported = self.expand_macros(&line_tokens)?; - self.macros.exported.remove_all(exported.split_whitespace()); - } - continue; - } bail!( "error: line {}: unknown line \"{}\"", line_number, @@ -543,7 +525,49 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { } } - fn read_rule(&mut self, line_tokens: &TokenString, line_number: usize) -> Result<()> { + fn read_include(&mut self, mut line_tokens: TokenString, line_number: usize) -> Result<()> { + let suppress_errors = line_tokens.starts_with("-"); + line_tokens.strip_prefix("-"); + line_tokens.strip_prefix("include "); + // remove extra leading space + line_tokens.trim_start(); + let line = self.expand_macros(&line_tokens)?; + let fields = line.split_whitespace(); + // POSIX says we only have to handle a single filename, but GNU make + // handles arbitrarily many filenames, and it's not like that's more work + for field in fields { + let child_macros = self.macros.with_overlay(); + let child = MakefileReader::read_file(self.args, child_macros, field) + .with_context(|| format!("while including {}", field)); + match child { + Ok(child) => { + let child = child.finish(); + self.extend(child); + } + Err(err) => { + if !suppress_errors { + match err.downcast_ref::() { + Some(err) if err.kind() == IoErrorKind::NotFound => { + log::error!( + "{}:{}: included makefile {} not found", + &self.file_name, + line_number, + field, + ); + self.failed_includes.push(field.to_owned()); + } + _ => { + return Err(err); + } + } + } + } + } + } + Ok(()) + } + + fn read_rule(&mut self, line_tokens: TokenString, line_number: usize) -> Result<()> { let (targets, not_targets) = line_tokens .split_once(':') .ok_or_else(|| eyre!("read_rule couldn't find a ':' on line {}", line_number))?; @@ -754,7 +778,8 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { Ok(()) } - fn read_macro(&mut self, mut line_tokens: TokenString, line_number: usize) -> Result<()> { + /// If successful, returns the name of the macro which was read. + fn read_macro(&mut self, mut line_tokens: TokenString, line_number: usize) -> Result { let (name, mut value) = if cfg!(feature = "full") && line_tokens.starts_with("define ") { line_tokens.strip_prefix("define "); if line_tokens.ends_with("=") { @@ -814,19 +839,22 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { value }; - match self.macros.get(name) { + let skipped = match self.macros.get(name) { // We always let command line or MAKEFLAGS macros override macros from the file. Some(Macro { source: ItemSource::CommandLineOrMakeflags, .. - }) => return Ok(()), + }) => true, // We let environment variables override macros from the file only if the command-line argument to do that was given Some(Macro { source: ItemSource::Environment, .. - }) if self.args.environment_overrides => return Ok(()), - Some(_) if skip_if_defined => return Ok(()), - _ => {} + }) => self.args.environment_overrides, + Some(_) => skip_if_defined, + None => false, + }; + if skipped { + return Ok(name.to_owned()); } log::trace!( @@ -863,7 +891,7 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { }; self.macros.set(name.into(), value); - Ok(()) + Ok(name.to_owned()) } fn expand_macros(&self, text: &TokenString) -> Result { -- cgit v1.2.3