From b8f66237d7bb0a6c0a415cc1cc5defb02a64db54 Mon Sep 17 00:00:00 2001 From: YdrMaster Date: Wed, 11 May 2022 09:36:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(xtask):=20=E7=BB=9F=E4=B8=80=20rootfs=20?= =?UTF-8?q?=E5=AD=98=E6=94=BE=EF=BC=8Clibc-test=20=E6=88=90=E4=B8=BA?= =?UTF-8?q?=E5=AD=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - .gitmodules | 3 + libc-test | 1 + xtask/CHANGLOG.md | 9 +++ xtask/README.md | 4 +- xtask/src/arch.rs | 163 +++++++++++++++++++++++------------------- xtask/src/dir.rs | 12 ++-- xtask/src/download.rs | 1 + 8 files changed, 113 insertions(+), 81 deletions(-) create mode 160000 libc-test create mode 100644 xtask/CHANGLOG.md diff --git a/.gitignore b/.gitignore index 98b411e2..4f0832c8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ Cargo.lock /ignored /rootfs -/riscv_rootfs /prebuilt/linux/**/minirootfs.tar.* zCore/src/platform/riscv/kernel-vars.ld diff --git a/.gitmodules b/.gitmodules index 38982db8..a96daf49 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "tests"] path = tests url = https://github.com/rcore-os/zcore-tests.git +[submodule "libc-test"] + path = libc-test + url = https://github.com/rcore-os/libc-test diff --git a/libc-test b/libc-test new file mode 160000 index 00000000..1426bea9 --- /dev/null +++ b/libc-test @@ -0,0 +1 @@ +Subproject commit 1426bea9f3482dec1aa98c31dcc3733a750fb090 diff --git a/xtask/CHANGLOG.md b/xtask/CHANGLOG.md new file mode 100644 index 00000000..503cef4b --- /dev/null +++ b/xtask/CHANGLOG.md @@ -0,0 +1,9 @@ +# 更新公告 + +最新的更新将出现在最上方。 + +## 20220511(YdrMaster) + +- 现在用于 linux 模式的 rootfs 统一放在 rootfs/$ARCH,未来新增 aarch64 或更多架构也将放在这个目录; +- libc-test 现在是一个子模块,不再需要单独 git clone; +- 使用 `std::os::unix::fs::symlink` 建立符号链接,不再依赖 `ln` 应用程序; diff --git a/xtask/README.md b/xtask/README.md index f2aaff2c..f0713fa8 100644 --- a/xtask/README.md +++ b/xtask/README.md @@ -1,5 +1,7 @@ # zCore tasks +[更新公告](CHANGLOG.md) + ## 使用说明 使用 `cargo xtask help` 将打印出命令说明。对主要子命令的简要说明如下: @@ -12,7 +14,7 @@ 6. `libc-test `: 向启动文件系统加入 libc 测试; 7. `image `: 打包指定架构的系统镜像; -其中 5、6、7 必须顺序执行,后者依赖前者的结果; +其中 6、7 执行时若 5 的结果不存在,将自动递归执行 5; ## 项目愿景 diff --git a/xtask/src/arch.rs b/xtask/src/arch.rs index 71b8ae0c..8f7886ff 100644 --- a/xtask/src/arch.rs +++ b/xtask/src/arch.rs @@ -1,13 +1,10 @@ -use crate::{ - dir, - download::{git_clone, wget}, - CommandExt, ALPINE_ROOTFS_VERSION, ALPINE_WEBSITE, -}; +use crate::{dir, download::wget, CommandExt, ALPINE_ROOTFS_VERSION, ALPINE_WEBSITE}; use dircpy::copy_dir; use std::{ ffi::{OsStr, OsString}, fs, io::Write, + os::unix, path::{Path, PathBuf}, process::Command, }; @@ -26,53 +23,62 @@ enum ArchCommands { X86_64, } +impl ArchCommands { + const fn as_str(&self) -> &'static str { + match self { + ArchCommands::Riscv64 => "riscv64", + ArchCommands::X86_64 => "x86_64", + } + } +} + impl Arch { /// 构造启动内存文件系统 rootfs。 /// - /// 将在文件系统中放置必要的库文件,并下载用于交叉编译的工具链。 + /// 若 `clear` == true,将清除已存在的目录。 + /// + /// 将在文件系统中放置必要的库文件。 pub fn rootfs(&self, clear: bool) { self.wget_alpine(); match self.command { ArchCommands::Riscv64 => { - const DIR: &str = "riscv_rootfs"; - const ARCH: &str = "riscv64"; + const ARCH: &str = ArchCommands::Riscv64.as_str(); - let dir = Path::new(DIR); + let dir = PathBuf::from(format!("rootfs/{ARCH}")); if dir.is_dir() && !clear { return; } - dir::clear(dir).unwrap(); + dir::clear(&dir).unwrap(); let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap(); - Tar::xf(&tar, Some(DIR)) + Tar::xf(&tar, Some(&dir)) .args(&["--strip-components", "1"]) .join(); - Command::new("ln") - .args(&["-s", "busybox", "riscv_rootfs/bin/ls"]) - .status() - .unwrap() - .exit_ok() - .expect("FAILED: ln -s busybox riscv_rootfs/bin/ls"); + let mut ls = dir; + ls.push("bin"); + ls.push("ls"); + unix::fs::symlink("busybox", ls).unwrap(); } ArchCommands::X86_64 => { - const DIR: &str = "rootfs"; - const ARCH: &str = "x86_64"; + const ARCH: &str = ArchCommands::X86_64.as_str(); - let dir = Path::new(DIR); + let dir = PathBuf::from(format!("rootfs/{ARCH}")); if dir.is_dir() && !clear { return; } - dir::clear(DIR).unwrap(); - let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap(); - Tar::xf(&tar, Some(DIR)).join(); - // libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore - fs::copy( - "prebuilt/linux/libc-libos.so", - format!("{DIR}/lib/ld-musl-{ARCH}.so.1"), - ) - .unwrap(); + { + dir::clear(&dir).unwrap(); + let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap(); + Tar::xf(&tar, Some(&dir)).join(); + // libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore + let mut dir = dir.clone(); + dir.push("lib"); + dir.push(format!("ld-musl-{ARCH}.so.1")); + fs::copy("prebuilt/linux/libc-libos.so", dir).unwrap(); + } { const TEST_DIR: &str = "linux-syscall/test"; - const DEST_DIR: &str = "rootfs/bin/"; + let mut dest_dir = dir; + dest_dir.push("bin"); // for linux syscall tests fs::read_dir(TEST_DIR) .unwrap() @@ -80,13 +86,12 @@ impl Arch { .map(|entry| entry.path()) .filter(|path| path.extension().map_or(false, |ext| ext == OsStr::new("c"))) .for_each(|c| { - let o = format!( - "{DEST_DIR}/{}", - c.file_prefix().and_then(|s| s.to_str()).unwrap() - ); + let mut o = dest_dir.clone(); + o.push(c.file_prefix().and_then(|s| s.to_str()).unwrap()); Command::new("gcc") .arg(&c) - .args(&["-o", &o]) + .arg("-o") + .arg(&o) .arg("-Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1") .status() .unwrap() @@ -101,44 +106,46 @@ impl Arch { /// 将 libc-test 放入 rootfs。 pub fn libc_test(&self) { self.rootfs(false); - git_clone( - "https://github.com/rcore-os/libc-test.git", - "ignored/libc-test", - ); match self.command { ArchCommands::Riscv64 => { - const DIR: &str = "riscv_rootfs/libc-test"; - const PRE: &str = "riscv_rootfs/libc-test-prebuild"; + const ARCH: &str = ArchCommands::Riscv64.as_str(); - fs::rename(DIR, PRE).unwrap(); - copy_dir("ignored/libc-test", DIR).unwrap(); - fs::copy(format!("{DIR}/config.mak.def"), format!("{DIR}/config.mak")).unwrap(); + let rootfs = format!("rootfs/{ARCH}"); + let dir = format!("{rootfs}/libc-test"); + let pre = format!("{rootfs}/libc-test-prebuilt"); + + fs::rename(&dir, &pre).unwrap(); + copy_dir("libc-test", &dir).unwrap(); + fs::copy(format!("{dir}/config.mak.def"), format!("{dir}/config.mak")).unwrap(); Make::new(None) - .env("ARCH", "riscv64") + .env("ARCH", ARCH) .env("CROSS_COMPILE", "riscv64-linux-musl-") .env("PATH", riscv64_linux_musl_cross()) - .current_dir(DIR) + .current_dir(&dir) .join(); fs::copy( - format!("{PRE}/functional/tls_align-static.exe"), - format!("{DIR}/src/functional/tls_align-static.exe"), + format!("{pre}/functional/tls_align-static.exe"), + format!("{dir}/src/functional/tls_align-static.exe"), ) .unwrap(); - dir::rm(PRE).unwrap(); + dir::rm(pre).unwrap(); } ArchCommands::X86_64 => { - const DIR: &str = "rootfs/libc-test"; + const ARCH: &str = ArchCommands::X86_64.as_str(); - dir::rm(DIR).unwrap(); - copy_dir("ignored/libc-test", DIR).unwrap(); - fs::copy(format!("{DIR}/config.mak.def"), format!("{DIR}/config.mak")).unwrap(); + let rootfs = format!("rootfs/{ARCH}"); + let dir = format!("{rootfs}/libc-test"); + + dir::rm(&dir).unwrap(); + copy_dir("libc-test", &dir).unwrap(); + fs::copy(format!("{dir}/config.mak.def"), format!("{dir}/config.mak")).unwrap(); fs::OpenOptions::new() .append(true) - .open(format!("{DIR}/config.mak")) + .open(format!("{dir}/config.mak")) .unwrap() .write_all(b"CC := musl-gcc\nAR := ar\nRANLIB := ranlib") .unwrap(); - Make::new(None).current_dir(DIR).join(); + Make::new(None).current_dir(dir).join(); } } } @@ -148,35 +155,45 @@ impl Arch { self.rootfs(false); let image = match self.command { ArchCommands::Riscv64 => { - const ARCH: &str = "riscv64"; + const ARCH: &str = ArchCommands::Riscv64.as_str(); + let rootfs = format!("rootfs/{ARCH}"); let image = format!("zCore/{ARCH}.img"); - fuse("riscv_rootfs", &image); + fuse(rootfs, &image); image } ArchCommands::X86_64 => { - const ARCH: &str = "x86_64"; - const TMP_ROOTFS: &str = "/tmp/rootfs"; - const ROOTFS_LIB: &str = "rootfs/lib"; + const ARCH: &str = ArchCommands::X86_64.as_str(); + + let tmp: usize = rand::random(); + let tmp_rootfs = format!("/tmp/{tmp}"); + + let rootfs = format!("rootfs/{ARCH}"); + let rootfs_lib = format!("{rootfs}/lib"); // ld-musl-x86_64.so.1 替换为适用 bare-matel 的版本 - dir::clear(TMP_ROOTFS).unwrap(); + dir::clear(&tmp_rootfs).unwrap(); + dir::clear(&rootfs_lib).unwrap(); + let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap(); - Tar::xf(&tar, Some(TMP_ROOTFS)).join(); - dir::clear(ROOTFS_LIB).unwrap(); + Tar::xf(&tar, Some(&tmp_rootfs)).join(); + fs::copy( - format!("{TMP_ROOTFS}/lib/ld-musl-x86_64.so.1"), - format!("{ROOTFS_LIB}/ld-musl-x86_64.so.1"), + format!("{tmp_rootfs}/lib/ld-musl-x86_64.so.1"), + format!("{rootfs_lib}/ld-musl-x86_64.so.1"), + ) + .unwrap(); + dir::rm(tmp_rootfs).unwrap(); + + let image = format!("zCore/{ARCH}.img"); + fuse(rootfs, &image); + + fs::copy( + "prebuilt/linux/libc-libos.so", + format!("{rootfs_lib}/ld-musl-x86_64.so.1"), ) .unwrap(); - let image = format!("zCore/{ARCH}.img"); - fuse("rootfs", &image); - fs::copy( - "prebuilt/linux/libc-libos.so", - format!("{ROOTFS_LIB}/ld-musl-x86_64.so.1"), - ) - .unwrap(); image } }; @@ -273,7 +290,7 @@ impl AsMut for Tar { impl CommandExt for Tar {} impl Tar { - fn xf(src: &impl AsRef, dst: Option<&str>) -> Self { + fn xf(src: &impl AsRef, dst: Option>) -> Self { let mut cmd = Command::new("tar"); cmd.arg("xf").arg(src); if let Some(dst) = dst { diff --git a/xtask/src/dir.rs b/xtask/src/dir.rs index 69c62022..66d6389c 100644 --- a/xtask/src/dir.rs +++ b/xtask/src/dir.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; /// 删除指定路径。 /// /// 如果返回 `Ok(())`,`path` 将不存在。 -pub fn rm(path: &(impl AsRef + ?Sized)) -> std::io::Result<()> { +pub fn rm(path: impl AsRef) -> std::io::Result<()> { let path = path.as_ref(); if !path.exists() { Ok(()) @@ -19,15 +19,15 @@ pub fn rm(path: &(impl AsRef + ?Sized)) -> std::io::Result<()> { /// 清理 `path` 目录。 /// /// 如果返回 `Ok(())`,`path` 将是一个存在的空目录。 -pub fn clear(path: &(impl AsRef + ?Sized)) -> std::io::Result<()> { - rm(path)?; - std::fs::create_dir_all(path) +pub fn clear(path: impl AsRef) -> std::io::Result<()> { + rm(&path)?; + std::fs::create_dir_all(&path) } /// 在 `dir` 目录中根据文件名前半部分 `prefix` 找到对应文件。 /// /// 不会递归查找。 -pub fn detect(path: &(impl AsRef + ?Sized), prefix: &str) -> Option { +pub fn detect(path: impl AsRef, prefix: impl AsRef) -> Option { path.as_ref() .read_dir() .ok()? @@ -37,6 +37,6 @@ pub fn detect(path: &(impl AsRef + ?Sized), prefix: &str) -> Option, dst: impl AsRef) { } } +#[allow(unused)] pub(crate) fn git_clone(repo: impl AsRef, dst: impl AsRef) { let dst = dst.as_ref(); if dst.is_dir() {