Foreign Function Interface(FFI)

임효진·2024년 4월 1일
1

Flutter

목록 보기
13/22

Foreign Function Interface(FFI)는 한 프로그래밍 언어에서 다른 프로그래밍 언어로 작성된 함수나 서비스를 호출할 수 있게 해주는 매커니즘이다.
FFI를 사용하면 예를 들어, 고성능이 필요한 애플리케이션의 특정 부분을 C 언어로 작성한 후, Python이나 JavaScript, Dart와 같은 다른 언어로 작성된 프로그램 내에서 이를 호출하여 사용할 수 있다. 이는 다양한 언어의 장점을 결합하고, 기존 코드를 재사용하여 개발 시간을 단축하며, 성능을 최적화할 수 있는 방법을 제공한다.

FFI의 주요 사용 사례

성능 최적화:
고수준 언어로 작성된 애플리케이션이 특정 작업에서 더 빠른 실행 속도를 필요로 할 때, 그 부분을 C 같은 저수준 언어로 작성하여 성능을 향상시킬 수 있다.

기존 라이브러리 활용:
다른 언어로 작성된 기존 라이브러리나 시스템 함수를 현재 개발 중인 프로그램에서 사용하고 싶을 때, FFI를 통해 이를 호출할 수 있다.

플랫폼 특정 기능 사용:
특정 운영 체제의 API나 하드웨어 관련 기능을 사용해야 할 때, 그 플랫폼에 특화된 언어나 인터페이스를 통해 접근할 수 있다.

FFI의 작동 방식
FFI를 사용하려면, 대상 언어에서 외부 함수를 호출하기 위한 선언이 필요하다.
이는 일반적으로 다음 단계를 포함한다:

함수 시그니처 선언:
호출하려는 외부 함수의 시그니처(반환 타입, 매개변수 타입 등)를 선언한다.
라이브러리 링크:
외부 함수가 포함된 라이브러리나 실행 파일을 프로그램에 링크한다.
함수 호출:
선언한 시그니처에 따라 함수를 호출하고, 필요한 경우 매개변수를 전달한다.

FFI의 도전 과제

타입 호환성:
다른 언어 간에 타입 시스템이 다를 수 있어, 데이터 타입을 올바르게 매핑하는 것이 중요합하다.
메모리 관리:
FFI를 통해 사용하는 메모리는 호출하는 언어의 가비지 컬렉터에 의해 자동으로 관리되지 않을 수 있어, 메모리 누수를 방지하기 위한 주의가 필요하다.
오류 처리:
외부 함수 호출로 인한 오류를 적절히 처리하고, 언어 간의 예외 메커니즘 차이를 극복해야 할 수 있다.
FFI는 프로그래밍 언어와 플랫폼 간의 경계를 넘어 코드를 재사용하고, 애플리케이션의 성능과 기능성을 향상시키는 데 매우 유용한 도구다.

다음은 Flutter에서 FFI를 사용하여 간단한 C 함수를 호출하는 예제다.

#include <stdint.h>

// 두 정수를 더하는 간단한 함수
int32_t native_add(int32_t x, int32_t y) {
    return x + y;
}

그런 다음, 이 C 파일을 동적 라이브러리로 컴파일한다.
컴파일 방법은 운영 체제에 따라 다르다.
예를 들어, Linux나 macOS에서는 다음과 같이 gcc를 사용할 수 있다.

gcc -shared -o libnative_add.so native_add.c

단계 2: Dart에서 FFI를 사용하여 C 함수 호출
먼저, Flutter 프로젝트에 ffi 패키지를 추가해야 한다.
pubspec.yaml 파일에 다음 의존성을 추가한다.

dependencies:
  ffi: ^1.0.0

그런 다음, Dart 코드에서 FFI를 사용하여 C 함수를 호출할 수 있다.
다음은 native_add 함수를 호출하는 Dart 코드의 예시다.

import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;

// C 함수의 시그니처를 정의한다.
typedef NativeAdd = ffi.Int32 Function(ffi.Int32 x, ffi.Int32 y);
typedef NativeAddDart = int Function(int x, int y);

void main() {
  // 동적 라이브러리를 로드.
  var path = 'libnative_add.so';
  if (Platform.isWindows) {
    path = 'native_add.dll';
  } else if (Platform.isMacOS) {
    path = 'libnative_add.dylib';
  }
  final dylib = ffi.DynamicLibrary.open(path);

  // C 함수를 Dart 함수로 매핑.
  final NativeAddDart nativeAdd = dylib
      .lookup<ffi.NativeFunction<NativeAdd>>('native_add')
      .asFunction();

  // C 함수를 호출.
  final result = nativeAdd(2, 3);
  print('2 + 3 = $result');
}

위의 예에서는 DynamicLibrary.open을 사용하여 컴파일된 C 라이브러리를 로드하고,
lookup 메서드를 사용하여 C 함수를 Dart 함수로 매핑한다.
그런 다음, 매핑된 Dart 함수를 호출하여 C 함수의 결과를 얻는다.

FFI를 사용할 때는 컴파일된 라이브러리 파일(.so, .dll, .dylib)의 위치와 이름이 올바르게 지정되어 있는지 확인해야 한다.
또한, 사용하는 플랫폼에 따라 라이브러리 파일의 형식이 달라질 수 있으므로
주의해야 한다.

profile
핫바리임

0개의 댓글