Skip to content

Commit 609f595

Browse files
committed
wip
1 parent 5e2c247 commit 609f595

File tree

17 files changed

+428
-410
lines changed

17 files changed

+428
-410
lines changed

packages/cli/src/build/builder.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use crate::{
44
};
55
use std::time::{Duration, Instant};
66

7+
use super::BuildMode;
8+
79
/// The component of the serve engine that watches ongoing builds and manages their state, handle,
810
/// and progress.
911
///
@@ -17,6 +19,7 @@ pub(crate) struct Builder {
1719
pub krate: DioxusCrate,
1820
pub request: BuildRequest,
1921
pub build: tokio::task::JoinHandle<Result<AppBundle>>,
22+
pub bundle: tokio::task::JoinHandle<Result<AppBundle>>,
2023
pub tx: ProgressTx,
2124
pub rx: ProgressRx,
2225

@@ -39,7 +42,7 @@ impl Builder {
3942
/// Create a new builder and immediately start a build
4043
pub(crate) fn start(krate: &DioxusCrate, args: BuildArgs) -> Result<Self> {
4144
let (tx, rx) = futures_channel::mpsc::unbounded();
42-
let request = BuildRequest::new(krate.clone(), args, tx.clone(), None);
45+
let request = BuildRequest::new(krate.clone(), args, tx.clone(), BuildMode::Fat);
4346

4447
Ok(Self {
4548
krate: krate.clone(),
@@ -52,6 +55,7 @@ impl Builder {
5255

5356
request.build_all().await
5457
}),
58+
bundle: tokio::spawn(async move { futures_util::future::pending().await }),
5559
tx,
5660
rx,
5761
compiled_crates: 0,
@@ -177,13 +181,26 @@ impl Builder {
177181
update
178182
}
179183

184+
pub(crate) fn patch_rebuild(&mut self, args: BuildArgs) {
185+
// Abort all the ongoing builds, cleaning up any loose artifacts and waiting to cleanly exit
186+
self.abort_all();
187+
188+
// And then start a new build, resetting our progress/stage to the beginning and replacing the old tokio task
189+
let request = BuildRequest::new(self.krate.clone(), args, self.tx.clone(), BuildMode::Fat);
190+
self.request = request.clone();
191+
self.stage = BuildStage::Restarting;
192+
193+
// This build doesn't have any extra special logging - rebuilds would get pretty noisy
194+
self.build = tokio::spawn(async move { request.build_all().await });
195+
}
196+
180197
/// Restart this builder with new build arguments.
181198
pub(crate) fn rebuild(&mut self, args: BuildArgs) {
182199
// Abort all the ongoing builds, cleaning up any loose artifacts and waiting to cleanly exit
183200
self.abort_all();
184201

185202
// And then start a new build, resetting our progress/stage to the beginning and replacing the old tokio task
186-
let request = BuildRequest::new(self.krate.clone(), args, self.tx.clone(), None);
203+
let request = BuildRequest::new(self.krate.clone(), args, self.tx.clone(), BuildMode::Fat);
187204
self.request = request.clone();
188205
self.stage = BuildStage::Restarting;
189206

packages/cli/src/build/bundle.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,16 @@ use tokio::process::Command;
9090
pub(crate) struct AppBundle {
9191
pub(crate) build: BuildRequest,
9292
pub(crate) app: BuildArtifacts,
93+
pub(crate) assets: AssetManifest,
9394
pub(crate) server: Option<BuildArtifacts>,
95+
pub(crate) server_assets: Option<AssetManifest>,
9496
}
9597

98+
/// The result of the `cargo rustc` including any additional metadata
9699
#[derive(Debug)]
97100
pub struct BuildArtifacts {
98101
pub(crate) exe: PathBuf,
99102
pub(crate) direct_rustc: Vec<Vec<String>>,
100-
pub(crate) assets: AssetManifest,
101103
pub(crate) time_taken: Duration,
102104
}
103105

@@ -265,7 +267,13 @@ impl AppBundle {
265267
app: BuildArtifacts,
266268
server: Option<BuildArtifacts>,
267269
) -> Result<Self> {
268-
let mut bundle = Self { app, server, build };
270+
let mut bundle = Self {
271+
app,
272+
server,
273+
build,
274+
assets: Default::default(),
275+
server_assets: Default::default(),
276+
};
269277

270278
tracing::debug!("Assembling app bundle");
271279

@@ -292,6 +300,31 @@ impl AppBundle {
292300
Ok(bundle)
293301
}
294302

303+
/// Apply this build as a patch to the given bundle
304+
pub(crate) async fn write_patch(&mut self, exe: &Path) -> Result<()> {
305+
Ok(())
306+
}
307+
308+
/// Traverse the target directory and collect all assets from the incremental cache
309+
///
310+
/// This uses "known paths" that have stayed relatively stable during cargo's lifetime.
311+
/// One day this system might break and we might need to go back to using the linker approach.
312+
pub(crate) async fn collect_assets(&self, exe: &Path) -> Result<AssetManifest> {
313+
tracing::debug!("Collecting assets ...");
314+
315+
if self.build.build.skip_assets {
316+
return Ok(AssetManifest::default());
317+
}
318+
319+
// walk every file in the incremental cache dir, reading and inserting items into the manifest.
320+
let mut manifest = AssetManifest::default();
321+
322+
// And then add from the exe directly, just in case it's LTO compiled and has no incremental cache
323+
_ = manifest.add_from_object_path(exe);
324+
325+
Ok(manifest)
326+
}
327+
295328
/// Take the output of rustc and make it into the main exe of the bundle
296329
///
297330
/// For wasm, we'll want to run `wasm-bindgen` to make it a wasm binary along with some other optimizations
@@ -366,7 +399,6 @@ impl AppBundle {
366399
_ = tokio::fs::create_dir_all(&asset_dir).await;
367400
// Create a set of all the paths that new files will be bundled to
368401
let mut keep_bundled_output_paths: HashSet<_> = self
369-
.app
370402
.assets
371403
.assets
372404
.values()
@@ -426,7 +458,7 @@ impl AppBundle {
426458
let mut assets_to_transfer = vec![];
427459

428460
// Queue the bundled assets
429-
for (asset, bundled) in &self.app.assets.assets {
461+
for (asset, bundled) in &self.assets.assets {
430462
let from = asset.clone();
431463
let to = asset_dir.join(bundled.bundled_path());
432464

@@ -720,7 +752,6 @@ impl AppBundle {
720752
writeln!(
721753
glue, "export const __wasm_split_load_chunk_{idx} = makeLoad(\"/assets/{url}\", [], fusedImports);",
722754
url = self
723-
.app
724755
.assets
725756
.register_asset(&path, AssetOptions::Unknown)?.bundled_path(),
726757
)?;
@@ -747,7 +778,6 @@ impl AppBundle {
747778

748779
// Again, register this wasm with the asset system
749780
url = self
750-
.app
751781
.assets
752782
.register_asset(&path, AssetOptions::Unknown)?.bundled_path(),
753783

@@ -789,12 +819,11 @@ impl AppBundle {
789819
}
790820

791821
// Make sure to register the main wasm file with the asset system
792-
self.app
793-
.assets
822+
self.assets
794823
.register_asset(&post_bindgen_wasm, AssetOptions::Unknown)?;
795824

796825
// Register the main.js with the asset system so it bundles in the snippets and optimizes
797-
self.app.assets.register_asset(
826+
self.assets.register_asset(
798827
&self.build.wasm_bindgen_js_output_file(),
799828
AssetOptions::Js(JsAssetOptions::new().with_minify(true).with_preload(true)),
800829
)?;

packages/cli/src/build/patch.rs

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct PatchData {
3131
}
3232

3333
pub async fn attempt_partial_link(
34+
work_dir: PathBuf,
3435
old_cache: PathBuf,
3536
new_cache: PathBuf,
3637
proc_main_addr: u64,
@@ -44,7 +45,7 @@ pub async fn attempt_partial_link(
4445
.new
4546
.iter()
4647
.flat_map(|(_, f)| f.file.exports().unwrap())
47-
.map(|e| e.name().to_utf8())
48+
.map(|e| e.name())
4849
.collect::<HashSet<_>>();
4950

5051
let mut adrp_imports = HashSet::new();
@@ -89,13 +90,13 @@ pub async fn attempt_partial_link(
8990
.unwrap();
9091

9192
for i in f.file.imports().unwrap() {
92-
if all_exports.contains(i.name().to_utf8()) {
93-
adrp_imports.insert(i.name().to_utf8());
93+
if all_exports.contains(i.name()) {
94+
adrp_imports.insert(i.name());
9495
}
9596
}
9697

9798
for e in f.file.exports().unwrap() {
98-
satisfied_exports.insert(e.name().to_utf8());
99+
satisfied_exports.insert(e.name());
99100
}
100101
}
101102

@@ -106,7 +107,7 @@ pub async fn attempt_partial_link(
106107

107108
// Assemble the stub
108109
let stub_data = make_stub_file(proc_main_addr, patch_target, adrp_imports);
109-
let stub_file = workspace_dir().join("stub.o");
110+
let stub_file = work_dir.join("stub.o");
110111
std::fs::write(&stub_file, stub_data).unwrap();
111112

112113
let out = Command::new("cc")
@@ -126,7 +127,7 @@ pub async fn attempt_partial_link(
126127

127128
let err = String::from_utf8_lossy(&out.stderr);
128129
println!("err: {err}");
129-
std::fs::write(workspace_dir().join("link_errs_partial.txt"), &*err).unwrap();
130+
std::fs::write(work_dir.join("link_errs_partial.txt"), &*err).unwrap();
130131

131132
// // -O0 ? supposedly faster
132133
// // -reproducible - even better?
@@ -152,11 +153,13 @@ pub async fn attempt_partial_link(
152153
// .await?;
153154
}
154155

155-
fn system_cc(platform: Platform) -> &'static str {
156+
/// todo: detect if the user specified a custom linker
157+
fn system_linker(platform: Platform) -> &'static str {
156158
match platform {
159+
// mac + linux use just CC unless the user is trying to use something like mold / lld
157160
Platform::MacOS => "cc",
158-
Platform::Windows => "cc",
159161
Platform::Linux => "cc",
162+
Platform::Windows => "cc",
160163
Platform::Ios => "cc",
161164
Platform::Android => "cc",
162165
Platform::Server => "cc",
@@ -618,33 +621,22 @@ fn compare_masked<'a>(
618621

619622
fn symbol_name_of_relo<'a>(obj: &impl Object<'a>, target: RelocationTarget) -> Option<&'a str> {
620623
match target {
621-
RelocationTarget::Symbol(symbol_index) => Some(
622-
obj.symbol_by_index(symbol_index)
623-
.unwrap()
624-
.name_bytes()
625-
.unwrap()
626-
.to_utf8(),
627-
),
624+
RelocationTarget::Symbol(symbol_index) => obj
625+
.symbol_by_index(symbol_index)
626+
.unwrap()
627+
.name_bytes()
628+
.ok()
629+
.and_then(|s| std::str::from_utf8(s).ok()),
628630
RelocationTarget::Section(_) => None,
629631
RelocationTarget::Absolute => None,
630632
_ => None,
631633
}
632634
}
633635

634-
trait ToUtf8<'a> {
635-
fn to_utf8(&self) -> &'a str;
636-
}
637-
638-
impl<'a> ToUtf8<'a> for &'a [u8] {
639-
fn to_utf8(&self) -> &'a str {
640-
std::str::from_utf8(self).unwrap()
641-
}
642-
}
643-
644636
fn make_stub_file(
645637
proc_main_addr: u64,
646638
patch_target: PathBuf,
647-
adrp_imports: HashSet<&str>,
639+
adrp_imports: HashSet<&[u8]>,
648640
) -> Vec<u8> {
649641
let data = fs::read(&patch_target).unwrap();
650642
let old = File::parse(&data as &[u8]).unwrap();
@@ -654,7 +646,7 @@ fn make_stub_file(
654646
.symbols()
655647
.filter_map(|sym| {
656648
adrp_imports
657-
.get(sym.name().ok()?)
649+
.get(sym.name_bytes().ok()?)
658650
.copied()
659651
.map(|o| (o, sym.address() + aslr_offset))
660652
})
@@ -689,7 +681,7 @@ fn build_stub(
689681
format: BinaryFormat,
690682
architecture: Architecture,
691683
endian: Endianness,
692-
adrp_imports: HashMap<&str, u64>,
684+
adrp_imports: HashMap<&[u8], u64>,
693685
) -> Result<Vec<u8>> {
694686
use object::{
695687
write::{Object, Symbol, SymbolSection},
@@ -745,7 +737,7 @@ fn build_stub(
745737
// _$LT$generational_box..references..GenerationalRef$LT$R$GT$$u20$as$u20$core..fmt..Display$GT$::fmt::h455abb35572b9c11
746738
// let name = strip_mangled(name);
747739

748-
let name = if name.starts_with("_") {
740+
let name = if name.starts_with(b"_") {
749741
&name[1..]
750742
} else {
751743
name

0 commit comments

Comments
 (0)