프로그램의 초기화를 위한 컴파일시 실행

전종필

Perl 스크립트를 만들고 난 후 실행하는 단계는 실행하는 사람에게는 순식간이지만, Perl 내부에서는 많은 과정이 거쳐집니다.
크게 나누면 컴파일과정과 실행을 동반하는 인터프레팅 과정인데, 프로그램이 실행될 때는 이미 컴파일이 모두 끝나있는 상태입니다.
하지만, 컴파일 당시에 어떤 내용이 실행되어져야 하는 경우가 있습니다. 대개는 프로그램을 초기화하기 위해 컴파일시 실행이 요구됩니다.
use의 경우는 require와는 달리 컴파일시에 실행이 되기 때문에 ''use''할 모듈은 @INC 배열에 포함되어있는 디렉토리에 들어가 있어야 합니다. 만일 그렇지 않으면

Can't locate XXX.pm in @INC (@INC contains: /usr/local/...중략.. /perl5/site_perl .) at - line 1.
BEGIN failed--compilation aborted at - line 1.
와 같은 오류가발행하고 진행을 멈춥니다. 이 때문에

use lib qw(/other/additional/directory);
와 같이 해당 모듈이 들어 있는 추가적인 디렉토리를 lib 모듈을 통해 @INC 특수배열에 집어넣어주는 것입니다.
하지만, 만약, 원하는 디렉토리가 상황에 따라 달라질 수 있다면 어떻게 해야할까요? 예를 들어 같은 이름의 모듈이 여러 디렉토리에 있는데, 어떤 설정 파일안에 사용할 모듈의 디렉토리 이름이 들어있는 경우를 상상해 봅시다.

./dir1/Mymod.pm	: Mymod 모듈
./dir2/Mymod.pm : Mymod 모듈, 조금 다른 내용
./dir.conf      : 설정파일. ./dir1 또는 ./dir2 또는 잘못된 값이 적혀있음

# ./dir1/Mymod.pm
package Mymod;

sub whoami {
        print "This is Mymod from dir1\n";
}

1;


# ./dir2/Mymod.pm
package Mymod;

sub whoami {
        print "Another Mymod from dir2\n";
}

1;
이 경우 backtick을 이용하여

use lib ( @{ [ `cat ./dir.conf` ] } );
할 수는 있지만, 만일 dir.conf에 들어있는 내용에 오류가 있거나, 아니면 아주 간단하게, 개행문자가 하나 붙어있다면, 결국 use Mymod는 오류를 출력하게 됩니다. 따라서 이런 설정오류등을 제거하기위해 다양한 작업들을 해야 하는데, 이를 위해서 BEGIN 서브루틴을 작성하게 됩니다. BEGIN 서브루틴 안에 들어 있는 내용 역시 use 처럼 컴파일시에 실행되기 때문입니다.

sub BEGIN {
	my $dir = `head -1 dir.conf`;
	chomp $dir;
	$dir = './dir1' unless -f "$dir/Mymod.pm";
	push @INC, ( $dir || "./dir1" );
} # 좀 더 많은 오류처리가 필요합니다만...

use Mymod;

Mymod::whoami();
이때 주의할 점은 use Mymod 전에 sub BEGIN {...}을 먼저 두어야 한다는 것입니다. use와 BEGIN 서브루틴은 컴파일시 파일에서 발견된 순서대로 실행되기때문입니다.
위와 같이 하면, @INC 특수배열에는 원하는 디렉토리가 추가되고, 그 디렉토리에 있는 Mymod.pm 파일이 사용될 수 있는 것입니다. 증명을 위해서 dir.conf 파일에 매번 Mymod.pm 모듈이 들어있는 서로 다른 디렉토리 이름 혹은 들어있지 않는 디렉토리 이름을 넣어두고 프로그램을 실행해 보시기 바랍니다.

이런 필요 외에도 다양한 부분에서 BEGIN 함수를 사용할 수 있습니다만, 그 것들은 또 다른 팁에서 볼 수 있을 것이라고 생각됩니다.... 

Comments