1project('mstrap',
2 'c',
3 meson_version : '>= 0.62.0',
4 license : 'MIT',
5 version : '0.7.2',
6 default_options : [
7 'buildtype=debugoptimized',
8 'default_library=static'
9 ]
10)
11
12cc = meson.get_compiler('c')
13target_arch = host_machine.cpu_family()
14target_system = host_machine.system()
15target_triple = target_arch + '-unknown-' + target_system
16
17buildtype = get_option('buildtype')
18is_darwin = target_system == 'darwin'
19is_static = get_option('default_library') == 'static'
20is_static_libc = false
21needs_macos_classic_linker = false
22
23if target_system == 'linux'
24 target_cabi = meson.get_external_property('target_triple_suffix', 'gnu')
25
26 target_triple += '-' + target_cabi
27
28 if target_cabi == 'musl' and is_static
29 is_static_libc = true
30 add_global_link_arguments('-static', language : 'c')
31 endif
32elif target_system == 'darwin'
33 macos_abi = meson.get_external_property('macos_version', '12')
34 macos_arch = target_arch == 'aarch64' ? 'arm64' : target_arch
35
36 target_triple = macos_arch + '-apple-macos' + macos_abi
37 add_global_arguments('-target', target_triple, language : 'c', native : false)
38 add_global_link_arguments('-target', target_triple, language : 'c', native : false)
39
40 # Use legacy linker with xcode 15+
41 xcode_version_output = run_command(find_program('xcodebuild'), '-version', check : true).stdout()
42 xcode_version = xcode_version_output.split('\n').get(0, '').replace('Xcode', '').strip()
43
44 if xcode_version.version_compare('>=15.0') and cc.has_link_argument('-Wl,-ld_classic')
45 needs_macos_classic_linker = true
46 add_global_link_arguments('-Wl,-ld_classic', language : 'c')
47 endif
48endif
49
50crystal = find_program(get_option('crystal'), version : '>= 1.8.0', required : true)
51shards = find_program(get_option('shards'), required : true)
52
53# Basics
54libiconv_dep = dependency('iconv', static : is_static and not is_darwin)
55libm_dep = cc.find_library('m', required : false, static : is_static)
56libpcre2_dep = dependency('libpcre2-8', static : is_static)
57thread_dep = dependency('threads', static : is_static)
58zlib_dep = dependency('zlib', static : is_static and not is_darwin)
59
60# OpenSSL/LibreSSL (for fetching profiles & strap.sh over HTTPS)
61libcrypto_dep = dependency('libcrypto', version : '>= 1.1.1', static : is_static)
62libssl_dep = dependency('libssl', version : '>= 1.1.1', static : is_static)
63
64embedded_openssl = libcrypto_dep.type_name() != 'pkgconfig'
65
66if embedded_openssl
67 pkg = import('pkgconfig')
68 pkg.generate(
69 name : 'libcrypto',
70 description: 'OpenSSL-libcrypto',
71 version : libcrypto_dep.version(),
72 libraries : [libcrypto_dep]
73 )
74 pkg.generate(
75 name : 'libssl',
76 description: 'OpenSSL-libssl',
77 version : libssl_dep.version(),
78 libraries : [libssl_dep]
79 )
80endif
81
82# Libevent (required for Crystal runtime < 1.15.0 or platforms not supported by
83# lifetime event loop in Crystal 1.15.0+)
84crystal_requires_libevent = crystal.version().version_compare('< 1.15.0') or \
85 (target_system != 'linux' and target_system != 'darwin' and target_system != 'freebsd')
86
87libevent_dep = dependency(
88 'libevent',
89 version : '>= 2.1.2',
90 static : is_static,
91 required : false,
92)
93if not libevent_dep.found() and crystal_requires_libevent
94 cmake = import('cmake')
95 libevent_options = cmake.subproject_options()
96 libevent_options.add_cmake_defines({
97 'EVENT__LIBRARY_TYPE': 'STATIC',
98 'BUILD_SHARED_LIBS': false,
99 'BUILD_SHARED_AND_STATIC_LIBS': false,
100 'CMAKE_C_FLAGS': '-fPIC',
101 'EVENT__DISABLE_OPENSSL': true,
102 'EVENT__DISABLE_BENCHMARK': true,
103 'EVENT__DISABLE_TESTS': true,
104 'EVENT__DISABLE_REGRESS': true,
105 'EVENT__DISABLE_SAMPLES': true,
106 })
107 libevent_options.set_override_option('werror', 'false')
108 libevent_options.set_override_option('warning_level', '0')
109 libevent_proj = cmake.subproject('libevent', options: libevent_options)
110 libevent_dep = libevent_proj.dependency('event_core_static')
111endif
112
113# libgc (required for Crystal runtime)
114libgc_dep = dependency(
115 'bdw-gc',
116 version : '>= 8.0.4',
117 static : is_static,
118 required : false
119)
120if not libgc_dep.found()
121 cmake = import('cmake')
122 libgc_options = cmake.subproject_options()
123 libgc_options.add_cmake_defines({
124 'BUILD_SHARED_LIBS': false,
125 'enable_docs': false,
126 'enable_large_config': true,
127 'disable_gc_debug': true,
128 'CMAKE_C_FLAGS': '-fPIC',
129 })
130 libgc_options.set_override_option('werror', 'false')
131 libgc_options.set_override_option('warning_level', '0')
132 libgc_proj = cmake.subproject('bdwgc', options: libgc_options)
133 libgc_dep = libgc_proj.dependency('gc')
134endif
135
136if run_command(shards, 'check', check : false).returncode() != 0
137 run_command(shards, 'install', '--frozen', check : true)
138endif
139
140crystal_path = run_command(
141 crystal, 'env', 'CRYSTAL_PATH',
142 check : true
143).stdout().strip()
144env = environment({
145 'CRYSTAL_PATH': crystal_path,
146})
147env.prepend('CRYSTAL_PATH', join_paths(meson.project_source_root(), 'lib'))
148
149if embedded_openssl
150 env.set('PKG_CONFIG_PATH', join_paths(meson.project_build_root(), 'meson-uninstalled'))
151endif
152
153crystal_build_flags = [
154 '--error-trace',
155 '--cross-compile',
156 '--target',
157 target_triple,
158]
159
160if buildtype.contains('debug')
161 crystal_build_flags += ['--debug', '--error-trace']
162else
163 crystal_build_flags += ['--no-debug']
164endif
165
166if buildtype in ['release', 'debugoptimized']
167 crystal_build_flags += ['--release']
168endif
169
170if is_static_libc
171 crystal_build_flags += ['--static']
172endif
173
174if needs_macos_classic_linker
175 crystal_build_flags += ['--link-flags=-Wl,-ld_classic']
176endif
177
178mstrap_build_cmd = [crystal, 'build'] + crystal_build_flags + ['-o', 'mstrap', '@INPUT@']
179
180mstrap_o = custom_target(
181 'mstrap.o',
182 build_always_stale : true,
183 command : mstrap_build_cmd,
184 depend_files : [files('shard.lock')],
185 env : env,
186 input : [files('src/cli.cr')],
187 output : ['mstrap.o']
188)
189
190executable(
191 'mstrap',
192 mstrap_o,
193 dependencies : [
194 libcrypto_dep,
195 libevent_dep,
196 libgc_dep,
197 libiconv_dep,
198 libm_dep,
199 libpcre2_dep,
200 libssl_dep,
201 zlib_dep,
202 thread_dep
203 ],
204 install : true
205)