22
33require 'rake/clean'
44
5+ require_relative '../../lib/sass/elf'
6+
7+ ELF = Sass . const_get ( :ELF )
8+
59task default : %i[ install clean ]
610
711task install : %w[ cli.rb ] do
1115CLEAN . include %w[
1216 protoc.exe
1317 ruby
18+ true-*
1419 *.proto
1520 *.tar.gz
1621 *.zip
6570
6671task 'dart-sass' do
6772 Rake ::Task [ 'dart-sass/sass' ] . invoke
73+
74+ if SassConfig . linuxulator?
75+ begin
76+ sh 'dart-sass/sass' , File ::NULL
77+ rescue StandardError
78+ rm_rf 'dart-sass'
79+ raise NotImplementedError
80+ end
81+ end
6882rescue NotImplementedError
6983 Rake ::Task [ 'node_modules/sass' ] . invoke
7084end
7185
7286file 'cli.rb' => %w[ dart-sass ] do |t |
73- require_relative '../../lib/sass/elf'
74-
7587 begin
7688 exe = 'dart-sass/sass'
7789 exe = "#{ exe } #{ [ '' , '.bat' , '.exe' ] . find { |ext | File . exist? ( "#{ exe } #{ ext } " ) } } "
@@ -89,7 +101,7 @@ file 'cli.rb' => %w[dart-sass] do |t|
89101 end
90102
91103 interpreter = File . open ( command [ 0 ] , 'rb' ) do |file |
92- Sass . const_get ( : ELF) . new ( file ) . interpreter
104+ ELF . new ( file ) . interpreter
93105 rescue ArgumentError
94106 nil
95107 end
@@ -158,6 +170,119 @@ rule '_pb.rb' => %w[.proto protoc.exe] do |t|
158170 sh './protoc.exe' , '--proto_path=.' , '--ruby_out=.' , t . source
159171end
160172
173+ rule ( /^true-\w +$/ ) do |t |
174+ case t . name . delete_prefix ( 'true-' )
175+ when 'aarch64'
176+ ei_class = ELF ::ELFCLASS64
177+ ei_data = ELF ::ELFDATA2LSB
178+ e_machine = 0xb7
179+ e_flags = 0
180+
181+ # 0x0000000000000078: A8 0B 80 D2 mov x8, #0x5d
182+ # 0x000000000000007c: 00 00 80 D2 mov x0, #0
183+ # 0x0000000000000080: 01 00 00 D4 svc #0
184+ entry_point = [ 'a80b80d2000080d2010000d4' ] . pack ( 'H*' )
185+ when 'arm'
186+ ei_class = ELF ::ELFCLASS32
187+ ei_data = ELF ::ELFDATA2LSB
188+ e_machine = 0x28
189+ e_flags = 0x5000400
190+
191+ # 0x0000000000000054: 00 00 A0 E3 mov r0, #0
192+ # 0x0000000000000058: 01 70 A0 E3 mov r7, #1
193+ # 0x000000000000005c: 00 00 00 EF svc #0
194+ entry_point = [ '0000a0e30170a0e3000000ef' ] . pack ( 'H*' )
195+ when 'riscv64'
196+ ei_class = ELF ::ELFCLASS64
197+ ei_data = ELF ::ELFDATA2LSB
198+ e_machine = 0xf3
199+ e_flags = 0x5
200+
201+ # 0x0000000000000078: 93 08 D0 05 addi a7, x0, 93
202+ # 0x000000000000007c: 01 45 c.li a0, 0
203+ # 0x000000000000007e: 73 00 00 00 ecall
204+ entry_point = [ '9308d005014573000000' ] . pack ( 'H*' )
205+ when 'x86_64'
206+ ei_class = ELF ::ELFCLASS64
207+ ei_data = ELF ::ELFDATA2LSB
208+ e_machine = 0x3e
209+ e_flags = 0
210+
211+ # 0x0000000000000078: 31 FF xor edi, edi
212+ # 0x000000000000007a: B8 3C 00 00 00 mov eax, 0x3c
213+ # 0x000000000000007f: 0F 05 syscall
214+ entry_point = [ '31ffb83c0000000f05' ] . pack ( 'H*' )
215+ when 'i386'
216+ ei_class = ELF ::ELFCLASS32
217+ ei_data = ELF ::ELFDATA2LSB
218+ e_machine = 0x03
219+ e_flags = 0
220+
221+ # 0x0000000000000054: 31 DB xor ebx, ebx
222+ # 0x0000000000000056: B8 01 00 00 00 mov eax, 1
223+ # 0x000000000000005b: CD 80 int 0x80
224+ entry_point = [ '31dbb801000000cd80' ] . pack ( 'H*' )
225+ else
226+ raise NotImplementedError
227+ end
228+
229+ File . open ( t . name , 'wb' , 0o755 ) do |file |
230+ ELF . allocate . instance_eval do
231+ case ei_class
232+ when ELF ::ELFCLASS32
233+ e_ehsize = ELF ::Elf32_Ehdr . sizeof
234+ e_phentsize = ELF ::Elf32_Phdr . sizeof
235+ e_shentsize = ELF ::Elf32_Shdr . sizeof
236+ when ELF ::ELFCLASS64
237+ e_ehsize = ELF ::Elf64_Ehdr . sizeof
238+ e_phentsize = ELF ::Elf64_Phdr . sizeof
239+ e_shentsize = ELF ::Elf64_Shdr . sizeof
240+ else
241+ raise EncodingError
242+ end
243+ e_phoff = e_ehsize
244+ p_offset = e_phoff + e_phentsize
245+ e_entry = ( 2 **22 ) + p_offset
246+ p_vaddr = e_entry
247+ p_filesz = entry_point . length
248+ p_memsz = p_filesz
249+
250+ @ehdr = {
251+ e_ident : [ 127 , 69 , 76 , 70 , ei_class , ei_data , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
252+ e_type : ELF ::ET_EXEC ,
253+ e_machine :,
254+ e_version : 1 ,
255+ e_entry :,
256+ e_phoff :,
257+ e_shoff : 0 ,
258+ e_flags :,
259+ e_ehsize :,
260+ e_phentsize :,
261+ e_phnum : 1 ,
262+ e_shentsize :,
263+ e_shnum : 0 ,
264+ e_shstrndx : 0
265+ }
266+ @phdrs = [
267+ {
268+ p_type : ELF ::PT_LOAD ,
269+ p_flags : ELF ::PF_R | ELF ::PF_X ,
270+ p_offset :,
271+ p_vaddr :,
272+ p_paddr : 0 ,
273+ p_filesz :,
274+ p_memsz :,
275+ p_align : 4096
276+ }
277+ ]
278+ @shdrs = [ ]
279+
280+ dump ( file )
281+ end
282+ file . write ( entry_point )
283+ end
284+ end
285+
161286# This is a FileUtils extension that defines several additional commands to be
162287# added to the FileUtils utility functions.
163288module FileUtils
305430# The {SassConfig} module.
306431module SassConfig
307432 module Platform
308- OS = case RbConfig ::CONFIG [ 'host_os' ] . downcase
309- when /darwin/
310- 'darwin'
311- when /linux-android/
312- 'linux-android'
313- when /linux-musl/
314- 'linux-musl'
315- when /linux-uclibc/
316- 'linux-uclibc'
317- when /linux/
318- 'linux'
319- when *Gem ::WIN_PATTERNS
320- 'windows'
321- else
322- RbConfig ::CONFIG [ 'host_os' ] . downcase
323- end
324-
325433 CPU = case RbConfig ::CONFIG [ 'host_cpu' ] . downcase
326434 when /amd64|x86_64|x64/
327435 'x86_64'
@@ -337,13 +445,97 @@ module SassConfig
337445 RbConfig ::CONFIG [ 'host_cpu' ]
338446 end
339447
448+ LINUXULATOR = begin
449+ raise NotImplementedError unless RbConfig ::CONFIG [ 'host_os' ] . include? ( 'freebsd' )
450+
451+ Rake ::Task [ "true-#{ CPU } " ] . invoke
452+
453+ raise NotImplementedError unless system ( "./true-#{ CPU } " )
454+
455+ begin
456+ require 'fiddle'
457+
458+ lib = Fiddle . dlopen ( nil )
459+ sysctlbyname = Fiddle ::Function . new (
460+ lib [ 'sysctlbyname' ] ,
461+ [ Fiddle ::TYPE_VOIDP , Fiddle ::TYPE_VOIDP , Fiddle ::TYPE_VOIDP , Fiddle ::TYPE_VOIDP , Fiddle ::TYPE_SIZE_T ] ,
462+ Fiddle ::TYPE_INT
463+ )
464+
465+ name = Fiddle ::Pointer . to_ptr ( 'compat.linux.emul_path' )
466+ oldp = Fiddle ::NULL
467+ oldlenp = Fiddle ::Pointer . malloc ( Fiddle ::SIZEOF_SIZE_T , Fiddle ::RUBY_FREE )
468+ newp = Fiddle ::NULL
469+ newlen = 0
470+ raise SystemCallError . new ( nil , Fiddle . last_error ) if sysctlbyname . call ( name , oldp , oldlenp , newp , newlen ) == -1
471+
472+ oldp = Fiddle ::Pointer . malloc ( oldlenp . ptr . to_i , Fiddle ::RUBY_FREE )
473+ raise SystemCallError . new ( nil , Fiddle . last_error ) if sysctlbyname . call ( name , oldp , oldlenp , newp , newlen ) == -1
474+
475+ path = oldp . to_s
476+ rescue SystemCallError
477+ raise NotImplementedError
478+ end
479+
480+ RbConfig ::CONFIG [ 'host_os' ] = case
481+ when ( CPU == 'aarch64' &&
482+ File . exist? ( File . absolute_path ( 'lib/ld-linux-aarch64.so.1' , path ) ) ) ||
483+ ( CPU == 'arm' &&
484+ File . exist? ( File . absolute_path ( 'lib/ld-linux-armhf.so.3' , path ) ) ) ||
485+ ( CPU == 'riscv64' &&
486+ File . exist? ( File . absolute_path ( 'lib/ld-linux-riscv64-lp64d.so.1' , path ) ) ) ||
487+ ( CPU == 'x86_64' &&
488+ File . exist? ( File . absolute_path ( 'lib64/ld-linux-x86-64.so.2' , path ) ) ) ||
489+ ( CPU == 'i386' &&
490+ File . exist? ( File . absolute_path ( 'lib/ld-linux.so.2' , path ) ) )
491+ 'linux-gnu'
492+ when ( ( CPU == 'aarch64' || CPU == 'riscv64' || CPU == 'x86_64' || CPU == 'i386' ) &&
493+ File . exist? ( File . absolute_path ( "lib/ld-musl-#{ CPU } .so.1" , path ) ) ) ||
494+ ( CPU == 'arm' &&
495+ File . exist? ( File . absolute_path ( 'lib/ld-musl-armhf.so.1' , path ) ) )
496+ 'linux-musl'
497+ when ( ( CPU == 'aarch64' || CPU == 'riscv64' || CPU == 'x86_64' ) &&
498+ File . exist? ( File . absolute_path ( 'system/bin/linker64' , path ) ) ) ||
499+ ( ( CPU == 'arm' || CPU == 'i386' ) &&
500+ File . exist? ( File . absolute_path ( 'system/bin/linker' , path ) ) )
501+ 'linux-android'
502+ else
503+ 'linux-none'
504+ end
505+
506+ true
507+ rescue NotImplementedError
508+ false
509+ end
510+
511+ OS = case RbConfig ::CONFIG [ 'host_os' ] . downcase
512+ when /darwin/
513+ 'darwin'
514+ when /linux-android/
515+ 'linux-android'
516+ when /linux-musl/
517+ 'linux-musl'
518+ when /linux-none/
519+ 'linux-none'
520+ when /linux/
521+ 'linux'
522+ when *Gem ::WIN_PATTERNS
523+ 'windows'
524+ else
525+ RbConfig ::CONFIG [ 'host_os' ] . downcase
526+ end
527+
340528 ARCH = "#{ CPU } -#{ OS } " . freeze
341529 end
342530
343531 private_constant :Platform
344532
345533 module_function
346534
535+ def linuxulator?
536+ Platform ::LINUXULATOR
537+ end
538+
347539 def package_json ( path = '.' )
348540 require 'json'
349541
@@ -415,7 +607,7 @@ module SassConfig
415607 os = case Platform ::OS
416608 when 'darwin'
417609 'osx'
418- when 'linux' , 'linux-android' , 'linux-musl' , 'linux-uclibc '
610+ when 'linux' , 'linux-android' , 'linux-musl' , 'linux-none '
419611 'linux'
420612 when 'windows'
421613 'windows'
0 commit comments