MenuIcon

Owl-Networks Archive

LoginIcon

Perl / Win32 / PAR::Packer - 한글 사용자 이름을 갖는 계정에서 PAR::Packer 실행 바이너리가 실행되지 않는 문제점의 해결

| 분류: Perl | 최초 작성: 2011-12-25 00:04:22 |

참고(2012년 01월 30일 추가, 2012년 3월 27일 수정):

이 문제는 얼마 전 필자가 포스팅했던, 윈도우 사용자 이름에 한글이 포함되어 있을 때 PAR::Packer 로 빌드된 실행 바이너리가 실행되지 않는 문제([[LINK::402]])의 해결 방법입니다.

국내 Perl 커뮤니티의 @gypark 님의 도움으로, 이 문제는 CPAN에 버그 리포트가 이루어졌으며, 제작자가 수정의견을 받아들여 이를 패치하였습니다. 따라서 PAR::Packer 의 1.013 버전 이후에는 이 문제는 발생하지 않으며, 자신의 PAR::Packer 를 1.013 버전 또는 그 이후 버전으로 업그레이드 함으로써 이 문제는 완전히 해결이 가능합니다.

즉, 이 글을 보고 계신 분이 PAR::Packer 를 사용하시는 Perl 개발자이고, 자신의 PAR::Packer 모듈 버전이 1.013 또는 그 이후 버전이라면 이 글에서 논의되는 문제는 이미 해결되었을 것이므로, 이 글을 읽으실 필요는 없습니다.

다만, 필자가 생각하기에, 이 패치 방법은 이 글에서 제기하는 문제가 해결된 이후에도 PAR::Packer 를 이용하는 Perl 개발자에게 있어서는 다른 용도로서 그 의미를 갖고 있다고 생각합니다. 따라서 기존의 원문은 그대로 놓아둔 채로, 이 글의 마지막에 새로운 장을 설정하여 그에 관한 논의를 더 하였습니다. 관심있는 분께서는 참고하시기 바랍니다.



1. 들어가면서


Perl에 대한, 해커나 시스템 관리자들이 사용하는 언어라는 일반적인 통념과는 달리, 윈도우 환경에서도 Perl은 나무랄 데 없는 활용도를 가지고 있습니다. 윈도우의 GUI 환경 역시 적용이 가능하며, 여러 CPAN 모듈들을 사용하여 일반 목적의 각종 프로그램을 별 무리 없이 작성할 수도 있습니다.

그러나 이렇게 작성된 프로그램을 막상 배포하려 하면 골치아픈 문제와 맞닥뜨립니다. 유닉스/리눅스와는 달리 윈도우에는 대개 Perl 이 설치되어 있지 않기 때문에, 다른 시스템에서 이 스크립트를 실행할 수 있으리라는 보장이 없습니다. Perl 도 닷넷 프레임워크 같은 실행 런타임이 있으면 좋겠지만, 안타깝게도 그런 것은 존재하지 않는군요. 그렇다고 "이 프로그램을 사용하시려면 먼저 시스템에 Perl 을 설치하세요." 라는 것은 일반 사용자에게는 배보다 배꼽이 더 큰 일입니다.

그래서, 작성한 프로그램을 실행 바이너리로 배포할 수 있도록 몇 개의 도구들이 등장했는데, 다음과 같은 것들이 대표적입니다.

- PerlApp  (ActiveState)
- Perl2Exe (Indigo Software)

다만 위 프로그램들은 모두 상업용 소프트웨어로써, 정식으로 사용하려면 만만치 않은 자금의 지출이 필요합니다. 게다가 모두 외국에서 만들어진 프로그램이어서, 카드로 달러 결제를 해야 하는 등 상당히 번거롭습니다. 프로그램을 만들어서 돈 받고 팔려는 것도 아닌데, 40여만원의 지출(PerlApp이 포함된 Perl Dev Kit의 경우)은 뭔가 격에 맞지 않는 짓이죠.

이런 경우에 사용할 수 있는 도구가 바로 PAR::Packer 라고 하는 Perl 모듈입니다. 이 모듈은 대상 Perl 스크립트에 사용된 모든 모듈을 한데 모아서 Perl 해석기[Interpreter]와 함께 하나의 실행 파일로 만들어 줍니다. Perl 해석기가 포함되어 있는 실행 바이너리이기 때문에, Perl이 설치되지 않은 시스템에서도 문제 없이 사용할 수 있습니다. 초기 구동 속도가 조금 느리다는 단점은 있지만, 일반 목적의 배포에는 큰 문제가 되지 않습니다.

ActivePerl 의 경우에는 PPM 으로부터 설치할 수 있으며, Strawberry Perl의 경우에는 CPAN 을 통해 설치가 가능합니다. ActivePerl 의 경우에는 MinGW 와 dmake 를 함께 설치해 주어야 합니다.(MinGW에 포함되어 있는 오픈소스 컴파일러인 gcc를 컴파일에 사용하기 위해서입니다. Strawberry Perl의 경우에는 이미 gcc 가 설치되어 있습니다.)

제가 주로 사용하는 Perl 바이너리가 ActivePerl 이기 때문에, 이하의 모든 이야기는 ActivePerl을 기준으로 합니다. 아마 Strawberry Perl 역시 동일할 것입니다.


PAR::Packer 의 Packager 인 pp 의 구체적인 사용법은 여기를 참조하시면 되므로 여기서는 더 이상 설명하지 않습니다. 애초에 이 글의 목적이 PAR::Packer 를 소개하자는 글은 아니기 때문입니다.



2. 대한민국에서만 발생하는, PAR::Packer 의 문제점


그런데, 이 PAR::Packer 에 관하여, 이 곳 대한민국에서만 발생하는 골치아픈 문제가 하나 있습니다. 그것은 바로 사용자 이름과 관련되는 문제입니다. 무슨 이야기일까요? 이 부분을 이해하기 위해서는, PAR::Packer 로 패키징된 실행 바이너리의 실행 과정에 대한 이해가 선행되어야 합니다.

일단 PAR::Packer 가 Perl 코드 자체를 컴파일하지는 않는다는 점을 이해해야 합니다. Perl은 인터프리터 언어이고, 실행 바이너리로 패키징한다 하여 이 점은 변하지 않습니다. PAR::Packer 는 대상 Perl 스크립트와, 그 스크립트가 사용하는 모든 모듈을 한데 모아서 ZIP 으로 묶고, 여기에 Perl 실행에 필요한 해석기를 포함하여 일종의 자동 풀림 형태의 EXE 압축 파일로 만듭니다. 그래서, PAR::Packer 로 만들어진 실행 파일을 실행하면, PAR::Packer는 먼저 특정한 위치에 ZIP 압축을 풀어 놓은 후, 포함되어 있는 Perl 해석기를 통하여 스크립트를 실행하게 됩니다.

그래서 PAR::Packer 로 빌드한 실행 바이너리를 실행하면, 동일한 이름의 파일 두 개가 프로세스 목록에 모-자 프로세스 형태로 떠 있는 것을 확인하실 수 있습니다. 물론 프로그램을 종료하면 두 개의 프로세스가 동시에 꺼집니다.


이 압축을 푸는 과정이 문제입니다. PAR는 압축을 윈도우 TEMP 폴더에 풀어놓는데, 그냥 TEMP 폴더에 풀어놓는 것이 아니라, TEMP 폴더 밑에 PAR-[사용자 이름] 이라는 폴더를 하나 만들고, 그 밑에 다시 cachexxxxxx.. 라는 폴더를 만들어서 그 안에 압축을 풀어놓습니다. 예를 들면 윈도우 7에서는 이런 구조가 됩니다.

C:\Users\사용자 이름\AppData\Local\Temp\par-사용자 이름\cache-xxxxxxxxxxxxxxxxxx
(x는 무작위. 내부적으로는 SHA-1 해시를 사용합니다.)

그림 1. 사용자 이름이 OwlNetworks 인 경우. par-OwlNetworks 라는 폴더가 TEMP폴더 이하에 만들어지고, 그 이하에 캐시 폴더가 만들어지면서 스크립트 및 모듈의 압축이 풀립니다.
그림 1. 사용자 이름이 OwlNetworks 인 경우. par-OwlNetworks 라는 폴더가 TEMP폴더 이하에 만들어지고, 그 이하에 캐시 폴더가 만들어지면서 스크립트 및 모듈의 압축이 풀립니다.


문제는 사용자 이름에 한글이 포함되는 경우입니다. 이게 왜 문제가 될까요? 바로 한글 인코딩 때문입니다. PAR::Packer 는 우선 시스템의 TEMP 폴더의 경로를 찾아 문자열로 저장합니다. 그리고 그 문자열 뒤에 "par-사용자 이름" 이라는 문자열을 덧붙이게 되는데, 이 과정에서 2바이트(CP949의 경우)문자인 한글의 특성을 고려하지 않고, 이름에 사용된 문자를 모두 1바이트 문자(영문자 등)로 간주하여 그 이외의 문자를 일괄적으로 _ 로 변경해 버립니다. 이 과정에서 한글을 구성하는 2바이트 중 일부가 멋대로 _ 문자로 변경되어 버리고, 짝을 잃은 나머지 1바이트는 이상한 문자로 바뀌어 버리는 것이죠. 이렇게 이상하게 변한 문자가 끼어 있는 경로로 폴더를 만들려고 시도하면? 폴더 이름에 깨진 문자가 포함되어 있는 결과 폴더 작성에 실패하게 되겠죠. 그 결과 creation of private temporary subdirectory ~~~~ failed. 라는 오류를 내면서 실행이 중단되어 버립니다. 눈에 보이는 결과는 둘 중 하나입니다. --gui 옵션을 주어서 빌드한 EXE 파일이라면 파일을 더블클릭해도 아무런 반응이 없는 모습이 될 것이고, 그것이 아니라면 콘솔 화면이 잠깐 나타났다가 꺼지는 모습이 나타나겠죠.

그림 2. 사용자 이름이 한글인 상태에서 PAR::Packer 로 패키징된 실행 바이너리를 실행한 모습. 배치 파일의 pause 를 이용하여 에러 메시지를 잡았습니다. 중간의 글자 한 자가 깨진 상태가 되어 폴더 작성에 실패한 상태입니다.
그림 2. 사용자 이름이 한글인 상태에서 PAR::Packer 로 패키징된 실행 바이너리를 실행한 모습. 배치 파일의 pause 를 이용하여 에러 메시지를 잡았습니다. 중간의 글자 한 자가 깨진 상태가 되어 폴더 작성에 실패한 상태입니다.




3. 문제를 해결하는 방법?


한글과 관련한 문제이다 보니, 구글링을 해봐도 해결 방법이 없습니다. 아예 이런 현상에 대한 논의 자체가 없죠. 대한민국의 Perl 사용자가 적기 때문이기도 하겠지만, 가까운 일본만 해도 인코딩 문제로 인한 말썽이 많은 CJK 문자권에 들어가는데다 Perl 인구도 많은 편인데, 이런 문제가 이슈가 안 되는 것이 좀 의아할 따름입니다.

각설하고, 이 문제는 PAR::Packer 에서 스크립트의 압축을 해제하는 폴더를 변경할 수 있게 해준다면 간단히 해결이 가능합니다. 그러나, pp 명령행 옵션에 압축 해제된 스크립트가 저장되는 위치를 변경하는 옵션은 없습니다. -T 또는 --tempcache 옵션이 있습니다만, 이 옵션은 Temp 폴더 대신 압축을 풀 폴더를 지정하는 옵션으로서, 문제가 되는 "par-사용자 이름" 부분이 이 뒤에 그대로 따라가므로 전혀 문제가 해결되지 않습니다.

이쯤 되면, 배포자 입장에서는 이 문제를 해결하지 않는 것이 사실 속 편합니다. 프로그램 사용자들에게, 사용자 이름이 한글이면 실행이 안 되니까, 영문자 및 숫자로 구성된 사용자 계정을 만든 후 사용하라고 readme.txt 파일에 적어서 배포하는 것이죠. 저도 방법을 찾지 못해서, 한동안 이런 방식으로 배포했습니다.

그러나, 생각해 보면 어처구니가 없는 일입니다. 사용자 이름을 한글로 쓰는 것이 물론 (호환성을 생각하면) 좋은 습관은 아니지만, 이런 방식으로 사용자 이름을 만들어 사용하는 사람이 차고 넘칠 정도로 많은데다, 윈도우에서도 멀쩡하게 허용하고 있는 터에 일개 프로그램에서 쓰지 말라고 할 수는 없는 것 아니겠습니까. 영 불가항력이 아닌 바에야, 프로그램상에 존재하는 문제의 해결을 사용자에게 떠넘기는 것도 별로 좋은 태도는 아니죠.


(1) 첫 번째 시도: PL/PM 파일의 수정

결국 소스 레벨에서의 해결밖에 방법이 없겠다 싶어서, 내부의 모듈들을 뒤졌습니다. 일단 두 개의 파일이 검색되었습니다.

1) site/bin/par.pl 의 _set_par_temp 서브루틴
2) site/lib/PAR/SetupTemp.pm 의 _get_par_user_tempdir 서브루틴

여기구나 싶어서, 이 두 부분에서 임시 폴더 작성에 사용되는 사용자 이름을 항상 OwlNetworks 로 돌려주도록 코드를 수정했습니다. 아래 그림처럼 말이죠.

저에 맞추어서 OwlNetworks 라고 적은 것 뿐, 다른 분들은 자신에게 맞추어 임의로 영문자 및 숫자를 섞어서 정하시면 됩니다.


그림 3. par.pl 의 _set_par_temp 서브루틴 중간에 $username = "OwlNetworks"; 라는 줄을 추가해 넣었습니다. 그림에는 나타나지 않았지만, SetupTemp.pm 의 _get_par_user_tempdir 서브루틴에도 동일한 코드를 삽입하였습니다.
그림 3. par.pl 의 _set_par_temp 서브루틴 중간에 $username = "OwlNetworks"; 라는 줄을 추가해 넣었습니다. 그림에는 나타나지 않았지만, SetupTemp.pm 의 _get_par_user_tempdir 서브루틴에도 동일한 코드를 삽입하였습니다.


결과는? 실패입니다. 여전히 만들어진 실행 바이너리는 사용자 이름이 포함된 폴더에 압축을 풀더군요. 임시 폴더의 경로를 만드는 코드가 다른 어디에도 존재하지 않았기 때문에, 이 수정이 제대로 동작하지 않는다면 아마도 PAR::Packer 가 컴파일시 이 코드를 사용하지 않는다는 추정이 가능했습니다. 그 때, 제 눈에 띈 주석 한 줄.

# The C version of this code appears in myldr/mktmpdir.c

....PAR::Packer 를 컴파일하기 전의 C 소스 레벨에서의 수정이 필요했던 것입니다. 그 이야기는, 이미 컴파일 된 상태로 제공되는 PPM 파일을 사용할 수 없다는 의미였습니다. 오리지날 소스의 수정이 필요하므로, CPAN 을 통한 설치도 안됩니다. 오 마이 갓. 저는 C 언어를 모릅니다. orz...


(2) 두 번째 시도: C 소스의 수정 후 재컴파일

지푸라기라도 잡는 심정으로, 제가 사용하고 있는 버전과 동일한 버전의 PAR::Packer 0.991 버전의 소스를 metacpan.org 을 통하여 다운로드 받았습니다.

제가 사용하는 ActivePerl 의 버전이 5.10.1 Build 1007 이고, 이 버전에서 PPM을 통해 제공되는 PAR 의 버전은 1.002, PAR::Packer 의 버전은 0.991 입니다. [ActivePerl과 최근 버전의 PAR/PAR::Packer 사이에 궁합이 묘하게 좋지 않아서, 5.10.1.1007 버전의 경우 제공되는 PAR/PAR::Packer PPM 의 버전은 조금 오래된 버전입니다.]

참고로, 공식적인 ActiveState PPM 에서 제공되는 5.10 버전의 PPM 목록에는 PAR::Packer 가 없습니다. ActiveState PPM 에서는 공식적으로 Win32 환경에서 PAR::Packer 는 컴파일 오류가 발생하는 것으로 되어 있습니다. PAR 의 경우에도 현재 최신 버전은 1.005이지만 등록은 1.002까지만 되어 있습니다. 다만 이 경우는 컴파일 실패가 아니라 아직 컴파일 및 테스트가 진행되지 않았기 때문인 점을 유의하시기 바랍니다.

그림 4. ActiveState 의 공식 PPM 에는 이와 같이 PAR::Packer 모듈이 컴파일에 실패하는 것으로 되어 있으며, 제공되지 않습니다. 그림에는 나오지 않았지만, 5.12 및 5.14 도 같습니다. http://code.activestate.com/ppm/PAR-Packer/
그림 4. ActiveState 의 공식 PPM 에는 이와 같이 PAR::Packer 모듈이 컴파일에 실패하는 것으로 되어 있으며, 제공되지 않습니다. 그림에는 나오지 않았지만, 5.12 및 5.14 도 같습니다. http://code.activestate.com/ppm/PAR-Packer/


따라서, PPM 으로 5.10.1 버전에서 PAR::Packer 바이너리를 구하려면 bribes.org PPM 레퍼지토리를 이용하여야 합니다. 여기에서 제공되는 버전 역시 0.991 버전입니다.

참고로, trouchelle PPM 레퍼지토리를 이용하면 PAR::Packer 1.008 버전을 다운로드 받을 수 있습니다만, 필자의 경우에는 적용시켜 본 결과 오류가 발생하여 실행 바이너리의 빌드가 불가능하였습니다.

(bribes, trouchelle 모두 ActivePerl 5.10 버전의 Perl Package Manager 를 이용하여 연결이 가능합니다.)


다운로드 받은 소스 파일의 압축을 푼 후, myldr/mktmpdir.c 파일을 찾아서 텍스트 에디터로 (읽지 못할 걸 알면서도) 열어보았습니다.

    /* "$TEMP/par-$USER" */

    stmp_len =
        strlen(tmpdir) +
        strlen(subdirbuf_prefix) +
        strlen(username) +
        strlen(subdirbuf_suffix) + 1024;


다행히, 파일에 주석이 잘 달려 있어서 쉽게 찾을 수 있었습니다. 아무리 C 를 모르는 저이지만, Perl 로 굴러먹던(..) 통밥으로 찾아보니 대충 뭐가 어떻게 돌아가는지는 알겠더군요. 그래서 위 코드 바로 앞에 이렇게 한 줄을 추가했습니다. 경로를 만들기 바로 직전에, username 을 강제로 OwlNetworks 로 변경하는 코드를 삽입한 것입니다.

        /* Temporarily fixed Korean(CP949/UTF16LE) Encoding Problem */

        username = "OwlNetworks";


그림 5. myldr/mktmpdir.c 파일의 수정을 끝낸 후의 모습. stmp_len 문자열 변수가 만들어지기 바로 전에 username 을 강제로 "OwlNetworks" 로 변경하는 라인을 한 줄 삽입하였습니다.
그림 5. myldr/mktmpdir.c 파일의 수정을 끝낸 후의 모습. stmp_len 문자열 변수가 만들어지기 바로 전에 username 을 강제로 "OwlNetworks" 로 변경하는 라인을 한 줄 삽입하였습니다.


이제 이 코드를 컴파일만 하면 됩니다. MinGW 가 설치된 상태이므로 gcc 컴파일러가 존재하기 때문에 충분히 가능한 작업입니다. CPAN 을 사용하지 못하지만, 이런 경우에는 일반적으로 (다 되는 것은 아닙니다) 아래와 같이 4줄의 명령어를 입력하면 됩니다.

perl makefile.pl
dmake
dmake test
dmake install



(3) PAR::Packer 의 컴파일 과정에서 겪은 오류들

그런데, 세 번째 과정인 dmake test 과정에서 자꾸 묘한 오류가 발생했습니다. 전혀 예상 못한 상황이었지요.

그림 6. PAR::Packer 0.991 버전의 dmake test 과정에서 발생한 오류. 최종적으로는 32번만 오류인 것으로 나옵니다만, 실상 31번 및 32번 모두 오류가 발생한 것으로 봐야 합니다. (리소스 영역이 잘못 생성된 것으로 추정되며, 아이콘과 관련된 문제로서 사실상 동일한 원인에 의한 것입니다.)
그림 6. PAR::Packer 0.991 버전의 dmake test 과정에서 발생한 오류. 최종적으로는 32번만 오류인 것으로 나옵니다만, 실상 31번 및 32번 모두 오류가 발생한 것으로 봐야 합니다. (리소스 영역이 잘못 생성된 것으로 추정되며, 아이콘과 관련된 문제로서 사실상 동일한 원인에 의한 것입니다.)


t/20-pp.t 의 테스트 과정 중 31번째와 32번째에서 오류가 계속 오류가 발생합니다.

31st: No resource section found in file ~~~~ at C:/usr/site/bin/Win32/Exe.pm line ~~~.
      Can't call method "remove" on an undefined value at C:/usr/site/bin/Win32/Exe.pm line ~~~.
32nd: Failed test.


혹시나 싶어서 그대로 dmake install 을 수행한 후 스크립트의 컴파일을 시도하였으나, 위 31번의 오류 메시지와 같은 내용의 오류를 내면서 빌드에 실패하였습니다.

그림 7. 테스트 오류를 무시하고 강제 설치 후 실행 바이너리 빌드 테스트를 시행한 결과. 위 31번과 똑같은 오류를 내면서 빌드 실패.
그림 7. 테스트 오류를 무시하고 강제 설치 후 실행 바이너리 빌드 테스트를 시행한 결과. 위 31번과 똑같은 오류를 내면서 빌드 실패.


Win32::Exe 모듈의 No resource section found in file 메시지로 구글링을 해 보니, 이 오류, 여러 사람 머리를 복잡하게 만든 오류더군요. 실행 파일을 만드는 과정에서 사용하는 Win32::Exe 모듈과 PAR::Packer 모듈 사이의 궁합 문제인 듯 한데, PAR::Packer 버전 및 Win32::Exe 의 버전에 따라서 발생하기도 하고 발생하지 않기도 하는 기묘한 문제였습니다. 구글링상에 나타나는 대부분의 문제는 Win32::Exe 버전 0.14 에서 발생하는 문제였는데, 제 경우는 Win32::Exe 버전 0.17 (최신 버전) 인데도 이런 문제가 발생했습니다.

직접 문제를 해결할 능력이 안 되기 때문에, 할 수 있는 것은 오류가 해결된 PAR::Packer 버전을 찾는 방법 뿐이었습니다. PAR::Packer 의 Change Log 를 열심히 뒤졌습니다.

그림 8. PAR::Packer 1.005 버전의 Change Log 내용. 이 오류가 해결되었다는 내용이 보입니다. (푸른색 음영 부분)
그림 8. PAR::Packer 1.005 버전의 Change Log 내용. 이 오류가 해결되었다는 내용이 보입니다. (푸른색 음영 부분)


1.005 버전에서 해당 오류가 해결된 것으로 나오는군요. 그래서 1.0.5 버전을 다운로드 받은 후 같은 내용으로 수정을 합니다. 그리고 컴파일. 어라? 이번엔 아예 dmake 과정에서 parldyn.exe 가 없다는 오류가 뜹니다. 제길.

그림 9. PAR::Packer 1.005 버전의 dmake 실패. parldyn.exe 파일을 찾을 수 없다는 오류가 나옵니다.
그림 9. PAR::Packer 1.005 버전의 dmake 실패. parldyn.exe 파일을 찾을 수 없다는 오류가 나옵니다.


다시 Change Log 를 뒤집니다. 바로 위에 있습니다. 좀 자세히 볼 걸.

그림 10. PAR::Packer 1.006 버전의 Change Log 내용. 이 오류가 해결되었다는 내용이 보입니다. (푸른색 음영 부분. 로그상으로는 딸기 펄의 문제로 되어 있지만, ActivePerl 에서도 똑같은 문제가 발생합니다.)
그림 10. PAR::Packer 1.006 버전의 Change Log 내용. 이 오류가 해결되었다는 내용이 보입니다. (푸른색 음영 부분. 로그상으로는 딸기 펄의 문제로 되어 있지만, ActivePerl 에서도 똑같은 문제가 발생합니다.)


1.006 버전의 소스를 다운로드 받아 myldr/mktmpdir.c 의 해당 부분을 수정한 후 다시 컴파일합니다. dmake test 도 무사히 통과합니다. dmake install 을 수행한 후 테스트를 수행합니다. 무사히 실행 바이너리가 만들어집니다. 실행도 잘 됩니다. 압축이 풀리는 임시 폴더도 강제 지정한 대로 잘 만들어집니다.

이제 실전 테스트만 남았습니다. VMWare Player 를 이용하여 사용자 이름이 한글인 윈도우 XP 를 기동한 후 실행해 봅니다. 아래 그림과 같이 매우 잘 실행됩니다. 만세!

그림 11. 그림 2와 같이 사용자 이름이 한글인 윈도우 XP 환경에서 새로 빌드한 실행 바이너리를 실행한 모습. 정상적으로 실행이 된다.
그림 11. 그림 2와 같이 사용자 이름이 한글인 윈도우 XP 환경에서 새로 빌드한 실행 바이너리를 실행한 모습. 정상적으로 실행이 된다.


참고로, 앞의 (1) 에서 시도한 바 있는, 사용자 이름으로 TEMP 폴더의 경로를 만드는 서브루틴이 포함된 두 개의 PL/PM 파일은 수정하지 않아도 됩니다. 이 두 파일은 빌드 과정에서는 사용되지 않습니다. (실행 파일을 만들지 않고 단순히 par 파일을 만들거나, standalone pl 파일을 만들 때에는 이 코드가 사용이 됩니다.)




4. 남은 이야기


사실, 이 부분을 제대로 해결하자면, 해당 코드 부분에서 사용자 이름의 인코딩을 확인하여 적절히 처리를 해 주도록 변경하는 것이 정석이겠습니다. 그러나 앞에서도 말한 바와 같이 저는 C 언어를 모릅니다. 게다가 C 에서의 인코딩 처리가 Perl 처럼 간단(?)하지 않다는 것은 아무리 저라도 익히 짐작할 수 있습니다. 그래서, 일단 임시방편으로 이와 같은 방법으로 처리를 하였습니다.

실제로 1.013 버전에서는, 사용자 이름이 한글인 경우 이를 16진수로 변환하여 영문자-숫자 형태로 변경한 후에 사용하도록 패치되었습니다. (2012-03-27 추가)


제가 PAR::Packer 를 다시 컴파일하는 과정에서 겪은 오류들은, 어떤 버전의 Perl 및 모듈을 선택하느냐에 따라 겪게 될 수도, 아닐 수도 있습니다. (제 경우 ActivePerl 5.10.1.1007, PAR 1.002, PAR::Packer 1.006, Win32::Exe 0.17 의 조합으로 성공하였습니다. ) 만약 오류가 발생하는 경우 PAR::Packer 의 버전을 변경해 가면서 여러 버전에서 확인을 해 보셔야만 합니다.

참고로, PAR::Packer 1.011 버전은 Perl 버전은 최소 5.8.1을, PAR 버전은 1.004 를 요구합니다. 또한 PAR::Packer 의 최신 버전인 1.012 버전은 PAR 버전이 1.005 (최신 버전) 여야만 합니다. 따라서 ActivePerl 에서 PPM을 통해 설치할 수 있는 PAR 1.002 버전을 기준으로 본다면 설치할 수 있는 PAR::Packer 는 최대 1.010 버전까지입니다. 전술한 바와 같이, trouchelle PPM 레퍼지토리에서 받을 수 있는 PAR::Packer 버전 1.008의 경우 제 시스템에서는 오류가 발생하였습니다.




5. 덧붙임 (2012/01/30 추가)


이 글의 첫머리에 덧붙인 것과 같이, 이 문제는 PAR::Packer 가 사용자 이름이 한글인 경우를 충분히 고려하지 않은 문제로서, 이미 제작자가 이에 관한 패치를 하여 CVS에 반영하였기 때문에, 이 문제를 해결한 버전인 1.013 버전을 설치하면 해결됩니다.

그러나 필자는, 위와 같은 패치 방법은 다른 용도로 이용할 수 있다고 생각합니다. 그래서 이에 관한 이야기를 조금 더 해 보고자 합니다. 이하의 이야기는 PAR::Packer 를 패키징 도구로 사용하는 Perl 개발자에게만 유용하며, 일반 이용자들은 읽을 필요가 없습니다.


(1) PAR::Packer 의 임시 폴더 생성 방식의 무의미함

아마도, PAR::Packer 의 제작자가 패키지의 압축이 풀리는 폴더를 만들면서 그 폴더명에 사용자 이름을 넣게 된 이유는, Perl의 주 무대인 xNIX(유닉스/리눅스. 이하 편의상 리눅스 환경이라고 통칭하겠습니다) 환경이 여러 사람이 함께 사용하는 환경이기 때문에, 권한 문제나 여러 사람이 사용하는 패키지가 서로 섞이는 등의 여러 가지 문제를 미연에 방지하기 위함인 것으로 생각됩니다. (제 리눅스 환경에 대한 지식은 매우 일천한 관계로, 더 이상의 자세한 논의는 무리입니다.)

그러나, 윈도우 환경은 이런 리눅스 환경과 차이가 있습니다. 공용 컴퓨팅 환경인 리눅스 환경과 달리, 대부분의 윈도우 머신은 1인의 사용자가 사용하는 개인 컴퓨팅 환경입니다. 그래서 특별한 상황이 아니라면 다른 사람의 시스템 환경을 고려해야 할 필요성이 거의 없습니다. 게다가, 애초에 임시 폴더 자체가 사용자 별로 다르게 만들어지기 때문에, 시스템에서 주어지는 임시 폴더 경로를 그대로 받아 사용하기만 한다면 권한 문제가 발생할 여지가 없습니다. 따라서, 이런 PAR::Packer 의 임시 폴더 네이밍 방식은, 최소한 윈도우즈용 Perl 에 대해서는, "전혀"라고까지는 하지 않겠습니다만(개발 환경에서는 필요성이 있을 수도 있으니까) 최소한 만들어진 응용프로그램을 사용하는 사용자의 입장에서는 필요가 없는 절차라고 할 수 있습니다. 그냥 다른 프로그램에서 하는 대로, 프로그램 이름 (예를 들면 PAR-Packer) 으로 임시 폴더를 만들고 그 안에 압축을 풀면 될 일이죠.


(2) 사고의 전환: 생산자/응용프로그램 구분으로의 활용

그러나, 이왕 만들어져 있는 코드, 이런 식으로 활용할 수도 있지 않을까 싶습니다. 기존의 사용자 구분의 용도로 만들어진 이 코드를, 코드 수정을 통해 프로그램 생산자 구분의 방식으로, 혹은 어플리케이션 구분의 방식으로 이용하면 어떨까 싶은 것이죠.

예를 들면 이런 것입니다. PAR::Packer 는 일단 임시 폴더에 풀린 패키지 파일들을, 패키징 시 특별한 옵션 (-C 옵션)을 주지 않는 한 삭제하지 않습니다. 2회차 이후의 실행에서 패키지를 다시 풀어놓는 시간을 절약함으로써 프로그램 실행 속도를 끌어올리기 위한 것이죠. 최초로 패키지를 풀고 해석하는 데 상당히 시간이 오래 걸리기 때문에, 이후의 실행 속도를 생각하면 이것은 상당히 효과적인 정책입니다. 그러나 이렇게 하면 일단 임시 폴더 내에 기록된 파일들이 사용자가 따로 삭제하지 않는 한 지워지지 않고 계속 남아 있기 때문에, 차후 프로그램을 삭제하거나 버전업을 하였을 때에도 이 내용들이 그냥 남아서 디스크의 용량을 차지하게 됩니다. 윈도우 안에 임시 폴더라는 게 있는지도 모르는 일반 사용자들이 널려 있는 판국에, 이것은 절대 좋은 상황은 아닙니다. 제 경우는 조금 큰 규모의 프로그램을 몇 번 버전업 했더니만 PAR::Packer 임시 폴더가 100메가바이트를 넘어가는 상황까지도 겪었습니다.

그렇다면 언인스톨러 비슷하게 임시 폴더 삭제용 툴을 따로 배포하면 되지 않느냐. 물론 그렇게 하는 것이 정답이겠지만, 이것이 그렇게 만만하지가 않습니다. 본문의 사진에서 한번 보여드린 바 있지만, PAR::Packer 는 [윈도우 임시 폴더]\[PAR-사용자 이름 폴더] 이하에 패키지들 간의 섞임을 막기 위해 한 번 더 temp-#####.. 와 같은 무작위의 임시 폴더를 만들고 그 안에 패키지의 압축을 풀기 때문입니다. 이 temp-#####.. 폴더의 이름을 알기가 어렵기 때문에, 그 프로그램에 대한 임시 폴더만 선택적으로 삭제하기가 상당히 까다로워집니다. 그냥 [PAR-사용자 이름] 폴더 자체를 날려 버려도 사실 일반 사용자 입장에서는 큰 문제가 없을 것 같기는 하지만, 이 역시 100% 문제가 없을 것이라고 장담할 수 있을지 모르겠습니다.

그래서, 이 사용자 이름을 입력하는 부분에, 제작자명 또는 프로그램명을 입력하면 어떨까 하는 생각을 해 보았습니다. 위에서 논의한 패치 방법을 이용하여 사용자 이름 대신 제작자명 또는 프로그램명을 입력한 후 PAR::Packer 를 다시 컴파일하면, 그 환경에서 제작된 프로그램은 항상 지정된 폴더명으로 임시 폴더를 만들게 되므로, 패키징할 때에 -C 옵션을 사용하지 않더라도 차후 임시 폴더를 관리하는 데 (언인스톨러를 제공하는 데) 상당히 좋은 환경이 만들어지게 됩니다. 프로그램별로 혹은 제작자별로 독립적으로 만들어지는 정해진 폴더를 별다른 위험 부담 없이 살포시 날리면 되기 때문입니다.

☞ 태그: PAR::Packer, Win32, 한글 사용자 이름,

☞ 트랙백 접수 모듈이 설치되지 않았습니다.

☞ 덧글이 1 개 있고, 트랙백이 없습니다.

덧글을 남기시려면 여기를 클릭하십시오.

□ keedi 님께서 2011-12-29 14:28:32 에 작성해주셨습니다.

꼼꼼한 버그 리포팅++
@owl0908++
@gypark++

https://rt.cpan.org/Public/Bug/Display.html?id=73491

곧 해결되겠네요. ;-)

⇒ 부엉이 님께서 2011-12-31 04:40:44 에 답글을 작성하셨습니다.

감사합니다.
CPAN에 리포팅하는 수고를 마다하지 않으신 gypark 님의 노고가 크죠. ^^
다음 릴리즈에 해결된다고 하니 일단 기대를 해봅니다.

그나저나 1.012에서 --gui 옵션이 제대로 안 돌아가던데, 그 버그는 해결이 됐으려나 모르겠습니다. ^^

[489] < [418] [416] [415] [413] [412] ... [410] ... [408] [407] [406] [405] [403] > [19]

(C) 2000-2023, Owl-Networks. Powered by Perl. 이 페이지는 HTML 5 표준에 따라 작성되었습니다.