diff --git a/.gitignore b/.gitignore index 41e709cbb5128..1e12050636646 100644 --- a/.gitignore +++ b/.gitignore @@ -184,3 +184,10 @@ sphinx_*/ # Rust analyzer configuration /rust-project.json + +# Reproducible build artifacts +/build-repro-1/ +/build-repro-2/ +/reproducibility-report/ +/result +/result-* diff --git a/Makefile b/Makefile index 3345d6257350d..b651f06f01d28 100644 --- a/Makefile +++ b/Makefile @@ -1041,8 +1041,10 @@ KBUILD_AFLAGS += $(KAFLAGS) KBUILD_CFLAGS += $(KCFLAGS) KBUILD_RUSTFLAGS += $(KRUSTFLAGS) -KBUILD_LDFLAGS_MODULE += --build-id=sha1 -LDFLAGS_vmlinux += --build-id=sha1 +# Allow build-id to be overridden via KBUILD_BUILD_ID (e.g., for reproducible builds) +KBUILD_BUILD_ID ?= sha1 +KBUILD_LDFLAGS_MODULE += --build-id=$(KBUILD_BUILD_ID) +LDFLAGS_vmlinux += --build-id=$(KBUILD_BUILD_ID) KBUILD_LDFLAGS += -z noexecstack ifeq ($(CONFIG_LD_IS_BFD),y) diff --git a/Microsoft/build-hcl-kernel-pipeline.sh b/Microsoft/build-hcl-kernel-pipeline.sh new file mode 100755 index 0000000000000..234482b128909 --- /dev/null +++ b/Microsoft/build-hcl-kernel-pipeline.sh @@ -0,0 +1,513 @@ +#!/bin/bash +# +# Build script for HCL kernel in Azure DevOps pipeline +# This script mirrors the structure of Microsoft/build-hcl-kernel.sh +# but implements the same functionality as the pipeline's inline build steps. +# +# This script is called ONLY for HCL product builds. Other products (WSL, mariner, +# lcow, lvbs) continue to use the inline pipeline logic. +# + +set -eo pipefail + +usage() { + cat << EOF +Usage: $0 [OPTIONS] + +Build HCL kernel for pipeline with specified configuration. + +OPTIONS: + -s, --source-dir DIR Path to kernel source directory (required) + -b, --build-dir DIR Path to build output directory (required) + -c, --config FILE Path to kernel config file relative to source dir (required) + -a, --arch ARCH Target architecture: amd64 or arm64 (required) + -k, --kernel-type TYPE Kernel type: none or cvm (default: none) + --compiler CC Compiler to use (default: gcc) + --scripts-dir DIR Path to msft-lkt scripts directory (required for cvm) + --reproducible Enable reproducible build mode (uses Nix environment) + -h, --help Show this help message + +EXAMPLE: + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-x64.config -a amd64 + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-arm64.config -a arm64 -k cvm + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-x64.config -a amd64 --reproducible + +EOF + exit 1 +} + +# Default values +KERNEL_TYPE="none" +COMPILER="gcc" +SCRIPTS_DIR="" +REPRODUCIBLE_BUILD="" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case "$1" in + -s|--source-dir) + SOURCE_DIR="$2" + shift 2 + ;; + -b|--build-dir) + BUILD_DIR="$2" + shift 2 + ;; + -c|--config) + CONFIG="$2" + shift 2 + ;; + -a|--arch) + ARCH="$2" + shift 2 + ;; + -k|--kernel-type) + KERNEL_TYPE="$2" + shift 2 + ;; + --compiler) + COMPILER="$2" + shift 2 + ;; + --scripts-dir) + SCRIPTS_DIR="$2" + shift 2 + ;; + --reproducible) + REPRODUCIBLE_BUILD="1" + shift + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" >&2 + usage + ;; + esac +done + +# Validate required arguments +if [[ -z "$SOURCE_DIR" ]] || [[ -z "$BUILD_DIR" ]] || [[ -z "$CONFIG" ]] || [[ -z "$ARCH" ]]; then + echo "Error: Missing required arguments" >&2 + usage +fi + +# Validate scripts-dir is provided for CVM builds +if [[ "$KERNEL_TYPE" == "cvm" ]] && [[ -z "$SCRIPTS_DIR" ]]; then + echo "Error: --scripts-dir is required for CVM kernel builds" >&2 + usage +fi + +# Validate architecture +if [[ "$ARCH" != "amd64" ]] && [[ "$ARCH" != "arm64" ]]; then + echo "Error: Invalid architecture '$ARCH'. Must be 'amd64' or 'arm64'" >&2 + exit 1 +fi + +# +# Reproducible build setup - enter Nix environment if requested +# +setup_reproducible_build() { + if [[ -n "$REPRODUCIBLE_BUILD" ]] && [[ -z "${IN_NIX_SHELL:-}" ]]; then + echo ">>> Setting up reproducible build environment..." + + # Run nix-setup.sh to ensure Nix is installed and configured + NIX_SETUP_SCRIPT="$SOURCE_DIR/Microsoft/nix-setup.sh" + if [[ -f "$NIX_SETUP_SCRIPT" ]]; then + chmod +x "$NIX_SETUP_SCRIPT" + "$NIX_SETUP_SCRIPT" + fi + + # Source nix profile if not already available + if ! command -v nix &> /dev/null; then + if [[ -f ~/.nix-profile/etc/profile.d/nix.sh ]]; then + . ~/.nix-profile/etc/profile.d/nix.sh + export PATH="$HOME/.nix-profile/bin:$PATH" + + else + echo "Error: Nix is not installed or not in PATH" >&2 + echo "Please run: ./Microsoft/nix-setup.sh" >&2 + exit 1 + fi + fi + + # Re-execute this script inside nix develop shell + # Use --ignore-environment (-i) to create a pure shell that excludes system packages + # Keep essential variables: HOME (for temp files), USER (for build metadata), TERM (for output) + echo "Entering Nix development shell (pure mode)..." + cd "$SOURCE_DIR" + exec nix --extra-experimental-features "nix-command flakes" develop \ + --ignore-environment \ + --keep-env-var HOME \ + --keep-env-var USER \ + --keep-env-var TERM \ + --command \ + "$0" \ + --source-dir "$SOURCE_DIR" \ + --build-dir "$BUILD_DIR" \ + --config "$CONFIG" \ + --arch "$ARCH" \ + --kernel-type "$KERNEL_TYPE" \ + --compiler "$COMPILER" \ + ${SCRIPTS_DIR:+--scripts-dir "$SCRIPTS_DIR"} \ + --reproducible + fi +} + +# Call reproducible build setup before anything else +setup_reproducible_build + +# Detect host architecture +HOST_ARCH="$(uname -m)" + +# Set architecture-specific variables +if [[ "$ARCH" == "amd64" ]]; then + MAKE_ARCH="x86" + KERNEL_ARCH="x86_64" + CROSS_COMPILE_PREFIX="" + # For reproducible builds, ensure we use Nix's gcc + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + COMPILER="gcc" + fi +else + MAKE_ARCH="arm64" + KERNEL_ARCH="arm64" + # Only use cross-compiler when cross-compiling (host != target) + # On native arm64 machines, use native compiler (no prefix) + if [[ "$HOST_ARCH" == "aarch64" ]]; then + # Native arm64 build - no cross-compile prefix needed + CROSS_COMPILE_PREFIX="" + # For reproducible builds, ensure we use Nix's gcc + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + COMPILER="gcc" + fi + elif [[ -n "$REPRODUCIBLE_BUILD" ]]; then + # Cross-compiling from x86_64 with Nix toolchain + CROSS_COMPILE_PREFIX="aarch64-unknown-linux-gnu-" + COMPILER="${CROSS_COMPILE_PREFIX}gcc" + else + # Cross-compiling from x86_64 with system toolchain + CROSS_COMPILE_PREFIX="aarch64-linux-gnu-" + fi +fi + +# Resolve paths +SOURCE_DIR=$(realpath "$SOURCE_DIR") +BUILD_DIR=$(realpath "$BUILD_DIR") + +# Define output directories (matching pipeline structure) +LINUX_HEADERS_DIR="$BUILD_DIR/linux-headers" +DEBUG_SYMBOL_DIR="$BUILD_DIR/debug_symbols" +LINUX_DIR="$BUILD_DIR/linux_dir" +LINUX_BOOT_DIR="$LINUX_DIR/boot" + +# Setup reproducible build environment variables +if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-1609459200}" + export LANG="C.UTF-8" + export LC_ALL="C.UTF-8" + export TZ="UTC" + export KBUILD_BUILD_TIMESTAMP="@${SOURCE_DATE_EPOCH}" + export KBUILD_BUILD_USER="${KBUILD_BUILD_USER:-builder}" + export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST:-nixos}" + export KBUILD_BUILD_VERSION="1" + + # Unset Nix-specific compiler flags that might interfere with kernel build + unset NIX_CFLAGS_COMPILE + unset NIX_CFLAGS_COMPILE_FOR_TARGET + unset NIX_LDFLAGS + unset NIX_LDFLAGS_FOR_TARGET +fi + +echo "==============================================" +echo "HCL Kernel Pipeline Build Script" +echo "==============================================" +echo "Source directory: $SOURCE_DIR" +echo "Build directory: $BUILD_DIR" +echo "Config file: $CONFIG" +echo "Architecture: $ARCH (make arch: $MAKE_ARCH)" +echo "Kernel type: $KERNEL_TYPE" +echo "Compiler: $COMPILER" +if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo "Reproducible: YES" + echo " SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH" + echo " KBUILD_BUILD_USER: $KBUILD_BUILD_USER" + echo " KBUILD_BUILD_HOST: $KBUILD_BUILD_HOST" +fi +echo "==============================================" + +# Create output directories +mkdir -p "$BUILD_DIR" +mkdir -p "$LINUX_HEADERS_DIR" +mkdir -p "$DEBUG_SYMBOL_DIR" +mkdir -p "$LINUX_DIR" +mkdir -p "$LINUX_BOOT_DIR" + +cd "$SOURCE_DIR" + +# +# Step 0: CVM Config Merge (only for cvm kernel type) +# +merge_cvm_config() { + echo "" + echo ">>> Merging CVM config for HCL..." + + # Map architecture to config file naming + if [[ "$ARCH" == "amd64" ]]; then + CONFIG_ARCH="x64" + BASE_CONFIG="hcl-x64.config" + FRAGMENT_CONFIG="x64-cvm.config" + else + CONFIG_ARCH="arm64" + BASE_CONFIG="hcl-arm64.config" + FRAGMENT_CONFIG="arm64-cvm.config" + fi + + cd "$SOURCE_DIR/Microsoft" + + # Verify config files exist + if [[ ! -f "$BASE_CONFIG" ]]; then + echo "Error: Base config file $BASE_CONFIG not found!" >&2 + exit 1 + fi + if [[ ! -f "$FRAGMENT_CONFIG" ]]; then + echo "Error: Fragment config file $FRAGMENT_CONFIG not found!" >&2 + exit 1 + fi + + # Copy base config to .config in source directory + cp "$BASE_CONFIG" "$SOURCE_DIR/.config" + + # Merge the fragment configuration + cd "$SOURCE_DIR" + chmod +x "$SCRIPTS_DIR/merge_config_hcl.sh" + "$SCRIPTS_DIR/merge_config_hcl.sh" -m .config "Microsoft/$FRAGMENT_CONFIG" + + # Ensure merged config is valid + make olddefconfig + + # Move merged config back to Microsoft directory (overwrites original) + mv .config "Microsoft/hcl-$CONFIG_ARCH.config" + echo ">>> CVM config merged: Microsoft/hcl-$CONFIG_ARCH.config" + + cd "$SOURCE_DIR" +} + +# +# Step 1: Build kernel +# +build_kernel() { + echo "" + echo ">>> Building kernel..." + + # For CVM kernel type, run mrproper first + if [[ "$KERNEL_TYPE" == "cvm" ]]; then + echo "Running make mrproper for CVM build..." + make mrproper + fi + + # Copy config to build directory + cp "$CONFIG" "$BUILD_DIR/.config" + + # Build make arguments + local make_args=() + make_args+=("ARCH=$KERNEL_ARCH") + make_args+=("LOCALVERSION=") + make_args+=("CC=$COMPILER") + make_args+=("O=$BUILD_DIR") + + # Add cross-compile prefix for arm64 + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + # Add reproducible build flags + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + make_args+=("KBUILD_BUILD_ID=none") + make_args+=("KCFLAGS=-fdebug-prefix-map=$SOURCE_DIR=.") + fi + + # Run olddefconfig + echo "Running olddefconfig..." + make "${make_args[@]}" olddefconfig + + # Build kernel with all targets + echo "Building kernel (make all)..." + make "${make_args[@]}" -j "$(nproc)" all + + echo ">>> Kernel build complete" +} + +# +# Step 2: Install headers +# +build_headers() { + echo "" + echo ">>> Installing kernel headers..." + + local make_args=("CC=$COMPILER" "O=$BUILD_DIR" "ARCH=$KERNEL_ARCH") + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + make "${make_args[@]}" headers_install INSTALL_HDR_PATH="$LINUX_HEADERS_DIR" + + echo ">>> Headers installed to $LINUX_HEADERS_DIR" +} + +# +# Step 3: Install modules +# +build_modules() { + echo "" + echo ">>> Installing kernel modules..." + + local make_args=("CC=$COMPILER" "O=$BUILD_DIR" "ARCH=$KERNEL_ARCH") + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + make "${make_args[@]}" modules_install INSTALL_MOD_PATH="$LINUX_DIR" + + echo ">>> Modules installed to $LINUX_DIR" +} + +# +# Step 4: Generate debug symbols +# +build_debug_symbols() { + echo "" + echo ">>> Generating debug symbols..." + + cd "$BUILD_DIR" + + # Use cross-compile objcopy for arm64 + local OBJCOPY="${CROSS_COMPILE_PREFIX}objcopy" + + # Copy vmlinux to debug symbol directory + cp -a "$BUILD_DIR/vmlinux" "$DEBUG_SYMBOL_DIR/" + + # Generate kernel debug symbols with compression + echo "Extracting vmlinux debug symbols..." + $OBJCOPY --only-keep-debug --compress-debug-sections "$DEBUG_SYMBOL_DIR/vmlinux" \ + "$DEBUG_SYMBOL_DIR/vmlinux.debug" + + # Generate module debug symbols and strip modules + echo "Processing module debug symbols..." + for module_path in $(find "$BUILD_DIR" -name '*.ko'); do + module=$(basename "$module_path") + + # Copy module to debug symbol directory + cp -a "$module_path" "$DEBUG_SYMBOL_DIR/" + + # Extract debug symbols with compression + $OBJCOPY --only-keep-debug --compress-debug-sections "$DEBUG_SYMBOL_DIR/$module" \ + "$DEBUG_SYMBOL_DIR/$module.debug" + + # Strip debug symbols from original module + # For reproducible builds, skip --add-gnu-debuglink as it embeds a CRC + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + $OBJCOPY --strip-unneeded "$module_path" + else + $OBJCOPY --strip-unneeded "$module_path" + fi + done + + echo ">>> Debug symbols generated in $DEBUG_SYMBOL_DIR" +} + +# +# Step 5: Package kernel files to boot directory +# +package_kernel() { + echo "" + echo ">>> Packaging kernel files..." + + cd "$SOURCE_DIR" + + # Use cross-compile objcopy for arm64 + local OBJCOPY="${CROSS_COMPILE_PREFIX}objcopy" + + # Get kernel version + KERNEL_VERSION=$(cat "$BUILD_DIR/include/config/kernel.release") + echo "Kernel version: $KERNEL_VERSION" + + # Copy architecture-specific kernel image + if [[ "$MAKE_ARCH" == "arm64" ]]; then + cp -a "$BUILD_DIR/arch/arm64/boot/Image" \ + "$LINUX_BOOT_DIR/Image-$KERNEL_VERSION" + echo "Copied Image to $LINUX_BOOT_DIR/Image-$KERNEL_VERSION" + else + cp -a "$BUILD_DIR/arch/x86/boot/bzImage" \ + "$LINUX_BOOT_DIR/vmlinuz-$KERNEL_VERSION" + echo "Copied bzImage to $LINUX_BOOT_DIR/vmlinuz-$KERNEL_VERSION" + fi + + # Strip and copy vmlinux + echo "Stripping vmlinux..." + $OBJCOPY --strip-all "$BUILD_DIR/vmlinux" + cp -a "$BUILD_DIR/vmlinux" "$LINUX_BOOT_DIR/vmlinux-$KERNEL_VERSION" + + # Copy config and System.map + cp -a "$BUILD_DIR/.config" "$LINUX_BOOT_DIR/config-$KERNEL_VERSION" + cp -a "$BUILD_DIR/System.map" "$LINUX_BOOT_DIR/System.map-$KERNEL_VERSION" + + echo ">>> Kernel files packaged in $LINUX_BOOT_DIR" +} + +# +# Main build sequence +# +main() { + # Merge CVM config if building CVM kernel + if [[ "$KERNEL_TYPE" == "cvm" ]]; then + merge_cvm_config + fi + + echo ">>> [1/5] Building kernel..." + build_kernel + echo ">>> [2/5] Installing headers..." + build_headers + echo ">>> [3/5] Installing modules..." + build_modules + echo ">>> [4/5] Generating debug symbols..." + build_debug_symbols + echo ">>> [5/5] Packaging kernel files..." + package_kernel + + echo "" + echo "==============================================" + echo "Build completed successfully!" + echo "==============================================" + echo "Output locations:" + echo " Build output: $BUILD_DIR" + echo " Boot files: $LINUX_BOOT_DIR" + echo " Modules: $LINUX_DIR/lib/modules/" + echo " Headers: $LINUX_HEADERS_DIR" + echo " Debug symbols: $DEBUG_SYMBOL_DIR" + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo "" + echo "Reproducible build completed with:" + echo " SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH" + echo " KBUILD_BUILD_USER: $KBUILD_BUILD_USER" + echo " KBUILD_BUILD_HOST: $KBUILD_BUILD_HOST" + fi + + # Print sha256sum of vmlinux for reproducibility verification + local KERNEL_VERSION + KERNEL_VERSION=$(cat "$BUILD_DIR/include/config/kernel.release" 2>/dev/null || echo "unknown") + if [[ -f "$LINUX_BOOT_DIR/vmlinux-$KERNEL_VERSION" ]]; then + echo "" + echo "Reproducibility verification:" + echo " vmlinux sha256sum: $(sha256sum "$LINUX_BOOT_DIR/vmlinux-$KERNEL_VERSION" | cut -d' ' -f1)" + elif [[ -f "$BUILD_DIR/vmlinux" ]]; then + echo "" + echo "Reproducibility verification:" + echo " vmlinux sha256sum: $(sha256sum "$BUILD_DIR/vmlinux" | cut -d' ' -f1)" + fi + echo "==============================================" +} + +# Run main +main diff --git a/Microsoft/build-hcl-kernel.sh b/Microsoft/build-hcl-kernel.sh index 0906371fb82c3..f33c950d858c0 100755 --- a/Microsoft/build-hcl-kernel.sh +++ b/Microsoft/build-hcl-kernel.sh @@ -70,12 +70,46 @@ if test -z "$arch"; then arch=("x64") fi +# Detect host architecture +HOST_ARCH="$(uname -m)" + objcopy=("objcopy") -makeargs=("ARCH=x86_64") +if [ -n "$REPRODUCIBLE_BUILD" ]; then + # For reproducible builds, explicitly set CC to use Nix's gcc + makeargs=("ARCH=x86_64" "CC=gcc") +else + makeargs=("ARCH=x86_64") +fi targets=("vmlinux modules") if [ "$arch" = "arm64" ]; then - objcopy=("aarch64-linux-gnu-objcopy") - makeargs=("ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-") + # Only use cross-compiler when cross-compiling (host != target) + if [ "$HOST_ARCH" = "aarch64" ]; then + # Native arm64 build - no cross-compile prefix needed + cross_prefix="" + elif [ -n "$REPRODUCIBLE_BUILD" ]; then + # Cross-compiling from x86_64 with Nix toolchain + cross_prefix="aarch64-unknown-linux-gnu-" + else + # Cross-compiling from x86_64 with system toolchain + cross_prefix="aarch64-linux-gnu-" + fi + + if [ -n "$cross_prefix" ]; then + objcopy=("${cross_prefix}objcopy") + # For reproducible builds, explicitly set CC to use the Nix cross-compiler + if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs=("ARCH=arm64" "CROSS_COMPILE=${cross_prefix}" "CC=${cross_prefix}gcc") + else + makeargs=("ARCH=arm64" "CROSS_COMPILE=${cross_prefix}") + fi + else + # For native builds, explicitly set CC to ensure we use Nix's gcc in reproducible mode + if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs=("ARCH=arm64" "CC=gcc") + else + makeargs=("ARCH=arm64") + fi + fi targets=("vmlinux Image modules") fi @@ -84,15 +118,30 @@ set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" SRC_DIR=`realpath ${SCRIPT_DIR}/..` +# For reproducible builds, add flags to disable Build ID and normalize debug paths +if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs+=("KBUILD_BUILD_ID=none") + makeargs+=("KCFLAGS=-fdebug-prefix-map=$SRC_DIR=.") + # Prevent + suffix from being added to version string + makeargs+=("LOCALVERSION=") +fi + build_kernel() { if [ -n "$clean" ]; then make mrproper fi export KCONFIG_CONFIG=$LINUX_SRC/Microsoft/hcl-$arch.config - make $makeargs -j `nproc` olddefconfig $targets + make "${makeargs[@]}" -j `nproc` olddefconfig $targets cp $LINUX_SRC/Microsoft/hcl-$arch.config $OUT_DIR $objcopy --only-keep-debug --compress-debug-sections $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux.dbg - $objcopy --strip-all --add-gnu-debuglink=$BUILD_DIR/vmlinux.dbg $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + # For reproducible builds, skip --add-gnu-debuglink as it embeds a CRC of the debug file + # which can vary between builds. The debuglink is only used for debugging and is not + # essential for the kernel to function. + if [ -n "$REPRODUCIBLE_BUILD" ]; then + $objcopy --strip-all $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + else + $objcopy --strip-all --add-gnu-debuglink=$BUILD_DIR/vmlinux.dbg $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + fi find $BUILD_DIR -name '*.ko' | while read -r mod; do relative_path="${mod#$BUILD_DIR/linux}" @@ -100,7 +149,11 @@ build_kernel() { mkdir -p "$dest_dir" outmod="$dest_dir/$(basename $mod)" $objcopy --only-keep-debug --compress-debug-sections "$mod" "$outmod.dbg" - $objcopy --strip-unneeded --add-gnu-debuglink "$outmod.dbg" "$mod" "$outmod" + if [ -n "$REPRODUCIBLE_BUILD" ]; then + $objcopy --strip-unneeded "$mod" "$outmod" + else + $objcopy --strip-unneeded --add-gnu-debuglink "$outmod.dbg" "$mod" "$outmod" + fi done cp $BUILD_DIR/vmlinux $OUT_DIR/build/native/bin/$arch diff --git a/Microsoft/nix-build.sh b/Microsoft/nix-build.sh new file mode 100755 index 0000000000000..a0bec7438224f --- /dev/null +++ b/Microsoft/nix-build.sh @@ -0,0 +1,192 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Reproducible kernel build script for NixOS +# This script ensures consistent build environment for reproducible builds + +set -euo pipefail + +# Auto-detect and enter Nix environment if not already in one +if [ -z "${IN_NIX_SHELL:-}" ]; then + # Check if nix is available + if ! command -v nix &> /dev/null; then + # Try to source nix profile + if [ -f ~/.nix-profile/etc/profile.d/nix.sh ]; then + . ~/.nix-profile/etc/profile.d/nix.sh + else + echo "Error: Nix is not installed or not in PATH" + echo "Please run: ./Microsoft/nix-setup.sh" + exit 1 + fi + fi + + # Re-execute this script inside nix develop with experimental features enabled + # Use --ignore-environment (-i) to create a pure shell that excludes system packages + # Keep essential variables: HOME (for temp files), USER (for build metadata), TERM (for output) + exec nix --extra-experimental-features "nix-command flakes" develop \ + --ignore-environment \ + --keep-env-var HOME \ + --keep-env-var USER \ + --keep-env-var TERM \ + --command "$0" "$@" +fi + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $*" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $*" +} + +# Parse architecture and build type from command line +ARCH_TYPE="${1:-x64}" # Default to x64 +BUILD_TYPE="${2:-}" # Optional: cvm + +# Validate architecture +case "${ARCH_TYPE}" in + x64|x86_64|amd64) + ARCH_TYPE="x64" + KERNEL_ARCH="x86_64" + ;; + arm64|aarch64) + ARCH_TYPE="arm64" + KERNEL_ARCH="arm64" + CROSS_COMPILE="aarch64-linux-gnu-" + ;; + build|clean|help|--help|-h) + # These are commands, not architectures - will be handled later + ;; + *) + log_error "Unknown architecture: ${ARCH_TYPE}" + log_error "Supported: x64, arm64" + exit 1 + ;; +esac + +# Build configuration +BUILD_OUTPUT="${BUILD_OUTPUT:-${KERNEL_ROOT}/build}" +MAKE_JOBS="${MAKE_JOBS:-$(nproc)}" + +# Reproducible build environment +export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-1609459200}" +export LANG="C.UTF-8" +export LC_ALL="C.UTF-8" +export TZ="UTC" + +# Flag to indicate reproducible build mode (used by build-hcl-kernel.sh) +export REPRODUCIBLE_BUILD=1 + +# Kernel-specific reproducible flags +export KBUILD_BUILD_TIMESTAMP="@${SOURCE_DATE_EPOCH}" +export KBUILD_BUILD_USER="${KBUILD_BUILD_USER:-builder}" +export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST:-nixos}" +export KBUILD_BUILD_VERSION="1" + +main() { + log_info "Starting reproducible kernel build..." + log_info "Kernel source: ${KERNEL_ROOT}" + log_info "Build output: ${BUILD_OUTPUT}" + log_info "Reproducible environment:" + log_info " SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}" + log_info " KBUILD_BUILD_USER=${KBUILD_BUILD_USER}" + log_info " KBUILD_BUILD_HOST=${KBUILD_BUILD_HOST}" + + # Set environment for reproducibility + export KBUILD_BUILD_TIMESTAMP="${KBUILD_BUILD_TIMESTAMP}" + export KBUILD_BUILD_USER="${KBUILD_BUILD_USER}" + export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST}" + export KBUILD_BUILD_VERSION="${KBUILD_BUILD_VERSION}" + + # Unset Nix-specific compiler flags that might interfere with kernel build + unset NIX_CFLAGS_COMPILE + unset NIX_CFLAGS_COMPILE_FOR_TARGET + unset NIX_LDFLAGS + unset NIX_LDFLAGS_FOR_TARGET + + cd "${KERNEL_ROOT}" + + # Handle CVM build if requested + if [ "${BUILD_TYPE}" = "cvm" ]; then + log_info "Building with CVM config..." + "${KERNEL_ROOT}/Microsoft/merge-cvm-config.sh" + fi + + # Invoke the existing build-hcl-kernel.sh script + log_info "Invoking build-hcl-kernel.sh..." + "${KERNEL_ROOT}/Microsoft/build-hcl-kernel.sh" "${ARCH_TYPE}" + + log_info "Build completed successfully!" + log_info "Build artifacts are in: ${BUILD_OUTPUT}" + + # Print sha256sum of vmlinux for reproducibility verification + if [ -f "${BUILD_OUTPUT}/vmlinux" ]; then + echo "" + log_info "Reproducibility verification:" + echo " vmlinux sha256sum: $(sha256sum "${BUILD_OUTPUT}/vmlinux" | cut -d' ' -f1)" + fi +} + +# Handle command line arguments +# Determine command (3rd arg for arch builds, or 1st arg if no arch specified) +COMMAND="${3:-build}" +if [ "${ARCH_TYPE}" = "build" ] || [ "${ARCH_TYPE}" = "clean" ] || [ "${ARCH_TYPE}" = "help" ] || [ "${ARCH_TYPE}" = "--help" ] || [ "${ARCH_TYPE}" = "-h" ]; then + COMMAND="${ARCH_TYPE}" + ARCH_TYPE="x64" # Reset to default +fi +if [ "${BUILD_TYPE}" = "build" ] || [ "${BUILD_TYPE}" = "clean" ] || [ "${BUILD_TYPE}" = "help" ]; then + COMMAND="${BUILD_TYPE}" + BUILD_TYPE="" +fi + +case "${COMMAND}" in + build) + main + ;; + clean) + log_info "Cleaning build directory: ${BUILD_OUTPUT}" + rm -rf "${BUILD_OUTPUT}" + log_info "Clean completed" + ;; + help|--help|-h) + echo "Usage: $0 [ARCH] [BUILD_TYPE] [COMMAND]" + echo "" + echo "Arguments:" + echo " ARCH - Architecture: x64, arm64 (default: x64)" + echo " BUILD_TYPE - Build type: cvm (optional)" + echo " COMMAND - Command: build, clean, help (default: build)" + echo "" + echo "Examples:" + echo " $0 x64 - Build for x64" + echo " $0 arm64 - Build for arm64" + echo " $0 x64 cvm - Build for x64 with CVM config" + echo " $0 arm64 cvm - Build for arm64 with CVM config" + echo "" + echo "Commands:" + echo " build - Build the kernel (default)" + echo " clean - Clean build artifacts" + echo " help - Show this help message" + echo "" + echo "Environment variables:" + echo " BUILD_OUTPUT - Build output directory (default: ./build)" + echo " MAKE_JOBS - Number of parallel jobs (default: nproc)" + echo " CONFIG_FILE_OVERRIDE - Override config file (default: auto-detect Microsoft config)" + echo " SOURCE_DATE_EPOCH - Timestamp for reproducible builds" + echo " KBUILD_BUILD_USER - Username for kernel build" + echo " KBUILD_BUILD_HOST - Hostname for kernel build" + ;; + *) + log_error "Unknown command: $1" + log_info "Run '$0 help' for usage information" + exit 1 + ;; +esac diff --git a/Microsoft/nix-clean.sh b/Microsoft/nix-clean.sh new file mode 100755 index 0000000000000..f606eaeb256f3 --- /dev/null +++ b/Microsoft/nix-clean.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Clean build artifacts + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +echo "Cleaning build artifacts..." + +# Remove build directory +rm -rf "${KERNEL_ROOT}/build" + +# Clean in-tree builds +cd "${KERNEL_ROOT}" +make mrproper 2>/dev/null || true + +echo "Clean completed!" diff --git a/Microsoft/nix-setup.sh b/Microsoft/nix-setup.sh new file mode 100755 index 0000000000000..18d22093873e1 --- /dev/null +++ b/Microsoft/nix-setup.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Quick setup script for reproducible builds with NixOS + +set -euo pipefail + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +echo "===============================================" +echo "OHCL Kernel - Reproducible Build Setup" +echo "===============================================" +echo "" + +# Helper function to source nix and update PATH +source_nix_profile() { + if [ -f ~/.nix-profile/etc/profile.d/nix.sh ]; then + . ~/.nix-profile/etc/profile.d/nix.sh + export PATH="$HOME/.nix-profile/bin:$PATH" + return 0 + elif [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then + . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh + export PATH="/nix/var/nix/profiles/default/bin:$PATH" + return 0 + fi + return 1 +} + +# Check if nix is installed +if ! command -v nix &> /dev/null; then + # Try to source nix profile first in case it's installed but not in PATH + if source_nix_profile; then + echo ">>> Nix profile sourced from existing installation" + fi +fi + +# Check again after sourcing +if ! command -v nix &> /dev/null; then + # Check if /nix directory exists (Nix is installed but profile not sourced) + if [ -d /nix ]; then + echo "⚠️ Nix is installed but not in PATH" + echo "" + echo "Please restart your shell or run:" + echo " . ~/.nix-profile/etc/profile.d/nix.sh" + echo "" + echo "Then run this script again: $0" + exit 0 + fi + + echo "⚠️ Nix is not installed!" + echo "" + echo "Installing Nix (single-user installation)..." + echo "This will download and install Nix package manager." + echo "" + + # Create nixbld group and users for sandboxed builds (required for Nix sandbox) + if ! getent group nixbld > /dev/null 2>&1; then + echo "Creating nixbld group and users for sandbox..." + groupadd -r nixbld || sudo groupadd -r nixbld + + # Create 10 build users (Nix uses these for parallel isolated builds) + for i in $(seq 1 10); do + useradd -r -g nixbld -G nixbld \ + -d /var/empty -s /sbin/nologin \ + -c "Nix build user $i" \ + "nixbld$i" 2>/dev/null || \ + sudo useradd -r -g nixbld -G nixbld \ + -d /var/empty -s /sbin/nologin \ + -c "Nix build user $i" \ + "nixbld$i" 2>/dev/null || true + done + echo "✓ Created nixbld group and 10 build users" + fi + + # Install Nix + echo "install nix" + if curl -L https://nixos.org/nix/install | sh -s -- --no-daemon; then + echo "" + echo "✓ Nix installed successfully!" + echo "" + # Source nix profile immediately for current session + if source_nix_profile; then + echo "✓ Nix environment loaded" + else + echo "⚠️ Could not source Nix profile" + fi + # Continue with setup instead of exiting + else + echo "" + echo "❌ Nix installation failed!" + echo "" + echo "You can try manually installing with:" + echo " curl -L https://nixos.org/nix/install | sh" + echo "" + echo "Or for multi-user installation:" + echo " curl -L https://nixos.org/nix/install | sh -s -- --daemon" + echo "" + exit 1 + fi +fi + +echo "✓ Nix is installed" + +# Check if flakes are enabled +echo "Enabling flakes..." +mkdir -p ~/.config/nix +if ! grep -q "experimental-features.*flakes" ~/.config/nix/nix.conf 2>/dev/null; then + echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf + echo "✓ Flakes enabled in ~/.config/nix/nix.conf" +else + echo "✓ Flakes already enabled in ~/.config/nix/nix.conf" +fi + +# Verify flakes work +if nix --extra-experimental-features "nix-command flakes" flake --version &> /dev/null 2>&1; then + echo "✓ Nix flakes are working" +else + echo "⚠ Could not verify flakes, but config is set" +fi + +# Initialize flake.lock if it doesn't exist (must be in kernel root where flake.nix is) +if [ -f "${KERNEL_ROOT}/flake.nix" ]; then + if [ ! -f "${KERNEL_ROOT}/flake.lock" ]; then + echo "" + echo "Initializing flake.lock..." + cd "${KERNEL_ROOT}" + nix --extra-experimental-features "nix-command flakes" flake lock + echo "✓ flake.lock created" + else + echo "✓ flake.lock already exists" + fi +else + echo "⚠ No flake.nix found in ${KERNEL_ROOT}, skipping flake.lock initialization" +fi + +# Source nix profile for current session (ensure it's available) +source_nix_profile && echo "✓ Nix environment ready" + +echo "" +echo "===============================================" +echo "Setup Complete!" +echo "===============================================" +echo "" +echo "You can now build the kernel with:" +echo "" +echo " ./Microsoft/nix-build.sh x64" +echo " ./Microsoft/nix-build.sh arm64" +echo "" +echo "The script will automatically enter the Nix environment." +echo "" +echo "For more information, run:" +echo " ./Microsoft/nix-build.sh --help" +echo "" diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index 35685c0360441..e09030acb8740 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -21,8 +21,9 @@ btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti # potential future proofing if we end up with internal calls to the exported # routines, as x86 does (see 6f121e548f83 ("x86, vdso: Reimplement vdso.so # preparation in build-time C")). +# For reproducible builds, use --build-id=none to avoid non-deterministic Build IDs. ldflags-y := -shared -soname=linux-vdso.so.1 \ - -Bsymbolic --build-id=sha1 -n $(btildflags-y) + -Bsymbolic --build-id=none -n $(btildflags-y) ifdef CONFIG_LD_ORPHAN_WARN ldflags-y += --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL) diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile index 25a2cb6317f35..d55232104b209 100644 --- a/arch/arm64/kernel/vdso32/Makefile +++ b/arch/arm64/kernel/vdso32/Makefile @@ -98,7 +98,8 @@ VDSO_AFLAGS += -D__ASSEMBLY__ # From arm vDSO Makefile VDSO_LDFLAGS += -Bsymbolic --no-undefined -soname=linux-vdso.so.1 VDSO_LDFLAGS += -z max-page-size=4096 -z common-page-size=4096 -VDSO_LDFLAGS += -shared --build-id=sha1 +# For reproducible builds, use --build-id=none to avoid non-deterministic Build IDs. +VDSO_LDFLAGS += -shared --build-id=none VDSO_LDFLAGS += --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL) diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index c9216ac4fb1eb..f986ef2c165d9 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -154,7 +154,8 @@ quiet_cmd_vdso = VDSO $@ -T $(filter %.lds,$^) $(filter %.o,$^) && \ sh $(src)/checkundef.sh '$(NM)' '$@' -VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 \ +# For reproducible builds, use --build-id=none to avoid non-deterministic Build IDs. +VDSO_LDFLAGS = -shared --hash-style=both --build-id=none \ $(call ld-option, --eh-frame-hdr) -Bsymbolic -z noexecstack quiet_cmd_vdso_and_check = VDSO $@ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000000..2468070f754b8 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000000..5881076175e5b --- /dev/null +++ b/flake.nix @@ -0,0 +1,213 @@ +{ + description = "OHCL Linux Kernel - Reproducible Build Environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = false; + }; + + # Kernel build dependencies + kernelBuildInputs = with pkgs; [ + # Core build tools + gcc + gnumake + binutils + bison + flex + bc + perl + python3 + + # Shell utilities needed for build scripts + getopt + coreutils + findutils + gnugrep + gnused + gawk + bash + rsync + hostname + which + + # ARM64 cross-compilation toolchain + pkgsCross.aarch64-multiplatform.stdenv.cc + pkgsCross.aarch64-multiplatform.buildPackages.binutils + + # Compression tools + gzip + bzip2 + xz + zstd + + # Additional tools + elfutils + openssl + pkg-config + ncurses + + # For device tree compilation + dtc + + # For reproducibility checking + diffoscope + + # Version control + git + ]; + + # Reproducible build environment variables + reproducibleEnv = { + # Disable timestamps in build output + SOURCE_DATE_EPOCH = "1609459200"; # 2021-01-01 00:00:00 UTC + + # Set consistent locale + LANG = "C.UTF-8"; + LC_ALL = "C.UTF-8"; + + # Kernel build flags for reproducibility + KBUILD_BUILD_TIMESTAMP = "@1609459200"; + KBUILD_BUILD_USER = "builder"; + KBUILD_BUILD_HOST = "nixos"; + + # Disable hostname and username + KBUILD_BUILD_VERSION = "1"; + + # Set consistent timezone + TZ = "UTC"; + }; + + in + { + # Development shell with all dependencies + devShells.default = pkgs.mkShell { + buildInputs = kernelBuildInputs; + + shellHook = '' + echo "OHCL Linux Kernel - Reproducible Build Environment" + echo "==================================================" + echo "" + echo "Available commands:" + echo " ./Microsoft/nix-build.sh - Build kernel reproducibly" + echo " ./Microsoft/nix-check-repro.sh - Verify reproducibility" + echo " ./Microsoft/nix-clean.sh - Clean build artifacts" + echo "" + echo "Environment configured for reproducible builds:" + echo " SOURCE_DATE_EPOCH=${reproducibleEnv.SOURCE_DATE_EPOCH}" + echo " KBUILD_BUILD_USER=${reproducibleEnv.KBUILD_BUILD_USER}" + echo " KBUILD_BUILD_HOST=${reproducibleEnv.KBUILD_BUILD_HOST}" + echo "" + + # Export reproducible environment variables + export SOURCE_DATE_EPOCH="${reproducibleEnv.SOURCE_DATE_EPOCH}" + export LANG="${reproducibleEnv.LANG}" + export LC_ALL="${reproducibleEnv.LC_ALL}" + export KBUILD_BUILD_TIMESTAMP="${reproducibleEnv.KBUILD_BUILD_TIMESTAMP}" + export KBUILD_BUILD_USER="${reproducibleEnv.KBUILD_BUILD_USER}" + export KBUILD_BUILD_HOST="${reproducibleEnv.KBUILD_BUILD_HOST}" + export KBUILD_BUILD_VERSION="${reproducibleEnv.KBUILD_BUILD_VERSION}" + export TZ="${reproducibleEnv.TZ}" + ''; + }; + + # Packages for building the kernel + packages = { + # Build the kernel + kernel = pkgs.stdenv.mkDerivation { + pname = "ohcl-linux-kernel"; + version = "6.x"; + + src = ./.; + + nativeBuildInputs = kernelBuildInputs; + + # Apply reproducible build environment + inherit (reproducibleEnv) + SOURCE_DATE_EPOCH + LANG + LC_ALL + KBUILD_BUILD_TIMESTAMP + KBUILD_BUILD_USER + KBUILD_BUILD_HOST + KBUILD_BUILD_VERSION + TZ; + + configurePhase = '' + runHook preConfigure + + # Use default config or provided config + if [ -f .config ]; then + echo "Using existing .config" + else + make defconfig + fi + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + + # Build with reproducible flags + make -j$NIX_BUILD_CORES \ + KBUILD_BUILD_TIMESTAMP="$KBUILD_BUILD_TIMESTAMP" \ + KBUILD_BUILD_USER="$KBUILD_BUILD_USER" \ + KBUILD_BUILD_HOST="$KBUILD_BUILD_HOST" \ + KBUILD_BUILD_VERSION="$KBUILD_BUILD_VERSION" + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/boot + cp arch/*/boot/Image $out/boot/ 2>/dev/null || true + cp arch/*/boot/bzImage $out/boot/ 2>/dev/null || true + cp arch/*/boot/zImage $out/boot/ 2>/dev/null || true + cp System.map $out/boot/ + cp .config $out/boot/config + + mkdir -p $out/lib/modules + make INSTALL_MOD_PATH=$out modules_install + + runHook postInstall + ''; + + enableParallelBuilding = true; + }; + + default = self.packages.${system}.kernel; + }; + + # Apps for easy execution + apps = { + build = { + type = "app"; + program = "${pkgs.writeShellScript "build-kernel" '' + set -e + cd "$(dirname "$0")/.." + exec ${pkgs.bash}/bin/bash ./Microsoft/nix-build.sh "$@" + ''}"; + }; + + check-repro = { + type = "app"; + program = "${pkgs.writeShellScript "check-reproducibility" '' + set -e + cd "$(dirname "$0")/.." + exec ${pkgs.bash}/bin/bash ./Microsoft/nix-check-repro.sh "$@" + ''}"; + }; + }; + } + ); +}