삽질하는플머

소금과 후추를 위해 fpc 간만에 진지하게 가지고 놀기

Lazarus

잘 될지는 모르지만... 구글의 소금과 후추에서 FPC로 만든 바이너리를 한 번 링크해보고 싶다는 욕망!이 생겼다. 

기왕이면 최근에 발표된 2.6.0 을 가지고 놀아보자. 점심먹고 잠시 짬이나 우분투에 올려봄. 


ftp://freepascal.stack.nl/pub/fpc/dist/2.6.0/


여기서 i386-linux 를 다운받아 압축풀고 sudo ./install.sh 실행. /usr 에 설치. 

프리파스칼 IDE인 fp 도 함께 설치. 돌려보니 libtinfo.so.5 가 없다는 에러만 나온다. 


http://community.freepascal.org/bboards/message?message_id=682920&forum_id=24082


위 링크 참조. sudo ln -s /lib/libncurses.so.5 /usr/lib/libtinfo.so.5 실행. 

이제 제대로 돌아가네. 










소금과 후추를 위해서는 32비트와 64비트 환경이 모두 필요. 


32비트 우분투 서버에서 64비트용 FPC 크로스 빌드환경을 만들어보자. 

방법은 예전 i386-wince 크로스 빌드때와 별반 다를 바 없음. 


일단 fpcbuild-2.6.0.tar.gz 다운로드. 


# tar -xzf fpcbuild-2.6.0.tar.gz

# cd fpcbuild-2.6.0/fpcsrc

# cd compiler

# make cycle CPU_TARGET=x86_64 OS_TARGET=linux



생성된 ppcrossx64를 옮기고 심볼릭 링크


# sudo cp ppcrossx64 /usr/lib/fpc/2.6.0/

# ln -s /usr/lib/fpc/2.6.0/ppcrossx64 /usr/bin/ppcrossx64 



이제 RTL을 빌드해야 하는데... 어셈블러 x86-64_linux-as 와 링커 x86_64-linux-ld 가 필요하다. 
어디서 이 물건들을 구하지... 하고 한참을 고민했는데... gcc 에 -m64 라는 플래그가 있던 걸 기억해냄. 

다음 사이트를 참조. 
http://wiki.freepascal.org/Cross_compiling

/usr/bin 에서 어셈블러 스크립트 작업. 

# cd /usr/bin
# sudo vi x86_64-linux-as


#!/bin/bash
as --64 $@


마찬가지로 링커 스크립트도 만든다. 

# sudo vi x86_64-linux-ld

#!/bin/bash
ld -A elf_x86_64  $@


실행권한을 주고 

# sudo chmod +x x86_64-linux-ld
# sudo chmod +x x86_64-linux-as


RTL 빌드. 

# cd .... /rtl
# make CPU_TARGET=x86_64 OS_TARGET=linux PP=ppcrossx64 


생성된 라이브러리를 이동. 

# sudo mv units/x86_64-linux/ /usr/lib/fpc/2.6.0/units/x86_64-linux/rtl


test.pas 를 만들어보자. 

program test;

begin
  WriteLn('Hello World!');
end.


64비트로 컴파일. 빌드 과정을 구경하기 위해 실행파일이 아닌 어셈블러와 링크 명령이 나오게 하자. 

# ppcrossx64 -a -s -vbr test.pas


생성된 ppas.sh 를 돌려주면 실행파일 test가 생긴다. 
이 스크립트의 속을 들여다보면 앞에서 만든 어셈블러와 링커 스크립트 대신 as, ld 를 직접 호출하고 있네. 흠냐... 재미있군. 



아무래도 소금을 위해서는... 이 RTL들이 후추의 툴체인으로 재컴파일되어야 하는 것 아닌가 싶은데... 







C 에서 파스칼로 만든 코드 호출 테스트. 



먼저  SumTest() 함수를 정의한 pas_unit.pas 파일 작성


{$ifdef FPC}

  {$mode delphi}

{$endif}


unit pas_unit;


interface


function SumTest(a, b: Integer): Integer; cdecl; export;


implementation


function SumTest(a, b: Integer): Integer;

begin

  Result := a + b;

end;


end.



메인 프로그램은 C로 만든다. c_main.c 작성. 

#include <stdio.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

int SumTest(int a, int b);

#ifdef __cplusplus
}
#endif

int main() {
    int a = SumTest(3,5);

    printf("Hello world! %d \n", a);
    return 0;
}


파스칼 코드부터 컴파일. 

# fpc pas_unit.pas 


C코드 컴파일. -c 옵션을 주어 컴파일 까지만 진행한다. 

# gcc -c main.c


생성된 오브젝트 파일들을 버무려 링크. 

# gcc -o test c_main.o pas_unit.o


만들어진 실행파일 test 를 돌려보면 "Hello world! 8" 이라고 출력됨. 
파스칼에서 만든 SumTest 함수가 제대로 호출되고 있다. 이 상태 까지는 후추의 툴체인으로도 빌드 가능


단순한 함수가 아닌, 파스칼의 RTL을 호출하는 경우는 어떨까?? pas_unit.pas 를 다음과 같이 수정. 

........

function SumTest(a, b: Integer): Integer; cdecl; export;
procedure PrintTest(); cdecl; export;

implementation

........

procedure PrintTest();
begin
  WriteLn('Hello world! from Pascal!!');
end;

end.


C 코드도 다음과 같이 수정. 

..........

int SumTest(int a, int b);
void PrintTest();

int main() {

   ..........
    PrintTest();
    return 0;
}


각각 컴파일 후 링크 시도. 

# gcc -o test c_main.o pas_unit.o


파스칼 쪽에서 링크 에러가 주르륵 발생한다. 예전 아이폰 SDK 삽질의 기억을 되살려 다음과 같이 시도. 

# upath=/usr/lib/fpc/2.6.0/units/i386-linux
# ar -q ./libfpc.a `ls "$upath"/*/*.o | grep -v 'linux/fv/'`
# ranlib libfpc.c
# gcc -o test c_test.o pas_unit.o -L. -lfpc


잘 안되는군... si_*.o 에서 "_start" 함수가 중복된다고 빽빽거림. 

위에서 사용했던 a -s -vbr 옵션으로 파스칼 프로그램을 하나 컴파일. 생성된 링크 스크립트 "link.res" 를 살펴보자. 
INPUT() 섹션에 system.o 와 함께 si_prc.o 가 포함된다. 
이 링크 스크립트를 복사해 INPUT 섹션을 수정하고 si_prc.o 는 지운 뒤 링크 시도. 

.......
INPUT(
c_main.o
pas_unit.o
/usr/lib/fpc/2.6.0/units/i386-linux/rtl/system.o
)
.......


# ld -o test link.res 


이번에는 system.o  내의 함수들이 링크되지 않는군... 쩝쩝... 






2013.1.23. 추가. 


결론부터 말해... 파스칼에서 라이브러리로 정의해 출력된 오브젝트 파일은 문제없이 링크 가능하다. 


다음과 같은 파스칼 라이브러리를 만들고


testl.pas


library testl;


procedure print_test; cdecl; export;

begin

  WriteLn('Hello world from Pascal');

end;


function sum_test(a: Integer; b: Integer): Integer; cdecl; export;

begin

  sum_test := a + b;

end;


end.




fpc로 빌드하면 libtestl.so 가 나온다. 얘는 안쓸꺼니까 버리고, testl.o 파일만 잘 챙겨두자. 


C코드는 다음과 같이. 

testc.c

include <stdio.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

int sum_test(int a, int b);
void print_test();

#ifdef __cplusplus
}
#endif

int main() {
    int a = sum_test(3,5);

    printf("Hello world! sum_test(3,5) -> %d \n", a);
    print_test();
    return 0;
}



-c 옵션으로 컴파일만 되게 하고

gcc -c testc.c


앞에서 챙겨둔 testl.o, libfpc.a 와 링크. 

gcc -o test testc.o testl.o -L. -lfpc


실행시켜보면 잘 동작한다. 



글 시작은 우분투였는데 화면이 맥인건... 그 사이에 삽질용 맥이 생겼기 때문... 잇힝~

굳이 이렇게 C 기반위에 파스칼을 붙이는 키메라를 깨작거려보는건,
안드로이드에서 FPC를 가지고 놀다가 -XX, -CX가 거의 무용지물이길래 혹시나 싶어 다시 꺼내들어 본건데...
필요한 함수가 있으면 귀찮은 헤더변환따위도 필요없이 C로 만든 메인에 구현하고 바로 빨아먹는 장점도 있고...

하지만 결과물의 크기는 FPC의 최대 단점. FPC의 XCode용 iOS 템플릿은 이렇게까지 커지지 않았는데...
뭔가 쌈박한 링크옵션이 있는건가...