Skip to content

Commit 385b43f

Browse files
authored
Add new compile_intermediates function. (#914)
* 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
1 parent f17047d commit 385b43f

File tree

2 files changed

+98
-44
lines changed

2 files changed

+98
-44
lines changed

src/lib.rs

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,48 +1131,7 @@ impl Build {
11311131
};
11321132
let dst = self.get_out_dir()?;
11331133

1134-
let mut objects = Vec::new();
1135-
for file in self.files.iter() {
1136-
let obj = if file.has_root() || file.components().any(|x| x == Component::ParentDir) {
1137-
// If `file` is an absolute path or might not be usable directly as a suffix due to
1138-
// using "..", use the `basename` prefixed with the `dirname`'s hash to ensure name
1139-
// uniqueness.
1140-
let basename = file
1141-
.file_name()
1142-
.ok_or_else(|| Error::new(ErrorKind::InvalidArgument, "file_name() failure"))?
1143-
.to_string_lossy();
1144-
let dirname = file
1145-
.parent()
1146-
.ok_or_else(|| Error::new(ErrorKind::InvalidArgument, "parent() failure"))?
1147-
.to_string_lossy();
1148-
let mut hasher = hash_map::DefaultHasher::new();
1149-
hasher.write(dirname.to_string().as_bytes());
1150-
dst.join(format!("{:016x}-{}", hasher.finish(), basename))
1151-
.with_extension("o")
1152-
} else {
1153-
dst.join(file).with_extension("o")
1154-
};
1155-
let obj = if !obj.starts_with(&dst) {
1156-
dst.join(obj.file_name().ok_or_else(|| {
1157-
Error::new(ErrorKind::IOError, "Getting object file details failed.")
1158-
})?)
1159-
} else {
1160-
obj
1161-
};
1162-
1163-
match obj.parent() {
1164-
Some(s) => fs::create_dir_all(s)?,
1165-
None => {
1166-
return Err(Error::new(
1167-
ErrorKind::IOError,
1168-
"Getting object file details failed.",
1169-
));
1170-
}
1171-
};
1172-
1173-
objects.push(Object::new(file.to_path_buf(), obj));
1174-
}
1175-
1134+
let objects = objects_from_files(&self.files, &dst)?;
11761135
let print = PrintThread::new()?;
11771136

11781137
self.compile_objects(&objects, &print)?;
@@ -1316,6 +1275,32 @@ impl Build {
13161275
}
13171276
}
13181277

1278+
/// Run the compiler, generating intermediate files, but without linking
1279+
/// them into an archive file.
1280+
///
1281+
/// This will return a list of compiled object files, in the same order
1282+
/// as they were passed in as `file`/`files` methods.
1283+
pub fn compile_intermediates(&self) -> Vec<PathBuf> {
1284+
match self.try_compile_intermediates() {
1285+
Ok(v) => v,
1286+
Err(e) => fail(&e.message),
1287+
}
1288+
}
1289+
1290+
/// Run the compiler, generating intermediate files, but without linking
1291+
/// them into an archive file.
1292+
///
1293+
/// This will return a result instead of panicing; see `compile_intermediates()` for the complete description.
1294+
pub fn try_compile_intermediates(&self) -> Result<Vec<PathBuf>, Error> {
1295+
let dst = self.get_out_dir()?;
1296+
let objects = objects_from_files(&self.files, &dst)?;
1297+
let print = PrintThread::new()?;
1298+
1299+
self.compile_objects(&objects, &print)?;
1300+
1301+
Ok(objects.into_iter().map(|v| v.dst).collect())
1302+
}
1303+
13191304
#[cfg(feature = "parallel")]
13201305
fn compile_objects(&self, objs: &[Object], print: &PrintThread) -> Result<(), Error> {
13211306
use std::cell::Cell;
@@ -2379,6 +2364,7 @@ impl Build {
23792364
}
23802365

23812366
fn apple_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
2367+
#[allow(dead_code)]
23822368
enum ArchSpec {
23832369
Device(&'static str),
23842370
Simulator(&'static str),
@@ -3837,6 +3823,54 @@ fn wait_on_child(cmd: &Command, program: &str, child: &mut Child) -> Result<(),
38373823
}
38383824
}
38393825

3826+
/// Find the destination object path for each file in the input source files,
3827+
/// and store them in the output Object.
3828+
fn objects_from_files(files: &[Arc<Path>], dst: &Path) -> Result<Vec<Object>, Error> {
3829+
let mut objects = Vec::with_capacity(files.len());
3830+
for file in files {
3831+
let basename = file
3832+
.file_name()
3833+
.ok_or_else(|| {
3834+
Error::new(
3835+
ErrorKind::InvalidArgument,
3836+
"No file_name for object file path!",
3837+
)
3838+
})?
3839+
.to_string_lossy();
3840+
let dirname = file
3841+
.parent()
3842+
.ok_or_else(|| {
3843+
Error::new(
3844+
ErrorKind::InvalidArgument,
3845+
"No parent for object file path!",
3846+
)
3847+
})?
3848+
.to_string_lossy();
3849+
3850+
// Hash the dirname. This should prevent conflicts if we have multiple
3851+
// object files with the same filename in different subfolders.
3852+
let mut hasher = hash_map::DefaultHasher::new();
3853+
hasher.write(dirname.to_string().as_bytes());
3854+
let obj = dst
3855+
.join(format!("{:016x}-{}", hasher.finish(), basename))
3856+
.with_extension("o");
3857+
3858+
match obj.parent() {
3859+
Some(s) => fs::create_dir_all(s)?,
3860+
None => {
3861+
return Err(Error::new(
3862+
ErrorKind::InvalidArgument,
3863+
"dst is an invalid path with no parent",
3864+
));
3865+
}
3866+
};
3867+
3868+
objects.push(Object::new(file.to_path_buf(), obj));
3869+
}
3870+
3871+
Ok(objects)
3872+
}
3873+
38403874
#[cfg(feature = "parallel")]
38413875
fn try_wait_on_child(
38423876
cmd: &Command,

tests/test.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ fn gnu_smoke() {
2424
.must_have("-c")
2525
.must_have("-ffunction-sections")
2626
.must_have("-fdata-sections");
27-
test.cmd(1).must_have(test.td.path().join("foo.o"));
27+
test.cmd(1)
28+
.must_have(test.td.path().join("d1fba762150c532c-foo.o"));
2829
}
2930

3031
#[test]
@@ -399,7 +400,8 @@ fn msvc_smoke() {
399400
.must_not_have("-Z7")
400401
.must_have("-c")
401402
.must_have("-MD");
402-
test.cmd(1).must_have(test.td.path().join("foo.o"));
403+
test.cmd(1)
404+
.must_have(test.td.path().join("d1fba762150c532c-foo.o"));
403405
}
404406

405407
#[test]
@@ -576,3 +578,21 @@ fn clang_apple_tvsimulator() {
576578
test.cmd(0).must_have("-mappletvsimulator-version-min=9.0");
577579
}
578580
}
581+
582+
#[test]
583+
fn compile_intermediates() {
584+
let test = Test::gnu();
585+
let intermediates = test
586+
.gcc()
587+
.file("foo.c")
588+
.file("x86_64.asm")
589+
.file("x86_64.S")
590+
.asm_flag("--abc")
591+
.compile_intermediates();
592+
593+
assert_eq!(intermediates.len(), 3);
594+
595+
assert!(intermediates[0].display().to_string().contains("foo"));
596+
assert!(intermediates[1].display().to_string().contains("x86_64"));
597+
assert!(intermediates[2].display().to_string().contains("x86_64"));
598+
}

0 commit comments

Comments
 (0)