자우르스 기반의 프로그램을 개발할 수 있도록 개발환경을 구축하는 방법을 기술하고 있다.
필자가 그동안 자우르스에서 사용하는 QT 기반의 개발환경을 구축하기 위해 여러가지 방법들을 사용해봤지만, 그 중에서 가장 간단한 방법을 설명할 것이다.
준비 운동하기
참고로 여기서는 윈도우 기반에서의 개발환경에 대해서 설명한다. 아무래도 가장 좋은 환경은 같은 리눅스 기반이겠지만, 현재 필자가 주로 작업하는 환경이 윈도우이다보니, 어쩔 수가 없다 -_-;
내가 참고한 곳은 http://kopsisengineering.com/kopsis/SharpZaurusSdkDsl#live-cd 이다.
본격적으로 설명하기 전에 개발환경 구축에 필요한 파일들을 알아보자!!
이름 | 파일명 | 주소 | 설명 |
QEMU | qemu-0.8.0-windows-2.zip | http://www.h7.dion.ne.jp/~qemu-win/ | 흔히 VMware 와 비슷하게 가상으로 윈도에서 리눅스를 돌려주는 프로그램이다 |
Filesystem | sharp_zsdk_dsl_disk.zip | http://prdownloads.sourceforge.net/pyqplayer/sharp_zsdk_dsl_disk.zip?download | 개발환경을 통째로 파일시스템으로 만들었다 |
준비가 되었으면 본격적으로 시작해보자!!
개발환경 구축하기
필자가 앞에서도 말했듯이 가장 간단한 방법이라고 했다. QEMU 라는 에뮬레이팅 프로그램을 앞에서 받은 Filesystem 을 마운트 해서 부팅시키면 끝난다.
QEMU 는 따로 설치가 필요없다. 그냥 압축을 풀면 그것으로 끝이다.
여기서는 D:\download 라는 디렉토리로 하겠다. 여기에 앞에서 받은 QEMU 파일의 압축을 푼다. 이제는 Filesystem 의 압축을 푼다. 압축을 풀면, sharp_zsdk_dsl_disk.img 파일이 나온다. 이 파일을 앞서 QEMU 디렉토리안에 복사한다.
QEMU 는 .bat 파일로 실행되기 때문에 약간의 수정이 필요하다. 파일이름은 qemu-win.bat 이다.
REM Start qemu on windows. @ECHO OFF REM SDL_VIDEODRIVER=directx is faster than windib. But keyboard cannot work well. SET SDL_VIDEODRIVER=windib REM SDL_AUDIODRIVER=waveout or dsound can be used. Only if QEMU_AUDIO_DRV=sdl. SET SDL_AUDIODRIVER=dsound REM QEMU_AUDIO_DRV=dsound or fmod or sdl or none can be used. See qemu -audio-help. SET QEMU_AUDIO_DRV=dsound REM QEMU_AUDIO_LOG_TO_MONITOR=1 displays log messages in QEMU monitor. SET QEMU_AUDIO_LOG_TO_MONITOR=0 qemu.exe -L . -m 128 -hda sharp_zsdk_dsl_disk.img -soundhw sb16,es1370 -localtime ## 여기를 수정한다!!
수정후에 qemu-win.bat 을 실행한다.
부팅이 되면 개발환경 구축 완료다!! ^^;
개발하기
이미 개발환경이 구축되어 있기 때문에, 환경파일만 실행시켜주면 된다.
- dev-arm-qpe.sh : ARM 용 크로스 컴파일 환경
- dev-x86-qpe.sh : X86 용 컴파일 환경
dsl@box:~$ . dev-arm-qpe.sh
여기서는 example 프로그램을 컴파일 해보겠다.
dsl@box:~$ cd example dsl@box:~/example$ make clean dsl@box:~/example$ rm Makefile dsl@box:~/example$ tmake -o Makefile example.pro dsl@box:~/example$ make
에러 없이 컴파일 되었다면, example 파일이 생성되었을 것이다.
ipk 파일 만들기
앞에서 컴파일했던 example 프로그램의 경우, 아주 간단한 프로그램이기 때문에 오브젝트 파일만 자우르스에 복사를 해서 실행해도 큰 문제가 되지 않는다. 하지만, 여러개의 소스코드로 이루어진 복잡한(?) 프로그램의 경우에는 얘기가 좀 다르다.
설치할 때 마다 일일이 복사를 해주어야 하고, 삭제할 때 역시 마찬가지다. 이만저만 귀찮은 일이 아니다. 그래서 나온 것이 ipk 파일이다. Redhat 에 rpm 이 있다면, QT 에는 ipk 이 있다. 프로그램 추가/삭제를 간편하게 해준다. 하지만, 편한데 반해 단점도 있다.
예를 들어 A,B 이렇게 두 개의 프로그램이 설치시에 C 라는 파일을 수정한다고 하자. 먼저 A 프로그램을 설치한다. 이 때 파일 C를 수정한다. 이후에 B 프로그램을 수정한다. 이 때 역시 C 파일을 수정한다. 이후에 A 프로그램은 실행이 안된다. 하지만 B 프로그램은 아무 이상없이 실행이 잘 된다. 바로 서로의 의존성을 무시해서 발생되는 문제이다.
ipk 파일의 경우 이런 문제가 종종 발생할 수 있다. 문제는 이런 의존성 문제가 설치시에 아무런 에러 메세지 없이 수행된다는 것이다. 현재로서는 뾰족한 해결법은 없는 것으로 보인다.
이제 실제로 ipk 파일을 만들어보자!!
ipk 파일을 만들 때 중요한 것은, 자우르스에 설치될 디렉토리 트리구조를 만들어야 한다는 것이다. ipk 파일이 자우르스에서 설치될 때는 압축이 풀리면서 절대경로(/)를 기준으로 설치된다.
root 권한이 필요하기 때문에 다음과 같이 실행한다.
dsl@box:~/example$ sudo su -
디렉토리 구조는 다음과 같다. 가장 상위 디렉토리이름을 example_arm 으로 한다.
일단 그림과 같이 디렉토리들을 생성한다. 위에서 디렉토리 이름에 제한이 없는 것은 example_arm 과 example-pack 이다. 이 것들은 마음대로 지어도 된다. 하지만 나머지 디렉토리들은 반드시 지켜야 한다.
이제 example-pack 밑에 있는 디렉토리 부터 살펴보도록 하겠다.
디렉토리명 | 설명 |
CONTROL | ipk 패키지가 설치될 때의 정보를 담는 파일이 들어간다(반드시 이름을 대문자로 적어야 한다!! |
opt | 자우르스에 /opt 디렉토리라고 보면 된다 |
먼저 CONTROL 디렉토리 아래에 들어갈 control 파일을 보자!
Package: zsubway Priority: optional Section: qpe/applications Version: 0.0.1 Architecture: arm Maintainer: danyoh <danyoh@hotmail.com> License: Public Domain Description: A Subway View program
파일의 내용은 위와 같다. 얼핏 보면, 설치될 프로그램의 버전과 제작자, 설명등으로 나누어져 있다. 여기서 주의할 것은 절대 탭이나, 특수 문자를 사용해서는 안된다는 것이다.
이제는 opt 디렉토리를 보자! 자우르스를 보면 /opt 디렉토리가 있다. 다시 말하면 자우르스의 /opt 아래의 디렉토리 구조를 똑같이 만드는 것이다.
내가 만일 /opt/apps 아래에 example 라는 디렉토리 아래에 복사하고 싶으면 그대로 똑같이 디렉토리 구조를 만들면 되는 것이다.
경로 | 설명 |
/opt/QtPalmtop/apps/Applications | 일반적으로 프로그램이름으로 디렉토리가 생성되고, 설정파일들이 이 경로에 많이 설치된다. 윈도우의 Program_Files 라고 보면 된다 |
/opt/QtPalmtop/bin | 실행파일을 복사한다. 이 경로가 PATH 가 걸려있기 때문이다 |
/opt/QtPalmtop/pics | 그림이나 아이콘 파일들을 저장한다 |
이제 각 디렉토리와 경로에 대해서 이해가 되었을 것이다. 이제 각 디렉토리에 맞게 파일들을 넣어주고, ipk 파일을 만들기만 하면 된다.
ipk 는 스크립트 파일로 만드는 데, 파일이름은 ipkg-build.sh 이다. 파일은 다음과 같다.
#!/bin/sh # ipkg-build -- construct a .ipk from a directory # Carl Worth <cworth@east.isi.edu> # based on a script by Steve Redler IV, steve@sr-tech.com 5-21-2001 set -e ipkg_extract_value() { sed -e "s/^[^:]*:[[:space:]]*//" } required_field() { field=$1 value=`grep "^$field:" < $CONTROL/control | ipkg_extract_value` if [ -z "$value" ]; then echo "*** Error: $CONTROL/control is missing field $field" >&2 return 1 fi echo $value return 0 } pkg_appears_sane() { local pkg_dir=$1 local owd=`pwd` cd $pkg_dir PKG_ERROR=0 large_uid_files=`find . -uid +99` if [ -n "$large_uid_files" ]; then echo "*** Warning: The following files have a UID greater than 99. You probably want to chown these to a system user: " >&2 ls -ld $large_uid_files echo >&2 fi if [ ! -f "$CONTROL/control" ]; then echo "*** Error: Control file $pkg_dir/$CONTROL/control not found." >&2 cd $owd return 1 fi pkg=`required_field Package` [ "$?" -ne 0 ] && PKG_ERROR=1 version=`required_field Version | sed 's/.*://;'` [ "$?" -ne 0 ] && PKG_ERROR=1 arch=`required_field Architecture` [ "$?" -ne 0 ] && PKG_ERROR=1 required_field Maintainer >/dev/null [ "$?" -ne 0 ] && PKG_ERROR=1 required_field Description >/dev/null [ "$?" -ne 0 ] && PKG_ERROR=1 section=`required_field Section` [ "$?" -ne 0 ] && PKG_ERROR=1 if [ -z "$section" ]; then echo "The Section field should have one of the following values:" >&2 echo "admin, base, comm, editors, extras, games, graphics, kernel, libs, misc, net, text, web, x11" >&2 fi priority=`required_field Priority` [ "$?" -ne 0 ] && PKG_ERROR=1 if [ -z "$priority" ]; then echo "The Priority field should have one of the following values:" >&2 echo "required, important, standard, optional, extra." >&2 echo "If you don't know which priority value you should be using, then use \`optional'" >&2 fi if echo $pkg | grep '[^a-z0-9.+-]'; then echo "*** Error: Package name $name contains illegal characters, (other than [a-z0-9.+-])" >&2 PKG_ERROR=1; fi local bad_fields=`sed -ne 's/^\([^[:space:]][^:[:space:]]\+[[:space:]]\+\)[^:].*/\1/p' < $CONTROL/control | sed -e 's/\\n//'` if [ -n "$bad_fields" ]; then bad_fields=`echo $bad_fields` echo "*** Error: The following fields in $CONTROL/control are missing a ':'" >&2 echo " $bad_fields" >&2 echo "ipkg-build: This may be due to a missing initial space for a multi-line field value" >&2 PKG_ERROR=1 fi for script in $CONTROL/preinst $CONTROL/postinst $CONTROL/prerm $CONTROL/postrm; do if [ -f $script -a ! -x $script ]; then echo "*** Error: package script $script is not executable" >&2 PKG_ERROR=1 fi done if [ -f $CONTROL/conffiles ]; then for cf in `cat $CONTROL/conffiles`; do if [ ! -f ./$cf ]; then echo "*** Error: $CONTROL/conffiles mentions conffile $cf which does not exist" >&2 PKG_ERROR=1 fi done fi cd $owd return $PKG_ERROR } ### # ipkg-build "main" ### case $# in 1) dest_dir=. ;; 2) dest_dir=$2 ;; *) echo "Usage: ipkg-build <pkg_directory> [<destination_directory>]" >&2 exit 1 ;; esac pkg_dir=$1 if [ ! -d $pkg_dir ]; then echo "*** Error: Directory $pkg_dir does not exist" >&2 exit 1 fi # CONTROL is second so that it takes precedence CONTROL= [ -d $pkg_dir/DEBIAN ] && CONTROL=DEBIAN [ -d $pkg_dir/CONTROL ] && CONTROL=CONTROL if [ -z "$CONTROL" ]; then echo "*** Error: Directory $pkg_dir has no CONTROL subdirectory." >&2 exit 1 fi if ! pkg_appears_sane $pkg_dir; then echo >&2 echo "ipkg-build: Please fix the above errors and try again." >&2 exit 1 fi tmp_dir=$dest_dir/IPKG_BUILD.$$ mkdir $tmp_dir tar -C $pkg_dir -czf $tmp_dir/data.tar.gz . --exclude=$CONTROL tar -C $pkg_dir/$CONTROL -czf $tmp_dir/control.tar.gz . echo "2.0" > $tmp_dir/debian-binary pkg_file=$dest_dir/${pkg}_${version}_${arch}.ipk tar -C $tmp_dir -czf $pkg_file ./debian-binary ./data.tar.gz ./control.tar.gz rm $tmp_dir/debian-binary $tmp_dir/data.tar.gz $tmp_dir/control.tar.gz rmdir $tmp_dir echo "Packaged contents of $pkg_dir into $pkg_file"
이 스크립트 파일은 example_arm 디렉토리 바로 아래에 있어야 한다. 마지막으로 debian-binary 파일에 대해서 설명하겠다.
이 파일의 용도는 확실하지는 않지만, 혹시나 하는 마음에 만들어 둔다. 파일명은 debian-binary 이고 내용은
2.0
이다. 이 파일역시 example_arm 디렉토리 바로 아래에 위치해야 한다. 이제 모든 준비가 끝났다. 터미널을 실행해서
#cd example_arm #./ipkg-build.sh example-pack
하면, example_0.0.1.arm.ipk 파일이 생성된다. 이제 자우르스에 옮겨 직접 설치해보자!!