|
1 |
| -// TODO - Make this code less awful |
| 1 | +// TODO - Reuse compilation artifacts so core isn't compiled so many times |
2 | 2 | use llvm_tools::{exe, LlvmTools};
|
3 | 3 | use std::env;
|
4 | 4 | use std::path::Path;
|
5 | 5 | use std::process::Command;
|
6 | 6 |
|
7 | 7 | fn main() {
|
8 |
| - println!("cargo:warning=Compiling..."); |
9 |
| - let out_dir = env::var("OUT_DIR").unwrap(); |
| 8 | + // Read environment variables set by cargo |
| 9 | + let cargo_path = env::var("CARGO").expect("Missing CARGO environment variable"); |
| 10 | + let cargo = Path::new(&cargo_path); |
| 11 | + |
| 12 | + let manifest_dir_path = env::var("CARGO_MANIFEST_DIR").expect("Missing CARGO_MANIFEST_DIR environment variable"); |
| 13 | + let manifest_dir = Path::new(&manifest_dir_path); |
| 14 | + |
| 15 | + // Calculate target directory |
| 16 | + let current_dir = env::current_dir().expect("Couldn't get current directory"); |
| 17 | + let target_dir_rel = manifest_dir.join("target"); |
| 18 | + let target_dir = current_dir.join(target_dir_rel); |
| 19 | + |
| 20 | + // Find the objcopy binary |
10 | 21 | let llvm_tools = LlvmTools::new().expect("LLVM tools not found");
|
11 | 22 | let objcopy = llvm_tools
|
12 | 23 | .tool(&exe("llvm-objcopy"))
|
13 | 24 | .expect("llvm-objcopy not found");
|
14 | 25 |
|
15 |
| - /*build_subproject( |
| 26 | + // Build the bootsector |
| 27 | + build_subproject( |
16 | 28 | Path::new("src/real/bootsector"),
|
17 | 29 | &[
|
18 | 30 | "_start",
|
19 | 31 | "real_mode_println",
|
20 | 32 | "no_int13h_extensions",
|
21 | 33 | "dap_load_failed",
|
22 | 34 | ],
|
23 |
| - "x86_64-bootsector.json", |
24 |
| - &out_dir, |
| 35 | + "i8086-bootsector.json", |
| 36 | + &target_dir, |
25 | 37 | &objcopy,
|
26 |
| - );*/ |
27 |
| - |
28 |
| - println!("cargo:warning=Compiling stage2..."); |
| 38 | + &cargo, |
| 39 | + ); |
29 | 40 |
|
| 41 | + // Build stage 2 |
30 | 42 | build_subproject(
|
31 | 43 | Path::new("src/real/stage_2"),
|
32 | 44 | &[
|
33 | 45 | "second_stage",
|
34 | 46 | ],
|
35 |
| - "x86_64-stage_2.json", |
36 |
| - &out_dir, |
| 47 | + "i8086-stage_2.json", |
| 48 | + &target_dir, |
37 | 49 | &objcopy,
|
| 50 | + &cargo, |
38 | 51 | );
|
39 |
| - |
40 | 52 | }
|
41 | 53 |
|
42 | 54 | fn build_subproject(
|
43 | 55 | subproject_dir: &Path,
|
44 | 56 | global_symbols: &[&str],
|
45 |
| - target: &str, |
46 |
| - out_dir: &str, |
| 57 | + target_file_path: &str, |
| 58 | + target_dir: &Path, |
47 | 59 | objcopy: &Path,
|
| 60 | + cargo: &Path, |
48 | 61 | ) {
|
49 |
| - let dir_name = subproject_dir.file_name().unwrap().to_str().unwrap(); |
50 |
| - let out_dir_path = Path::new(&out_dir); |
51 |
| - |
52 |
| - let target_dir = out_dir_path.join("..").join("..").join("..").join("..").join(".."); |
| 62 | + let subproject_name = subproject_dir.file_stem().expect("Couldn't get subproject name").to_str().expect("Subproject Name is not valid UTF-8"); |
| 63 | + let target_file = Path::new(&target_file_path).file_stem().expect("Couldn't get target file stem"); |
53 | 64 |
|
| 65 | + // We have to export at least 1 symbol |
54 | 66 | assert!(
|
55 | 67 | global_symbols.len() > 0,
|
56 | 68 | "must have at least one global symbol"
|
57 | 69 | );
|
58 | 70 |
|
59 |
| - // build |
60 |
| - let mut cmd = Command::new("cargo"); |
61 |
| - cmd.current_dir(&subproject_dir); |
62 |
| - |
63 |
| - cmd.arg("build").arg("--release").arg("-Zbuild-std=core"); |
64 |
| - cmd.arg("--verbose"); |
65 |
| - |
66 |
| - cmd.arg(format!( |
67 |
| - "--target={}", |
68 |
| - target |
69 |
| - )); |
70 |
| - |
71 |
| - cmd.arg("-Zunstable-options"); |
72 |
| - cmd.arg("--out-dir").arg(&out_dir); |
73 |
| - cmd.arg("--target-dir") |
74 |
| - .arg(&target_dir); |
75 |
| - cmd.env_remove("RUSTFLAGS"); |
76 |
| - cmd.env( |
77 |
| - "XBUILD_SYSROOT_PATH", |
78 |
| - out_dir_path.join("target").join(dir_name).join("sysroot"), |
79 |
| - ); |
| 71 | + // Use cargo in CARGO environment variable (set on build) |
| 72 | + let mut build_cmd = Command::new(cargo); |
80 | 73 |
|
81 |
| - println!("cargo:warning=Out Dir - {}", &out_dir_path.display()); |
82 |
| - println!("cargo:warning=Subproject Dir - {}", &subproject_dir.display()); |
83 |
| - println!("cargo:warning=Dir Name - {}", &dir_name); |
84 |
| - println!("cargo:warning=Target Dir - {}", &target_dir.display()); |
| 74 | + // Build inside the subproject |
| 75 | + build_cmd.current_dir(&subproject_dir); |
85 | 76 |
|
86 |
| - let status = cmd.status().unwrap(); |
87 |
| - assert!(status.success(), "Subcrate build failed!"); |
| 77 | + // Build in release mode |
| 78 | + build_cmd.arg("build").arg("--release"); |
88 | 79 |
|
89 |
| - // localize symbols |
90 |
| - let mut cmd = Command::new(objcopy); |
| 80 | + // Cross-compile core (cargo-xbuild no longer needed) |
| 81 | + build_cmd.arg("-Zbuild-std=core"); |
| 82 | + |
| 83 | + // Use root package target directory |
| 84 | + build_cmd.arg(format!("--target-dir={}", &target_dir.join(&subproject_name).display())); |
| 85 | + |
| 86 | + // Use the passed target |
| 87 | + build_cmd.arg("--target").arg(target_file_path); |
| 88 | + |
| 89 | + // Run the command and make sure it succeeds |
| 90 | + let build_status = build_cmd.status().expect("Subcrate build failed!"); |
| 91 | + assert!(build_status.success(), "Subcrate build failed!"); |
| 92 | + |
| 93 | + // Compute the path to the binary |
| 94 | + let binary_dir = target_dir.join(&subproject_name).join(&target_file).join("release"); |
| 95 | + let binary_path = binary_dir.join(format!("lib{}.a", &subproject_name)); |
| 96 | + |
| 97 | + // Use passed objcopy |
| 98 | + let mut objcopy_cmd = Command::new(objcopy); |
| 99 | + |
| 100 | + // Localize all symbols except those passed |
91 | 101 | for symbol in global_symbols {
|
92 |
| - cmd.arg("-G").arg(symbol); |
| 102 | + objcopy_cmd.arg("-G").arg(symbol); |
93 | 103 | }
|
94 |
| - cmd.arg(target_dir.join(format!("lib{}.a", dir_name))); |
95 |
| - let status = cmd.status().unwrap(); |
96 |
| - assert!(status.success(), "Objcopy failed!"); |
97 | 104 |
|
98 |
| - // emit linker flags |
99 |
| - println!("cargo:rustc-link-search=native={}", out_dir); |
100 |
| - println!("cargo:rustc-link-lib=static={}", dir_name); |
| 105 | + // Pass the binary as argument |
| 106 | + objcopy_cmd.arg(binary_path); |
| 107 | + |
| 108 | + // Run the command and make sure it succeeds |
| 109 | + let objcopy_status = objcopy_cmd.status().expect("Objcopy failed!"); |
| 110 | + assert!(objcopy_status.success(), "Objcopy failed!"); |
| 111 | + |
| 112 | + // Emit flags to the linker |
| 113 | + // |
| 114 | + // Staticlibs can't be used as normal dependencies, they have to be linked by a build script |
| 115 | + println!("cargo:rustc-link-search=native={}", &binary_dir.display()); |
| 116 | + println!("cargo:rustc-link-lib=static={}", &subproject_name); |
101 | 117 | }
|
0 commit comments