Skip to content

Commit 2526462

Browse files
committed
Make ROMFS files and bin files.
1 parent 5c07e30 commit 2526462

File tree

6 files changed

+203
-19
lines changed

6 files changed

+203
-19
lines changed

.github/workflows/rust.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
with:
1515
submodules: true
1616
- run: rustup target add ${{ matrix.target }}
17+
- run: rustup component add llvm-tools-preview
1718
- run: cargo nbuild binary --target=${{ matrix.target }} --start-address=${{ matrix.start_address }}
1819
- uses: actions/upload-artifact@v4
1920
if: ${{success()}}
@@ -22,6 +23,8 @@ jobs:
2223
if-no-files-found: error
2324
path: |
2425
./target/${{ matrix.target }}/release/neotron-os
26+
./target/${{ matrix.target }}/release/neotron-os.bin
27+
./target/${{ matrix.target }}/release/romfs.bin
2528
linux-libraries:
2629
runs-on: ubuntu-latest
2730
steps:

nbuild/Cargo.lock

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nbuild/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ readme = "README.md"
1212
repository = "https://github.com/neotron-compute/Neotron-OS"
1313

1414
[dependencies]
15+
chrono = { version = "0.4.39", default-features = false, features = ["std"] }
1516
clap = { version = "4.5.23", features = ["derive"] }
17+
embedded-io = { version = "0.6.1", features = ["std"] }
18+
neotron-api = "0.2.0"
19+
neotron-romfs = "2.0"

nbuild/src/lib.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
33
/// The ways that spawning `cargo` can fail
44
#[derive(Debug)]
5-
pub enum CargoError {
5+
pub enum ProcessError {
66
SpawnError(std::io::Error),
77
RunError(std::process::ExitStatus),
88
}
99

10-
impl std::fmt::Display for CargoError {
10+
impl std::fmt::Display for ProcessError {
1111
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1212
match self {
13-
CargoError::SpawnError(error) => write!(f, "Failed to spawn `cargo`: {}", error),
14-
CargoError::RunError(exit_status) => write!(
13+
ProcessError::SpawnError(error) => write!(f, "Failed to spawn command: {}", error),
14+
ProcessError::RunError(exit_status) => write!(
1515
f,
16-
"Failed to complete `cargo` command ({}). There should be an error above",
16+
"Failed to complete command ({}). There should be an error above",
1717
exit_status
1818
),
1919
}
@@ -33,9 +33,16 @@ pub enum PackageKind {
3333
pub struct Package {
3434
pub name: &'static str,
3535
pub path: &'static std::path::Path,
36-
pub output: &'static std::path::Path,
3736
pub kind: PackageKind,
3837
pub testable: bool,
38+
pub output_template: Option<&'static str>,
39+
}
40+
41+
impl Package {
42+
pub fn output(&self, target: &str, profile: &str) -> Option<String> {
43+
self.output_template
44+
.map(|s| s.replace("{target}", target).replace("{profile}", profile))
45+
}
3946
}
4047

4148
/// Parse an integer, with an optional `0x` prefix.
@@ -60,7 +67,11 @@ where
6067
}
6168

6269
/// Runs cargo
63-
pub fn cargo<P>(commands: &[&str], target: Option<&str>, manifest_path: P) -> Result<(), CargoError>
70+
pub fn cargo<P>(
71+
commands: &[&str],
72+
target: Option<&str>,
73+
manifest_path: P,
74+
) -> Result<(), ProcessError>
6475
where
6576
P: AsRef<std::path::Path>,
6677
{
@@ -73,7 +84,7 @@ pub fn cargo_with_env<P>(
7384
target: Option<&str>,
7485
manifest_path: P,
7586
environment: &[(&'static str, String)],
76-
) -> Result<(), CargoError>
87+
) -> Result<(), ProcessError>
7788
where
7889
P: AsRef<std::path::Path>,
7990
{
@@ -93,11 +104,45 @@ where
93104

94105
println!("Running: {:?}", command_line);
95106

96-
let output = command_line.output().map_err(CargoError::SpawnError)?;
107+
let output = command_line.output().map_err(ProcessError::SpawnError)?;
97108

98109
if output.status.success() {
99110
Ok(())
100111
} else {
101-
Err(CargoError::RunError(output.status))
112+
Err(ProcessError::RunError(output.status))
113+
}
114+
}
115+
116+
/// Make a binary version of an ELF file
117+
pub fn make_bin<P>(path: P) -> Result<std::path::PathBuf, ProcessError>
118+
where
119+
P: AsRef<std::path::Path>,
120+
{
121+
let path = path.as_ref();
122+
println!("Making binary of: {}", path.display());
123+
let output = std::process::Command::new("rustc")
124+
.arg("--print")
125+
.arg("target-libdir")
126+
.output()
127+
.expect("Failed to run rustc --print target-libdir");
128+
let sysroot = String::from_utf8(output.stdout).expect("sysroot path isn't UTF-8");
129+
let sysroot: std::path::PathBuf = sysroot.trim().into();
130+
let mut objcopy = sysroot.clone();
131+
objcopy.pop();
132+
objcopy.push("bin");
133+
objcopy.push("llvm-objcopy");
134+
let mut command_line = std::process::Command::new(objcopy);
135+
command_line.args(["-O", "binary"]);
136+
command_line.arg(path);
137+
let output_file = path.with_extension("bin");
138+
command_line.arg(&output_file);
139+
println!("Running: {:?}", command_line);
140+
let output = command_line.output().map_err(ProcessError::SpawnError)?;
141+
if output.status.success() {
142+
Ok(output_file)
143+
} else {
144+
Err(ProcessError::RunError(output.status))
102145
}
103146
}
147+
148+
// End of file

nbuild/src/main.rs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,21 @@ fn packages() -> Vec<nbuild::Package> {
4545
nbuild::Package {
4646
name: "nbuild",
4747
path: std::path::Path::new("./nbuild/Cargo.toml"),
48-
output: std::path::Path::new("./nbuild/target/debug/nbuild{exe}"),
48+
output_template: None,
4949
kind: nbuild::PackageKind::NBuild,
5050
testable: true,
5151
},
5252
nbuild::Package {
53-
name: "flames utility",
53+
name: "flames",
5454
path: std::path::Path::new("./utilities/flames/Cargo.toml"),
55-
output: std::path::Path::new("./target/{target}/{profile}/flames"),
55+
output_template: Some("./target/{target}/{profile}/flames"),
5656
kind: nbuild::PackageKind::Utility,
5757
testable: false,
5858
},
5959
nbuild::Package {
6060
name: "Neotron OS",
6161
path: std::path::Path::new("./neotron-os/Cargo.toml"),
62-
output: std::path::Path::new("./target/{target}/{profile}/neotron-os"),
62+
output_template: Some("./target/{target}/{profile}/neotron-os"),
6363
kind: nbuild::PackageKind::Os,
6464
testable: false,
6565
},
@@ -91,11 +91,16 @@ fn main() {
9191

9292
/// Builds the utility and OS packages as binaries
9393
fn binary(packages: &[nbuild::Package], start_address: &str, target: &str) {
94+
use chrono::{Datelike, Timelike};
95+
9496
let mut is_error = false;
9597
let Ok(start_address) = nbuild::parse_int(start_address) else {
9698
eprintln!("{:?} was not a valid integer", start_address);
9799
std::process::exit(1);
98100
};
101+
102+
let mut romfs_entries = Vec::new();
103+
// Build utilities
99104
for package in packages
100105
.iter()
101106
.filter(|p| p.kind == nbuild::PackageKind::Utility)
@@ -108,7 +113,57 @@ fn binary(packages: &[nbuild::Package], start_address: &str, target: &str) {
108113
eprintln!("Build of {} failed: {}", package.name, e);
109114
is_error = true;
110115
}
116+
let package_output = package
117+
.output(target, "release")
118+
.expect("utilties should have an output");
119+
let contents = match std::fs::read(&package_output) {
120+
Ok(contents) => contents,
121+
Err(e) => {
122+
eprintln!("Reading of {} failed: {}", package_output, e);
123+
continue;
124+
}
125+
};
126+
let ctime = std::time::SystemTime::now();
127+
let ctime = chrono::DateTime::<chrono::Utc>::from(ctime);
128+
romfs_entries.push(neotron_romfs::Entry {
129+
metadata: neotron_romfs::EntryMetadata {
130+
file_name: package.name,
131+
ctime: neotron_api::file::Time {
132+
year_since_1970: (ctime.year() - 1970) as u8,
133+
zero_indexed_month: ctime.month0() as u8,
134+
zero_indexed_day: ctime.day0() as u8,
135+
hours: ctime.hour() as u8,
136+
minutes: ctime.minute() as u8,
137+
seconds: ctime.second() as u8,
138+
},
139+
file_size: contents.len() as u32,
140+
},
141+
contents,
142+
});
111143
}
144+
145+
// Build ROMFS
146+
let mut buffer = Vec::new();
147+
let _size = match neotron_romfs::RomFs::construct_into(&mut buffer, &romfs_entries) {
148+
Ok(size) => size,
149+
Err(e) => {
150+
eprintln!("Making ROMFS failed: {:?}", e);
151+
std::process::exit(1);
152+
}
153+
};
154+
let mut romfs_path = std::path::PathBuf::new();
155+
romfs_path.push(std::env::current_dir().expect("We have no CWD?"));
156+
romfs_path.push("target");
157+
romfs_path.push(target);
158+
romfs_path.push("release");
159+
romfs_path.push("romfs.bin");
160+
if let Err(e) = std::fs::write(&romfs_path, &buffer) {
161+
eprintln!("Writing ROMFS to {} failed: {:?}", romfs_path.display(), e);
162+
std::process::exit(1);
163+
}
164+
println!("Built ROMFS at {}", romfs_path.display());
165+
166+
// Build OS
112167
for package in packages
113168
.iter()
114169
.filter(|p| p.kind == nbuild::PackageKind::Os)
@@ -117,10 +172,13 @@ fn binary(packages: &[nbuild::Package], start_address: &str, target: &str) {
117172
"Cross-compiling {}, using start address 0x{:08x} and target {:?}",
118173
package.name, start_address, target
119174
);
120-
let environment = [(
121-
"NEOTRON_OS_START_ADDRESS",
122-
format!("0x{:08x}", start_address),
123-
)];
175+
let environment = [
176+
(
177+
"NEOTRON_OS_START_ADDRESS",
178+
format!("0x{:08x}", start_address),
179+
),
180+
("ROMFS_PATH", romfs_path.to_string_lossy().to_string()),
181+
];
124182
if let Err(e) = nbuild::cargo_with_env(
125183
&["build", "--release"],
126184
Some(target),
@@ -130,6 +188,13 @@ fn binary(packages: &[nbuild::Package], start_address: &str, target: &str) {
130188
eprintln!("Build of {} failed: {}", package.name, e);
131189
is_error = true;
132190
}
191+
let package_output = package
192+
.output(target, "release")
193+
.expect("PackageKind::Os should always have output");
194+
if let Err(e) = nbuild::make_bin(&package_output) {
195+
eprintln!("objcopy of {} failed: {}", package_output, e);
196+
is_error = true;
197+
}
133198
}
134199
if is_error {
135200
std::process::exit(1);

neotron-os/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ fn main() {
3636
println!("cargo::rustc-link-lib=dylib=msvcrt");
3737
}
3838

39-
if option_env!("ROMFS_PATH").is_some() {
39+
if let Some(path) = option_env!("ROMFS_PATH") {
4040
println!("cargo::rustc-cfg=romfs_enabled=\"yes\"");
4141
println!("cargo::rerun-if-env-changed=ROMFS_PATH");
42+
println!("cargo::rerun-if-changed={}", path);
4243
}
4344
println!("cargo::rustc-check-cfg=cfg(romfs_enabled, values(\"yes\"))");
4445
}

0 commit comments

Comments
 (0)