Fiddle 모듈
Fiddle 모듈 (Fiddle)
Fiddle은 Ruby를 위한 libffi 래퍼예요. 외부 함수 인터페이스(FFI)를 Ruby로 번역해 주는 확장이죠.
Fiddle은 널리 쓰이는 C 라이브러리인 libffi를 감싸요. libffi는 한 언어로 작성된 코드가 다른 언어로 작성된 코드를 호출할 수 있게 해주는 이식 가능한 인터페이스를 제공해요.
여기서는 Fiddle::Function으로 libm의 floor(3)를 감싸는 예시를 볼게요.
require 'fiddle'
libm = Fiddle.dlopen('/lib/libm.so.6')
floor = Fiddle::Function.new(
libm['floor'],
[Fiddle::TYPE_DOUBLE],
Fiddle::TYPE_DOUBLE
)
puts floor.call(3.14159) #=> 3.0
출처: Ruby 3.3 API
본문
상수 (Constants)
Fiddle에는 타입 크기·정렬·동적 라이브러리 조작에 쓰이는 상수들이 있어요.
- 정렬 크기(alignment) 상수:
ALIGN_BOOL,ALIGN_CHAR,ALIGN_DOUBLE,ALIGN_FLOAT,ALIGN_INT,ALIGN_INT16_T,ALIGN_INT32_T,ALIGN_INT64_T,ALIGN_INT8_T,ALIGN_INTPTR_T,ALIGN_LONG,ALIGN_LONG_LONG,ALIGN_PTRDIFF_T,ALIGN_SHORT,ALIGN_SIZE_T,ALIGN_SSIZE_T,ALIGN_UINTPTR_T,ALIGN_VOIDP— 각 C 타입의 정렬 크기 - 크기(size) 상수:
SIZEOF_BOOL,SIZEOF_CHAR,SIZEOF_CONST_STRING,SIZEOF_DOUBLE,SIZEOF_FLOAT,SIZEOF_INT,SIZEOF_INT16_T,SIZEOF_INT32_T,SIZEOF_INT64_T,SIZEOF_INT8_T,SIZEOF_INTPTR_T,SIZEOF_LONG,SIZEOF_LONG_LONG,SIZEOF_PTRDIFF_T,SIZEOF_SHORT,SIZEOF_SIZE_T,SIZEOF_SSIZE_T,SIZEOF_UCHAR,SIZEOF_UINT,SIZEOF_UINT16_T,SIZEOF_UINT32_T,SIZEOF_UINT64_T,SIZEOF_UINT8_T,SIZEOF_UINTPTR_T,SIZEOF_ULONG,SIZEOF_ULONG_LONG,SIZEOF_USHORT,SIZEOF_VOIDP— 각 C 타입의 크기(바이트) BUILD_RUBY_PLATFORM— 빌드된 플랫폼(예:"x86_64-linux").RUBY_PLATFORM참고.Qfalse,Qnil,Qtrue,Qundef— Ruby 내부Q상수 값RUBY_FREE—ruby_xfree()함수의 주소VERSION— 모듈 버전WINDOWS— 호스트가 WIN32인지 여부를 나타내는 불리언
::dlopen (Public Class Method)
dlopen(library) → Fiddle::Handle — library를 여는 새 핸들러를 만들고 Fiddle::Handle 인스턴스를 돌려줘요. library에 nil을 주면 RTLD_DEFAULT에 해당하는 Fiddle::Handle::DEFAULT를 사용해요(man 3 dlopen 참고).
lib = Fiddle.dlopen(nil)
기본값은 OS에 따라 달라지며, 이미 로드된 모든 라이브러리에 대한 핸들을 제공해요. 대부분의 경우 libc 함수나 rb_str_new 같은 ruby 함수에 접근하는 데 쓸 수 있어요. Fiddle::Handle.new 참고.
# File ext/fiddle/lib/fiddle.rb, line 60
def dlopen library
begin
Fiddle::Handle.new(library)
rescue DLError => error
case RUBY_PLATFORM
when /linux/
case error.message
when /\A(\/.+?): (?:invalid ELF header|file too short)/
# This may be a linker script:
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
else
raise
end
File.open(path) do |input|
input.each_line do |line|
case line
when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
# TODO: Should we support multiple files?
return dlopen($1)
end
end
end
# Not found
raise
end
end
::dlunwrap
dlunwrap(addr) — 메모리 주소 addr에 저장된 Ruby 객체를 돌려줘요. (dlwrap의 역)
x = Object.new
Fiddle.dlwrap(x)
# => 4425504880
Fiddle.dlunwrap(_)
# => #<Object:0x...>
::dlwrap
dlwrap(val) — val에 저장된 Ruby 객체의 메모리 주소를 돌려줘요.
x = Object.new
Fiddle.dlwrap(x)
# => 4425504880
val이 힙 할당 객체가 아닌 경우에는 태깅된 포인터 값을 돌려줘요.
Fiddle.dlwrap(123)
# => 247
::free
free(addr) — 주소 addr의 메모리를 해제해요.
::last_error
last_error() — 현재 실행 중인 스레드의 마지막 에러를 돌려줘요. 없으면 nil.
# File ext/fiddle/lib/fiddle.rb, line 35
def self.last_error
Thread.current[:__FIDDLE_LAST_ERROR__]
end
::last_error=
last_error=(error) — 현재 실행 중인 스레드의 마지막 에러를 error로 설정해요.
# File ext/fiddle/lib/fiddle.rb, line 40
def self.last_error= error
Thread.current[:__DL2_LAST_ERROR__] = error
Thread.current[:__FIDDLE_LAST_ERROR__] = error
end
::malloc
malloc(size) — size 바이트의 메모리를 할당하고, 할당된 메모리의 정수 주소를 돌려줘요.
::realloc
realloc(addr, size) — 메모리 주소 addr에 할당된 메모리의 크기를 size 바이트로 바꿔요. 재할당된 메모리의 주소를 돌려주는데, 전달한 주소와 다를 수 있어요.
::win32_last_error
win32_last_error() — 현재 실행 중인 스레드의 마지막 win32 에러를 돌려줘요. 없으면 nil.
::win32_last_error=
win32_last_error=(error) — 현재 스레드의 마지막 win32 에러를 error로 설정해요.
::win32_last_socket_error
win32_last_socket_error() — 현재 실행 중인 스레드의 마지막 win32 소켓 에러를 돌려줘요. 없으면 nil.
::win32_last_socket_error=
win32_last_socket_error=(error) — 현재 스레드의 마지막 win32 소켓 에러를 error로 설정해요.