diff --git a/.gitignore b/.gitignore index b55f6b82c..378e4538d 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ build_i686/ build_x86_64/ build_conan/ +# nix +/result + # ignore log files in test tree test/**/*.log diff --git a/example/vm.json b/example/vm.json new file mode 100644 index 000000000..2c63c0851 --- /dev/null +++ b/example/vm.json @@ -0,0 +1,2 @@ +{ +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..e2b612b34 --- /dev/null +++ b/flake.lock @@ -0,0 +1,63 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1748026580, + "narHash": "sha256-rWtXrcIzU5wm/C8F9LWvUfBGu5U5E7cFzPYT1pHIJaQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "11cb3517b3af6af300dd6c055aeda73c9bf52c48", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1748026580, + "narHash": "sha256-rWtXrcIzU5wm/C8F9LWvUfBGu5U5E7cFzPYT1pHIJaQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "11cb3517b3af6af300dd6c055aeda73c9bf52c48", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "vmrunner": "vmrunner" + } + }, + "vmrunner": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1774383306, + "narHash": "sha256-ZX5ONXEGaNx5No6pk9AoO1NoQ25eBzSVCHt/U1jd0eI=", + "owner": "mazunki", + "repo": "vmrunner", + "rev": "bf1db5862c7355f9892c63fa471255dcd46b878a", + "type": "github" + }, + "original": { + "owner": "mazunki", + "ref": "flakify", + "repo": "vmrunner", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..4cbdae68c --- /dev/null +++ b/flake.nix @@ -0,0 +1,92 @@ +{ + description = "IncludeOS"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/25.05"; + vmrunner.url = "github:includeos/vmrunner"; + }; + + outputs = { self, nixpkgs, vmrunner }: + let + system = "x86_64-linux"; + + mkIncludeos = { withCcache ? false, smp ? false }: + let + overlays = [ + (import ./overlay.nix { + inherit withCcache smp; + disableTargetWarning = true; + }) + ]; + pkgs = import nixpkgs { config = {}; inherit overlays system; }; + pkgsIncludeOS = pkgs.pkgsIncludeOS; + stdenvIncludeOS = pkgs.stdenvIncludeOS; + includeos = pkgsIncludeOS.includeos; + + chainloader = + let + chainloaderPkgs = import nixpkgs { + inherit system; + config = {}; + overlays = [ + (import ./overlay.nix { inherit withCcache; smp = false; disableTargetWarning = true; }) + ]; + crossSystem = { config = "i686-unknown-linux-musl"; }; + }; + in import ./chainloader.nix { + inherit nixpkgs withCcache; + pkgs = chainloaderPkgs; + }; + in { + inherit stdenvIncludeOS; # modified stdenv scope used by includeos (llvm, musl, libcxx) + inherit pkgsIncludeOS; # the musl/clang package scope used by IncludeOS + inherit pkgs; # nixpkgs with the IncludeOS overlay applied + inherit includeos; # the IncludeOS derivation to add to buildInputs + inherit chainloader; # 32-bit boot stub that hotswaps into the 64-bit unikernel + }; + + default = mkIncludeos {}; + mkUnikernel = import ./mkUnikernel.nix { inherit system default vmrunner; }; + in { + packages.${system} = { + default = default.includeos; + chainloader = default.chainloader; + example = mkUnikernel { unikernel = ./example; }; + }; + + devShells.${system}.default = import ./develop.nix { includeos = default.includeos; }; + + lib.${system} = { inherit mkIncludeos mkUnikernel; }; + + apps.${system} = { + default = self.apps.${system}.boot-unikernel; + + boot = { + type = "app"; + program = "${vmrunner.lib.${system}.mkBoot default.chainloader}/bin/boot"; + }; + + boot-unikernel = { + type = "app"; + program = "${default.pkgs.writeShellScript "boot-unikernel" '' + set -e + dir="''${1:-./result}" + shift || true + exec ${vmrunner.lib.${system}.mkBoot default.chainloader}/bin/boot \ + -j $dir/vm.json \ + $dir/*.elf.bin \ + "$@" + ''}"; + }; + + example = { + type = "app"; + program = "${default.pkgs.writeShellScript "run-example" '' + set -e + built=$(nix build path:${self.outPath}#example --no-link --print-out-paths) + exec ${self.apps.${system}.boot-unikernel.program} $built "$@" + ''}"; + }; + }; + }; +} diff --git a/mkUnikernel.nix b/mkUnikernel.nix new file mode 100644 index 000000000..b90569737 --- /dev/null +++ b/mkUnikernel.nix @@ -0,0 +1,79 @@ +# mkUnikernel.nix +{ system, default, vmrunner }: +args: +let + ios = if args ? includeos then args.includeos else default; + vmrunnerPkg = if args ? vmrunner then args.vmrunner + else vmrunner.packages.${system}.default; + + unikernel = args.unikernel or ./example; + test = args.test or "test.py"; + doCheck = args.doCheck or false; + arch = args.arch or "x86_64"; + forProduction = args.forProduction or false; + + src = unikernel; +in +ios.includeos.stdenv.mkDerivation { + pname = "includeos_unikernel"; + version = "dev"; + dontStrip = true; + inherit doCheck; + inherit src; + + nativeBuildInputs = [ + ios.pkgs.buildPackages.nasm + ios.pkgs.buildPackages.cmake + ios.pkgsIncludeOS.suppressTargetWarningHook + ]; + + buildInputs = [ + ios.includeos + ios.chainloader + ]; + + cmakeFlags = [ + "-DARCH=${arch}" + "-DINCLUDEOS_PACKAGE=${ios.includeos}" + "-DCMAKE_MODULE_PATH=${ios.includeos}/cmake" + "-DFOR_PRODUCTION=${if forProduction then "ON" else "OFF"}" + ]; + + installPhase = '' + runHook preInstall + # we want to place any files required by the test into the output + find -mindepth 1 -maxdepth 1 -type f -exec install -v -D -t "$out/" {} \; + + # especially the unikernel image, in case it wasn't at the rootdir already + find -mindepth 2 -name '*.elf.bin' -exec install -v -t "$out/" {} \; + runHook postInstall + ''; + + nativeCheckInputs = [ + vmrunnerPkg + ios.pkgs.grub2 + ios.pkgs.python3 + ios.pkgs.qemu + ios.pkgs.iputils + ios.pkgs.xorriso + ]; + + checkInputs = [ + ios.includeos.lest + ]; + + checkPhase = '' + runHook preCheck + set -e + if [ -e "${src}/${test}" ]; then + echo "Running IncludeOS test: ${src}/${test}" + python3 "${src}/${test}" + else + echo "Default test script '${test}', but no test was found 😟" + echo "For a custom path, consider specifying the path to the test script:" + echo " --argstr test 'path/to/test.py'" + exit 1 + fi + runHook postCheck + ''; +}