Oct-File에서 외부 코드 호출하기

Oct-File에서 외부 코드 호출하기 (Calling External Code from Oct-Files)

oct-file에서 외부 C 코드를 호출하는 일은 비교적 간단해요. 다만 외부 C 함수의 선언이 C 함수로 명시적으로 정의되어야 할 수 있고, Fortran 코드를 호출할 때는 name-mangling 문제를 다뤄야 하죠. Octave가 제공하는 매크로를 중심으로 Appendix A.1.9절을 정리해 볼게요.

출처: Calling External Code from Oct-Files

본문

외부 C 코드를 Octave에 연결하는 것은 비교적 간단해요. C 함수는 C++에서 직접 호출하기 쉽기 때문이죠. 한 가지 가능한 문제는 외부 C 함수의 선언이 컴파일러에 C 함수로 명시적으로 정의되어야 할 수 있다는 점이에요. 외부 C 함수의 선언이 헤더 foo.h에 있다면, C++ 컴파일러가 이 선언들을 C 코드로 취급하도록 보장하는 방법은 다음과 같아요.

#ifdef __cplusplus
extern "C"
{
#endif
#include "foo.h"
#ifdef __cplusplus
}  /* end extern "C" */
#endif

Fortran 코드 호출

Fortran 코드로 구현된 함수를 호출할 때는 몇 가지 특이점을 고려해야 해요. Fortran의 기호 이름은 대소문자를 구분하지 않고, 사용하는 Fortran 컴파일러에 따라 함수 이름이 모두 소문자 또는 모두 대문자로 내보내집니다. 게다가 일부 컴파일러는 내보낸 함수 이름의 끝에 밑줄 "_"을 0개, 1개 또는 2개 붙여요. 이것을 "name-mangling"이라고 합니다.

Octave는 여러 다른 Fortran 컴파일러에 대한 name-mangling을 자동으로 처리하는 코드를 작성할 수 있게 해 주는 매크로를 제공해요. 이 매크로는 F77_FUNCF77_FUNC_입니다. 전자는 이름에 밑줄을 포함하지 않는 Fortran 함수에 쓰고, 후자는 이름에 밑줄이 있는 Fortran 함수에 써요. 두 매크로 모두 두 인자를 받습니다. 첫 번째는 모두 소문자의 Fortran 함수 이름, 두 번째는 모두 대문자의 같은 Fortran 함수 이름이에요.

name-mangling 외에도, 다른 컴파일러들이 일부 유형에 대해 다른 호출 규약을 사용해요. Octave는 서로 다른 Fortran 호출 규약과 함께 쓸 수 있는 코드를 작성하게 해 주는 다음 전처리기 매크로를 정의합니다.

희소한 점으로, Octave는 Fortran 함수를 직접 다루려 하지 않아요. 항상 그것들을 위해 서브루틴 래퍼를 사용하고, 반환 값을 추가 인자로 전달합니다. 다음 매크로를 사용해 C에서 Fortran으로 문자 문자열을 전달하세요.

  F77_CHAR_ARG(x)
  F77_CONST_CHAR_ARG(x)
  F77_CXX_STRING_ARG(x)
  F77_CHAR_ARG_LEN(l)
  F77_CHAR_ARG_DECL
  F77_CONST_CHAR_ARG_DECL
  F77_CHAR_ARG_LEN_DECL

Fortran 스타일 문자 문자열을 받는 C 언어 함수를 작성하려면 다음 매크로를 사용하세요.

  F77_CHAR_ARG_DEF(s, len)
  F77_CONST_CHAR_ARG_DEF(s, len)
  F77_CHAR_ARG_LEN_DEF(len)
  F77_CHAR_ARG_USE(s)
  F77_CHAR_ARG_LEN_USE(s, len)

C++ 코드에서 Fortran 유형에 대해서는 다음 매크로를 사용하세요.

  • F77_INT4 — Fortran INTEGER*4 유형과 동등.
  • F77_DBLE — Fortran DOUBLE PRECISION 유형과 동등.
  • F77_REAL — Fortran REAL 유형과 동등.
  • F77_CMPLX — Fortran COMPLEX 유형과 동등.
  • F77_DBLE_CMPLX — Fortran DOUBLE COMPLEX 유형과 동등.
  • F77_LOGICAL — Fortran LOGICAL 유형과 동등.
  • F77_RET_T — Fortran 서브루틴처럼 동작하는 C++ 함수의 반환 유형.

Fortran 서브루틴처럼 동작하도록 의도된 C 언어 함수에서 반환하려면 다음 매크로를 사용하세요. F77_NORETURN"noreturn" 속성이 붙은 그런 함수의 마지막 문장으로 쓰기 위한 것입니다.

  F77_RETURN(retval)
  F77_NORETURN(retval)

기본 Fortran 코드는 Fortran STOP 함수를 대체하기 위해 XSTOPX 함수를 사용해야 해요. XSTOPX는 Octave 예외 처리기를 사용해 Fortran 코드의 실패 경우를 명시적으로 처리합니다. Octave가 자체 대체 BLAS XERBLA 함수를 제공하며, 그것은 XSTOPX를 사용한다는 점을 유의하세요.

예시

다음 예시는 oct-file에 Fortran 함수를 포함하는 방법을 보여줘요. C++ 래퍼는 다음과 같습니다.

#include <octave/oct.h>
#include <octave/f77-fcn.h>

extern "C"
{
  F77_RET_T
  F77_FUNC (fortransub, FORTRANSUB)
    (const F77_INT&, F77_DBLE*, F77_CHAR_ARG_DECL F77_CHAR_ARG_LEN_DECL);
}

DEFUN_DLD (fortrandemo, args, , "Fortran Demo")
{
  if (args.length () != 1)
    print_usage ();

  NDArray a = args(0).array_value ();

  double *av = a.rwdata ();
  octave_idx_type na = a.numel ();

  OCTAVE_LOCAL_BUFFER (char, ctmp, 128);

  F77_FUNC (fortransub, FORTRANSUB)
            (na, av, ctmp F77_CHAR_ARG_LEN (128));

  return ovl (a, std::string (ctmp));
}

그리고 Fortran 함수는 다음과 같습니다.

      subroutine fortransub (n, a, s)
      implicit none
      character*(*) s
      real*8 a(*)
      integer*4 i, n, ioerr
      do i = 1, n
        if (a(i) .eq. 0d0) then
          call xstopx ('fortransub: divide by zero')
        else
          a(i) = 1d0 / a(i)
        endif
      enddo
      write (unit = s, fmt = '(a,i3,a,a)', iostat = ioerr)
     $       'There are ', n,
     $       ' values in the input vector', char(0)
      if (ioerr .ne. 0) then
        call xstopx ('fortransub: error writing string')
      endif
      return
      end

이 예시는 배열과 문자열을 넘기고 예외 처리를 포함한, 외부 Fortran 함수에 연결하는 데 필요한 대부분의 기능을 보여줘요. 예시가 동작하려면 Fortran과 C++ 파일을 모두 컴파일해야 합니다.

mkoctfile fortrandemo.cc fortransub.f
[b, s] = fortrandemo (1:3)
⇒
  b = 1.00000   0.50000   0.33333
  s = There are   3 values in the input vector
[b, s] = fortrandemo (0:3)
error: fortrandemo: fortransub: divide by zero

더 알아보기

  • octave-external-code-interface — 외부 코드 인터페이스 개요
  • octave-character-strings-in-oct-files — oct-file에서의 문자열 다루기
  • octave-mex-files — mex-파일 인터페이스