Update to rscons 3.0.0

This commit is contained in:
josh committed 2022-02-28 13:40:08 -05:00
1 parent c6ae200a54
commit 56c3be9207
10 files changed
+235 -230

No files matched your search

+1 -5
View File
@@ -5,9 +5,5 @@
*.map *.map
*.bin *.bin
.rscons* .rscons*
/i686-elf-gcc/build*/ /i686-elf-gcc/
/i686-elf-gcc/*.xz
/i686-elf-gcc/binutils-*/
/i686-elf-gcc/gcc-*/
/i686-elf-gcc/i686-elf-gcc/
/build/ /build/
-15
View File
@@ -1,15 +0,0 @@
.PHONY: all
all:
./rscons build
.PHONY: run-efi
run-efi: all
qemu-system-x86_64 -bios OVMF.fd -hda build/hos-efi.img
.PHONY: run
run: all
qemu-system-x86_64 -hda build/hos.img
.PHONY: clean
clean:
./rscons clean
+131 -120
View File
@@ -1,7 +1,7 @@
path_prepend "i686-elf-gcc/i686-elf-gcc/bin" path_prepend "i686-elf-gcc/bin"
configure do configure do
rscons "i686-elf-gcc" rscons "i686-elf-gcc.rb", "-b", "#{build_dir}/i686-elf-gcc"
check_c_compiler "i686-elf-gcc" check_c_compiler "i686-elf-gcc"
check_program "genext2fs" check_program "genext2fs"
check_program "grub-mkstandalone" check_program "grub-mkstandalone"
@@ -10,146 +10,157 @@ configure do
check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype" check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype"
end end
build do require "tmpdir"
require "tmpdir"
# EFI (w/ GRUB) partition size (MiB) # EFI (w/ GRUB) partition size (MiB)
EFI_PART_SIZE = 8 EFI_PART_SIZE = 8
# HOS partition size (MiB) # HOS partition size (MiB)
HOS_PART_SIZE = 4 HOS_PART_SIZE = 4
# Kernel default font size # Kernel default font size
KFONT_SIZE = 15 KFONT_SIZE = 15
class BiosImage < Builder class BiosImage < Builder
def run(options) def run(options)
unless @cache.up_to_date?(@target, nil, @sources, @env) unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Generating BIOS boot image #{@target}", nil) print_run_message("Generating BIOS boot image #{@target}", nil)
Dir.mktmpdir do |tmpdir| Dir.mktmpdir do |tmpdir|
# Create iso directory. # Create iso directory.
FileUtils.mkdir_p("#{tmpdir}/iso/boot/grub") FileUtils.mkdir_p("#{tmpdir}/iso/boot/grub")
File.open("#{tmpdir}/iso/boot/grub/grub.cfg", "wb") do |fh| File.open("#{tmpdir}/iso/boot/grub/grub.cfg", "wb") do |fh|
fh.write(<<EOF) fh.write(<<EOF)
set default="0" set default="0"
set timeout=1 set timeout=1
menuentry "HOS" { menuentry "HOS" {
insmod multiboot2 insmod multiboot2
multiboot2 /hos.elf multiboot2 /hos.elf
} }
EOF EOF
end
@sources.each do |source|
FileUtils.cp(source, "#{tmpdir}/iso")
end
# Build bootable GRUB image.
system(*%W[grub-mkrescue -o #{@target} #{tmpdir}/iso], err: "#{@env.build_root}/grub-mkrescue.log")
end end
@cache.register_build(@target, nil, @sources, @env) @sources.each do |source|
FileUtils.cp(source, "#{tmpdir}/iso")
end
# Build bootable GRUB image.
system(*%W[grub-mkrescue -o #{@target} #{tmpdir}/iso], err: "#{@env.build_root}/grub-mkrescue.log")
end end
true @cache.register_build(@target, nil, @sources, @env)
end end
true
end end
end
class EfiImage < Builder class EfiImage < Builder
def run(options) def run(options)
unless @cache.up_to_date?(@target, nil, @sources, @env) unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Generating EFI boot image #{@target}", nil) print_run_message("Generating EFI boot image #{@target}", nil)
Dir.mktmpdir do |tmpdir| Dir.mktmpdir do |tmpdir|
# Build a standalone GRUB. # Build a standalone GRUB.
File.open("#{tmpdir}/grub.cfg", "wb") do |fh| File.open("#{tmpdir}/grub.cfg", "wb") do |fh|
fh.write(<<EOF) fh.write(<<EOF)
insmod part_gpt insmod part_gpt
configfile (hd0,gpt2)/grub.cfg configfile (hd0,gpt2)/grub.cfg
EOF EOF
end end
system(*%W[grub-mkstandalone -O x86_64-efi -o #{tmpdir}/BOOTX64.EFI boot/grub/grub.cfg=#{tmpdir}/grub.cfg]) system(*%W[grub-mkstandalone -O x86_64-efi -o #{tmpdir}/BOOTX64.EFI boot/grub/grub.cfg=#{tmpdir}/grub.cfg])
# Create EFI partition. # Create EFI partition.
system(*%W[dd if=/dev/zero of=#{tmpdir}/efi.part bs=1M count=#{EFI_PART_SIZE}], err: "/dev/null") system(*%W[dd if=/dev/zero of=#{tmpdir}/efi.part bs=1M count=#{EFI_PART_SIZE}], err: "/dev/null")
system(*%W[mformat -i #{tmpdir}/efi.part ::]) system(*%W[mformat -i #{tmpdir}/efi.part ::])
system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI]) system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI])
system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI/BOOT]) system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI/BOOT])
system(*%W[mcopy -i #{tmpdir}/efi.part #{tmpdir}/BOOTX64.EFI ::/EFI/BOOT]) system(*%W[mcopy -i #{tmpdir}/efi.part #{tmpdir}/BOOTX64.EFI ::/EFI/BOOT])
# Create ext2 HOS partition. # Create ext2 HOS partition.
FileUtils.mkdir_p("#{tmpdir}/ext2") FileUtils.mkdir_p("#{tmpdir}/ext2")
@sources.each do |source| @sources.each do |source|
FileUtils.cp(source, "#{tmpdir}/ext2") FileUtils.cp(source, "#{tmpdir}/ext2")
end end
File.open("#{tmpdir}/ext2/grub.cfg", "wb") do |fh| File.open("#{tmpdir}/ext2/grub.cfg", "wb") do |fh|
fh.write(<<EOF) fh.write(<<EOF)
set default="0" set default="0"
set timeout=1 set timeout=1
menuentry "HOS" { menuentry "HOS" {
insmod part_gpt insmod part_gpt
insmod multiboot2 insmod multiboot2
set root=(hd0,gpt2) set root=(hd0,gpt2)
multiboot2 /hos.elf multiboot2 /hos.elf
} }
EOF EOF
end
system(*%W[genext2fs -b #{HOS_PART_SIZE * 1024} -d #{tmpdir}/ext2 #{tmpdir}/ext2.part])
# Create full disk image.
system(*%W[dd if=/dev/zero of=#{@target} bs=1M count=#{EFI_PART_SIZE + HOS_PART_SIZE + 2}], err: "/dev/null")
system(*%W[parted -s #{@target} mklabel gpt])
system(*%W[parted -s #{@target} mkpart efi 1MiB #{EFI_PART_SIZE + 1}MiB])
system(*%W[parted -s #{@target} mkpart hos #{EFI_PART_SIZE + 1}MiB #{EFI_PART_SIZE + HOS_PART_SIZE + 1}MiB])
system(*%W[dd if=#{tmpdir}/efi.part of=#{@target} bs=1M seek=1 conv=notrunc], err: "/dev/null")
system(*%W[dd if=#{tmpdir}/ext2.part of=#{@target} bs=1M seek=#{1 + EFI_PART_SIZE} conv=notrunc], err: "/dev/null")
end end
@cache.register_build(@target, nil, @sources, @env) system(*%W[genext2fs -b #{HOS_PART_SIZE * 1024} -d #{tmpdir}/ext2 #{tmpdir}/ext2.part])
# Create full disk image.
system(*%W[dd if=/dev/zero of=#{@target} bs=1M count=#{EFI_PART_SIZE + HOS_PART_SIZE + 2}], err: "/dev/null")
system(*%W[parted -s #{@target} mklabel gpt])
system(*%W[parted -s #{@target} mkpart efi 1MiB #{EFI_PART_SIZE + 1}MiB])
system(*%W[parted -s #{@target} mkpart hos #{EFI_PART_SIZE + 1}MiB #{EFI_PART_SIZE + HOS_PART_SIZE + 1}MiB])
system(*%W[dd if=#{tmpdir}/efi.part of=#{@target} bs=1M seek=1 conv=notrunc], err: "/dev/null")
system(*%W[dd if=#{tmpdir}/ext2.part of=#{@target} bs=1M seek=#{1 + EFI_PART_SIZE} conv=notrunc], err: "/dev/null")
end end
true @cache.register_build(@target, nil, @sources, @env)
end end
end true
class FontGen < Builder
def run(options)
if @command
finalize_command
else
@sources += ["build/fontgen"]
command = %W[build/fontgen #{@sources.first} #{KFONT_SIZE} #{@target}]
standard_command("FontGen <target>#{@target}<reset>", command, {})
end
end
end
class Size < Builder
def run(options)
if @command
finalize_command
else
@vars["_SOURCES"] = @sources
@vars["_TARGET"] = @target
command = @env.build_command(%w[${SIZE} ${_SOURCES}], @vars)
standard_command("Size <target>#{@target}<reset>", command, stdout: @target)
end
end
end
# FontGen Environment
Environment.new(use: "freetype") do |env|
env["CC"] = "gcc"
env.Program("build/fontgen", glob("fontgen/**/*.c"))
end
# Kernel Environment
Environment.new do |env|
env.add_builder(EfiImage)
env.add_builder(BiosImage)
env.add_builder(FontGen)
env.add_builder(Size)
env["OBJDUMP"] = "i686-elf-objdump"
env["SIZE"] = "i686-elf-size"
env["CCFLAGS"] += %w[-ffreestanding -Wall -O2]
env["LDFLAGS"] += %w[-ffreestanding -nostdlib -T src/link.ld]
env["LDFLAGS"] += %W[-Wl,-Map,${_TARGET}.map]
env["LIBS"] += %w[gcc]
env.FontGen("^/kfont/kfont.c", "font/Hack-Regular.ttf")
env["CPPPATH"] += ["#{env.build_root}/kfont"]
env.Program("^/hos.elf", glob("src/**/*.{S,c}") + ["^/kfont/kfont.c"])
env.depends("#{env.build_root}/hos.elf", "src/link.ld")
env.Disassemble("^/hos.elf.txt", "^/hos.elf")
env.Size("^/hos.elf.size", "^/hos.elf")
env.EfiImage("build/hos-efi.img", %w[^/hos.elf])
env.BiosImage("build/hos.img", %w[^/hos.elf])
end end
end end
class FontGen < Builder
def run(options)
if @command
finalize_command
else
fontgen = @vars["fontgen"]
@sources += [fontgen]
command = %W[#{fontgen} #{@sources.first} #{KFONT_SIZE} #{@target}]
standard_command("FontGen <target>#{@target}<reset>", command, {})
end
end
end
class Size < Builder
def run(options)
if @command
finalize_command
else
@vars["_SOURCES"] = @sources
@vars["_TARGET"] = @target
command = @env.build_command(%w[${SIZE} ${_SOURCES}], @vars)
standard_command("Size <target>#{@target}<reset>", command, stdout: @target)
end
end
end
# FontGen Environment
fontgen_env = env "fontgen", use: "freetype" do |env|
env["CC"] = "gcc"
env.Program("^/fontgen.bin", glob("fontgen/**/*.c"))
end
# Kernel Environment
kernel_env = env "kernel" do |env|
env.add_builder(EfiImage)
env.add_builder(BiosImage)
env.add_builder(FontGen)
env.add_builder(Size)
env["OBJDUMP"] = "i686-elf-objdump"
env["SIZE"] = "i686-elf-size"
env["CCFLAGS"] += %w[-ffreestanding -Wall -O2]
env["LDFLAGS"] += %w[-ffreestanding -nostdlib -T src/link.ld]
env["LDFLAGS"] += %W[-Wl,-Map,${_TARGET}.map]
env["LIBS"] += %w[gcc]
env.FontGen("^/kfont/kfont.c", "font/Hack-Regular.ttf",
"fontgen" => fontgen_env.expand("^/fontgen.bin"))
env.barrier
env["CPPPATH"] += ["#{env.build_root}/kfont"]
env.Program("^/hos.elf", glob("src/**/*.{S,c}") + ["^/kfont/kfont.c"])
env.depends("#{env.build_root}/hos.elf", "src/link.ld")
env.Disassemble("^/hos.elf.txt", "^/hos.elf")
env.Size("^/hos.elf.size", "^/hos.elf")
env.EfiImage("^/hos-efi.img", %w[^/hos.elf])
env.BiosImage("^/hos.img", %w[^/hos.elf])
end
task "run", desc: "Run HOS in QEMU" do
img = kernel_env.expand("^/hos.img")
sh %W[qemu-system-x86_64 -hda #{img}]
end
task "run-efi", desc: "Run HOS EFI in QEMU" do
img = kernel_env.expand("^/hos-efi.img")
sh %W[qemu-system-x86_64 -bios OVMF.fd -hda #{img}]
end
Vendored
-2
View File
@@ -1,2 +0,0 @@
#!/bin/sh
exec ./rscons configure "$@"
+75
View File
@@ -0,0 +1,75 @@
binutils_version = "2.35"
binutils_checksum = "1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
gcc_version = "10.2.0"
gcc_checksum = "b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
install_path = File.expand_path("i686-elf-gcc")
target = "i686-elf"
path_prepend "#{install_path}/bin"
configure do
check_c_compiler "gcc"
check_program "make"
check_program "bison"
check_program "flex"
check_program "texi2any", on_fail: "Install the texinfo package"
check_program "wget"
check_lib "gmp", on_fail: "Install the libgmp-dev package"
check_lib "mpc", on_fail: "Install the libmpc-dev package"
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
end
default do
unless Dir.exist?(install_path)
# Download archives.
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256sum: gcc_checksum
# Extract archives.
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir
# Build binutils.
rm_rf "#{build_dir}/build-binutils"
mkdir_p "#{build_dir}/build-binutils"
cd "#{build_dir}/build-binutils" do
sh %W[../binutils-#{binutils_version}/configure
--target=#{target} --prefix=#{install_path} --with-sysroot --disable-nls
--disable-werror]
sh "make"
sh "make install"
end
# Build gcc.
rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do
sh %W[../gcc-#{gcc_version}/configure
--target=#{target} --prefix=#{install_path} --disable-nls
--enable-languages=c,c++ --without-headers]
sh "make all-gcc"
sh "make all-target-libgcc"
sh "make install-gcc"
sh "make install-target-libgcc"
end
# Remove archives and build directories if everything succeeded.
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
rm_rf "#{build_dir}/binutils-#{binutils_version}"
rm_rf "#{build_dir}/build-binutils"
rm_f "#{build_dir}/gcc-#{gcc_version}.tar.xz"
rm_rf "#{build_dir}/gcc-#{gcc_version}"
rm_rf "#{build_dir}/build-gcc"
end
end
distclean do
rm_rf install_path
end
-17
View File
@@ -1,17 +0,0 @@
configure do
check_c_compiler "gcc"
check_program "make"
check_program "bison"
check_program "flex"
check_program "texi2any", on_fail: "Install the texinfo package"
check_program "wget"
check_lib "gmp", on_fail: "Install the libgmp-dev package"
check_lib "mpc", on_fail: "Install the libmpc-dev package"
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
end
build do
unless File.exist?("i686-elf-gcc")
system("./build.sh")
end
end
-64
View File
@@ -1,64 +0,0 @@
#!/bin/bash
BINUTILS_VERSION="2.35"
BINUTILS_CHECKSUM="1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
GCC_VERSION="10.2.0"
GCC_CHECKSUM="b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
if [ ! -e binutils-${BINUTILS_VERSION}.tar.xz ]; then
wget -O binutils-${BINUTILS_VERSION}.tar.xz https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VERSION}.tar.xz
fi
if [[ ! `sha256sum binutils-${BINUTILS_VERSION}.tar.xz` =~ $BINUTILS_CHECKSUM ]]; then
echo "Invalid binutils-${BINUTILS_VERSION}.tar.xz checksum"
exit
fi
if [ ! -d binutils-${BINUTILS_VERSION} ]; then
tar xJf binutils-${BINUTILS_VERSION}.tar.xz
fi
if [ ! -e gcc-${GCC_VERSION}.tar.xz ]; then
wget -O gcc-${GCC_VERSION}.tar.xz https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz
fi
if [[ ! `sha256sum gcc-${GCC_VERSION}.tar.xz` =~ $GCC_CHECKSUM ]]; then
echo "Invalid gcc-${GCC_VERSION}.tar.xz checksum"
exit
fi
if [ ! -d gcc-${GCC_VERSION} ]; then
tar xJf gcc-${GCC_VERSION}.tar.xz
fi
export PREFIX="$PWD/i686-elf-gcc"
export TARGET="i686-elf"
export PATH="$PREFIX/bin:$PATH"
function build_binutils()
{
rm -rf build-binutils
mkdir -p build-binutils
(
cd build-binutils
../binutils-${BINUTILS_VERSION}/configure --target="$TARGET" --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror && \
make && \
make install
)
}
function build_gcc()
{
rm -rf build-gcc
mkdir -p build-gcc
(
cd build-gcc
../gcc-${GCC_VERSION}/configure --target="$TARGET" --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers && \
make all-gcc && \
make all-target-libgcc && \
make install-gcc && \
make install-target-libgcc
)
}
build_binutils && build_gcc
-2
View File
@@ -1,2 +0,0 @@
#!/bin/sh
rm -rf build build-* binutils* gcc-*
-2
View File
@@ -1,2 +0,0 @@
#!/bin/sh
exec ../rscons configure
+28 -3
View File
@@ -1,5 +1,30 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
script = File.join(File.dirname(__FILE__), ".rscons-2.3.0-272f26340e9affa341050e282d22641f.rb")
# Copyright (c) 2013-2022 Josh Holtrop
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
script = File.join(File.dirname(__FILE__), ".rscons-3.0.0-077c0388ca4d1d902141299abcc4b8f6.rb")
unless File.exists?(script) unless File.exists?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/ if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib" require "zlib"
@@ -16,6 +41,6 @@ unless File.exists?(script)
end end
load script load script
if __FILE__ == $0 if __FILE__ == $0
Rscons::Cli.run(ARGV) Rscons::Cli.new.run(ARGV)
end end
#==>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 truncated #==>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 truncated