메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

예제로 배우는 배쉬 프로그래밍: Part 3

ebuild 시스템

Daniel Robbins, President/CEO, Gentoo Technologies, Inc
Daniel Robbins는 Gentoo Project의 수석 아키텍트이자 Gentoo Technologies, inc.의 CEO이다. 또한 Linux Advanced Multimedia Project (LAMP)에 많은 도움을 주고 있다. Caldera OpenLinux Unleashed, SuSE Linux Unleashed, Samba Unleashed 등에 기고활동을 하고 있다.

요약:  예제로 배우는 배쉬 프로그래밍’ 시리즈의 마지막회 이다. Daniel Robbins는 배쉬의 장점이 부각된 Gentoo Linux ebuild 시스템을 자세하게 설명한다. 또한 ebuild 시스템이 어떻게 구현되었는지를 단계적으로 설명하고, 다루기 쉬운 배쉬 기술과 구축 전략을 다룬다. 이 시리즈를 충분히 이해했다면 완벽한 배쉬 기반의 애플리케이션을 만들 수 있을 것이다. 자신만의 자동 구축(auto-build) 시스템을 코딩 할 수도 있을 것이다.

원문 게재일:  2002 년 7 월 08 일 (출판일: 2000 년 4 월 01 일)
난이도:  초급
페이지뷰:  1429 회
의견:  


ebuild 시스템

Part 1Part 2를 통해 배쉬 프로그래밍의 기초를 충분히 다졌다고 생각한다. 이제는 좀더 수준높은 주제를 다뤄보도록 하자. 배쉬 애플리케이션 개발과 프로그램 디자인은 어떤가? 이 글을 통해, 코딩과 정리 작업에 많은 시간을 투자했던 Gentoo Linux ebuild 시스템 프로젝트를 소개하고 실질적인 배쉬 개발 경험을 나누고자 한다.

나는 차세대 리눅스인 Gentoo Linux의 수석 아키텍트이다. 주요한 임무 중 하나는 모든 바이너리 패키지가 적절히 만들어져 원활히 작동할 수 있도록 하는 것이다. 표준 리눅스 시스템은 하나의 통일된 소스 트리로 구성되어있는 것이 아니라 25+ 핵심 패키지가 함께 작동한다. 다음은 패키지에 포함된 것 들이다:

패키지 설명
linux실제 커널
util-linux다양한 리눅스 관련 프로그램 모음
e2fsprogsext2 파일시스템 관련 유틸리티 모음
glibcGNU C 라이브러리

각 패키지는 tarball에 있고 개발자들이나 개발 팀들이 관리한다. 배포판을 만들기 위해서는, 각 패키지의 다운로드, 컴파일, 패키징이 개별적으로 수행되어야 한다. 패키지가 픽스되고 업그레이드 될 때마다 컴파일과 패키징 단계는 반복되어야 한다. 패키지 만들기와 업데이트의 반복적인 단계를 줄이기 위해서 ebuild 시스템을 만들었다. 거의 모든것이 배쉬로 작성된 것이다. ebuild 시스템을 언패킹하고 컴파일하는 부분을 구현하는 방법을 단계적으로 설명하겠다.


왜 배쉬인가?

배쉬는 Gentoo Linux ebuild system의 필수 컴포넌트이다. 여러가지 이유로 ebuild의 기본 언어로 선택되었다. 우선, 복잡하지 않고 익숙한 신택스를 갖추고 있어서 특별히 외부 프로그램을 호출하기에 알맞다. 자동 구현 시스템은 외부 프로그램 호출을 자동화 하는 "글루 코드(glue code)" 이고, 배쉬는 이러한 유형의 애플리케이션에 적합하다. 그리고, 배쉬는 ebuild 시스템이 모듈식의 이해하기 쉬운 코드가 되도록 함수를 지원한다. 마지막으로, ebuild 시스템은 배쉬가 환경 변수를 지원하는 것을 이용하여 패키지 관리자와 개발자가 쉽게 설정할 수 있도록 했다.


구현 과정

ebuild 시스템을 보기전에, 패키지를 컴파일하고 설치에 무엇이 포함되었는지를 살펴보자. 예제에서는, "sed" 패키지를 검토할 것이다. 이것은 리눅스 배포판의 일부분인 표준 GNU 텍스트 스트림 편집 유틸리티이다. 우선 source tarball (sed-3.02.tar.gz) (참고자료)을 다운로드 한다. 이 아카이브를 /usr/src/distfiles에 저장할 것이다. 이 디렉토리는 "$DISTDIR" 환경 변수를 사용할 때 참조할 것이다. "$DISTDIR"는 원래 source tarball이 있는 곳에 있는 디렉토리이다.

다음 단계는 "work"라는 임시 디렉토리를 만드는 것이다. 이것은 압축하지 않은 소스 저장소이다. 이 디렉토리를 "$WORKDIR" 환경 변수를 사용하면서 후에 참조할 것이다. 이를 위해, 쓰기 권한을 가지고 있는 곳의 디렉토리로 변경하고 다음을 타이핑 한다:


sed 압축 풀기
$ mkdir work
$ cd work
$ tar xzf /usr/src/distfiles/sed-3.02.tar.gz



sed 압축 풀기
$ cd sed-3.02
$ ./configure --prefix=/usr
(autoconf generates appropriate makefiles, this can take a while)

$ make

(the package is compiled from sources, also takes a bit of time)



unpack/compile 프로세스를 수행하는 배쉬 스크립트
#!/usr/bin/env bash

if [ -d work ]
then
# remove old work directory if it exists 
	rm -rf work
fi
mkdir work
cd work
tar xzf /usr/src/distfiles/sed-3.02.tar.gz
cd sed-3.02
./configure --prefix=/usr
make



일반적인 스크립트
#!/usr/bin/env bash

# P is the package name

P=sed-3.02

# A is the archive name

A=${P}.tar.gz

export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
export SRCDIR=${WORKDIR}/${P}

if [ -z "$DISTDIR" ]
then
	# set DISTDIR to /usr/src/distfiles if not already set
	DISTDIR=/usr/src/distfiles
fi
export DISTDIR

if [ -d ${WORKDIR} ]
then	
	# remove old work directory if it exists 
	rm -rf ${WORKDIR}
fi

mkdir ${WORKDIR}
cd ${WORKDIR}
tar xzf ${DISTDIR}/${A}
cd ${SRCDIR}
./configure --prefix=/usr
make



sed-3.02.ebuild
#the sed ebuild file -- very simple!
P=sed-3.02
A=${P}.tar.gz
	



ebuild 스크립트
#!/usr/bin/env bash


if [ $# -ne 1 ]
then
	echo "one argument expected."
	exit 1
fi

if [ -e "$1" ]
then
	source $1
else
	echo "ebuild file $1 not found."
	exit 1
fi

export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
export SRCDIR=${WORKDIR}/${P}

if [ -z "$DISTDIR" ]
then
	# set DISTDIR to /usr/src/distfiles if not already set
	DISTDIR=/usr/src/distfiles
fi
export DISTDIR

if [ -d ${WORKDIR} ]
then	
	# remove old work directory if it exists 
	rm -rf ${WORKDIR}
fi

mkdir ${WORKDIR}
cd ${WORKDIR}
tar xzf ${DISTDIR}/${A}
cd ${SRCDIR}
./configure --prefix=/usr
make


$ ./ebuild sed-3.02.ebuild

"ebuild"가 실행할 때 이것은 "$1" 변수를 "source" 한다. 이것은 무엇을 의미하는가? part 2에서, "$1"는 첫 번째 명령행 인자라는 것을 기억할 것이다. 이 경우, "sed-3.02.ebuild" 이다. 배쉬에서, "source" 명령어는 파일에서부터 배쉬 문장을 읽고 그들이 "source" 명령어가 있는 파일에 나타난것처럼 그들을 실행한다. 그래서, "source ${1}"는 "ebuild" 스크립트가 "sed-3.02.ebuild"에 있는 명령어를 실행하도록 한다. 이러한 디자인 변경은 쉽다. sed 대신 다른 프로그램을 컴파일하길 원한다면 새로운 .ebuild 파일을 만들어서 이것을 인자로 해서 "ebuild" 스크립트로 전달할 수 있다. 그러한 방식이, ebuild 파일을 간단하게 하며 ebuild system의 핵심부분은 한 장소, 즉 "ebuild" 스크립트에 저장된다. 이러한 방식으로 "ebuild" 스크립트를 편집함으로서 간단히 ebuild 시스템을 업그레이드 하면서 구현 세부사항은 ebuild 외부에 보관한다. 다음은 gzip용 ebuild 파일이다:


gzip-1.2.4a.ebuild
#another really simple ebuild script!
P=gzip-1.2.4a
A=${P}.tar.gz



ebuild, revision 2
#!/usr/bin/env bash

if [ $# -ne 2 ]
then
	echo "Please specify two args - .ebuild file and unpack, compile or all"
	exit 1
fi


if [ -z "$DISTDIR" ]
then
	# set DISTDIR to /usr/src/distfiles if not already set
	DISTDIR=/usr/src/distfiles
fi
export DISTDIR

ebuild_unpack() {
	#make sure we're in the right directory	
	cd ${ORIGDIR}
	
	if [ -d ${WORKDIR} ]
	then	
		rm -rf ${WORKDIR}
	fi

	mkdir ${WORKDIR}
	cd ${WORKDIR}
	if [ ! -e ${DISTDIR}/${A} ]
	then
	    echo "${DISTDIR}/${A} does not exist.  Please download first."
	    exit 1
	fi    
	tar xzf ${DISTDIR}/${A}
	echo "Unpacked ${DISTDIR}/${A}."
	#source is now correctly unpacked


많은 변경이 이루어졌다. 우선, 우리는 컴파일과 언패킹 단계를 각자의 함수에 두고, ebuild_compile()와 ebuild_unpack()를 각각 호출했다. 코드는 점점 복잡해지고 새로운 함수는 어떤 것이든 조직화시키는 모듈화를 제공하기 때문에 이것은 좋은 현상이다. 각 함수의 첫 번째 라인에서 원하는 디렉토리로 "cd" 했다. "cd" 명령어는 분명히 올바른 장소에 위치시키고 실수를 방지한다.

또한, ebuild_compile() 함수의 시작에 "check"를 추가했다. 이것은 "$SRCDIR" 가 존재하는 지를 확인하고 그렇지 않다면 사용자에게 아카이브를 언패킹하고 종료하라는 에러 메시지를 프린팅한다. 원한다면 이러한 작동을 변경하여, "$SRCDIR"가 존재하지 않을 경우 ebuild 스크립트가 소스 아카이브를 자동으로 언패킹하도록 한다. ebuild_compile()을 다음의 코드로 대체함으로서 이를 수행할 수 있다:


ebuild_compile()
ebuild_compile() {
	#make sure we're in the right directory	 
	if [ ! -d "${SRCDIR}" ]
	then
		ebuild_unpack
    	fi
	cd ${SRCDIR}
	./configure --prefix=/usr
	make	 
}

$ ebuild sed-3.02.ebuild

실제로 에러 메시지를 받을 것이다. ebuild는 무엇을 해야할지에 대해 명령을 받아야 한다:

$ ebuild sed-3.02.ebuild unpack

또는

$ ebuild sed-3.02.ebuild compile

또는

$ ebuild sed-3.02.ebuild all


코드를 모듈화 하기

코드가 향상되고 기능적으로 되었다면 각자 선호하는 프로그램을 언패킹하고 컴파일 할 더 많은 ebuild 스크립트를 만들고 싶을 것이다. 여러분은 "./configure"를 사용하지 않는 소스를 생각할 것이고 아마도 비표준 컴파일 프로세스를 가진 다른 것을 생각하게 될 것이다. 프로그램을 자동화하기 위해서는 ebuild 시스템을 변경해야 한다. 하지만 그 전에 이를 어떻게 이뤄 나갈지를 생각해야 한다.

ebuild 시스템이 autoconf나 정상적인 Makefiles를 사용하지 않는 소스를 갖추도록 해야 한다. 이러한 문제를 풀기위해 ebuild 스크립트는 디폴트로 다음과 같은 것을 수행해야한다:

  1. "${SRCDIR}"에 설정 스크립트가 있다면 다음과 같이 실행한다:
    ./configure --prefix=/usr
    그렇지 않다면, 이 단계를 생략한다.

  2. 다음의 명령어를 실행한다:
    make

ebuild는 실제로 존재할 때 configure를 실행하기 때문에, autoconf를 사용하지 않고 표준 makefiles를 갖고있는 프로그램을 자동으로 갖출 수 있다. 하지만 "make" 가 몇 가지 소스에 대해 이 같은 트릭을 수행하지 않는다면 어떻게 하겠는가? 우리는 특정 코드를 이용하여 이러한 상황을 대처할 합리적인 방법이 필요하다. 이를 위해 ebuild_compile() 함수를 두 개의 함수로 변형할 것이다. 첫 번째 함수는 "부모" 함수라고 할 수 있는 ebuild_compile() 이다. 하지만 user_compile() 이라는 새로운 함수를 갖게 될 것이다:


ebuild_compile()를 두 개의 함수로 나누기
user_compile() {
	#we're already in ${SRCDIR}
	if [ -e configure ]
	then
		#run configure script if it exists
		./configure --prefix=/usr
	fi
	#run make
	make
}	       

ebuild_compile() {
	if [ ! -d "${SRCDIR}" ]
	then
		echo "${SRCDIR} does not exist -- please unpack first."
		exit 1
	fi
	#make sure we're in the right directory	 
	cd ${SRCDIR}
	user_compile
}



e2fsprogs-1.18.ebuild
#this ebuild file overrides the default user_compile()
P=e2fsprogs-1.18
A=${P}.tar.gz
 
user_compile() {
       ./configure --enable-elf-shlibs
       make
}


e2fsprogs는 원하는 방식으로 정확히 컴파일 될 것이다. 하지만 대부분의 패키지의 경우 .ebuild 파일에서 custom user_compile() 함수를 생략할 수 있고 default user_compile() 함수가 대신 사용된다.

ebuild 스크립트가 어떤 user_compile() 함수를 사용할 지를

이 예제에서 하나의 설정 옵션만을 추가했다. 원한다면 더 많은 것을 추가해도 된다. /etc/ebuild.conf가 소싱되면, "$MAKEOPTS"는 ebuild 스크립트내에서 정의된다. 일반적으로 이 옵션은 사용자가 ebuild에게 병렬(parallel) make를 수행하도록 명령할 수 있도록 한다.

병렬(parallel) make?

다중 프로세서 시스템에서 컴파일의 속도를 높이기 위해서는 프로그램 컴파일을 병렬로 지원해야 한다. 이것은 한번에 한 개의 소스 파일을 컴파일 하는 대신에 많은 사용자 스팩의 소스파일을 동시에 컴파일 한다는 것을 의미한다:

make -j4 MAKE="make -j4"

이 코드는 4개의 프로그램을 동시에 컴파일 한다. MAKE="make -j4" 인자는 make에게 -j4 옵션을 모든 자식 make 프로세스로 전달하도록 명령한다.

다음은 ebuild 프로그램의 마지막 버전이다:


ebuild
#!/usr/bin/env bash

if [ $# -ne 2 ]
then
	echo "Please specify ebuild file and unpack, compile or all"
	exit 1
fi

source /etc/ebuild.conf

if [ -z "$DISTDIR" ]
then
	# set DISTDIR to /usr/src/distfiles if not already set
	DISTDIR=/usr/src/distfiles
fi
export DISTDIR

ebuild_unpack() {
	#make sure we're in the right directory	
	cd ${ORIGDIR}
	
	if [ -d ${WORKDIR} ]
	then	
		rm -rf ${WORKDIR}
	fi

	mkdir ${WORKDIR}
	cd ${WORKDIR}
	if [ ! -e ${DISTDIR}/${A} ]
	then
		echo "${DISTDIR}/${A} does not exist.  Please download first."
		exit 1
	fi
	tar xzf ${DISTDIR}/${A}
	echo "Unpacked ${DISTDIR}/${A}."
	#source is now correctly unpacked
}

user_compile() {
	#we're already in ${SRCDIR}
	if [ -e configure ]
	then
		#run configure script if it exists
		./configure --prefix=/usr
	fi
    	#run make
    	make $MAKEOPTS MAKE="make $MAKEOPTS"  
} 

ebuild_compile() {
	if [ ! -d "${SRCDIR}" ]
	then
		echo "${SRCDIR} does not exist -- please unpack first."
		exit 1
	fi
    	#make sure we're in the right directory	 
	cd ${SRCDIR}
	user_compile
}

export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work

if [ -e "$1" ]
then
	source $1
else
	echo "Ebuild file $1 not found."
	exit 1
fi

export SRCDIR=${WORKDIR}/${P}

case "${2}" in
	unpack)
		ebuild_unpack
		;;
	compile)
		ebuild_compile
		;;
	all)
		ebuild_unpack
		ebuild_compile
		;;
	*)
		echo "Please specify unpack, compile or all as the second arg"
		exit 1
		;;
esac


/etc/ebuild.conf 가 파일의 거의 시작 부분에서 "source"되었다는 것을 주목하라. 그리고 default user_compile() 함수에서 "$MAKEOPTS"를 사용했다는 것도 주목해라. 우리는 /etc/ebuild.conf를 소싱하기 전에 "$MAKEOPTS"를 참조했다. 다행히 user_compile()가 실행될 때 변수 확장이 발생하기 때문에 정상적일 수 있었다.


결론

이 글을 통해 다양한 배쉬 프로그래밍 기술을 다뤘다. 하지만 배쉬의 표면만을 다루었을 뿐이다. 예를들어, Gentoo Linux ebuild 시스템은 각 패키지를 자동으로 언패킹하고 컴파일 할 뿐만아니라 다음과 같은 일도 수행할 수 있다:

  • "$DISTDIR"에 소스가 없다면 소스를 자동으로 다운로드 한다.
  • MD5 message digest를 사용하여 소스가 오염되지 않는다는 것을 확인한다.
  • 컴파일된 애플리케이션을 파일시스템에 설치하고, 설치된 모든 파일을 기록하여 나중에 패키지를 쉽게 언인스톨(uninstall)할 수 있도록 한다.
  • 컴파일된 애플리케이션을 tarball에 패키징하여 나중에 다른 컴퓨터에 설치 될 수 있도록 한다. 또는 CD 기반의 설치 프로세스동안에 설치될 수 있도록 한다.

이 글에서 다루었던 것 이상으로 배쉬가 더 많은 일을 수행한다. 툴을 다루는 기술을 익혀 개발 프로젝트를 발전시킬 수 있기를 기대한다.


참고자료

필자소개

Daniel Robbins는 Gentoo Project의 수석 아키텍트이자 Gentoo Technologies, inc.의 CEO이다. 또한 Linux Advanced Multimedia Project (LAMP)에 많은 도움을 주고 있다. Caldera OpenLinux Unleashed, SuSE Linux Unleashed, Samba Unleashed 등에 기고활동을 하고 있다.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=리눅스
ArticleID=18059
ArticleTitle=예제로 배우는 배쉬 프로그래밍: Part 3
publish-date=07082002
author1-email=
author1-email-cc=

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.