414 Argument struct for lucetc::Compiler::new()#418
Conversation
lucetc/src/compiler.rs
Outdated
| } | ||
|
|
||
| pub struct CompilerBuilder { | ||
| pub target: Triple, |
There was a problem hiding this comment.
I built this struct before seeing the with_ conventions in LucetOpts. There is one place (Lucetc.shared_object_file) that wants access to this. Making it pub was just a quick way to get something out for review. Can adopt a different naming convention here to differentiate "accessors" vs. "setters".
There was a problem hiding this comment.
- How about using
pub(crate)instead ofpub? I don't think exposing this toLucetc.shared_object_file, but that would keeptargetfrom being exposed outside of the crate as well. - You already noticed the
with_conventions, following these here would be nice 🙂 I'll tag one of the methods below with an example of the signature change I would hope to see.
lucet-wasi-sdk/tests/lucetc.rs
Outdated
| let mut builder = Compiler::builder(); | ||
| let c = builder | ||
| .validator(&Some(v)) | ||
| .create(&m, &b) | ||
| .expect("compile empty"); |
cratelyn
left a comment
There was a problem hiding this comment.
First off, thank you for opening a PR! We appreciate it 🙂
This is a wonderful job of implementing something using the builder pattern in Rust, especially for someone new to Rust, so I also would like to commend you for that! I have a few very small nitpicks regarding method signatures for CompilerBuilder, but this should be ready to merge after a few tiny fixes 🎉
lucetc/src/compiler.rs
Outdated
| pub fn validator(&mut self, validator: &Option<Validator>) -> &mut Self { | ||
| self.validator = validator.clone(); |
There was a problem hiding this comment.
Do you think that this could accept Option<Validator> instead? This will just move the .clone()'s to the places that this method is called.
| opt_level: OptLevel::default(), | ||
| cpu_features: CpuFeatures::default(), | ||
| heap: HeapSettings::default(), | ||
| builder: Compiler::builder(), |
There was a problem hiding this comment.
This too, looks much nicer now. 😸
lucetc/src/compiler.rs
Outdated
| } | ||
|
|
||
| pub struct CompilerBuilder { | ||
| pub target: Triple, |
There was a problem hiding this comment.
- How about using
pub(crate)instead ofpub? I don't think exposing this toLucetc.shared_object_file, but that would keeptargetfrom being exposed outside of the crate as well. - You already noticed the
with_conventions, following these here would be nice 🙂 I'll tag one of the methods below with an example of the signature change I would hope to see.
lucetc/src/compiler.rs
Outdated
| } | ||
| } | ||
|
|
||
| pub fn target(&mut self, target: Triple) -> &mut Self { |
There was a problem hiding this comment.
As you mentioned above, this could follow the LucetcOpts conventions 🙂
Instead of having this borrow the struct, we can have it consume self, and return an owned type, via the signature below. This just means passing ownership of the object along, instead of passing along the ability to mutate the object. Call-sites shouldn't change too much. 🤞
pub fn with_target(self, target: Triple) -> SelfThere was a problem hiding this comment.
if I try this signature, then within LucetOpts impl, it complains that CompilerBuilder needs to implement Copy. Lots of bits in there don't implement Copy (Triple, CpuFeatures, HeapSettings) so I'm wondering if I'm missing something about how to do this. I see how the impl of LucetOpts uses the following signature
fn with_target(mut self, target: Triple) -> Selfbut not sure why it doesn't need the Copy. Can dig more.
There was a problem hiding this comment.
ok, i think i have this how you're asking @katie-martin-fastly. Note there is still the _mut versions as below. as before, there are a lot more places to clean up if this looks good.
| pub fn cpu_features_mut(&mut self) -> &mut CpuFeatures { | ||
| &mut self.cpu_features | ||
| } |
There was a problem hiding this comment.
Building off of the with_ changes, I would change the signature of these mutator methods to look like
cpu_features(&mut self, cpu_features: CpuFeatures)This means code that changes the value of a member, CpuFeatures in this case, does so by passing the new value to our builder rather than borrowing and mutating the existing value.
There was a problem hiding this comment.
so if you look at the example of how we expose heap_settings to enable min_reserved_size, LucetOpts wants to be able to manipulate parts of heap_settings, not wholly overwrite it, which is what a signature like that would provide. Alternately, I could not expose heap_settings at all (like LucetOpts doesn't) and instead expose each of the individual modifiable parts (although that is opposite of the pattern it uses with cpu_features). I was trying to find a consistent way to handle both cpu_features and heap_settings where they don't seem to be handled consistently in LucetOpts. Open to this change, but then looking for suggestion on heap_settings
There was a problem hiding this comment.
Ah! Thank you for noticing this, it is very thoughtful.
I think the way you have this currently is great! Sometimes exceptions are needed, so an additional cpu_features_mut method because of implementation details seems perfectly reasonable to me. The min_reserved_size methods feel more like concerns of the public API, so I don't think this struct needs to mirror that.
There was a problem hiding this comment.
I commented elsewhere about this, but the target_ref method is another case like this. I think it's fine to have these, and the rest of the methods are there to provide a nice API surface for general-use.
lucetc/src/lib.rs
Outdated
| fn canonicalize_nans(&mut self, canonicalize_nans: bool) { | ||
| self.as_lucetc() | ||
| .builder | ||
| .canonicalize_nans(canonicalize_nans); | ||
| } | ||
|
|
||
| fn with_canonicalize_nans(mut self, canonicalize_nans: bool) -> Self { | ||
| self.canonicalize_nans(canonicalize_nans); | ||
| self | ||
| } |
7e9b7c7 to
9c63f8a
Compare
cratelyn
left a comment
There was a problem hiding this comment.
Sorry about letting this sit for a little while. This is excellent work! I am happy to see how this encapsulates around the call to Compiler::new 🎉
there are a lot more places to clean up if this looks good.
Do you mean that there is more you'd like to do here? If you are satisfied, I think this is already a great step in the right direction. ✔️
| pub fn cpu_features_mut(&mut self) -> &mut CpuFeatures { | ||
| &mut self.cpu_features | ||
| } |
There was a problem hiding this comment.
Ah! Thank you for noticing this, it is very thoughtful.
I think the way you have this currently is great! Sometimes exceptions are needed, so an additional cpu_features_mut method because of implementation details seems perfectly reasonable to me. The min_reserved_size methods feel more like concerns of the public API, so I don't think this struct needs to mirror that.
| let objpath = dir.path().join("tmp.o"); | ||
| self.object_file(objpath.clone())?; | ||
| link_so(objpath, &self.target, &output)?; | ||
| link_so(objpath, self.builder.target_ref(), &output)?; |
There was a problem hiding this comment.
You mentioned a similar thing with heap_settings_mut, I think the same thing applies here. As well. Having an extra method doesn't hurt us, especially if it's scoped with pub(crate)
| pub fn cpu_features_mut(&mut self) -> &mut CpuFeatures { | ||
| &mut self.cpu_features | ||
| } |
There was a problem hiding this comment.
I commented elsewhere about this, but the target_ref method is another case like this. I think it's fine to have these, and the rest of the methods are there to provide a nice API surface for general-use.
I just meant the last commit I just added where I clean up uses of |
10913cf to
f4bfe3b
Compare
Approach for #414
First time working in this code base and not a huge amount of rust experience so comments much appreciated!
This is an approach that attempts to make construction simpler without changing the signature for
Compiler::new.CompilerBuildercould easily be something more likeCompilerOptionsthat gets passed in as an argument to either a newCompilermethod orCompiler::newif that is really the desire.There are many more places using
Compiler::newthat I can update once I get some agreement on approach. Also can add some testing. Just throwing something out there fore feedback first.