aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-14 18:39:58 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-14 18:39:58 -0600
commit37fe6c926e1752e514de619542c6f0e9a4169444 (patch)
treedf8e911b37b10446160afba153a9cca58c87182d
parent30295f5a8d34e0101cf3e17d8c786c8fdd795072 (diff)
downloadmakers-37fe6c926e1752e514de619542c6f0e9a4169444.tar.gz
makers-37fe6c926e1752e514de619542c6f0e9a4169444.zip
make include/export/unexport their own line types & implement export+assign
-rw-r--r--src/makefile/input.rs196
1 files changed, 112 insertions, 84 deletions
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::<IoError>() {
- 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::<IoError>() {
+ 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<String> {
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<String> {