메뉴 건너뛰기


Developer > Open Source

Embeded PHP PHP에서 C 확장모듈 만들기 (1)

2013.11.16 02:32

푸우 조회 수:9957

너무 오랫동안 게시판을 비워둬서 원래 제가 쓰고자 하는 글은 아니지만 이 게시판을 열어보시는 분들께서 관심있으실 것 같아서 엑스맨 피클님의 블로그에서 퍼왔습니다.

===========================================================================================
 
[여담]
PHP에서 C확장 모듈을 만드는 법을 몇달간 미뤄오다가 오늘에서야 간단하게나마 정리해 보고자 한다.
이곳 게시판에 소스코드를 HTML로 변환해서 출력하는 기능이 필요하였다.
물론 PHP소스 코드를 HTML로 변환하는 것이라면 highlight_string 이라는 훌륭한 함수를 쓰면 된다.
내가 원하는 것은 다른 언어의 소스코드를 HTML로 변환하는 기능이다.
손안데고 코푸는 격으로 다른 사람이 만든게 없나 찾던중에 PHP로 작성된 모듈을 발견하였다.
그러나 그 모듈의 수행 속도가 너무 느리고, 한글문제도 있어 C로 작성된 다른 프로그램을 찾게 되었다.
내가 갑작스럽게 찾은 몇가지 중 가장 쓰기 쉽고 빠른 수행속도를 보이는 ibformat(http://daveb.net/format/ ) 이었다.
libformat.so를 이용하여 PHP확장 모듈을 만드는참에 정리해 보았다.
첨부파일은 php 소스코드의 ext 디렉토리 아래에 풀어서 사용이 가능하다.



확장 모듈이란 PHP문법을 이용하여 만들수 없는 함수나 오브젝트를 C/C++로 직접 작성하는 것이다.

대표적으로 많이 쓰는 확장모듈은 mysql 관련 함수들이다. 

PHP를 처음 배울때에 가장 많이 쓰는 예제중 하나가 mysql 연동 예제이다.

mysql_connect, mysql_query 등은 mysql이 C프로그래머를 위해 제공하는 libmysqlclient 라이브러리를 사용하는 확장모듈이다.

이러한 함수들은 PHP문법을 이용하여 직접만들기가 까다롭거나 불가능하다.

PHP로 만들수 없는 기능이나, C로 구현된 라이브러리가 존재하지만 PHP를 이용하여 급하게 사용해야할 경우, 우리는 C확장모듈을 만들어야 하는 상황에 봉착한다.

그럼 시작해보자.

먼저 http://daveb.net/format/ 에서 libformat-1.5.tar.gz을 받아 컴파일하여 설치하자.

tar -zxvf libformat-1.5.tar.gz
cd libformat-1.5
./configure --prefix=/usr
make
make install

참고 - 소스를 아름다운 HTML로 libformat-1.5


이 작업이 완료되면 아래와 같은 라이브러리들이 만들어진다.
확장자 a는 static library이고, so는 shared object 즉 dll이라고 생각하면 된다.
so.2, so.2.3.0 등은 버전 호환을 위해서 사용하는 soname이다. 그다지 중요하지 않으니까 그냥 넘어가자.

[root@joon ext]# ls /usr/lib/libformat*
/usr/lib/libformat.a /usr/lib/libformat.so /usr/lib/libformat.so.2.3.0
/usr/lib/libformat.la /usr/lib/libformat.so.2


이제 libformat 을 사용하는 PHP확장모듈을 만들어 보자.
내가 사용한 PHP버전은 4.1.2이다. 이것은 4.1의 마지막 버전이며 내가 생각하기에 가장 안정적으로 돌아가는 버전중에 하나이다. 

PHP소스를 풀고 ext 디렉토리에 들어가자

[root@joon php-4.1.2]# cd ext/
[root@joon ext]# ls
Makefile cyrus ftp mailparse oci8 recode wddx
Makefile.in db gd mbstring odbc satellite xml
aspell dba gettext mcal openssl session xmlrpc
bcmath dbase gmp mcrypt oracle shmop xslt
bz2 dbplus hyperwave medialand ovrimos skeleton yaz
calendar dbx icap mhash pcntl snmp yp
ccvs domxml iconv ming pcre sockets zip
com dotnet imap mnogosearch pdf standard zlib
cpdf exif informix msql pfpro swf
crack ext_skel ingres_ii mssql pgsql sybase
ctype fbsql interbase muscat posix sybase_ct
curl fdf ircg mysql pspell sysvsem
cybercash filepro java ncurses qtdom sysvshm
cybermut fribidi ldap notes readline vpopmail


여기 보이는 디렉토리들이 모두 확장모듈들이다. 이중 qtdom과 dotnet을 제외한 모든 모듈들은 C로 작성되었다.
qtdom과 dotnet은 C++을 사용한 보기드문 모듈인데, 만약 C++라이브러리를 이용하여 확장모듈을 만들 경우 참고할수 있다.
C++로 PHP확장 모듈로 만드는것에 대한 내용은 다음에 정리하겠다.

ext 디렉토리에는 ext_skel이라는 쉘스크립트가 있는데, 이것은 최초에 확장모듈을 만들기 위한 뼈대를 만들어준다.
매우 유용하고 꼭 필요한 기능이 아닐수 없다. 
Python에서도 확장모듈을 만들때 이런 쉘스크립트가 있다면 정말 편할 것이다.
--extname옵션에 libformat이라는 확장모듈 이름을 주고 실행해보자.

[root@joon ext]# ./ext_skel --extname=libformat

Creating directory libformat
Creating basic files: config.m4 Makefile.in .cvsignore libformat.c php_libformat.h CREDITS EXPERIMENTAL tests/001.phpt libformat.php [done].

To use your new extension, you will have to execute the following steps:

1. $ cd ..
2. $ vi ext/libformat/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-libformat
5. $ make
6. $ ./php -f ext/libformat/libformat.php
7. $ vi ext/libformat/libformat.c
8. $ make

Repeat steps 3-6 until you are satisfied with ext/libformat/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.


이런 메시지가 나온다면 성공한 것이다. 출력된 comment대로 확장모듈을 만들어 나가면 된다.
1-6 까지 모두 따라해보자. 
아래와 같은 결과가 나온다면 성공인 것이다.

[root@joon php-4.1.2]# ./php ext/libformat/libformat.php 
X-Powered-By: PHP/4.1.2
Content-type: text/html

Functions available in the test extension:

confirm_libformat_compiled



Congratulations! You have successfully modified ext/libformat/config.m4. Module libformat is now compiled into PHP.


libformat.php는 아까 ext_skel을 실행하였을때 만들어진 테스트 코드다. 
ext_skel은 이와같이 테스트코드까지 만들어준다. 정말 편리하다.
내용을 한번 살펴보자. 



<?
// 확장모듈 libformat이 로드되어 있지 않다면 libformat.so를 동적로드한다.
if(!extension_loaded('libformat')) {
    
dl('libformat.so');
}

$module = 'libformat';
// libformat의 함수이름을 array로 가져온다.
$functions = get_extension_funcs($module);
echo
"Functions available in the test extension:<br>\n";
// 함수 리스트들을 출력.
foreach($functions as $func) {
    echo
$func."<br>\n";
}
echo
"<br>\n";

// confirm_libformat_compiled 라는 함수를 실행한다.
$function = 'confirm_' . $module . '_compiled';
if (
extension_loaded($module)) {
    
$str = $function($module);
} else {
    
$str = "Module $module is not compiled into PHP";
}
echo
"$str\n";
?>


Congratulations! You have successfully modified ext/libformat/config.m4. Module libformat is now compiled into PHP.

라는 문구가 출력되면 성공이다.

또한 한가지 더 확인할 것이 있다.

컴파일된 php화일을 이용하여 phpinfo()를찍어보라.



자 이제 아까 ext_skel을 실행했을때 나온 코멘트데로 7번과 8번 과정을 계속 반복하면서 작업을 해보자.