1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/. -}
# frozen_string_literal: true
require 'uri'
require 'net/http'
require 'open3'
require 'pathname'
def gcc_verbose(gcc_binary)
read, write = IO.pipe
sh({'LC_ALL' => 'C'}, gcc_binary, '--verbose', err: write)
write.close
output = read.read
read.close
output
end
def find_build_target
gcc_verbose(ENV.fetch 'CC', 'gcc')
.lines
.find { |line| line.start_with? 'Target: ' }
.split(' ')
.last
.strip
end
def download_and_pipe(url, target, command)
target.mkpath
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_pipe URI.parse(response['location']), target, command
when Net::HTTPSuccess
Dir.chdir target.to_path do
Open3.popen2(*command) do |stdin, stdout, wait_thread|
Thread.new do
stdout.each { |line| puts line }
end
response.read_body do |chunk|
stdin.write chunk
end
stdin.close
wait_thread.value
end
end
else
response.error!
end
end
end
end
def link_frontend(source, destination)
File.symlink Pathname.new(source).relative_path_from(destination), (destination + File.basename(source))
end
namespace :gcc do
# Dependencies.
GCC_VERSION = "15.3.0"
HOST_GCC = 'build/host/gcc'
GCC_TREE = Pathname.new "build/tools/gcc-#{GCC_VERSION}"
GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/homebrew-core/refs/heads/main/Patches/gcc/gcc-15.3.0.diff'
directory HOST_GCC
directory 'build/host/install'
directory 'build/tools'
desc 'Download the bootstrap compiler and its prerequisites'
task download: 'build/tools' do
url = URI.parse "https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"
download_and_pipe url, GCC_TREE.dirname, ['tar', '-Jxv']
download_and_pipe URI.parse(GCC_PATCH), GCC_TREE, ['patch', '-p1']
sh 'contrib/download_prerequisites', chdir: GCC_TREE.to_path
end
desc 'Link the frontend into the GCC source tree'
task :link do
source_destination = GCC_TREE + 'gcc/elna'
test_destination = GCC_TREE + 'gcc/testsuite/elna.dg'
rm_rf [source_destination, test_destination]
mkdir_p [source_destination, test_destination]
FileList['boot', 'include', 'COPYING3', 'README.md', 'gcc/gcc', 'gcc/*.in', 'gcc/lang*'].each do |file|
link_frontend file, source_destination
end
FileList['testsuite/*', 'gcc/dg.exp', 'README.md'].each do |file|
link_frontend file, test_destination
end
destination = GCC_TREE + 'gcc/testsuite/lib'
FileList['gcc/testlib/*'].each do |file|
rm_f (destination + File.basename(file))
link_frontend file, destination
end
end
desc 'Configure the bootstrap compiler'
task configure: [HOST_GCC, 'build/host/install'] do |t|
build_target = find_build_target
configure_options = [
"--prefix=#{File.realpath t.prerequisites.last}",
'--enable-languages=c,c++,jit,elna',
'--disable-bootstrap',
'--disable-multilib',
'--enable-host-shared',
'--with-system-zlib',
"--target=#{build_target}",
"--build=#{build_target}",
"--host=#{build_target}"
]
mac_os_sdk = '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk'
configure_options << "--with-sysroot=#{mac_os_sdk}" if File.symlink? mac_os_sdk
env = ENV.slice 'CC', 'CXX'
env['CFLAGS'] = env['CXXFLAGS'] = '-O0 -g -fPIC -I/opt/homebrew/opt/flex/include'
configure = GCC_TREE.relative_path_from(HOST_GCC) + 'configure'
sh env, configure.to_path, *configure_options, chdir: HOST_GCC
end
desc 'Make and install the bootstrap compiler'
task :make do
sh 'make', '-j', Etc.nprocessors.to_s, chdir: HOST_GCC
sh 'make', 'install', chdir: HOST_GCC
end
desc 'Run tests'
task :check do
sh 'make', 'check-elna', chdir: File.join(HOST_GCC, 'gcc')
end
end
desc 'Build the bootstrap compiler'
task gcc: %w[gcc:download gcc:link gcc:configure gcc:make]
|