diff --git a/issues/build/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md b/issues/build/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md new file mode 100644 index 00000000000..96722376b4b --- /dev/null +++ b/issues/build/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md @@ -0,0 +1,29 @@ +--- +status: open +kind: defect +opened: 2026-10-01 +--- + +# A shared object does not link against the C sysroot with `-z defs` + +ToyOS loads shared objects, a program's `DT_NEEDED` and `dlopen`'s, and its +clang links one with `-shared`. None links against the C sysroot with +`-z defs`. A C one linked without it leaves `__tls_get_addr` undefined, and +lld refuses the executable that links it for that name. LLVM built for +`x86_64-unknown-toyos` +(`issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`) +builds `libLTO`, `libRemarks`, `libclang` and `libclang-cpp`, linked +`-shared -z defs`, and each stops on what the sysroot's archives were built +for, an executable: + +- `main`, undefined: `libtoyos_c.a`'s entry point, `start_c`, sits in an + object the link takes for other names. +- `__tls_get_addr`, undefined: a shared object reaches a thread-local, its own + or libc's, through it, and only std defines it. +- `R_X86_64_TPOFF32` against libc++abi's `eh_globals`, and `R_X86_64_PC32` + against libc++'s vtables: the C++ runtime is compiled for an executable + (`issues/build/a-rust-std-binary-cannot-link-the-cxx-runtime.md`). + +**Exit**: a C and a C++ shared object link against the C sysroot with +`-z defs`, LLVM's four build for ToyOS with their options on, and a guest case +`dlopen`s the C one and calls into it. diff --git a/issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md b/issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md index d495d5193b1..c2cc7c6442e 100644 --- a/issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md +++ b/issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md @@ -6,40 +6,32 @@ opened: 2026-09-30 # Bootstrap cannot build LLVM, clang and lld for a ToyOS host -M2's clang and lld (`issues/build/toyos-builds-itself.md`) are LLVM built for -`x86_64-unknown-toyos`. Read from the fork at `rust/` and from -`src/llvm-project` at `849da7d62`, not run, four things stop bootstrap's LLVM -step for that target: +M2's clang and lld (`issues/build/toyos-builds-itself.md`) are bootstrap's +`Llvm` step, with `clang = true`, and its `Lld` step for +`x86_64-unknown-toyos`, in a bootstrap build that names no `llvm-config` for +the build triple and so builds that triple's LLVM, and its `clang-tblgen`, +itself. CMake takes its toolchain file from +`CMAKE_TOOLCHAIN_FILE_x86_64_unknown_toyos`: one that includes the C sysroot's +`toolchain.cmake` and adds the ToyOS LLVM's install to `CMAKE_FIND_ROOT_PATH`, +because the `Lld` step names that LLVM to `find_package` by a hint, and the +sysroot's file has CMake find a package under a root alone. What stops the +build, in the order it stops it: -- **`clang-tblgen`.** With `clang = true`, the step for a target that is not - the host panics unless `clang-tblgen` is in the CMake build directory of a - host LLVM bootstrap built itself - (`src/bootstrap/src/core/build_steps/llvm.rs`, `CLANG_TABLEGEN`). Every - compiler build here names the store's LLVM (`src/llvm.rs`) as the host's - `llvm-config`, so bootstrap builds no host LLVM and the file is never there. -- **Its CMake system.** `configure_cmake` names no system for a ToyOS target and - falls back to `Generic`, under which LLVM sets `LLVM_ON_UNIX` to 0 - (`llvm/cmake/modules/HandleLLVMOptions.cmake`) and compiles no `Unix/` - implementation of `Support`. -- **`bit.h`.** `llvm/include/llvm/ADT/bit.h` includes `` on the - systems it lists and `` on any other, ToyOS among them. -- **`is_local_impl`.** `llvm/lib/Support/Unix/Path.inc` reads the BSDs' - `MNT_LOCAL` on a system it does not list. +- **Compile.** The first errors are `Support`'s: `Unix/Watchdog.inc` and + `Unix/Program.inc` call `alarm` (`issues/build/libc-has-no-alarm.md`), and + `Program.inc` stage 3's `wait` and `wait4` + (`issues/kernel/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). + Then ORC's `shm_open` and `shm_unlink`, the interpreter's `scanf` and + `llvm-objdump`'s `ctime` + (`issues/build/libc-lacks-names-llvm-for-a-toyos-host-calls.md`), and + clang's `std::ifstream`, which libc++ has only with `std::filesystem` + (`issues/build/libcxx-is-built-without-std-filesystem.md`). +- **Link.** clang needs `lround`, which libc does not define + (`issues/build/libc-lacks-names-llvm-for-a-toyos-host-calls.md`), beside + those above. LLVM's shared libraries, `libLTO`, `libRemarks`, `libclang` and + `libclang-cpp`, do not link against the C sysroot + (`issues/build/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md`). + clang and lld use none of them, and ToyOS's build turns them off. -The last three are ToyOS arms at existing dispatch sites, written as upstream -would take them. ToyOS joins `bit.h`'s `` list, so libc carries -POSIX's `endian.h` (`userland/libc/include/endian.h`) and no BSD name. With -those two arms on `849da7d62` and CMake told the system by hand, the 71 -libraries rustc links compile against the C sysroot but for objects of -`LLVMSupport`; without them, every object that includes `bit.h` stops. -Bootstrap's arm names the system `ToyOS`, which LLVM's configure refuses, -`Unable to determine platform`, until CMake knows ToyOS and sets `UNIX` -(`issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md`). - -`clang-tblgen` is no arm, and neither bootstrap nor LLVM changes for it: ToyOS's -build builds the LLVM for a ToyOS host in a bootstrap build that built the -host's LLVM itself, as `src/llvm.rs` builds the store's, never in a compiler -build that names the store's. - -**Exit**: bootstrap, with `clang = true`, installs a clang and an `ld.lld` for -`x86_64-unknown-toyos`. +**Exit**: ToyOS's build, with nothing supplied by hand, has bootstrap install +a clang and an `ld.lld` for `x86_64-unknown-toyos`. diff --git a/issues/build/cmake-ships-no-platform-module-for-toyos.md b/issues/build/cmake-ships-no-platform-module-for-toyos.md new file mode 100644 index 00000000000..7d41eead640 --- /dev/null +++ b/issues/build/cmake-ships-no-platform-module-for-toyos.md @@ -0,0 +1,16 @@ +--- +status: open +kind: tooling +opened: 2026-10-01 +--- + +# CMake ships no platform module for ToyOS, and each C sysroot carries one + +CMake knows a system by its `Modules/Platform/.cmake` and ships none for +ToyOS. Each C sysroot carries `Platform/ToyOS.cmake` and +`Platform/ToyOS-Initialize.cmake` beside the `toolchain.cmake` that puts them +on CMake's module path (`src/clang.rs`, `CMAKE`). No upstream merge request +carries them, because none is sent for now. + +**Exit**: CMake ships ToyOS's platform module, and the C sysroot carries only +its toolchain file. diff --git a/issues/build/libc-lacks-names-llvm-for-a-toyos-host-calls.md b/issues/build/libc-lacks-names-llvm-for-a-toyos-host-calls.md new file mode 100644 index 00000000000..c8deacd4f37 --- /dev/null +++ b/issues/build/libc-lacks-names-llvm-for-a-toyos-host-calls.md @@ -0,0 +1,23 @@ +--- +status: open +kind: defect +opened: 2026-10-01 +--- + +# libc lacks names LLVM for a ToyOS host calls + +LLVM, clang and lld built for `x86_64-unknown-toyos` +(`issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`) +call five names libc neither declares nor defines: + +- `shm_open` and `shm_unlink`, with which ORC maps memory on every Unix but + Android (`llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp`, + `TargetProcess/ExecutorSharedMemoryMapperService.cpp`). +- `scanf`, which LLVM's interpreter hands an interpreted program + (`llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp`). +- `ctime`, with which `llvm-objdump` prints a file's time stamp. +- `lround`, which libc++'s `std::lround` calls, from clang's `Basic` and its + static analyzer: clang does not link without it. + +**Exit**: libc declares and defines each, doing what POSIX says or refusing in +POSIX's form, asserted by a guest C case that reads its effect back. diff --git a/issues/build/libcxx-is-built-without-std-filesystem.md b/issues/build/libcxx-is-built-without-std-filesystem.md index ff743a45db6..7a98601903e 100644 --- a/issues/build/libcxx-is-built-without-std-filesystem.md +++ b/issues/build/libcxx-is-built-without-std-filesystem.md @@ -7,9 +7,11 @@ opened: 2026-09-30 # libc++ for ToyOS is built without `std::filesystem` `src/libcxx.rs` configures the C++ runtime with `LIBCXX_ENABLE_FILESYSTEM=OFF`, -so a ToyOS C++ program that includes `` does not compile. libc++'s -filesystem is written on the POSIX directory, `stat` and path calls, and libc -has no `dirent.h`. +so a ToyOS C++ program that includes `` does not compile, and +`` goes with the option: `std::ifstream` and `std::ofstream` are +undefined templates. Built with it, libc++ asks libc for `setbuf`, `fseeko`, +`ftello`, `utimes`, `truncate`, `pathconf`, `openat`, `unlinkat`, `fdopendir`, +`_PC_PATH_MAX`, `O_DIRECTORY`, `O_NOFOLLOW`, `AT_FDCWD` and `AT_REMOVEDIR`. **Exit**: libc carries what libc++'s `src/filesystem` calls, the option goes, and a guest test lists a directory through `std::filesystem`. diff --git a/issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md b/issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md deleted file mode 100644 index a2c8085f6f4..00000000000 --- a/issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-30 ---- - -# The C++ runtime's configure names ToyOS to CMake as `UNIX` - -CMake has no platform module for ToyOS, so `src/libcxx.rs` configures the -runtimes with `CMAKE_SYSTEM_NAME=ToyOS` and sets `UNIX=ON` beside it: the one -fact a platform module would give that the runtimes' build branches on. CMake -says so on every configure, once per check it runs: `System is unknown to -cmake, create: Platform/ToyOS to use this system`. Everything else a platform -module sets (library prefixes and suffixes, search paths, the shared-library -flags) CMake leaves at its defaults, which the runtimes' static-only build -happens not to read. - -**Exit**: CMake knows ToyOS, a `Modules/Platform/ToyOS.cmake` that sets what -its Unix-like neighbours set, and `UNIX=ON` goes from `src/libcxx.rs` with the -line every configure prints. diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index 59bc559ade3..d4dd3114d8a 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -123,13 +123,9 @@ goes when lld runs in the guest: the row, the crate and its host tests go togeth the published crates.io crate is yanked. **What stops M2: LLVM, clang and lld built for a ToyOS host**, in the order -each blocks the next. -- Configure: the `clang-tblgen` and the CMake system of - `issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`. -- Compile: the bootstrap issue's `bit.h` and `is_local_impl`, and `wait` and - `wait4` of the child-process track's stage 3 - with `issues/build/libc-has-no-alarm.md`. -- Link: the same stage 3 names and `alarm`. +each blocks the next, as +`issues/build/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md` +measures it. - Run: what `issues/build/libc-refuses-what-toyos-cannot-yet-answer.md` lists, `issues/build/libc-has-no-pread-or-pwrite.md`, and `issues/build/libc-stat-answers-one-serial-number-for-every-file.md`. diff --git a/rust b/rust index 6c7f996a4fe..95960d6c214 160000 --- a/rust +++ b/rust @@ -1 +1 @@ -Subproject commit 6c7f996a4fe3f8d8f08d7d2c9c30054946645e4f +Subproject commit 95960d6c214338e9375b1c7c6c0d4e5ece4c4ba3 diff --git a/src/clang.rs b/src/clang.rs index 35c9efdf886..17bc8e7e548 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -48,6 +48,47 @@ pub(crate) fn tools() -> impl Iterator { TOOLS.into_iter().chain(host_triple().ends_with("apple-darwin").then_some(APPLE_STRIP)) } +/// CMake's description of ToyOS, which CMake does not ship, as every C sysroot +/// carries it: a toolchain file that names the system, the target and the +/// sysroot it sits in, has CMake find a library, a header and a package there +/// alone and a program on the host alone, and puts beside it on CMake's module +/// path the platform module, laid out as CMake's `Modules/Platform` lays out a +/// Unix-like system. The compilers are the caller's, and so is the root of any +/// package it built outside the sysroot (`CMAKE_FIND_ROOT_PATH`). `@PROCESSOR@` +/// and `@TARGET@` are the sysroot's. +pub(crate) const CMAKE: [(&str, &str); 3] = [ + ( + "toolchain.cmake", + "set(CMAKE_SYSTEM_NAME ToyOS)\n\ + set(CMAKE_SYSTEM_PROCESSOR @PROCESSOR@)\n\ + set(CMAKE_SYSROOT \"${CMAKE_CURRENT_LIST_DIR}\")\n\ + set(CMAKE_C_COMPILER_TARGET @TARGET@)\n\ + set(CMAKE_CXX_COMPILER_TARGET @TARGET@)\n\ + set(CMAKE_ASM_COMPILER_TARGET @TARGET@)\n\ + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n\ + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n\ + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n\ + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n\ + list(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_LIST_DIR}\")\n", + ), + ("Platform/ToyOS-Initialize.cmake", "set(UNIX 1)\n"), + // `dlopen` and its kin are the C library's own. The loader finds a library + // by the name `DT_NEEDED` holds, beside its executable or in `/system/lib`, + // so a library carries its soname and one without is linked by name; and it + // reads no runtime path, so no flag asks the linker for one. The flags that + // switch a link between static and shared libraries and the `RESCAN` link + // group are left out too: no build of ToyOS's asks CMake for either. + ( + "Platform/ToyOS.cmake", + "set(CMAKE_DL_LIBS \"\")\n\ + set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG \"-Wl,-soname,\")\n\ + set(CMAKE_EXE_EXPORTS_C_FLAG \"-Wl,--export-dynamic\")\n\ + set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)\n\ + \n\ + include(Platform/UnixPaths)\n", + ), +]; + /// `lib/rustlib//bin` of `toolchain`, where `rust-lld` is. fn bin(toolchain: &Path) -> PathBuf { toolchain.join("lib/rustlib").join(host_triple()).join("bin") @@ -64,6 +105,8 @@ pub struct CSysroot { pub ar: PathBuf, /// The guest target, as clang's `--target` spells it. pub target: &'static str, + /// Its architecture, as CMake's `CMAKE_SYSTEM_PROCESSOR` spells it. + processor: &'static str, } impl CSysroot { @@ -75,6 +118,23 @@ impl CSysroot { clang: bin(toolchain).join("clang"), ar: bin(toolchain).join("llvm-ar"), target, + processor: arch.name(), + } + } + + /// Its CMake toolchain file, the first of [`CMAKE`]. + pub fn cmake_toolchain(&self) -> PathBuf { + self.dir.join(CMAKE[0].0) + } + + /// Write [`CMAKE`] into it. + pub fn write_cmake(&self) { + for (name, text) in CMAKE { + let path = self.dir.join(name); + let parent = path.parent().expect("a file in the sysroot"); + fs::create_dir_all(parent).unwrap_or_else(|e| panic!("create {}: {e}", parent.display())); + let text = text.replace("@PROCESSOR@", self.processor).replace("@TARGET@", self.target); + fs::write(&path, text).unwrap_or_else(|e| panic!("write {}: {e}", path.display())); } } diff --git a/src/libc.rs b/src/libc.rs index e8e442285de..0e9569710a4 100644 --- a/src/libc.rs +++ b/src/libc.rs @@ -114,6 +114,7 @@ pub fn build_c(root: &Path, toolchain: &Path, target_dir: &Path, arch: Arch) { .unwrap_or_else(|e| panic!("copy {} into {}: {e}", archive.display(), lib.display())); empty_libraries(&lib); crate::sysroot::clone_tree(&root.join(CRATE).join("include"), &c.dir.join("include")); + c.write_cmake(); links_naming_every_library(&c, target_dir); } diff --git a/src/libcxx.rs b/src/libcxx.rs index 09c9769dc5d..2f0403caeb4 100644 --- a/src/libcxx.rs +++ b/src/libcxx.rs @@ -12,7 +12,6 @@ use std::fs; use std::path::Path; use std::process::Command; -use crate::arch::Arch; use crate::clang::CSysroot; /// What of `src/llvm-project` the runtimes' build reads: the runtimes, the CMake @@ -20,14 +19,10 @@ use crate::clang::CSysroot; /// compiles in. pub(crate) const SOURCES: [&str; 7] = ["runtimes", "cmake", "llvm/cmake", "libunwind", "libcxxabi", "libcxx", "libc"]; -/// The runtimes' CMake options beyond the target's and the tools'. -pub(crate) const OPTIONS: [(&str, &str); 20] = [ +/// The runtimes' CMake options beyond the target's, which the C sysroot's +/// toolchain file names (`clang::CMAKE`), and the tools'. +pub(crate) const OPTIONS: [(&str, &str); 18] = [ ("CMAKE_BUILD_TYPE", "Release"), - // CMake has no platform module for ToyOS, and `UNIX` is how it says what - // the runtimes' build needs to know of one: an ELF system with POSIX threads - // (`issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md`). - ("CMAKE_SYSTEM_NAME", "ToyOS"), - ("UNIX", "ON"), ("LLVM_ENABLE_RUNTIMES", "libunwind;libcxxabi;libcxx"), ("LLVM_INCLUDE_TESTS", "OFF"), ("LLVM_INCLUDE_DOCS", "OFF"), @@ -52,10 +47,10 @@ pub(crate) const OPTIONS: [(&str, &str); 20] = [ ("LIBCXX_INCLUDE_TESTS", "OFF"), ]; -/// Build `arch`'s C++ runtime from the runtimes' `sources` into `c`, which holds +/// Build `c`'s C++ runtime from the runtimes' `sources` into it, which holds /// the C library already, under `ninja`, in `scratch`, which it removes when /// done. -pub fn build(c: &CSysroot, arch: Arch, sources: &Path, ninja: &Path, scratch: &Path) { +pub fn build(c: &CSysroot, sources: &Path, ninja: &Path, scratch: &Path) { eprintln!("Building the C++ runtime for {} under {}", c.target, ninja.display()); if scratch.exists() { fs::remove_dir_all(scratch).unwrap_or_else(|e| panic!("remove {}: {e}", scratch.display())); @@ -68,14 +63,12 @@ pub fn build(c: &CSysroot, arch: Arch, sources: &Path, ninja: &Path, scratch: &P .unwrap_or_else(|e| panic!("symlink {} -> {}: {e}", ranlib.display(), c.ar.display())); let path = |p: &Path| p.display().to_string(); let mut definitions: Vec<(String, String)> = OPTIONS.iter().map(|(n, v)| (n.to_string(), v.to_string())).collect(); - definitions.push(("CMAKE_SYSTEM_PROCESSOR".into(), arch.name().into())); + definitions.push(("CMAKE_TOOLCHAIN_FILE".into(), path(&c.cmake_toolchain()))); for lang in ["C", "CXX", "ASM"] { definitions.push((format!("CMAKE_{lang}_COMPILER"), path(&c.clang))); - definitions.push((format!("CMAKE_{lang}_COMPILER_TARGET"), c.target.into())); } definitions.push(("CMAKE_AR".into(), path(&c.ar))); definitions.push(("CMAKE_RANLIB".into(), path(&ranlib))); - definitions.push(("CMAKE_SYSROOT".into(), path(&c.dir))); definitions.push(("CMAKE_INSTALL_PREFIX".into(), path(&c.dir))); definitions.push(("CMAKE_MAKE_PROGRAM".into(), path(ninja))); diff --git a/src/sysroot.rs b/src/sysroot.rs index 8a916199f81..ca973dbfe65 100644 --- a/src/sysroot.rs +++ b/src/sysroot.rs @@ -86,10 +86,11 @@ const SOURCES: &str = "SOURCES"; /// is none of them, nor std's configuration ([`std_config`]), which the /// freestanding key reads whole. Moving it moves every key. const RECIPE: &str = "bootstrap stage-0 local rebuild, libraries from the stamp, libtoyos_c merged, \ - a C sysroot of libc's staticlib, the empty libraries beside it, and headers \ - per target, refused unless a C program naming each library links against \ - it, and its C++ runtime built under n2 from the runtimes' sources of the \ - compiler's LLVM, the freestanding libraries cloned from their key's; 12"; + a C sysroot of libc's staticlib, the empty libraries beside it, headers and \ + CMake's description of ToyOS per target, refused unless a C program naming \ + each library links against it, and its C++ runtime built under n2 from the \ + runtimes' sources of the compiler's LLVM, the freestanding libraries cloned \ + from their key's; 13"; /// Every sysroot on this host. pub fn sysroots_dir(rust_dir: &Path) -> PathBuf { @@ -464,11 +465,16 @@ pub(crate) fn key(root: &Path, freestanding: &Key) -> Key { } /// What a sysroot's build is beyond its sources and its freestanding libraries: -/// its targets, the C++ runtime's options and libc's cargo invocations. +/// its targets, the C++ runtime's options, CMake's description of ToyOS and +/// libc's cargo invocations. fn build_text() -> String { let targets = Libraries::Worktree.targets().join(" "); let (libc, staticlib) = (crate::libc::BUILD, crate::libc::BUILD_C); - format!("targets {targets}; C++ runtime {:?}; libc {libc:?} {staticlib:?}", crate::libcxx::OPTIONS) + format!( + "targets {targets}; C++ runtime {:?}; CMake {:?}; libc {libc:?} {staticlib:?}", + crate::libcxx::OPTIONS, + crate::clang::CMAKE, + ) } /// [`key`], with the build it reads. @@ -707,7 +713,7 @@ fn build(root: &Path, rust_dir: &Path, compiler: &Compiler, fork: &Path, keys: & for arch in Arch::ALL { let scratch = dir.with_extension(format!("libcxx-{}", arch.name())); let c = crate::clang::CSysroot::of(partial, arch); - crate::libcxx::build(&c, arch, &llvm.dir.join("src"), &ninja, &scratch); + crate::libcxx::build(&c, &llvm.dir.join("src"), &ninja, &scratch); } // The sources the key named are the ones built, or this is not that key's.