Skip to content

Commit

Permalink
Add new compile_intermediates function. (#914)
Browse files Browse the repository at this point in the history
* Add new compile_intermediates function.

This new function can be used to just compile the files to a bunch of .o
files.

* Pre-allocate objects vec in objects_from_files

* Remove some dead code in objects_from_file

Since #684 was merged, it is
impossible for `obj` to not start with dst - if `obj` is absolute or
contains `../` in its Path, then the path will be hashed, and the file
will still be placed under dst.

As such, this obj.starts_with(&dst) check is always true.

* Always hash the file prefix

* Fix error handling of objects_from_files

* Fix nightly warning
  • Loading branch information
roblabla committed Jan 24, 2024
1 parent f17047d commit 385b43f
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 44 deletions.
118 changes: 76 additions & 42 deletions src/lib.rs
Expand Up @@ -1131,48 +1131,7 @@ impl Build {
};
let dst = self.get_out_dir()?;

let mut objects = Vec::new();
for file in self.files.iter() {
let obj = if file.has_root() || file.components().any(|x| x == Component::ParentDir) {
// If `file` is an absolute path or might not be usable directly as a suffix due to
// using "..", use the `basename` prefixed with the `dirname`'s hash to ensure name
// uniqueness.
let basename = file
.file_name()
.ok_or_else(|| Error::new(ErrorKind::InvalidArgument, "file_name() failure"))?
.to_string_lossy();
let dirname = file
.parent()
.ok_or_else(|| Error::new(ErrorKind::InvalidArgument, "parent() failure"))?
.to_string_lossy();
let mut hasher = hash_map::DefaultHasher::new();
hasher.write(dirname.to_string().as_bytes());
dst.join(format!("{:016x}-{}", hasher.finish(), basename))
.with_extension("o")
} else {
dst.join(file).with_extension("o")
};
let obj = if !obj.starts_with(&dst) {
dst.join(obj.file_name().ok_or_else(|| {
Error::new(ErrorKind::IOError, "Getting object file details failed.")
})?)
} else {
obj
};

match obj.parent() {
Some(s) => fs::create_dir_all(s)?,
None => {
return Err(Error::new(
ErrorKind::IOError,
"Getting object file details failed.",
));
}
};

objects.push(Object::new(file.to_path_buf(), obj));
}

let objects = objects_from_files(&self.files, &dst)?;
let print = PrintThread::new()?;

self.compile_objects(&objects, &print)?;
Expand Down Expand Up @@ -1316,6 +1275,32 @@ impl Build {
}
}

/// Run the compiler, generating intermediate files, but without linking
/// them into an archive file.
///
/// This will return a list of compiled object files, in the same order
/// as they were passed in as `file`/`files` methods.
pub fn compile_intermediates(&self) -> Vec<PathBuf> {
match self.try_compile_intermediates() {
Ok(v) => v,
Err(e) => fail(&e.message),
}
}

/// Run the compiler, generating intermediate files, but without linking
/// them into an archive file.
///
/// This will return a result instead of panicing; see `compile_intermediates()` for the complete description.
pub fn try_compile_intermediates(&self) -> Result<Vec<PathBuf>, Error> {
let dst = self.get_out_dir()?;
let objects = objects_from_files(&self.files, &dst)?;
let print = PrintThread::new()?;

self.compile_objects(&objects, &print)?;

Ok(objects.into_iter().map(|v| v.dst).collect())
}

#[cfg(feature = "parallel")]
fn compile_objects(&self, objs: &[Object], print: &PrintThread) -> Result<(), Error> {
use std::cell::Cell;
Expand Down Expand Up @@ -2379,6 +2364,7 @@ impl Build {
}

fn apple_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
#[allow(dead_code)]
enum ArchSpec {
Device(&'static str),
Simulator(&'static str),
Expand Down Expand Up @@ -3837,6 +3823,54 @@ fn wait_on_child(cmd: &Command, program: &str, child: &mut Child) -> Result<(),
}
}

/// Find the destination object path for each file in the input source files,
/// and store them in the output Object.
fn objects_from_files(files: &[Arc<Path>], dst: &Path) -> Result<Vec<Object>, Error> {
let mut objects = Vec::with_capacity(files.len());
for file in files {
let basename = file
.file_name()
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidArgument,
"No file_name for object file path!",
)
})?
.to_string_lossy();
let dirname = file
.parent()
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidArgument,
"No parent for object file path!",
)
})?
.to_string_lossy();

// Hash the dirname. This should prevent conflicts if we have multiple
// object files with the same filename in different subfolders.
let mut hasher = hash_map::DefaultHasher::new();
hasher.write(dirname.to_string().as_bytes());
let obj = dst
.join(format!("{:016x}-{}", hasher.finish(), basename))
.with_extension("o");

match obj.parent() {
Some(s) => fs::create_dir_all(s)?,
None => {
return Err(Error::new(
ErrorKind::InvalidArgument,
"dst is an invalid path with no parent",
));
}
};

objects.push(Object::new(file.to_path_buf(), obj));
}

Ok(objects)
}

#[cfg(feature = "parallel")]
fn try_wait_on_child(
cmd: &Command,
Expand Down
24 changes: 22 additions & 2 deletions tests/test.rs
Expand Up @@ -24,7 +24,8 @@ fn gnu_smoke() {
.must_have("-c")
.must_have("-ffunction-sections")
.must_have("-fdata-sections");
test.cmd(1).must_have(test.td.path().join("foo.o"));
test.cmd(1)
.must_have(test.td.path().join("d1fba762150c532c-foo.o"));
}

#[test]
Expand Down Expand Up @@ -399,7 +400,8 @@ fn msvc_smoke() {
.must_not_have("-Z7")
.must_have("-c")
.must_have("-MD");
test.cmd(1).must_have(test.td.path().join("foo.o"));
test.cmd(1)
.must_have(test.td.path().join("d1fba762150c532c-foo.o"));
}

#[test]
Expand Down Expand Up @@ -576,3 +578,21 @@ fn clang_apple_tvsimulator() {
test.cmd(0).must_have("-mappletvsimulator-version-min=9.0");
}
}

#[test]
fn compile_intermediates() {
let test = Test::gnu();
let intermediates = test
.gcc()
.file("foo.c")
.file("x86_64.asm")
.file("x86_64.S")
.asm_flag("--abc")
.compile_intermediates();

assert_eq!(intermediates.len(), 3);

assert!(intermediates[0].display().to_string().contains("foo"));
assert!(intermediates[1].display().to_string().contains("x86_64"));
assert!(intermediates[2].display().to_string().contains("x86_64"));
}

0 comments on commit 385b43f

Please sign in to comment.