summaryrefslogtreecommitdiff
path: root/rakelib/cross.rake
diff options
context:
space:
mode:
Diffstat (limited to 'rakelib/cross.rake')
-rw-r--r--rakelib/cross.rake307
1 files changed, 307 insertions, 0 deletions
diff --git a/rakelib/cross.rake b/rakelib/cross.rake
new file mode 100644
index 0000000..3de7d79
--- /dev/null
+++ b/rakelib/cross.rake
@@ -0,0 +1,307 @@
+require 'pathname'
+require 'uri'
+require 'net/http'
+require 'rake/clean'
+require 'open3'
+require 'etc'
+
+GCC_VERSION = "14.2.0"
+BINUTILS_VERSION = '2.43.1'
+GLIBC_VERSION = '2.40'
+KERNEL_VERSION = '5.15.166'
+
+TMP = Pathname.new('./build')
+
+CLEAN.include TMP
+
+class BuildTarget
+ attr_accessor(:build, :gcc, :target, :tmp)
+
+ def gxx
+ @gcc.gsub 'c', '+'
+ end
+
+ def sysroot
+ tmp + 'sysroot'
+ end
+
+ def rootfs
+ tmp + 'rootfs'
+ end
+
+ def tools
+ tmp + 'tools'
+ end
+end
+
+def gcc_verbose(gcc_binary)
+ read, write = IO.pipe
+ sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
+ write.close
+ output = read.read
+ read.close
+ output
+end
+
+def find_build_target(gcc_version, task)
+ gcc_binary = 'gcc'
+ output = gcc_verbose gcc_binary
+
+ if output.start_with? 'Apple clang'
+ gcc_binary = "gcc-#{gcc_version.split('.').first}"
+ output = gcc_verbose gcc_binary
+ end
+ result = output
+ .lines
+ .each_with_object(BuildTarget.new) do |line, accumulator|
+ if line.start_with? 'Target: '
+ accumulator.build = line.split(' ').last.strip
+ elsif line.start_with? 'COLLECT_GCC'
+ accumulator.gcc = line.split('=').last.strip
+ end
+ end
+ result.tmp = TMP
+ task.with_defaults target: 'riscv32-unknown-linux-gnu'
+ result.target = task[:target]
+ result
+end
+
+def download_and_unarchive(url, target)
+ case File.extname url.path
+ when '.bz2'
+ archive_type = '-j'
+ root_directory = File.basename url.path, '.tar.bz2'
+ when '.xz'
+ archive_type = '-J'
+ root_directory = File.basename url.path, '.tar.xz'
+ else
+ raise "Unsupported archive type #{url.path}."
+ end
+
+ Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
+ request = Net::HTTP::Get.new url.request_uri
+
+ http.request request do |response|
+ case response
+ when Net::HTTPRedirection
+ download_and_unarchive URI.parse(response['location'])
+ when Net::HTTPSuccess
+ Open3.popen2 'tar', '-C', target.to_path, archive_type, '-xv' do |stdin, stdout, wait_thread|
+ stdout.close
+
+ response.read_body do |chunk|
+ stdin.write chunk
+ end
+ end
+ else
+ response.error!
+ end
+ end
+ end
+ target + root_directory
+end
+
+namespace :cross do
+ desc 'Build cross binutils'
+ task :binutils, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ options.tools.mkpath
+ source_directory = download_and_unarchive(
+ URI.parse("https://ftp.gnu.org/gnu/binutils/binutils-#{BINUTILS_VERSION}.tar.xz"),
+ options.tools)
+
+ cwd = source_directory.dirname + 'build-binutils'
+ cwd.mkpath
+ options.rootfs.mkpath
+
+ env = {
+ 'CC' => options.gcc,
+ 'CXX' => options.gxx
+ }
+ configure_options = [
+ "--prefix=#{options.rootfs.realpath}",
+ "--target=#{options.target}",
+ '--disable-nls',
+ '--enable-gprofng=no',
+ '--disable-werror',
+ '--enable-default-hash-style=gnu',
+ '--disable-libquadmath'
+ ]
+ configure = source_directory.relative_path_from(cwd) + 'configure'
+ sh env, configure.to_path, *configure_options, chdir: cwd.to_path
+ sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path
+ sh env, 'make', 'install', chdir: cwd.to_path
+ end
+
+ desc 'Build stage 1 GCC'
+ task :gcc1, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ options.tools.mkpath
+ source_directory = download_and_unarchive(
+ URI.parse("https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"),
+ options.tools)
+
+ cwd = source_directory.dirname + 'build-gcc'
+ cwd.mkpath
+ options.rootfs.mkpath
+ options.sysroot.mkpath
+
+ sh 'contrib/download_prerequisites', chdir: source_directory.to_path
+ configure_options = [
+ "--prefix=#{options.rootfs.realpath}",
+ "--with-sysroot=#{options.sysroot.realpath}",
+ '--enable-languages=c,c++',
+ '--disable-shared',
+ '--with-arch=rv32imafdc',
+ '--with-abi=ilp32d',
+ '--with-tune=rocket',
+ '--with-isa-spec=20191213',
+ '--disable-bootstrap',
+ '--disable-multilib',
+ '--disable-libmudflap',
+ '--disable-libssp',
+ '--disable-libquadmath',
+ '--disable-libsanitizer',
+ '--disable-threads',
+ '--disable-libatomic',
+ '--disable-libgomp',
+ '--disable-libvtv',
+ '--disable-libstdcxx',
+ '--disable-nls',
+ '--with-newlib',
+ '--without-headers',
+ "--target=#{options.target}",
+ "--build=#{options.build}",
+ "--host=#{options.build}"
+ ]
+ flags = '-O2 -fPIC'
+ env = {
+ 'CC' => options.gcc,
+ 'CXX' => options.gxx,
+ 'CFLAGS' => flags,
+ 'CXXFLAGS' => flags,
+ 'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
+ }
+ configure = source_directory.relative_path_from(cwd) + 'configure'
+ sh env, configure.to_path, *configure_options, chdir: cwd.to_path
+ sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path
+ sh env, 'make', 'install', chdir: cwd.to_path
+ end
+
+ desc 'Copy glibc headers'
+ task :headers, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ options.tools.mkpath
+
+ source_directory = download_and_unarchive(
+ URI.parse("https://ftp.gnu.org/gnu/glibc/glibc-#{GLIBC_VERSION}.tar.xz"),
+ options.tools)
+ include_directory = options.tools + 'include'
+
+ include_directory.mkpath
+ cp (source_directory + 'elf/elf.h'), (include_directory + 'elf.h')
+ end
+
+ desc 'Build linux kernel'
+ task :kernel, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ options.tools.mkpath
+
+ cwd = download_and_unarchive(
+ URI.parse("https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-#{KERNEL_VERSION}.tar.xz"),
+ options.tools)
+
+ env = {
+ 'CROSS_COMPILE' => "#{options.target}-",
+ 'ARCH' => 'riscv',
+ 'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}",
+ 'HOSTCFLAGS' => "-D_UUID_T -D__GETHOSTUUID_H -I#{options.tools.realpath + 'include'}"
+ }
+ sh env, 'make', 'rv32_defconfig', chdir: cwd.to_path
+ sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path
+ sh env, 'make', 'headers', chdir: cwd.to_path
+
+ user_directory = options.sysroot + 'usr'
+
+ user_directory.mkpath
+ cp_r (cwd + 'usr/include'), (user_directory + 'include')
+ end
+
+ desc 'Build glibc'
+ task :glibc, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ source_directory = options.tools + "glibc-#{GLIBC_VERSION}"
+ configure_options = [
+ '--prefix=/usr',
+ "--host=#{options.target}",
+ "--target=#{options.target}",
+ "--build=#{options.build}",
+ "--enable-kernel=#{KERNEL_VERSION}",
+ "--with-headers=#{options.sysroot.realpath + 'usr/include'}",
+ '--disable-nscd',
+ '--disable-libquadmath',
+ '--disable-libitm',
+ '--disable-werror',
+ 'libc_cv_forced_unwind=yes'
+ ]
+ bin = options.rootfs.realpath + 'bin'
+ env = {
+ 'PATH' => "#{bin}:#{ENV['PATH']}",
+ 'MAKE' => 'make' # Otherwise it uses gnumake which can be different and too old.
+ }
+ cwd = source_directory.dirname + 'build-glibc'
+ cwd.mkpath
+
+ configure = source_directory.relative_path_from(cwd) +'./configure'
+ sh env, configure.to_path, *configure_options, chdir: cwd.to_path
+ sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path
+ sh env, 'make', "install_root=#{options.sysroot.realpath}", 'install', chdir: cwd.to_path
+ end
+
+ desc 'Build stage 2 GCC'
+ task :gcc2, [:target] do |_, args|
+ options = find_build_target GCC_VERSION, args
+ source_directory = options.tools + "gcc-#{GCC_VERSION}"
+ cwd = options.tools + 'build-gcc'
+
+ rm_rf cwd
+ cwd.mkpath
+
+ configure_options = [
+ "--prefix=#{options.rootfs.realpath}",
+ "--with-sysroot=#{options.sysroot.realpath}",
+ '--enable-languages=c,c++,lto',
+ '--enable-lto',
+ '--enable-shared',
+ '--with-arch=rv32imafdc',
+ '--with-abi=ilp32d',
+ '--with-tune=rocket',
+ '--with-isa-spec=20191213',
+ '--disable-bootstrap',
+ '--disable-multilib',
+ '--enable-checking=release',
+ '--disable-libssp',
+ '--disable-libquadmath',
+ '--enable-threads=posix',
+ '--with-default-libstdcxx-abi=new',
+ '--disable-nls',
+ "--target=#{options.target}",
+ "--build=#{options.build}",
+ "--host=#{options.build}"
+
+ ]
+ flags = '-O2 -fPIC'
+ env = {
+ 'CFLAGS' => flags,
+ 'CXXFLAGS' => flags,
+ 'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
+ }
+ configure = source_directory.relative_path_from(cwd) + 'configure'
+ sh env, configure.to_path, *configure_options, chdir: cwd.to_path
+ sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path
+ sh env, 'make', 'install', chdir: cwd.to_path
+ end
+end
+
+task cross: ['cross:binutils', 'cross:gcc1', 'cross:headers', 'cross:kernel', 'cross:glibc', 'cross:gcc2'] do
+end