2017-10-04 2 views
3

저는 XS 초보자이며 웹에서이 답변을 찾기 위해 시간을 보냈습니다. 문제는 XS가 함수의 이름을 변경하고 컴파일 할 때 정의되지 않은 참조 오류가 발생한다는 것입니다. 예를 들어 아래의 XS 코드 고려해perl xs module writing - 같은 xs 파일에서 다른 함수를 사용하십시오.

size_t 
matrixIndex (colIndex, rowIndex,nCols,nRows) 
     size_t colIndex 
     size_t rowIndex 
     size_t nCols 
     size_t nRows 
    CODE: 
    size_t register i; 
    RETVAL = (rowIndex * nCols) + colIndex; 
    OUTPUT: 
     RETVAL 

은 그때 그때 make을 실행이

int 
matrixCopyColumnVector_dbl (colIndex,fromMatrix,nColsMatrix,nRowsMatrix,intoVector,nRowsVector) 
     size_t colIndex 
     SV * fromMatrix 
     size_t nColsMatrix 
     size_t nRowsMatrix 
     SV * intoVector 
     size_t nRowsVector 
    CODE: 
     size_t register x, n; 
     if(nRowsVector != nRowsMatrix) { RETVAL = 0; return RETVAL; } 
     n = 0; 
     for(x=0; x<= nRowsMatrix; x++) { 
     intoVector[n] = fromMatrix[matrixIndex /*USE OF FUNCTION HERE!!*/(colIndex,x,nColsMatrix,nRowsMatrix)]; 
     n++; 
     } 
     RETVAL = 1; 
     return RETVAL; 
    OUTPUT: 
     RETVAL 

처럼 다음과 같은 기능이 사용하려고하고 그것을 컴파일 과정을 통해 이동하고 오류가 발생합니다 연결 단계 인 것으로 보이는 부분은 undefined reference to 'matrixIndex'입니다.

그래서 같은 XS 파일 내에서 함수를 호출하는 표준 XS 방식이 궁금합니다.

+1

XS 함수 (파일의 앞부분에있는 C 함수와 반대)를 호출하려면 Perl 하위 함수로 호출해야합니다. XS 함수로 만들지 말고 C 함수로 만듭니다. – ikegami

답변

5

XS 코드는 Perl subs를 만듭니다. 그래서 XS 함수를 호출하는 것은 calling 다른 Perl 서브와 동일합니다.

복잡성과 비효율을 처리하는 대신 Perl 하위 대신 C 함수를 만듭니다. (당신은 독립적으로 당신이 원하는 경우 XS를 사용하여 해당 C 함수를 노출 할 수 있습니다.)

#define PERL_NO_GET_CONTEXT 
#include "EXTERN.h" 
#include "perl.h" 
#include "XSUB.h" 

static UV matrixIndex(UV colIndex, UV rowIndex, UV nCols, UV nRows) { 
    return (rowIndex * nCols) + colIndex; 
} 

MODULE = Foo::Bar PACKAGE = Foo::Bar 

int 
matrixCopyColumnVector_dbl(colIndex, fromMatrix, nColsMatrix, nRowsMatrix, intoVector, nRowsVector) 
    UV colIndex 
    SV * fromMatrix 
    UV nColsMatrix 
    UV nRowsMatrix 
    SV * intoVector 
    UV nRowsVector 
PREINIT: 
    UV register x, n; 
CODE: 
    if (nRowsVector == nRowsMatrix) { 
     RETVAL = 0; 
    } else { 
     n = 0; 
     for (x=0; x<=nRowsMatrix; x++) { 
      intoVector[n] = fromMatrix[matrixIndex(colIndex, x, nColsMatrix, nRowsMatrix)]; 
      n++; 
     } 
     RETVAL = 1; 
    } 
OUTPUT: 
    RETVAL 

return의 사용이 잘못되었습니다. 조기에 반환하려면 XSRETURN* 매크로 중 하나를 사용하십시오.

fromMatrix[...]intoVector[...]은 완전히 잘못되었습니다. fromMatrixintoVector은 C 배열입니다. (그들은 Perl 배열이 아니고 관련성이 없습니다.)

Perl 정수는 size_t 일 필요는없고 IV (또는 UV의 부호 없음)입니다. 최상의 호환성을 위해 사용하십시오.

이식성을 원한다면 C99를 사용할 수 없으므로 선언과 코드를 함께 사용할 수 없습니다. 선언문을 PREINIT에 넣거나 (변수 선언을위한 새로운 범위를 만들기 위해 curlies를 CODE에 사용하십시오).

+0

나는 본다. 그냥 컴파일하고 링크해야합니다. 유용한 정보도 있습니다. 감사! –

+0

'fromMatrix [...]'와'intoVector [...]'는 컴파일 및 링크되지만 작동하지는 않습니다. 여전히 문제를 해결해야합니다. 그리고 방금 업데이트를했습니다. – ikegami

+0

그래, Perl 배열에서 C 배열로 변환하고 다른 방향으로 변환하는 문서는 웹에서 찾고있다. 이 과정에서 좋은 링크가 있습니까? 다른 stackoverflow Q & A로 리디렉션하면 도움이 될 것입니다. –

2

XSUB는 C 함수가 아닙니다. XS 선행 처리기는 선언문에서 C 함수를 작성하지만, 부호는 void (CV*)입니다. 그런 다음 XSUB는 Perl 인수 스택에서 인수를 취하여 형식 맵을 사용하여 C 값으로 변환합니다. 따라서 XSUB를 직접 호출 할 수는 없습니다.

대신 XSUB를 다른 Perl 함수처럼 호출해야합니다. 즉, 인수를 SV*으로 스택에 푸시해야합니다. 자세한 내용은 perldoc perlcall을 참조하십시오. 분명히 이것은 지루하고 비효율적입니다.

더 나은 해결책은 Perl과 XS에서 사용하려는 모든 함수를 XS 파일의 static C 함수로 선언 한 다음 XS 글루 코드를 작성하여 Perl에 표시하는 것입니다. 여기에이 기능은 펄 API의 일부를 사용하는 경우, 당신은 또한 pTHXaTHX 매크로를 사용하도록

static size_t matrixIndex(size_t colIndex, size_t rowIndex, size_t nCols, size_t nRows) 
{ 
    size_t register i; // unneeded 
    return (rowIndex * nCols) + colIndex; 
} 

참고.

static size_t matrixIndex(pTHX_ size_t colIndex, etc...) ... 

및 C에서 호출 할 때 matrixIndex(aTHX_ colIndex, etc...)을 써서으로 선언 변경됩니다.

+1

예, 알아 냈습니다. 분명히 앞서 필요한 C 함수를 선언 한 다음 XS를 접착제로 사용하는 것이 좋습니다. 너무 깔끔한 방법. 배열을 앞뒤로 마샬링하는 데 문제가 있습니다. –

+1

@annoying_squid 그건 또 다른 질문입니다. – amon

관련 문제