이식성 있는 Perl 작성하기

이식성 있는 Perl 작성하기 (perlport)

Perl은 수많은 운영체제에서 실행돼요. 대부분이 공통점을 많이 공유하지만, 저마다 독특한 특징도 가지고 있죠. 이 문서는 무엇이 이식성 있는 Perl 코드를 이루는지 알아내도록 도와주는 게 목적이에요. 그래서 한번 이식성을 목표로 결정을 내리면, 선이 어디에 그어져 있는지 알고 그 안에 머물 수 있게 되는 거예요.

특정 컴퓨터의 장점을 100% 활용하는 것과 다양한 컴퓨터의 장점을 모두 활용하는 것 사이에는 트레이드오프가 있어요. 당연히 범위를 넓히고 다양해질수록 공통 요소는 줄어들고, 특정 작업을 수행하기 위해 운영할 수 있는 공통 지대는 점점 작아지죠. 그래서 문제를 공격하기 시작할 때, 트레이드오프 곡선의 어느 부분에서 운영하고 싶은지 고려하는 게 중요해요. 특히, 지금 코딩하는 작업이 이식성이라는 완전한 일반성을 갖는 게 중요한지, 아니면 지금 당장 작업을 끝내는 게 중요한지 결정해야 해요. 이것이 가장 어려운 선택이에요. 나머지는 쉽죠. 왜냐하면 Perl은 어느 쪽으로 접근하든 많은 선택지를 제공하니까요.

다른 방식으로 보면, 이식성 있는 코드를 쓰는 것은 보통 사용 가능한 선택지를 의도적으로 제한하는 것에 관한 거예요. 당연히 그렇게 하려면 훈련과 희생이 필요해요. 이식성과 편의성의 곱은 상수일지도 몰라요. 경고는 드렸어요.

두 가지 중요한 점을 알아두세요:

모든 Perl 프로그램이 이식성 있어야 하는 건 아니에요

Unix 도구를 서로 붙이는 접착제로 Perl을 쓰거나, Macintosh 앱의 프로토타입을 만들거나, Windows 레지스트리를 관리하는 데 쓰는 데 아무 이유가 없어요. 어떤 프로그램에서 이식성을 목표로 하는 게 어떤 이유로든 말이 안 된다면, 그냥 신경 쓰지 마세요.

거의 모든 Perl은 이미 이식성 이 있어요

이식성 있는 Perl 코드를 만드는 게 어렵다고 생각해선 안 돼요. 그렇지 않아요. Perl은 다른 플랫폼에서 사용 가능한 것과 그 기능을 사용하는 수단 사이의 간극을 메우기 위해 최선을 다해요. 따라서 거의 모든 Perl 코드는 수정 없이 어떤 머신에서도 실행돼요. 하지만 이식성 있는 코드를 쓰는 데는 몇 가지 중요한 이슈가 있고, 이 문서는 전적으로 그 이슈에 관한 거예요.

일반 규칙은 이거예요: 다양한 플랫폼에서 흔히 수행되는 작업에 접근할 때는 이식성 있는 코드를 쓰는 걸 생각하세요. 그러면 선택할 수 있는 구현 선택지를 별로 희생하지 않으면서, 사용자에게 많은 플랫폼 선택지를 줄 수 있어요. 반면, 특정 플랫폼의 독특한 기능을 활용해야 할 때는—Unix, Windows, VMS 등 시스템 프로그래밍에서 흔히 그렇듯—플랫폼별 코드를 고려하세요.

코드가 두세 개 운영체제에서만 실행된다면, 그 특정 시스템들의 차이점만 고려하면 될 거예요. 중요한 것은 코드가 어디서 실행될지 결정하고, 그 결정을 신중하게 내리는 거예요.

아래 자료는 세 주요 섹션으로 나뉘어요: 이식성의 주요 이슈("ISSUES"), 플랫폼별 이슈("PLATFORMS"), 그리고 다양한 포트에서 다르게 동작하는 내장 Perl 함수("FUNCTION IMPLEMENTATIONS").

이 정보는 완전하다고 간주하면 안 돼요. 몇몇 포트의 특이성에 관한 일시적인 정보를 포함할 수 있고, 거의 대부분이 끊임없이 진화하는 상태에 있으니까요. 따라서 이 자료는 영원한 작업 중(Under Construction)으로 간주해야 해요.

출처: Perl 공식 문서 - perlport

이슈 (ISSUES)

뉴라인 (Newlines)

대부분의 운영체제에서 파일의 라인은 뉴라인으로 종료돼요. 뉴라인으로 무엇을 쓰는지는 OS마다 달라질 수 있어요. Unix는 전통적으로 \012를 쓰고, 어떤 DOS식 I/O는 \015\012를 쓰며, Mac OS는 \015를, z/OS는 \025를 써요.

Perl은 "논리적" 뉴라인을 나타내기 위해 \n을 사용하는데, 논리적으로 무엇이냐는 사용 중인 플랫폼에 달려 있을 수 있어요. MacPerl에서 \n은 항상 \015를 뜻해요. EBCDIC 플랫폼에서 \n\025\045일 수 있어요. DOS식 perl에서 \n은 보통 \012를 뜻하지만, 파일을 "텍스트" 모드로 접근할 때 perl은 :crlf 레이어를 사용해서 읽거나 쓰는 방향에 따라 그것을 \015\012로 번역해요. Unix도 canonical 모드의 tty에서 같은 일을 해요. \015\012는 보통 CRLF라고 불러요.

텍스트 라인에서 뒤쪽 뉴라인을 잘라내려면 chomp를 사용하세요. 기본 설정으로 그 함수는 뒤쪽 \n 문자를 찾아서 이식성 있게 잘라내요.

바이너리 파일(또는 바이너리 모드의 텍스트 파일)을 다룰 때는 chomp를 사용하기 전에 $/을 파일 형식에 맞는 적절한 값으로 명시적으로 설정해야 해요.

"텍스트" 모드 번역 때문에 DOS식 perl은 "텍스트" 모드로 접근한 파일에서 seektell을 쓰는 데 제한이 있어요. tell에서 얻은 위치로만 seek하도록 지키면(그 외는 하지 말고), 보통 "텍스트" 모드에서도 seektell를 자유롭게 쓸 수 있어요. 임의 값으로 seektell 또는 다른 파일 연산을 쓰는 건 이식성 있지 않을 수 있어요. 다만 파일에 binmode를 쓰면 안전하게 임의 값으로 seektell를 할 수 있어요.

소켓 프로그래밍에서 흔한 오해는 \n이 어디서나 \012와 같다는 거예요. 흔한 인터넷 프로토콜 같은 프로토콜을 쓸 때는 \012\015가 명시적으로 요구되며, 논리적 \n\r(캐리지 리턴)의 값은 믿을 수 없어요.

print $socket "Hi there, client!\r\n";      # WRONG
print $socket "Hi there, client!\015\012";  # RIGHT

하지만 \015\012(또는 \cM\cJ, 또는 \x0D\x0A)를 쓰는 건 지루하고 보기 안 좋을 뿐 아니라, 코드를 유지 보수하는 사람들에게 혼란을 줄 수 있어요. 그래서 Socket 모듈은 원하는 사람들을 위해 "올바른 것(The Right Thing)"을 제공해요.

use Socket qw(:DEFAULT :crlf);
print $socket "Hi there, client!$CRLF"      # RIGHT

소켓에서 읽을 때, 기본 입력 레코드 구분자 $/\n이라는 걸 기억하세요. 하지만 견고한 소켓 코드는 라인 끝으로 \012 또는 \015\012를 인식할 거예요:

while (<$socket>) {  # NOT ADVISABLE!
    # ...
}

CRLF와 LF 둘 다 LF로 끝나기 때문에, 입력 레코드 구분자를 LF로 설정하고 나중에 어떤 CR든 제거할 수 있어요. 이렇게 쓰는 게 더 나아요:

use Socket qw(:DEFAULT :crlf);
local($/) = LF;      # not needed if $/ is already \012

while (<$socket>) {
    s/$CR?$LF/\n/;   # not sure if socket uses LF or CRLF, OK
#   s/\015?\012/\n/; # same thing
}

이 예제는 이전 예제보다 선호돼요—Unix 플랫폼에서조차—왜냐하면 이제 \015(\cM)들이 모두 제거되니까요(그리고 큰 환호가 있었지요).

비슷하게, 텍스트 데이터를 반환하는 함수—예를 들어 웹 페이지를 가져오는 함수—는 데이터를 반환하기 전에 로컬 뉴라인 표현으로 아직 번역되지 않았다면 뉴라인을 번역해야 할 때가 있어요. 한 줄 코드면 충분한 경우가 많아요:

$data =~ s/\015?\012/\n/g;
return $data;

이 중 일부는 혼란스러울 수 있어요. 여기 참고용으로 ASCII CR과 LF 문자 표가 있어요. 출력해서 지갑에 넣어 두세요.

LF  eq  \012  eq  \x0A  eq  \cJ  eq  chr(10)  eq  ASCII 10
CR  eq  \015  eq  \x0D  eq  \cM  eq  chr(13)  eq  ASCII 13

         | Unix | DOS  | Mac  |
    ---------------------------
    \n   |  LF  |  LF  |  CR  |
    \r   |  CR  |  CR  |  LF  |
    \n * |  LF  | CRLF |  CR  |
    \r * |  CR  |  CR  |  LF  |
    ---------------------------
    * text-mode STDIO

Unix 열은 canonical 모드의 직렬 라인(예: tty)에 접근하지 않는다고 가정해요. 접근한다면 입력에서 CR이 "\n"이 되고, 출력에서 "\n"이 CRLF가 돼요.

이것들은 Perl에서 \n\r의 가장 흔한 정의일 뿐이에요. 다른 정의도 있을 수 있어요. 예를 들어 z/OS(OS/390)나 OS/400(ILE 사용, PASE는 ASCII 기반) 같은 EBCDIC 구현에서는 위 내용이 "Unix"와 비슷하지만 코드 번호가 바뀌어요:

LF  eq  \025  eq  \x15  eq  \cU  eq  chr(21)  eq  CP-1047 21
LF  eq  \045  eq  \x25  eq           chr(37)  eq  CP-0037 37
CR  eq  \015  eq  \x0D  eq  \cM  eq  chr(13)  eq  CP-1047 13
CR  eq  \015  eq  \x0D  eq  \cM  eq  chr(13)  eq  CP-0037 13

         | z/OS | OS/400 |
    ----------------------
    \n   |  LF  |  LF    |
    \r   |  CR  |  CR    |
    \n * |  LF  |  LF    |
    \r * |  CR  |  CR    |
    ----------------------
    * text-mode STDIO

숫자의 엔디안과 너비 (Numbers endianness and Width)

서로 다른 CPU는 정수와 부동소수점 숫자를 서로 다른 순서(엔디안)와 너비(오늘날 가장 흔한 건 32비트와 64비트)로 저장해요. 이는 프로그램이 바이너리 형식의 숫자를 한 CPU 아키텍처에서 다른 CPU 아키텍처로 전송할 때—보통 네트워크 연결로 "실시간"이거나 디스크 파일이나 테이프 같은 보조 저장소에 저장할 때—영향을 줘요.

충돌하는 저장 순서는 숫자를 완전히 엉망으로 만들죠. 리틀엔디안 호스트(Intel, VAX)가 0x12345678(10진수 305419896)을 저장하면, 빅엔디안 호스트(Motorola, Sparc, PA)는 0x78563412(10진수 2018915346)로 읽어요. Alpha와 MIPS는 둘 다 가능해요: Digital/Compaq은 리틀엔디안 모드로 사용하고, SGI/Cray는 빅엔디안 모드로 사용해요. 네트워크(소켓) 연결에서 이 문제를 피하려면 packunpack 형식인 nN, 즉 "네트워크" 순서를 사용하세요. 이것들은 이식성이 보장돼요.

Perl 5.10.0부터는 >< 수정자를 사용해 빅엔디안 또는 리틀엔디안 바이트 순서를 강제할 수도 있어요. 이것은 예를 들어 부호 있는 정수나 64비트 정수를 저장하려고 할 때 유용해요.

네이티브 형식으로 패킹된 데이터 구조를 풀어서 플랫폼의 엔디안을 탐험할 수 있어요:

print unpack("h*", pack("s2", 1, 2)), "\n";
# '10002000' on e.g. Intel x86 or Alpha 21064 in little-endian mode
# '00100020' on e.g. Motorola 68040

엔디안 아키텍처를 구별해야 한다면 이렇게 설정된 변수 중 하나를 사용할 수 있어요:

$is_big_endian   = unpack("h*", pack("s", 1)) =~ /01/;
$is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;

너비 차이는 엔디안이 같은 플랫폼 사이에서도 잘림(truncation)을 일으킬 수 있어요. 너비가 짧은 플랫폼은 숫자의 상위 부분을 잃게 돼요. 이 문제에 대한 좋은 해결책은 없어요. 원시 바이너리 숫자를 전송하거나 저장하는 걸 피하는 것 외에는요.

이 두 문제를 두 가지 방법으로 우회할 수 있어요. 숫자를 원시 바이너리 대신 항상 텍스트 형식으로 전송·저장하거나, Data::DumperStorable 같은 모듈(Perl 5.8부터 포함) 사용을 고려하는 거예요. 모든 데이터를 텍스트로 유지하면 일이 크게 단순해져요.

파일과 파일시스템 (Files and Filesystems)

요즘 대부분의 플랫폼은 파일을 계층적으로 구조화해요. 그래서 모든 플랫폼이 시스템의 파일을 고유하게 식별하는 "경로(path)"라는 개념을 지원한다고 가정하는 게 합리적으로 안전해요. 다만 그 경로가 실제로 어떻게 쓰이는지는 상당히 달라져요.

비슷하긴 하지만, 파일 경로 명세는 Unix, Windows, Mac OS, OS/2, VMS, VOS, RISC OS, 그리고 아마 다른 것들 사이에서 다 달라요. 예를 들어 Unix는 단일 루트 디렉터리라는 우아한 아이디어를 가진 몇 안 되는 OS 중 하나예요.

DOS, OS/2, VMS, VOS, Windows는 /를 경로 구분자로 Unix와 비슷하게 동작하거나, 자신들만의 특이한 방식(여러 루트 디렉터리나 NIL:, LPT: 같은 다양한 "루트 없는" 장치 파일)으로 동작할 수 있어요.

Mac OS 9와 그 이전은 / 대신 :를 경로 구분자로 사용했어요.

파일시스템은 하드 링크(link)나 심볼릭 링크(symlink, readlink, lstat)를 지원하지 않을 수도 있어요.

파일시스템은 접근 타임스탬프나 변경 타임스탬프(즉 유일한 이식성 있는 타임스탬프가 수정 타임스탬프인 경우)를 지원하지 않을 수도 있고, 어떤 타임스탬프든 1초 단위로만 할 수도 있어요(예: FAT 파일시스템은 시간 단위를 2초로 제한해요).

"inode 변경 타임스탬프"(-C 파일테스트)는 실제로 "생성 타임스탬프"일 수 있어요(Unix에서는 그게 아니에요).

VOS perl은 /를 경로 구분자로 사용하는 Unix 파일명을 에뮬레이션할 수 있어요. 네이티브 경로명 문자인 greater-than, less-than, number-sign, percent-sign은 항상 허용돼요.

RISC OS perl은 /를 경로 구분자로 사용하는 Unix 파일명을 에뮬레이션하거나, 네이티브로 가서 .를 경로 구분자로, :로 파일시스템과 디스크 이름을 표시할 수 있어요.

Unix 파일시스템 접근 의미론을 가정하지 마세요: 읽기, 쓰기, 실행이 권한의 전부라고 가정하지 말고, 그것들이 존재하더라도 그 의미론(예: 디렉터리에서 r, w, x가 무엇을 의미하는지)이 Unix의 것이라고 가정하지 마세요. 다양한 Unix/POSIX 호환성 레이어는 보통 chmod 같은 인터페이스가 동작하게 하려고 하지만, 때로는 그냥 좋은 매핑이 없을 수도 있어요.

File::Spec 모듈은 경로 명세를 조작하고 각 플랫폼의 네이티브 형식으로 결과를 반환하는 메서드를 제공해요. Unix 스타일 경로가 Perl이 지원하는 모든 플랫폼에서 이해되므로 이게 불필요한 경우가 많지만, Unix 구문을 이해하지 못하는 네이티브 유틸리티를 위해 네이티브 경로를 생성해야 하거나, 알 수 없는(그래서 아마 네이티브) 구문의 경로나 경로 구성요소를 다룰 때는 File::Spec이 친구예요. 두 가지 짧은 예제예요:

use File::Spec::Functions;
chdir(updir());        # go up one directory

# Concatenate a path from its components
my $file = catfile(updir(), 'temp', 'file.txt');
# on Unix:    '../temp/file.txt'
# on Win32:   '..\temp\file.txt'
# on VMS:     '[-.temp]file.txt'

일반적으로 프로덕션 코드는 파일 경로를 하드코딩하면 안 돼요. 사용자가 제공하거나 설정 파일에서 읽게 하는 게 더 좋아요. 파일 경로 구문이 머신마다 다르다는 걸 명심하세요.

이것은 Makefile과 테스트 스위트 같은 스크립트에서 특히 눈에 띄는데, 종종 서브디렉터리에 대해 /을 경로 구분자로 가정해요.

또한 유용한 건 표준 배포의 File::Basename으로, 경로명을 조각(기본 파일명, 디렉터리 전체 경로, 파일 접미사)으로 나눠줘요.

단일 플랫폼에서도(Unix를 단일 플랫폼이라고 부를 수 있다면), /etc/passwd, /etc/sendmail.conf, /etc/resolv.conf 또는 심지어 /tmp/ 같은 특정 시스템별 파일이나 디렉터리의 존재나 내용을 믿지 마세요. 예를 들어 /etc/passwd가 존재할 수 있지만, 시스템이 어떤 형태의 강화된 보안을 사용해서 암호화된 비밀번호를 포함하지 않을 수도 있어요. 또는 NIS를 사용해서 모든 계정을 포함하지 않을 수도 있어요. 코드가 그런 파일에 의존해야 한다면, 파일과 그 형식에 대한 설명을 코드의 문서에 포함하고, 사용자가 파일의 기본 위치를 쉽게 재정의하게 하세요.

텍스트 파일이 뉴라인으로 끝날 거라고 가정하지 마세요. 그래야 하지만, 사람들이 잊어버리거든요.

test.plTest.pl 처럼 대소문자만 다른 같은 이름의 파일이나 디렉터리를 두 개 가지지 마세요. 많은 플랫폼이 대소문자 구분 없는(또는 적어도 대소문자 관대한) 파일명을 가지니까요. 또한 이름에 (. 제외한) 비단어 문자를 넣지 말고, 최대 이식성을 위해 8.3 규약으로 유지하세요. 다소 부담스러워 보여도요.

마찬가지로, AutoSplit 모듈을 사용할 때는 함수를 8.3 명명 및 대소문자 구분 없는 규약으로 유지하려고 하세요. 또는 적어도 결과 파일이 (대소문자 구분 없이) 고유한 첫 8자를 갖도록 하세요.

파일명의 공백은 대부분의 시스템에서 허용되지만, 전부는 아니고, 허용되는 시스템에서조차 어떤 유틸리티는 그런 공백에 혼란을 겪을 수 있어요.

많은 시스템(DOS, VMS ODS-2)은 파일명에 .을 하나 이상 가질 수 없어요.

>가 파일명의 첫 문자가 아닐 거라고 가정하지 마세요. 항상 3-인자 형식의 open을 사용하세요:

open my $fh, '<', $existing_file) or die $!;

2-인자 open은 마법적이라서 파일명의 >, <, | 같은 문자를 번역할 수 있는데, 보통 그건 잘못된 일이에요. sysopen과 3-인자 open에는 이 문제가 없어요.

파일명의 일부로 :을 사용하지 마세요. 많은 시스템이 그걸 자신들의 의미론에 사용하니까요(Mac OS Classic은 경로명 구성요소 분리에, 많은 네트워킹 스킴과 유틸리티는 노드명과 경로명 분리에 쓰는 등). 같은 이유로 @, ;, |도 피하세요.

경로명에서 두 개의 선행 슬래시 //를 하나로 접을 수 있다고 가정하지 마세요. 어떤 네트워킹과 클러스터링 파일시스템은 그것에 특별한 의미론이 있으니까요. 운영체제가 정리하게 두세요.

ANSI C가 정의한 이식성 있는 파일명 문자 는 이래요:

a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
. _ -

그리고 -는 첫 문자가 되면 안 돼요. 초정확해지고 싶다면, 대소문자 구분 없이 8.3 명명 규약 안에 머물러야 해요(모든 파일과 디렉터리는 이름을 소문자로 만들고 . 앞(있다면) 8자, . 뒤(있다면) 3자로 잘랐을 때 한 디렉터리 내에서 고유해야 해요). (그리고 디렉터리 이름에는 .을 쓰지 마세요.)

Windows에서 파일이나 디렉터리 이름 끝의 추가 .는 대부분의 상황에서 무시되고, 점만 세 개 이상 포함한 디렉터리 이름은 일부 API에서 현재 디렉터리로 취급돼요.

시스템 상호작용 (System Interaction)

모든 플랫폼이 명령줄을 제공하는 건 아니에요. 이들은 보통 사용자 상호작용을 위해 GUI(그래픽 사용자 인터페이스)에 주로 의존하는 플랫폼이에요. 명령줄 인터페이스를 요구하는 프로그램은 어디서나 동작하지 않을 수도 있어요. 이것은 아마 프로그램 사용자가 처리할 문제이므로, 밤새 걱정하지 마세요.

어떤 플랫폼은 시스템이 열어둔 파일을 삭제하거나 이름을 바꾸지 못해요. 파일 권한이나 소유자 같은 파일시스템 메타정보 변경에도 이 제한이 적용될 수 있어요. 파일을 다 썼으면 close하는 걸 기억하세요. 열린 파일을 unlink하거나 rename하지 마세요. 이미 tie되거나 열린 파일을 tie하거나 open하지 마세요. 먼저 untie하거나 close하세요.

쓰기 위해 같은 파일을 한 번에 두 번 이상 열지 마세요. 어떤 운영체제는 그런 파일에 강제 잠금을 걸거든요.

디렉터리에 대한 쓰기/수정 권한이 그 디렉터리에 파일/디렉터리를 추가하거나 삭제할 권리를 준다고 가정하지 마세요. 그것은 파일시스템별로 달라요: 어떤 파일시스템에서는 파일/디렉터리 자체에 쓰기/수정 권한도(또는 오직 그 권한만) 필요해요. 어떤 파일시스템(AFS, DFS)에서는 디렉터리 항목을 추가/삭제하는 권한이 완전히 별개의 권한이에요.

단일 unlink가 파일을 완전히 제거한다고 가정하지 마세요: 어떤 파일시스템(가장 두드러지게 VMS의 것)은 버전이 매겨진 파일시스템이고, unlink는 가장 최근 버전만 제거해요(그 플랫폼의 네이티브 도구도 기본적으로 가장 최근 버전만 제거하므로 모든 버전을 제거하지 않아요). 파일의 모든 버전을 제거하는 이식성 있는 관용구는 이래요:

1 while unlink "file";

이것은 파일이 어떤 이유로 삭제할 수 없으면(보호됨, 없음 등) 종료돼요.

특정 환경 변수가 %ENV에 존재할 거라고 믿지 마세요. %ENV 항목이 대소문자 구분이거나 대소문자를 보존한다고 믿지 마세요. %ENV = ();이라고 해서 %ENV를 비우려고 하지 마세요. 정말 해야 한다면 $^O ne 'VMS'를 조건으로 만들어야 해요. VMS에서 %ENV 테이블은 프로세스별 키-값 문자열 테이블 이상이니까요.

VMS에서 %ENV 해시의 어떤 항목은 키가 읽기에 사용될 때 이전에 존재하지 않았다면 동적으로 생성돼요. $ENV{HOME}, $ENV{TERM}, $ENV{PATH}, $ENV{USER}의 값은 동적으로 생성되는 것으로 알려져 있어요. 동적으로 생성되는 특정 이름은 VMS의 C 라이브러리 버전에 따라 다를 수 있고, 문서화된 것보다 더 많이 존재할 수 있어요.

VMS에서는 기본적으로 %ENV 해시에 대한 변경이 perl이 종료된 후에도 지속돼요. 같은 프로세스에서 perl을 다음에 호출하면 일시적이어야 할 환경 설정을 부지중에 상속받을 수 있어요.

신호나 %SIG에 어떤 것도 의존하지 마세요.

파일명 글로빙에 의존하지 마세요. 대신 opendir, readdir, closedir를 사용하세요.

프로그램별 환경 변수나 프로그램별 현재 디렉터리에 의존하지 마세요.

$!의 특정 값에 의존하지 마세요. 숫자든 특히 문자열 값이든요. 사용자가 로케일을 바꿔서 오류 메시지가 그들의 언어로 번역될 수 있어요. POSIXish 환경을 신뢰할 수 있다면, Errno 모듈이 정의한 ENOENT 같은 심볼을 이식성 있게 사용할 수 있어요. 그리고 실패한 시스템 호출 직후를 제외하고는 $!의 값에 전혀 의존하지 마세요.

명령 이름 대 파일 경로명 (Command names versus file pathnames)

system이나 exec로 명령이나 프로그램을 호출하는 데 사용된 이름을, 그 명령이나 프로그램의 실행 코드를 담은 파일의 존재를 테스트하는 데도 사용할 수 있다고 가정하지 마세요. 첫째, 많은 시스템에 셸이나 OS에 내장된 "내부" 명령이 있고, 이 명령들은 호출될 수는 있어도 대응하는 파일이 없어요. 둘째, 어떤 운영체제(예: Cygwin, OS/2, VOS)는 실행 파일에 필수 접미사를 요구해요. 이 접미사는 일반적으로 명령 이름에는 허용되지만 필수는 아니에요. 그래서 perl 같은 명령이 운영체제에 따라 perl, perl.exe, perl.pm 이라는 파일에 존재할 수 있어요. Config 모듈의 $Config{_exe} 변수는 실행 접미사(있다면)를 담고 있어요. 셋째, VMS 포트는 $^X$Config{perlpath}를 추가 처리가 필요하지 않도록 신중하게 설정해요. 그게 다행이에요. 왜냐하면 아래에서 사용하는 일치 정규표현식은 VMS 파일명의 가능한 뒤쪽 버전 번호를 처리해야 하기 때문이에요.

$^X를 파일 경로명으로 변환하려면, 다양한 운영체제 가능성의 요구사항을 고려해서 이렇게 하세요:

use Config;
my $thisperl = $^X;
if ($^O ne 'VMS') {
    $thisperl .= $Config{_exe}
        unless $thisperl =~ m/\Q$Config{_exe}\E$/i;
}

$Config{perlpath}를 파일 경로명으로 변환하려면:

use Config;
my $thisperl = $Config{perlpath};
if ($^O ne 'VMS') {
    $thisperl .= $Config{_exe}
        unless $thisperl =~ m/\Q$Config{_exe}\E$/i;
}

네트워킹 (Networking)

공용 인터넷에 도달할 수 있다고 가정하지 마세요.

공용 인터넷으로 가는 방화벽을 통과하는 방법이 하나뿐이라고 가정하지 마세요.

80 포트나 어떤 웹 프록시 외의 어떤 포트를 통해서도 외부 세계에 도달할 수 있다고 가정하지 마세요. ftp는 많은 방화벽에서 차단돼요.

로컬 SMTP 포트에 연결해서 이메일을 보낼 수 있다고 가정하지 마세요.

'localhost'라는 이름으로 자신이나 어떤 노드에 도달할 수 있다고 가정하지 마세요. '127.0.0.1'도 마찬가지예요. 둘 다 시도해 봐야 해요.

호스트에 네트워크 카드가 하나뿐이거나 많은 가상 IP 주소에 바인드할 수 없다고 가정하지 마세요.

특정 네트워크 장치 이름을 가정하지 마세요.

특정 세트의 ioctl이 동작할 거라고 가정하지 마세요.

호스트에 ping을 보내서 응답을 받을 수 있다고 가정하지 마세요.

어떤 특정 포트(서비스)가 응답할 거라고 가정하지 마세요.

Sys::Hostname(또는 다른 어떤 API나 명령)이 완전히 자격을 갖춘 호스트명이나 자격 없는 호스트명 중 하나를 반환한다고 가정하지 마세요: 전부 시스템이 어떻게 구성되었느냐에 달려 있어요. 또한 DHCP와 NAT 같은 것의 경우, 돌아온 호스트명이 별로 유용하지 않을 수도 있다는 걸 기억하세요.

위의 모든 "하지 마세요"는 위협적으로 보일 수 있고, 실제로 그래요. 하지만 핵심은 원하는 특정 네트워크 서비스에 도달할 수 없다면 우아하게 성능을 저하시키는(degrade gracefully) 거예요. 죽거나(croak) 매달리는 건(hang) 전문적으로 보이지 않아요.

프로세스 간 통신 - IPC (Interprocess Communication)

일반적으로 이식성을 의도한 코드에서는 시스템에 직접 접근하지 마세요. 즉, system, exec, fork, pipe, ` or qx//, |를 가진 open, 그리고 Perl 해커가 되는 게 가치 있게 만드는 다른 것들 전부를 쓰지 마세요.

외부 프로세스를 시작하는 명령은 대부분의 플랫폼에서 일반적으로 지원돼요(비록 many of them은 어떤 종류의 forking도 지원하지 않지만). 이들을 사용할 때 문제는 그것을 무엇에 호출하느냐에서 생겨요. 외부 도구는 종종 플랫폼마다 이름이 다르고, 같은 위치에 없을 수 있고, 다른 인자를 받을 수 있고, 다르게 동작할 수 있고, 플랫폼 의존적인 방식으로 결과를 제시하는 경우가 많아요. 그래서 일관된 결과를 내기 위해 그것들에 의존해서는 거의 안 돼요. (그렇다고 해도, netstat -a를 호출한다면 Unix와 CP/M 둘 다에서 실행되길 기대하지는 않을 거예요.)

특히 흔한 Perl 코드 한 조각은 sendmail에 파이프를 여는 거예요:

    open(my $mail, '|-', '/usr/lib/sendmail -t')
	or die "cannot fork sendmail: $!";

이것은 sendmail이 사용 가능한 것으로 알려진 시스템 프로그래밍에는 좋아요. 하지만 많은 비-Unix 시스템, 그리고 sendmail이 설치되지 않았을 수 있는 일부 Unix 시스템에는 좋지 않아요. 이식성 있는 해결책이 필요하다면, 그것을 다루는 CPAN의 다양한 배포판을 보세요. MailTools 배포판의 Mail::MailerMail::Send이 흔히 사용되고, 메일 전송 에이전트가 없을 때 mail, sendmail, 직접 SMTP( Net::SMTP 경유)를 포함한 여러 메일링 방법을 제공해요. Mail::Sendmail은 단순하고 플랫폼 독립적인 메일링을 제공하는 독립형 모듈이에요.

Unix System V IPC(msg*(), sem*(), shm*())는 모든 Unix 플랫폼에서조차 사용할 수 없어요.

pack("N", 10, 20, 30, 40)의 맨 결과나 맨 v-스트링(예: v10.20.30.40)을 IPv4 주소를 나타내는 데 사용하지 마세요: 두 형태 모두 그냥 네 바이트를 네트워크 순서로 패킹할 뿐이에요. 이것이 C 언어의 in_addr 구조체(소켓 코드가 내부적으로 사용하는 것)와 같을 거라는 보장은 없어요. 이식성 있게 하려면 Socket 모듈의 루틴, 예를 들어 inet_aton, inet_ntoa, sockaddr_in을 사용하세요.

이식성 있는 코드의 경험 법칙은 이거예요: 전부 이식성 있는 Perl로 하거나, 모듈을 사용하세요(내부적으로 플랫폼 특정 코드로 구현할 수 있지만 공통 인터페이스를 노출하는).

외부 서브루틴 - XS (External Subroutines)

XS 코드는 보통 어떤 플랫폼에서도 동작하게 만들 수 있지만, 의존 라이브러리, 헤더 파일 등은 쉽게 구할 수 없거나 이식성이 없을 수 있고, Perl 코드가 그럴 수 있듯이 XS 코드 자체도 플랫폼 특정적일 수 있어요. 라이브러리와 헤더가 이식성 있다면, XS 코드도 이식성 있게 만드는 게 보통 합리적이에요.

XS 코드를 작성할 때 다른 종류의 이식성 문제가 생겨요: 최종 사용자 시스템에서 C 컴파일러의 가용성이죠. C는 그 자체의 이식성 문제를 가져오고, XS 코드를 쓰면 그 중 일부를 접하게 돼요. 순수하게 Perl로 쓰는 건 이식성을 달성하는 더 쉬운 방법이에요.

표준 모듈 (Standard Modules)

일반적으로 표준 모듈은 플랫폼을 넘나들며 동작해요. 주목할 만한 예외는 CPAN 모듈(현재는 사용할 수 없을 수 있는 외부 프로그램에 연결을 만들고 있어요), 플랫폼 특정 모듈( ExtUtils::MM_VMS 같은), DBM 모듈이에요.

모든 플랫폼에서 사용할 수 있는 DBM 모듈은 하나도 없어요. SDBM_File과 다른 것들은 일반적으로 모든 Unix와 DOSish 포트에서 사용 가능하지만 MacPerl에서는 그렇지 않고, 거기에는 NDBM_FileDB_File만 있어요.

좋은 소식은 적어도 어떤 DBM 모듈은 사용 가능해야 하고, AnyDBM_File이 찾을 수 있는 어떤 모듈이든 사용할 거라는 거예요. 물론 그렇다면 코드는 최대 공약수(예: 각 레코드 1K를 넘지 않기)로 꽤 엄격해져서 어떤 DBM 모듈에서도 동작해야 해요. 자세한 내용은 AnyDBM_File을 보세요.

시간과 날짜 (Time and Date)

시스템의 시간과 달력 날짜에 대한 개념은 아주 다르게 제어돼요. 시간대가 $ENV{TZ}에 저장된다고 가정하지 말고, 저장되더라도 그 변수를 통해 시간대를 제어할 수 있다고 가정하지 마세요. 세 글자 시간대 약어에 대해 어떤 것도 가정하지 마세요(예: MST가 Mountain Standard Time이라고 하지 마세요, Moscow Standard Time을 뜻한다고 알려져 있으니까요). 시간대를 사용해야 한다면, UTC에서 분 단위 정확한 오프셋이나 POSIX 시간대 형식 같은 모호하지 않은 형식으로 표현하세요.

에포크가 1970년 1월 1일 00:00:00에 시작한다고 가정하지 마세요. 그것은 OS 및 구현별이기 때문이에요. 날짜를 모호하지 않은 표현으로 저장하는 게 더 좋아요. ISO 8601 표준은 날짜 형식으로 YYYY-MM-DD를, 또는 YYYY-MM-DDTHH:MM:SS(그건 날짜와 시간을 구분하는 리터럴 "T"예요)를 정의해요. 02/03/04가 무슨 날짜인지 추측하게 하지 말고 ISO 8601을 사용해 주세요. ISO 8601은 그대로 정렬도 잘 돼요. 텍스트 표현(예: "1987-12-18")은 Time::Piece 같은 모듈("Date Parsing" in Time::Piece)이나 Date::Parse를 사용해 OS 특정 값으로 쉽게 변환할 수 있어요. localtime이 반환하는 것 같은 값의 배열은 Time::Local을 사용해 OS 특정 표현으로 변환할 수 있어요.

특정 시간을 계산할 때(시간이나 날짜 모듈의 테스트 같은) 에포크에 대한 오프셋을 계산하는 것이 적절할 수 있어요.

use Time::Local qw(timegm);
my $offset = timegm(0, 0, 0, 1, 0, 1970);

Unix에서 $offset의 값은 0이지만, Mac OS Classic에서는 어떤 큰 숫자일 거예요. 그런 다음 $offset을 Unix 시간 값에 더하면 어떤 시스템에서도 올바른 값이 될 거예요.

문자 세트와 문자 인코딩 (Character sets and character encoding)

문자 세트에 대해 아주 조금만 가정하세요.

문자의 숫자 값(ord, chr)에 대해 아무것도 가정하지 마세요. 명시적 코드 포인트 범위(예: \xHH-\xHH)를 사용하지 마세요. 하지만 Perl v5.22부터는 qr/[\N{U+HH}-\N{U+HH}]/처럼 지정된 대괄호 문자 클래스 범위 정규식이 이식성 있고, Perl v5.24부터는 같은 범위가 tr///에서 이식성 있어요. [:print:] 같은 심볼릭 문자 클래스를 이식성 있게 사용할 수 있어요.

알파벳 문자가 (숫자적 의미에서) 연속적으로 인코딩된다고 가정하지 마세요. 간격이 있을 수 있어요. 하지만 Perl의 특별한 코딩은 qr/[A-Z]/, qr/[a-z]/, qr/[0-9]/의 모든 부분집합이 기대대로 동작함을 보장해요. tr///도 이 범위에 대해 똑같이 동작해요. 패턴에서 \N{...} 표기법의 끝점을 사용해 지정된 어떤 범위든 문자 세트 이식성을 보장하지만, v5.24에서 고쳐진, tr///에는 이게 사실이 아니라는 것이 Perl v5.22의 버그예요.

문자의 순서에 대해 아무것도 가정하지 마세요. 소문자가 대문자보다 앞이나 뒤에 올 수 있고, "a"와 "A" 둘 다 "b"보다 앞에 오도록 소문자와 대문자가 섞일 수 있으며, ä가 "b"보다 앞에 오도록 악센트 및 기타 국제 문자가 섞일 수 있어요. 이걸 모두 정리하려면 Unicode::Collate를 사용할 수 있어요.

국제화 (Internationalisation)

POSIX를 가정할 수 있다면(꽤 큰 가정이지만), POSIX 로케일 시스템에 대해 perllocale에서 더 읽을 수 있어요. 로케일 시스템은 적어도 사물을 조금 더 이식성 있게, 또는 적어도 비영어 사용자에게 더 편리하고 네이티브 친화적으로 만들려고 시도해요. 시스템은 최소한 문자 세트와 인코딩, 날짜와 시간 형식에 영향을 줘요—그리고 다른 것들 중에서도요.

정말 국제적이 되고 싶다면 Unicode를 고려해야 해요. 자세한 내용은 perluniintroperlunicode를 보세요.

기본적으로 Perl은 소스 코드가 8비트 ASCII 상위집합으로 쓰인다고 가정해요. 문자열과 정규식에 Unicode 문자를 포함하려면 \x{HH} 또는 (더 이식성 있게) \N{U+HH} 표기법을 사용할 수 있어요. utf8 프래그마를 사용하고 코드를 UTF-8로 쓸 수도 있는데, 그러면 Unicode 문자를 직접 사용할 수 있어요(인용 구조뿐 아니라 식별자에서도).

시스템 리소스 (System Resources)

코드가 심각하게 제한된(또는 없는!) 가상 메모리 시스템의 시스템을 대상으로 한다면, 다음과 같은 낭비적인 구조를 피하는 데 특히 주의해야 해요:

my @lines = <$very_large_file>;            # bad

while (<$fh>) {$file .= $_}                # sometimes bad
my $file = join('', <$fh>);                # better

마지막 두 구조는 대부분의 사람들에게 직관적으로 보이지 않을 수 있어요. 첫 번째는 문자열을 반복적으로 늘리는 반면, 두 번째는 한 번에 큰 메모리 청크를 할당해요. 어떤 시스템에서는 두 번째가 첫 번째보다 더 효율적이에요.

보안 (Security)

대부분의 다중 사용자 플랫폼은 기본 수준의 보안을 제공하며, 보통 파일시스템 수준에서 구현돼요. 하지만 일부는 안타깝게도 그렇지 않아요. 그래서 사용자 ID, "홈" 디렉터리, 심지어 로그인된 상태라는 개념 자체가 많은 플랫폼에서 알아볼 수 없을 수 있어요. 보안에 민감한 프로그램을 쓴다면, 어떤 유형의 시스템에서 실행될지 알아서 그 플랫폼(또는 플랫폼 클래스)을 위해 명시적으로 코드를 쓰는 게 보통 가장 좋아요.

Unix 파일시스템 접근 의미론을 가정하지 마세요: 운영체제나 파일시스템이 보통의 rwx보다 더 풍부한 언어인 어떤 ACL 시스템을 사용할 수 있어요. rwx가 존재하더라도 그 의미론이 다를 수 있어요.

(보안 관점에서, 무언가를 하기 전에 권한을 테스트하는 것은 어쨌든 어리석어요: 이렇게 하면 경쟁 조건(race condition)의 가능성이 있으니까요. 누군가나 무언가가 권한 검사와 실제 작업 사이에 권한을 바꿀 수 있어요. 그냥 작업을 시도하세요.)

Unix 사용자와 그룹 의미론을 가정하지 마세요: 특히 $<$>(또는 [$(](https://perldoc.perl.org/perlvar#%24\()와 $))가 정체성(또는 구성원) 전환에 동작할 거라고 기대하지 마세요.

set-uid와 set-gid 의미론을 가정하지 마세요. (그리고 가정한다 해도 두 번 생각하세요: set-uid와 set-gid는 잘 알려진 보안 웜의 항아리예요.)

스타일 (Style)

플랫폼 특정 코드가 필요한 그런 때를 위해, 플랫폼 특정 코드를 한 곳에 유지해서 다른 플랫폼으로의 포팅을 더 쉽게 만드는 것을 고려하세요. "PLATFORMS"에서 설명하듯, 플랫폼을 구별하려면 Config 모듈과 특별 변수 $^O를 사용하세요.

"else 증후군"을 조심하세요:

if ($^O eq 'MSWin32') {
  # code that assumes Windows
} else {
  # code that assumes Linux
}

else 분기는 정말 궁극적인 폴백(fallback)을 위해 써야 하지, 어떤 플랫폼에 특정한 코드를 위해 써야 하는 게 아니에요.

모듈이나 프로그램과 함께 제공하는 테스트에 조심하세요. 모듈 코드는 완전히 이식성 있을 수 있지만, 테스트는 그렇지 않을 수 있어요. 테스트가 다른 프로세스를 시작하거나 테스트를 돕기 위해 외부 프로그램을 호출할 때, 또는 (위에서 언급했듯) 테스트가 파일시스템과 경로에 대해 어떤 것을 가정할 때 자주 발생해요. 실패한 시스템 호출 후 $!을 확인할 때처럼 오류의 특정 출력 스타일에 의존하지 않도록 조심하세요. 출력으로 표시하는 것 외의 어떤 용도로든 $!을 사용하는 것은 의심스러워요(오류 값을 합리적으로 이식성 있게 테스트하는 Errno 모듈을 보세요). 어떤 플랫폼은 특정 출력 형식을 기대하고, 그 플랫폼의 Perl은 그에 맞게 조정되었을 수 있어요. 가장 특히, 오류 값을 테스트할 때 regex를 고정(anchor)하지 마세요.

CPAN 테스터 (CPAN Testers)

CPAN에 업로드된 모듈은 다양한 플랫폼의 다양한 자원봉사자들에 의해 테스트돼요. 이 CPAN 테스터들은 각 새 업로드를 메일로 통보받고, 관련 표기와 함께 PASS, FAIL, NA(이 플랫폼에 해당 없음), 또는 UNKNOWN(알 수 없음)으로 목록에 답해요.

테스트의 목적은 두 가지예요: 하나는 다른 플랫폼에서의 테스트 부족 때문에 코드에 나타난 문제를 개발자가 고치도록 돕는 것, 둘째는 주어진 모듈이 주어진 플랫폼에서 동작하는지에 대한 정보를 사용자에게 제공하는 거예요.

또한 보세요:

플랫폼 (PLATFORMS)

Perl은 빌드된 운영체제를 나타내는 $^O 변수와 함께 빌드돼요. 이것은 그렇지 않으면 use Config를 하고 $Config{osname}의 값을 사용해야 했을 코드의 속도를 높이는 데 구현되었어요. 물론 시스템에 대한 더 자세한 정보를 얻으려면 %Config을 살펴보는 것이 확실히 권장돼요.

하지만 %Config은 컴파일 시간에 빌드되었기 때문에 항상 신뢰할 수는 없어요. perl이 한 곳에서 빌드된 다음 다른 곳으로 전송되면 어떤 값이 잘못될 수 있어요. 값이 나중에 편집되었을 수도 있어요.

Unix

Perl은 놀라울 정도로 다양한 Unix 및 Unix 유사 플랫폼에서 동작해요(예: 소스 코드 키트의 hints/ 디렉터리 대부분의 파일을 보세요). 대부분의 이 시스템에서 $^O의 값(따라서 $Config{osname}도)은 셸 프롬프트에서 uname -a(또는 비슷한 명령)를 입력해 반환된 문자열의 첫 필드를 소문자로 만들고 구두점을 제거해서 결정되거나, 커널이나 헤더 파일 같은 고유한 이름의 파일의 존재를 위해 파일시스템을 테스트해서 결정돼요. 예를 들어 여기 더 인기 있는 몇 가지 Unix 변형이 있어요:

uname         $^O        $Config{archname}
--------------------------------------------
AIX           aix        aix
BSD/OS        bsdos      i386-bsdos
Darwin        darwin     darwin
DYNIX/ptx     dynixptx   i386-dynixptx
FreeBSD       freebsd    freebsd-i386
Haiku         haiku      BePC-haiku
Linux         linux      arm-linux
Linux         linux      armv5tel-linux
Linux         linux      i386-linux
Linux         linux      i586-linux
Linux         linux      ppc-linux
HP-UX         hpux       PA-RISC1.1
IRIX          irix       irix
Mac OS X      darwin     darwin
NeXT 3        next       next-fat
NeXT 4        next       OPENSTEP-Mach
openbsd       openbsd    i386-openbsd
OSF1          dec_osf    alpha-dec_osf
reliantunix-n svr4       RM400-svr4
SCO_SV        sco_sv     i386-sco_sv
SINIX-N       svr4       RM400-svr4
sn4609        unicos     CRAY_C90-unicos
sn6521        unicosmk   t3e-unicosmk
sn9617        unicos     CRAY_J90-unicos
SunOS         solaris    sun4-solaris
SunOS         solaris    i86pc-solaris
SunOS4        sunos      sun4-sunos

$Config{archname}의 값은 하드웨어 아키텍처에 의존할 수 있으므로, $^O의 값보다 더 많이 달라질 수 있어요.

DOS와 그 파생물 (DOS and Derivatives)

Perl은 오랫동안 PC-DOS, MS-DOS, OS/2, 그리고 언급할 수 있는 대부분의 Windows 플랫폼(Windows CE는 세지 않는다면) 같은 시스템에서 실행되는 Intel 스타일 마이크로컴퓨터로 포팅되어 왔어요. COMMAND.COM 이나 CMD.EXE 스타일 셸에 익숙한 사용자는 이 파일 명세들 각각에 미묘한 차이가 있을 수 있다는 걸 알아야 해요:

my $filespec0 = "c:/foo/bar/file.txt";
my $filespec1 = "c:\\foo\\bar\\file.txt";
my $filespec2 = 'c:\foo\bar\file.txt';
my $filespec3 = 'c:\\foo\\bar\\file.txt';

시스템 호출은 / 또는 \를 경로 구분자로 받아들여요. 하지만 DOS 시절의 많은 명령줄 유틸리티는 /를 옵션 접두사로 취급하므로, /를 포함한 파일명에 혼란을 겪을 수 있어요. 외부 프로그램을 호출하는 것 외에는 /가 잘 동작하고, 아마 더 잘 동작해요. 더 일반적인 용법과 일관되고, 무엇을 백슬래시할지 기억하는 문제를 피하니까요.

DOS FAT 파일시스템은 "8.3" 스타일 파일명만 수용할 수 있어요. "대소문자 구분 없지만 대소문자 보존"하는 HPFS(OS/2)와 NTFS(NT) 파일시스템에서는 readdir 같은 함수와 함께 반환되거나 open이나 opendir 같은 함수와 함께 사용되는 대소문자에 주의해야 할 수 있어요.

DOS는 또한 AUX, PRN, NUL, CON, COM1, LPT1, LPT2 등 여러 파일명을 특별하게 취급해요. 불행하게도, 때로는 명시적 디렉터리 접두사를 포함해도 이 파일명들이 동작하지 않을 수 있어요. 코드를 DOS와 그 파생물에 이식성 있게 하려면 그런 파일명을 피하는 게 가장 좋아요. 불행히도 이것들이 전부 무엇인지 알기 어려워요.

이 운영체제의 사용자는 또한 스크립트 주위에 래퍼를 두기 위해 pl2bat.bat 같은 스크립트를 사용하고 싶을 수 있어요.

뉴라인(\n)은 파일을 읽고 쓸 때 I/O 시스템에 의해 \015\012로 번역돼요("Newlines" 참조). binmode($filehandle)는 그 파일핸들에 대해 \n\012로 번역된 채 유지해요. 바이너리 데이터를 다루는 코드에는 binmode를 항상 사용해야 해요. 데이터가 바이너리라는 걸 미리 깨닫는다고 가정하는 거예요. 범용 프로그램은 보통 데이터에 대해 아무것도 가정하지 않아야 해요.

다양한 DOSish perl의 $^O 변수와 $Config{archname} 값은 이래요:

OS             $^O       $Config{archname}  ID    Version
---------------------------------------------------------
MS-DOS         dos       ?
PC-DOS         dos       ?
OS/2           os2       ?
Windows 3.1    ?         ?                  0     3 01
Windows 95     MSWin32   MSWin32-x86        1     4 00
Windows 98     MSWin32   MSWin32-x86        1     4 10
Windows ME     MSWin32   MSWin32-x86        1     ?
Windows NT     MSWin32   MSWin32-x86        2     4 xx
Windows NT     MSWin32   MSWin32-ALPHA      2     4 xx
Windows NT     MSWin32   MSWin32-ppc        2     4 xx
Windows 2000   MSWin32   MSWin32-x86        2     5 00
Windows XP     MSWin32   MSWin32-x86        2     5 01
Windows 2003   MSWin32   MSWin32-x86        2     5 02
Windows Vista  MSWin32   MSWin32-x86        2     6 00
Windows 7      MSWin32   MSWin32-x86        2     6 01
Windows 7      MSWin32   MSWin32-x64        2     6 01
Windows 2008   MSWin32   MSWin32-x86        2     6 01
Windows 2008   MSWin32   MSWin32-x64        2     6 01
Windows CE     MSWin32   ?                  3
Cygwin         cygwin    cygwin

다양한 MSWin32 Perl은 Win32::GetOSVersion()에서 반환된 목록의 다섯 번째 요소의 값을 통해 실행 중인 OS를 구별할 수 있어요. 예를 들어:

if ($^O eq 'MSWin32') {
    my @os_version_info = Win32::GetOSVersion();
    print +('3.1','95','NT')[$os_version_info[4]],"\n";
}

Win32::IsWinNT()|Win32/Win32::IsWinNT()Win32::IsWin95()|Win32/Win32::IsWin95(), 그리고 Win32::GetOSName()도 있어요. perldoc Win32을 시도해 보세요. 아주 이식성 있는 POSIX::uname()도 동작할 거예요:

c:\> perl -MPOSIX -we "print join '|', uname"
Windows NT|moonru|5.0|Build 2195 (Service Pack 2)|x86

Winsock 함수가 설정한 오류는 이제 $^E에 직접 들어가고, 관련 WSAE* 오류 코드는 이에 대해 테스트하기 위해 ErrnoPOSIX 모듈에서 내보내져요.

오류를(Perl 5.20.0부터 POSIX 스타일 E* 오류 코드로 변환해서) $!에 넣던 이전 동작은 같은 이름의 Winsock과 POSIX 오류 상수의 비동등성 때문에 버그가 있었어요. 이 관계는 안타깝게도 Perl 5.8.0부터 어떤 식으로든 확립되어 있었죠.

새 동작은 다른 OS를 위한 것이고 Winsock에 대해 다른 의미를 가질 수 있는 POSIX 테스트와 우연히 일치하지 않고, 이식성 있는 소프트웨어에서 Winsock 오류를 확인하는 훨씬 더 견고한 해결책을 제공해요.

이전 동작은 역호환성을 위해 지금도 유지되지만, 사용자들은 Winsock 오류에 대해 $!E* 상수와 테스트하는 어떤 코드든 $^EWSAE* 상수와 테스트하도록 바꾸는 것을 권장해요. Perl 5.24와 함께 시작된 적절한 폐기 기간 후에, 이전 동작은 제거되어 Winsock 함수 호출 후 $!을 변경하지 않고 남겨, 어느 오류 변수를 확인할지 혼란을 피할 수 있을 거예요.

또한 보세요:

VMS

VMS의 Perl은 Perl 배포판의 perlvms에서 논의돼요.

이 글 시점의 VMS 공식 이름은 OpenVMS예요.

DCL(Digital Command Language) 셸에서 Perl과 상호작용하는 것은 종종 Unix 셸과 다른 따옴표 세트를 요구해요. 예를 들어:

$ perl -e "print ""Hello, world.\n"""
Hello, world.

원한다면 Perl 스크립트를 DCL .COM 파일로 감싸는 여러 방법이 있어요. 예를 들어:

$ write sys$output "Hello from DCL!"
$ if p1 .eqs. ""
$ then perl -x 'f$environment("PROCEDURE")
$ else perl -x - 'p1 'p2 'p3 'p4 'p5 'p6 'p7 'p8
$ deck/dollars="__END__"
#!/usr/bin/perl

print "Hello from Perl!\n";

__END__
$ endif

Perl-in-DCL 스크립트가 $read = <STDIN>; 같은 일을 기대한다면 $ ASSIGN/nolog/user SYS$COMMAND: SYS$INPUT에 주의하세요.

VMS 운영체제는 ODS(온디스크 구조) 레벨로 지정된 두 파일시스템, ODS-2와 그 후속 ODS-5를 가져요. VMS로의 Perl 초기 포트는 ODS-5보다 앞서지만, 모든 현재 테스트와 개발은 ODS-5와 그 기능(대소문자 보존, 파일명의 확장 문자, 최대 8192바이트 이름)을 가정해요.

VMS의 Perl은 다음 두 가지처럼 VMS 스타일 또는 Unix 스타일 파일 명세를 받아들일 수 있어요:

$ perl -ne "print if /perl_setup/i" SYS$LOGIN:LOGIN.COM
$ perl -ne "print if /perl_setup/i" /sys$login/login.com

하지만 다음과 같이 둘의 혼합은 안 돼요:

$ perl -ne "print if /perl_setup/i" sys$login:/login.com
Can't open sys$login:/login.com: file specification syntax error

일반적으로 이식성의 가장 쉬운 길은 네이티브 명령이나 유틸리티로 처리해야 할 필요가 없을 때는 항상 Unix 형식으로 파일명을 지정하는 거예요. 이 후자의 고려 때문에 File::Spec 모듈은 기본적으로 입력 형식에 관계없이 네이티브 형식 명세를 반환해요. 환경에서 DECC$FILENAME_UNIX_REPORT 기능 논리명을 지정하면 이 기본값을 반대로 해서 파일명이 항상 Unix 형식으로 보고되게 할 수 있어요.

파일 유형(또는 확장자)은 0 길이일지라도 항상 VMS 형식 파일 명세에 존재해요. 이것은 기본적으로 readdir가 확장자 없는 파일에 뒤쪽 점을 반환한다는 뜻이라, Unix에서 "a"를 볼 곳에서 VMS에서는 "a."를 보게 돼요. 하지만 환경에서 DECC$READDIR_DROPDOTNOTYPE 기능을 활성화하면 뒤쪽 점을 억제할 수 있어요(CRTL 문서의 기능 논리명 참조).

\n이 나타내는 것은 열린 파일의 유형에 따라 달라져요. 보통 \012를 나타내지만, 파일 구성과 레코드 형식에 따라 \015, \012, \015\012, \000, \040 또는 아무것도 아닐 수도 있어요. VMS::Stdio 모듈은 VMS에서 비정상적인 속성의 파일의 특별한 fopen() 요구사항에 대한 접근을 제공해요.

OpenVMS의 $^O의 값은 "VMS"예요. 실행 중인 아키텍처를 결정하려면 $Config{archname}을 참조하세요.

VMS에서 perl은 SYS$TIMEZONE_DIFFERENTIAL 논리명에서 UTC 오프셋을 결정해요. VMS 에포크는 17-NOV-1858 00:00:00.00에 시작했지만, localtime 호출은 Unix처럼 01-JAN-1970 00:00:00.00부터의 오프셋을 세도록 조정돼요.

또한 보세요:

VOS

VOS(OpenVOS라고도 함)의 Perl은 Perl 배포판의 README.vos (perlvos로 설치됨)에서 논의돼요. VOS의 Perl은 다음 둘 다처럼 VOS 스타일 또는 Unix 스타일 파일 명세를 받아들일 수 있어요:

$ perl -ne "print if /perl_setup/i" >system>notices
$ perl -ne "print if /perl_setup/i" /system/notices

또는 이렇게 둘의 혼합도:

$ perl -ne "print if /perl_setup/i" >system/notices

VOS가 객체 이름에 슬래시 문자가 나타나는 것을 허용하지만, Perl의 VOS 포트가 그것을 경로명 구분 문자로 해석하기 때문에, 이름에 슬래시 문자가 포함된 VOS 파일, 디렉터리, 링크는 처리할 수 없어요. 그런 파일은 Perl이 처리할 수 있기 전에 이름을 바꿔야 해요.

VOS의 오래된 릴리스(OpenVOS Release 17.0 이전)는 파일 이름을 32자 이하로 제한하고, 파일 이름이 - 문자로 시작하는 것을 금지하며, 파일 이름에 (공백) 또는 !#%&'()*;<=>? 세트의 어떤 문자도 포함하는 것을 금지해요.

VOS의 새로운 릴리스(OpenVOS Release 17.0 이상)는 확장 이름(extended names)으로 알려진 기능을 지원해요. 이 릴리스에서 파일 이름은 최대 255자를 포함할 수 있고, - 문자로 시작하는 것이 금지되며, 금지된 문자 세트는 #%*<>?로 줄어들어요. 공백과 아포스트로피에 관한 제한이 있어요: 이 문자들은 이름을 시작하거나 끝낼 수 없고, 점 바로 앞이나 뒤에 올 수도 없어요. 또한 공백은 다른 공백이나 하이픈 바로 앞에 올 수 없어요. 구체적으로, 다음 문자 조합이 금지돼요: space-space, space-hyphen, period-space, space-period, period-apostrophe, apostrophe-period, 선행 또는 후행 공백, 선행 또는 후행 아포스트로피. 확장 파일 이름은 255자로 제한되지만, 경로 이름은 여전히 256자로 제한돼요.

VOS의 $^O의 값은 "vos"예요. 실행 중인 아키텍처를 결정하려면 $Config{archname}을 참조하세요.

또한 보세요:

  • README.vos ( perlvos로 설치됨)
  • VOS 메일링 목록.

VOS의 Perl에 대한 특정 메일링 목록은 없어요. 지역의 Stratus Technologies 고객 지원 센터(CAC)에 연락하거나, Stratus Anonymous FTP 사이트의 배포 파일에 있는 연락처 정보를 사용할 수 있어요.

EBCDIC 플랫폼 (EBCDIC Platforms)

v5.22 코어 Perl은 z/OS(이전 OS/390)에서 실행돼요. 이론상으로는 AS/400 미니컴퓨터의 OS/400 후속, VM/ESA, S/390 메인프레임용 BS2000에서도 실행될 수 있어요. 그런 컴퓨터는 내부적으로 EBCDIC 문자 세트(보통 OS/400은 Character Code Set ID 0037, S/390 시스템은 1047 또는 POSIX-BC)를 사용해요.

이 섹션의 나머지는 업데이트가 필요할 수 있지만, 우리는 무엇을 말해야 하는지 모르겠어요. https://github.com/Perl/perl5/issues에 의견을 제출해 주세요.

메인프레임에서 Perl은 현재 "OS/390용 Unix 시스템 서비스"(이전 OpenEdition), VM/ESA OpenEdition, 또는 BS200 POSIX-BC 시스템(BS2000은 Perl 5.6 이상에서 지원) 아래에서 동작해요. 자세한 내용은 perlos390을 보세요. OS/400에는 Perl 5.8.1/5.10.0 이후를 (ILE와 달리) ASCII 기반인 PASE로 포팅한 것도 있다는 점에 주목하세요. perlos400을 보세요.

OS/390용 USS의 R2.5와 VM/ESA의 Version 2.3부터 이 Unix 하위 시스템은 스크립트 호출을 위한 #! shebang 트릭을 지원하지 않아요. 따라서 OS/390과 VM/ESA에서 Perl 스크립트는 다음 간단한 스크립트와 비슷한 헤더로 실행될 수 있어요:

: # use perl
    eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
        if 0;
#!/usr/local/bin/perl     # just a comment really

print "Hello from perl!\n";

OS/390은 릴리스 2.8 이상에서 #! shebang 트릭을 지원할 거예요. system과 백틱 호출은 모든 S/390 시스템에서 POSIX 셸 구문을 사용할 수 있어요.

AS/400에서 PERL5가 라이브러리 목록에 있다면, Perl 스크립트를 CL 프로시저로 감싸서 이렇게 호출해야 할 수도 있어요:

BEGIN
  CALL PGM(PERL5/PERL) PARM('/QOpenSys/hello.pl')
ENDPGM

이것은 QOpenSys 파일시스템의 루트에서 Perl 스크립트 hello.pl 을 호출할 거예요. AS/400에서 system이나 백틱 호출은 CL 구문을 사용해야 해요.

이 플랫폼에서 EBCDIC 문자 세트가 일부 Perl 함수( chr, pack, print, printf, ord, sort, sprintf, unpack 같은)에서 일어나는 일에 영향을 줄 수 있고, ^, &, | 같은 연산자로 ASCII 상수를 비트 다루는 것에 영향을 줄 수 있으며, ASCII 컴퓨터와의 소켓 인터페이스( "Newlines" 참조)를 다루는 것에 영향을 줄 수 있다는 걸 명심하세요.

다행히도 메인프레임용 대부분의 웹 서버는 다음 문장의 \n을 ASCII 등가물로 올바르게 번역할 거예요(\r은 Unix와 z/OS 둘 다에서 같아요):

print "Content-type: text/html\r\n\r\n";

이 플랫폼 중 일부의 $^O의 값은 다음과 같아요:

uname         $^O        $Config{archname}
--------------------------------------------
OS/390        os390      os390
OS400         os400      os400
POSIX-BC      posix-bc   BS2000-posix-bc

EBCDIC 플랫폼에서 실행 중인지 결정하는 몇 가지 간단한 트릭은 다음 중 어떤 것이든(아마 전부) 포함할 수 있어요:

if ("\t" eq "\005")  { print "EBCDIC may be spoken here!\n"; }

if (ord('A') == 193) { print "EBCDIC may be spoken here!\n"; }

if (chr(169) eq 'z') { print "EBCDIC may be spoken here!\n"; }

의존하고 싶지 않을 한 가지는 구두점 문자의 EBCDIC 인코딩이에요. 왜냐하면 이것들이 코드 페이지마다 다를 수 있고(그리고 모듈이나 스크립트가 EBCDIC에서 동작한다는 소문이 나면, 사람들은 모든 EBCDIC 문자 세트에서 동작하기를 원할 거예요).

또한 보세요:

Acorn RISC OS

Acorn은 텍스트 파일에서 Unix처럼 뉴라인(\n)으로 \012를 사용하는 ASCII를 사용하고, Unix 파일명 에뮬레이션이 기본적으로 켜져 있기 때문에, 대부분의 간단한 스크립트는 아마 "그냥 바로" 동작할 거예요. 네이티브 파일시스템은 모듈식이고, 개별 파일시스템은 대소문자 구분이 있거나 없을 수 있으며, 보통 대소문자를 보존해요. 어떤 네이티브 파일시스템은 이름 길이 제한이 있고, 파일과 디렉터리 이름이 맞도록 조용히 잘려져요. 스크립트는 표준 파일시스템이 현재 10자 이름 길이 제한과 디렉터리에 최대 77개 항목을 가지지만, 다른 파일시스템은 그런 제한을 두지 않을 수 있다는 것을 알아야 해요.

네이티브 파일명은 이 형식이에요:

Filesystem#Special_Field::DiskName.$.Directory.Directory.File

여기서:

Special_Field is not usually present, but may contain . and $ .
Filesystem =~ m|[A-Za-z0-9_]|
DsicName   =~ m|[A-Za-z0-9_/]|
$ represents the root directory
. is the path separator
@ is the current directory (per filesystem but machine global)
^ is the parent directory
Directory and File =~ m|[^\0- ".$%&:@\^\|\177]+|

기본 파일명 번역은 대략 tr|/.|./|, 점과 슬래시를 서로 바꾸는 거예요.

"ADFS::HardDisk.$.File" ne 'ADFS::HardDisk.$.File'이고, 정규표현식에서 $ 보간의 두 번째 단계는 스크립트가 조심하지 않으면 $. 변수에 걸릴 거라는 것을 주목하세요.

쉼표로 구분된 검색 목록을 포함하는 시스템 변수가 지정한 논리 경로도 허용돼요. 따라서 System:Modules는 유효한 파일명이고, 파일시스템은 디스크의 객체를 가리키는 이름이 만들어질 때까지 System$Path의 각 섹션을 Modules에 접두사로 붙일 거예요. 새 파일 System:Modules에 쓰는 것은 System$Path가 단일 항목 목록을 포함할 때만 허용될 거예요. 파일시스템은 각괄호로 둘러싸이면 파일명의 시스템 변수도 확장할 것이므로, <System$Dir>.Modules는 파일 $ENV{'System$Dir'} . 'Modules'를 찾을 거예요. 이것의 명백한 의미는 완전히 자격을 갖춘 파일명이 <>로 시작할 수 있고 open의 3-인자 형식을 항상 사용해야 한다는 거예요.

.이 디렉터리 구분자로 사용 중이고 파일명이 10자 후에 고유하다고 가정할 수 없었기 때문에, Acorn은 C 컴파일러를 구현해서 소스 코드에 지정된 파일명의 뒤쪽 .c .h .s .o 접미사를 제거하고 각 파일을 접미사 이름을 딴 서브디렉터리에 저장했어요. 따라서 파일은 이렇게 번역돼요:

foo.h           h.foo
C:foo.h         C:h.foo        (logical path variable)
sys/os.h        sys.h.os       (C compiler groks Unix-speak)
10charname.c    c.10charname
10charname.o    o.10charname
11charname_.c   c.11charname   (assuming filesystem truncates at 10)

Unix 에뮬레이션 라이브러리의 네이티브로의 파일명 번역은 이런 종류의 번역이 필요하다고 가정하고, 이 방식으로 전치할 알려진 접미사 목록을 사용자가 정의할 수 있게 해줘요. 이것은 투명해 보일 수 있지만, 이 규칙으로 foo/bar/baz.hfoo/bar/h/baz 둘 다 foo.bar.h.baz 에 매핑되고, readdirglob은 역방향 매핑을 에뮬레이션할 수 없고 시도하지도 않는다는 것을 고려하세요. 파일명의 다른 ./로 번역돼요.

위에서 암시했듯, %ENV을 통해 접근하는 환경은 전역이고, 프로그램 특정 환경 변수의 형식은 Program$Name이라는 규약이에요. 각 파일시스템은 현재 디렉터리를 유지하고, 현재 파일시스템의 현재 디렉터리는 전역 현재 디렉터리예요. 결과적으로 사교적인 프로그램은 현재 디렉터리를 바꾸지 않고 전체 경로명에 의존하며, 프로그램(과 Makefile)은 현재 디렉터리를 부모(그리고 그 점에 대해 다른 모든 사람)에 영향 주지 않고 바꿀 수 있는 자식 프로세스를 생성할 수 있다고 가정할 수 없어요.

네이티브 운영체제 파일핸들은 전역이고 현재 255에서 아래로 할당되고 0이 예약된 값이기 때문에, Unix 에뮬레이션 라이브러리는 Unix 파일핸들을 에뮬레이션해요. 결과적으로 자식에게 STDIN, STDOUT, STDERR을 전달하는 것에 의존할 수 없어요.

사용자가 명령줄에서 <Foo$Dir>.Bar 형식의 파일명을 인용 없이 표현하려는 욕구도 문제를 일으켜요: ` 명령 출력 캡처는 추측 게임을 수행해야 해요. 그것은 <[^<>] +\$[^<>]> 문자열이 환경 변수에 대한 참조라고 가정하고, 다른 < 또는 >를 포함하는 것은 리다이렉션이라고 가정하며, 일반적으로 99% 맞는 편이에요. 물론 문제는 스크립트가 어떤 Unix 도구의 사용 가능성에 의존할 수 없거나, 찾은 어떤 도구가 Unix 같은 명령줄 인자를 가진다는 것에 의존할 수 없다는 거예요.

확장과 XS는 이론적으로 자유 도구를 사용하는 누구나 빌드할 수 있어요. 실제로는 Acorn 플랫폼의 사용자가 바이너리 배포에 익숙하므로 많은 사람이 하지 않아요. MakeMaker는 실행되지만, 사용 가능한 어떤 make도 현재 MakeMaker의 makefile을 다루지 못해요. 이것이 고쳐져야 한다 해도, Unix 같은 셸의 부재는 makefile 규칙, 특히 cd sdbm && make all 형태의 줄과 인용을 사용하는 어떤 것이든 문제를 일으킬 거예요.

"RISC OS"가 운영체제의 적절한 이름이지만, $^O의 값은 "riscos"예요(우리는 소리지르는 걸 좋아하지 않으니까요).

다른 perl (Other perls)

Perl은 위에 나열한 어떤 범주에도 맞지 않는 많은 플랫폼으로 포팅되었어요. AmigaOS, QNX, Plan 9, VOS 같은 일부는 표준 Perl 소스 코드 키트에 잘 통합되었어요. aos, Atari ST, lynxos, riscos, Novell Netware, Tandem Guardian, 같은 것들에 대한 정보와 가능하면 바이너리를 위해 CPAN의 ports/ 디렉터리를 봐야 할 수도 있어요. (네, 이 OS들 중 일부는 Unix 범주에 속할 수 있다는 걸 압니다만, 우리는 표준 기구가 아니에요.)

"OTHER" 범주의 몇 가지 대략적인 운영체제 이름과 $^O 값은 다음과 같아요:

OS            $^O        $Config{archname}
------------------------------------------
Amiga DOS     amigaos    m68k-amigos

또한 보세요:

  • Amiga, README.amiga ( perlamiga로 설치됨).
  • Plan 9, README.plan9

함수 구현 (FUNCTION IMPLEMENTATIONS)

아래에 완전히 구현되지 않았거나 다양한 플랫폼에서 다르게 구현된 함수가 나열돼 있어요. 각 설명 앞에는 (괄호로) 그 설명이 적용되는 플랫폼 목록이 있어요.

이 목록은 불완전하거나 어떤 곳에서는 잘못될 수 있어요. 의심스러우면 Perl 소스 배포판의 플랫폼 특정 README 파일과 주어진 포트에 수반되는 다른 문서 리소스를 참조하세요.

게다가 Unixish 시스템 사이에서조차 변형이 있다는 것을 알아두세요.

많은 함수에 대해 Config 모듈에서 기본으로 내보내는 %Config을 질의할 수도 있어요. 예를 들어 플랫폼에 lstat 호출이 있는지 확인하려면 $Config{d_lstat}을 확인하세요. 사용 가능한 변수의 전체 설명은 Config을 보세요.

Perl 함수의 알파벳 목록 (Alphabetical Listing of Perl Functions)

-X

(Win32) -w는 읽기 전용 파일 속성(FILE_ATTRIBUTE_READONLY)만 검사하는데, 그것은 디렉터리가 삭제될 수 있는지 결정하지 쓰기 가능한지 결정하지 않아요. 디렉터리는 임의 액세스 제어 목록(DACL)으로 거부되지 않는 한 항상 읽기와 쓰기 접근이 있어요.

(VMS) -r, -w, -x, -o는 파일이 접근 가능한지 알려주는데, UIC 기반 파일 보호를 반영하지 않을 수 있어요.

(RISC OS) 열린 파일의 이름으로 -s는 현재 범위(extent)가 아니라 디스크에 예약된 공간을 반환할 거예요. 열린 파일핸들의 -s는 현재 크기를 반환해요.

(Win32, VMS, RISC OS) -R, -W, -X, -O-r, -w, -x, -o와 구별할 수 없어요.

(Win32, VMS, RISC OS) -g, -k, -u, -A는 특히 의미 있지 않아요.

(VMS, RISC OS) -l은 특히 의미 있지 않아요.

(Win32) -l은 심볼릭 링크와 디렉터리 정션(junction) 둘 다에 대해 참을 반환해요.

(VMS, RISC OS) -p는 특히 의미 있지 않아요.

(VMS) -d는 명시적 디렉터리 없는 장치 명세를 전달하면 참이에요.

(Win32) -x(또는 -X)는 파일이 실행 가능한 접미사 중 하나로 끝나는지 결정해요.

(RISC OS) -x(또는 -X)는 파일이 실행 가능한 파일 유형을 가지는지 결정해요.

alarm

(Win32) Perl이 "안전한 신호"를 디스패치하려고 할 때마다 명시적으로 폴링해야 하는 타이머를 사용해 에뮬레이션되므로, 블로킹 시스템 호출을 중단할 수 없어요.

atan2

(Tru64, HP-UX 10.20) 다양한 CPU, 수학 라이브러리, 컴파일러, 표준의 이슈로 인해, atan2의 결과는 위의 어떤 조합에 따라 달라질 수 있어요. Perl은 atan2에서 반환된 결과에 대해 Open Group/IEEE 표준을 따르려고 시도하지만, Perl이 실행되는 시스템이 허용하지 않으면 강제할 수 없어요.

atan2 표준의 현재 버전은 http://www.opengroup.org/onlinepubs/009695399/functions/atan2.html에서 볼 수 있어요.

binmode

(RISC OS) 의미 없어요.

(VMS) 파일을 다시 열고 포인터를 복원해요. 함수가 실패하면, 기저 파일핸들이 닫히거나 포인터가 다른 위치에 있을 수 있어요.

(Win32) 호출 후 tell이 반환한 값이 영향을 받을 수 있고, 파일핸들이 플러시될 수 있어요.

chdir

(Win32) 시스템이 보고한 현재 디렉터리는 chdir()에 지정된 어떤 심볼릭 링크도 포함할 수 있어요.

chmod

(Win32) "owner" 읽기-쓰기 접근을 바꾸는 데만 좋아요. "group"과 "other" 비트는 의미 없어요.

(RISC OS) "owner"와 "other" 읽기-쓰기 접근을 바꾸는 데만 좋아요.

(VOS) 접근 권한은 VOS 액세스 제어 목록 변경에 매핑돼요.

(Cygwin) 실제 설정된 권한은 SYSTEM 환경 설정의 CYGWIN 변수의 값에 따라 달라져요.

(Android) 어떤 위치(일반적으로 /sdcard)에서 exec 비트를 설정하면 참을 반환하지만 실제로 비트를 설정하지는 않아요.

(VMS) 모드 인자 0은 모든 권한을 비활성화하는 대신 권한을 사용자의 기본 권한 마스크로 설정해요.

chown

(Plan 9, RISC OS) 구현되지 않았어요.

(Win32) 아무것도 하지 않지만 실패하지는 않아요.

(VOS) VOS의 소유권 개념이 약간 특이하므로 약간 특이해요.

chroot

(Win32, VMS, Plan 9, RISC OS, VOS) 구현되지 않았어요.

crypt

(Win32) perl을 빌드할 때 라이브러리나 소스가 제공되지 않았다면 사용할 수 없을 수 있어요.

(Android) 구현되지 않았어요.

dbmclose

(VMS, Plan 9, VOS) 구현되지 않았어요.

dbmopen

(VMS, Plan 9, VOS) 구현되지 않았어요.

dump

(RISC OS) 유용하지 않아요.

(Cygwin, Win32) 지원되지 않아요.

(VMS) VMS 디버거를 호출해요.

exec

(Win32) 간접 객체 구문(exec PROGRAM LIST) 없이 exec LIST는 첫 spawn()이 실패하면 셸을 시도하는 것으로 폴백할 수 있어요.

exec()의 목록 형식은 Win32 API CreateProcess()가 명령줄 인자 배열이 아니라 단순한 문자열을 받기 때문에 에뮬레이션된다는 점에 주목하세요. 이것은 코드에 보안 함의가 있을 수 있어요.

(SunOS, Solaris, HP-UX) 어떤 플랫폼에서는 출력 핸들을 자동으로 플러시하지 않아요.

exit

(VMS) Unix exit(exit 1이 오류를 나타낸다고 간주하는) 를 1SS$_ABORT(44)에 매핑해 에뮬레이션해요. 이 동작은 use vmsish 'exit' 프래그마로 재정의될 수 있어요. CRTL의 exit() 함수처럼, exit 0SS$_NORMAL(1)의 종료 상태로 매핑돼요. 이 매핑은 재정의할 수 없어요. exit의 다른 어떤 인자도 Perl의 종료 상태로 직접 사용돼요. VMS에서, 미래의 POSIX_EXIT 모드가 활성화되지 않으면, 종료 코드는 항상 일반 숫자가 아닌 유효한 VMS 종료 코드여야 해요. POSIX_EXIT 모드가 활성화되면, 일반 숫자는 GNV 패키지 같은 다른 프로그램, 특히 C로 쓰인 것들이 디코드할 수 있도록 C 라이브러리 _POSIX_EXIT 매크로와 호환되는 방법으로 인코딩될 거예요.

(Solaris) exit는 파일 포인터를 재설정하는데, fork가 만든 자식 프로세스에서 BEGIN에서 호출될 때 문제가 돼요. 해결책은 POSIX::_exit을 사용하는 거예요:

exit unless $Config{archname} =~ /\bsolaris\b/;
require POSIX;
POSIX::_exit(0);

fcntl

(Win32) 구현되지 않았어요.

(VMS) VMS 버전에 따라 일부 함수 사용 가능해요.

flock

(VMS, RISC OS, VOS) 구현되지 않았어요.

fork

(AmigaOS, RISC OS, VMS) 구현되지 않았어요.

(Win32) 다중 인터프리터를 사용해 에뮬레이션돼요. perlfork을 보세요.

(SunOS, Solaris, HP-UX) 어떤 플랫폼에서는 출력 핸들을 자동으로 플러시하지 않아요.

getlogin

(RISC OS) 구현되지 않았어요.

getpgrp

(Win32, VMS, RISC OS) 구현되지 않았어요.

getppid

(Win32, RISC OS) 구현되지 않았어요.

getpriority

(Win32, VMS, RISC OS, VOS) 구현되지 않았어요.

getpwnam

(Win32) 구현되지 않았어요.

(RISC OS) 유용하지 않아요.

getgrnam

(Win32, VMS, RISC OS) 구현되지 않았어요.

getnetbyname

(Android, Win32, Plan 9) 구현되지 않았어요.

getpwuid

(Win32) 구현되지 않았어요.

(RISC OS) 유용하지 않아요.

getgrgid

(Win32, VMS, RISC OS) 구현되지 않았어요.

getnetbyaddr

(Android, Win32, Plan 9) 구현되지 않았어요.

getprotobynumber

(Android) 구현되지 않았어요.

getpwent

(Android, Win32) 구현되지 않았어요.

getgrent

(Android, Win32, VMS) 구현되지 않았어요.

gethostbyname

(Irix 5) gethostbyname('localhost')는 어디서나 동작하지 않아요. gethostbyname('127.0.0.1')을 사용해야 할 수도 있어요.

(Win32) NAME 인자가 빈 문자열("")이거나 그것으로 강제되는 것( undef 같은)이라면, winsock.f 구현은 이것을 gethostname 호출로 취급하고 로컬 컴퓨터의 표준 호스트명을 반환할 거예요.

gethostent

(Win32) 구현되지 않았어요.

getnetent

(Android, Win32, Plan 9) 구현되지 않았어요.

getprotoent

(Android, Win32, Plan 9) 구현되지 않았어요.

getservent

(Win32, Plan 9) 구현되지 않았어요.

seekdir

(Android) 구현되지 않았어요.

sethostent

(Android, Win32, Plan 9, RISC OS) 구현되지 않았어요.

setnetent

(Win32, Plan 9, RISC OS) 구현되지 않았어요.

setprotoent

(Android, Win32, Plan 9, RISC OS) 구현되지 않았어요.

setservent

(Plan 9, Win32, RISC OS) 구현되지 않았어요.

endpwent

(Win32) 구현되지 않았어요.

(Android) 구현되지 않았거나 no-op이에요.

endgrent

(Android, RISC OS, VMS, Win32) 구현되지 않았어요.

endhostent

(Android, Win32) 구현되지 않았어요.

endnetent

(Android, Win32, Plan 9) 구현되지 않았어요.

endprotoent

(Android, Win32, Plan 9) 구현되지 않았어요.

endservent

(Plan 9, Win32) 구현되지 않았어요.

getsockopt

(Plan 9) 구현되지 않았어요.

glob

이 연산자는 대부분의 플랫폼에서 File::Glob 확장을 통해 구현돼요. 이식성 정보는 File::Glob을 보세요.

gmtime

이론적으로 gmtime은 -263에서 263-1까지 안정적이에요. 하지만 구현의 우회책(work-arounds)이 부동소수점 숫자를 사용하기 때문에, 시간이 커질수록 부정확해질 거예요. 이것은 버그이고 미래에 고쳐질 거예요.

(VOS) 시간 값은 32비트 양이에요.

ioctl

(VMS) 구현되지 않았어요.

(Win32) 소켓 핸들에서만 사용할 수 있고, Winsock API의 ioctlsocket() 호출이 하는 일을 해요.

(RISC OS) 소켓 핸들에서만 사용할 수 있어요.

kill

(RISC OS) 구현되지 않았으므로 taint 검사에 유용하지 않아요.

(Win32) kill은 Unix 플랫폼처럼 식별된 프로세스에 신호를 보내지 않아요. 대신 kill($sig, $pid)$pid가 식별한 프로세스를 종료하고, 종료 상태 $sig로 즉시 끝나게 해요. Unix처럼 $sig가 0이고 지정된 프로세스가 존재하면, 실제로 종료하지 않고 참을 반환해요.

(Win32) kill(-9, $pid)$pid가 지정한 프로세스와 그것이 소유한 모든 자식 프로세스를 재귀적으로 종료할 거예요. 이것은 신호가 $pid가 지정한 프로세스와 같은 프로세스 그룹의 모든 프로세스에 전달될 Unix 의미론과 달라요.

(VMS) 시스템의 모든 프로세스를 나타내는 -1의 pid는 현재 지원되지 않아요.

link

(RISC OS, VOS) 구현되지 않았어요.

(AmigaOS) 하드 링크가 그렇게 하드하지 않기 때문에 링크 카운트가 업데이트되지 않아요(하드와 소프트 링크 사이의 중간 정도예요).

(Win32) 하드 링크는 NTFS에서만 Win32에 구현돼요. Windows 2000 이상에서 네이티브로 지원돼요. Windows NT에서는 Windows POSIX 하위 시스템 지원을 사용해 구현되고, Perl 프로세스가 하드 링크를 만들려면 관리자 또는 Backup Operator 권한이 필요해요.

(VMS) 64비트 OpenVMS 8.2 이상에서 사용 가능해요.

localtime

localtime은 "gmtime"과 같은 범위를 가지지만, 시간대 규칙이 바뀌기 때문에 역사적·미래 시간에 대한 정확도가 저하될 수 있고, 보통 한 시간을 넘지 않아요.

lstat

(RISC OS) 구현되지 않았어요.

(Win32) 디렉터리 정션을 심볼릭 링크로 취급해요.

msgctl

msgget

msgsnd

msgrcv

(Android, Win32, VMS, Plan 9, RISC OS, VOS) 구현되지 않았어요.

open

(RISC OS) |--| 열기 모드는 지원되지 않아요.

(SunOS, Solaris, HP-UX) 프로세스를 여는 것은 어떤 플랫폼에서는 출력 핸들을 자동으로 플러시하지 않아요.

(Win32) |--| 모드 둘 다 지원되지만, Win32 API CreateProcess()가 인자 배열이 아니라 단순한 문자열을 받기 때문에 목록 형식이 에뮬레이션돼요. 이것은 코드에 보안 함의가 있을 수 있어요.

readlink

(VMS, RISC OS) 구현되지 않았어요.

(Win32) 디렉터리 정션의 readlink()는 단순한 경로가 아니라 객체 이름을 반환해요.

rename

(Win32) 다른 논리 볼륨의 디렉터리 사이에서 디렉터리를 이동할 수 없어요.

rewinddir

(Win32) readdir이 디렉터리 스트림을 다시 읽게 하지는 않아요. rewinddir 호출 전에 이미 읽은 항목은 그냥 캐시 버퍼에서 다시 반환될 거예요.

select

(Win32, VMS) 소켓에서만 구현돼요.

(RISC OS) 소켓에서만 안정적이에요.

select FILEHANDLE 형식은 일반적으로 이식성 있다는 것을 주목하세요.

semctl

semget

semop

(Android, Win32, VMS, RISC OS) 구현되지 않았어요.

setgrent

(Android, VMS, Win32, RISC OS) 구현되지 않았어요.

setpgrp

(Win32, VMS, RISC OS, VOS) 구현되지 않았어요.

setpriority

(Win32, VMS, RISC OS, VOS) 구현되지 않았어요.

setpwent

(Android, Win32, RISC OS) 구현되지 않았어요.

setsockopt

(Plan 9) 구현되지 않았어요.

shmctl

shmget

shmread

shmwrite

(Android, Win32, VMS, RISC OS) 구현되지 않았어요.

sleep

(Win32) alarm에 의해 중단될 수 있고 최대 4294967초(약 49일)로 제한되는 동기화 함수를 사용해 에뮬레이션돼요.

socketpair

(RISC OS) 구현되지 않았어요.

(VMS) 64비트 OpenVMS 8.2 이상에서 사용 가능해요.

stat

rdev, blksize, 또는 blocks가 없는 플랫폼은 이것들을 ''로 반환하므로, 이 필드의 숫자 비교나 조작이 'not numeric' 경고를 일으킬 수 있어요.

(Mac OS X) ctime은 UFS에서 지원되지 않아요.

(Win32) ctime은 inode 변경 시간이 아닌 생성 시간이에요.

(VMS) devino는 반드시 안정적이지는 않아요.

(RISC OS) mtime, atime, ctime 모두 마지막 수정 시간을 반환해요. devino는 반드시 안정적이지는 않아요.

(OS/2) dev, rdev, blksize, blocks는 사용할 수 없어요. ino는 의미 있지 않고 같은 파일에 대한 stat 호출 사이에 달라질 거예요.

(Cygwin) 일부 cygwin 버전은 stat("foo")를 하고 찾지 못하면 stat("foo.exe")를 시도할 수 있어요.

symlink

(RISC OS) 구현되지 않았어요.

(Win32) 상승된 권한이나 개발자 모드, 그리고 충분히 최신 버전의 Windows 10이 필요해요. 현재 프로세스가 필요한 권한을 가지는지 Win32::IsSymlinkCreationAllowed() 함수로 확인할 수 있어요.

Windows는 링크를 만들 때 대상이 디렉터리인지 알아야 하므로, 대상 Perl은 대상이 존재하고 디렉터리일 때만 링크를 디렉터리 링크로 만들 거예요.

Windows는 심볼릭 링크의 경로 구분자로 전방 슬래시를 인식하지 않아요. 따라서 Windows에서 symlink()의 OLDFILE 매개변수의 어떤 /\로 변환돼요. 이것은 readlink()가 반환한 결과에 반영돼요. 결과의 \/로 다시 변환되지 않아요.

(VMS) 64비트 VMS 8.3에서 구현돼요. VMS는 심볼릭 링크가 유효한 경로로 해결되도록 의도된 경우 Unix 구문이어야 해요.

syscall

(Win32, VMS, RISC OS, VOS) 구현되지 않았어요.

sysopen

(Mac OS, OS/390) 전통적인 0, 1, 2 MODE는 어떤 시스템에서 다른 숫자 값으로 구현돼요. 하지만 Fcntl이 내보낸 플래그(O_RDONLY, O_WRONLY, O_RDWR)는 어디서나 동작해야 해요.

system

(Win32) 최적화로, $ENV{PERL5SHELL}에 지정된 명령 셸을 호출하지 않을 수 있어요. system(1, @args)는 외부 프로세스를 생성하고, 종료를 기다리지 않고 즉시 그 프로세스 지정자를 반환해요. 반환 값은 이후 waitwaitpid에서 사용할 수 있어요. 하위 프로세스 spawn() 실패는 $?255 << 8로 설정해 표시돼요. $?는 Unix와 호환되는 방식으로 설정돼요(즉, 하위 프로세스의 종료 상태는 문서에 설명된 것처럼 $? >> 8로 얻어요).

system()의 목록 형식은 Win32 API CreateProcess()가 명령줄 인자 배열이 아니라 단순한 문자열을 받기 때문에 에뮬레이션된다는 점에 주목하세요. 이것은 코드에 보안 함의가 있을 수 있어요.

(RISC OS) 메타문자를 처리할 셸이 없고, 네이티브 표준은 "\n" "\r" 또는 "\0"으로 종료된 명령줄을 생성된 프로그램에 전달하는 거예요. > foo 같은 리다이렉션은 (있다면) 생성된 프로그램의 런타임 라이브러리가 수행해요. system LIST는 부모에서 유효한 stdin, stdout, stderr의 에뮬레이션을 제공하려고 시도하는 Unix 에뮬레이션 라이브러리의 exec 에뮬레이션을 호출할 거예요. 단 자식 프로그램이 호환 버전의 에뮬레이션 라이브러리를 사용한다는 전제 아래요. system SCALAR는 네이티브 명령줄을 직접 호출할 거고, 자식 Unix 프로그램의 그런 에뮬레이션은 발생하지 않아요. 주행거리(mileage)는 다를 거에요.

(Win32) 간접 객체 구문(system PROGRAM LIST) 없이 system LIST는 첫 spawn()이 실패하면 셸을 시도하는 것으로 폴백할 수 있어요.

(SunOS, Solaris, HP-UX) 어떤 플랫폼에서는 출력 핸들을 자동으로 플러시하지 않아요.

(VMS) Win32처럼, system(1, @args)는 외부 프로세스를 생성하고, 종료를 기다리지 않고 즉시 프로세스 지정자를 반환해요. 이 경우 반환 값은 이후 waitwaitpid에서 사용할 수 있어요. 그 외에는 반환 값이 POSIX 같은데(8비트 위로 이동), 이것은 네이티브 32비트 조건 코드의 심각도 비트에서 파생된 만들어진 값(use vmsish 'status'로 재정의되지 않는 한)을 위한 공간만 허용해요. 네이티브 조건 코드가 POSIX 값이 인코딩된 것이라면, POSIX 값이 디코드되어 기대된 종료 값을 추출할 거예요. 자세한 내용은 "$?" in perlvms을 보세요.

telldir

(Android) 구현되지 않았어요.

times

(Win32) "누적" 시간은 가짜일 거예요. Windows NT나 Windows 2000 외의 어떤 것에서 "system" 시간은 가짜일 거고, "user" 시간은 실제로 C 런타임 라이브러리의 clock() 함수가 반환한 시간이에요.

(RISC OS) 유용하지 않아요.

truncate

(VMS의 이전 버전) 구현되지 않았어요.

(VOS) 같거나 더 짧은 길이로의 잘림만 가능해요.

(Win32) FILEHANDLE이 제공되면 쓰기 가능하고 append 모드로 열려 있어야 해요(즉, open(my $fh, '>>', 'filename') 또는 sysopen(my $fh, ..., O_APPEND|O_RDWR) 사용). 파일명이 제공되면 다른 곳에서 열어두면 안 돼요.

umask

사용 불가한 곳에서 undef를 반환해요.

(AmigaOS) umask는 동작하지만 올바른 권한은 파일이 마침내 닫힐 때만 설정돼요.

utime

(VMS, RISC OS) 수정 시간만 업데이트돼요.

(Win32) 기대대로 동작하지 않을 수 있어요. 동작은 C 런타임 라이브러리의 utime() 구현과 사용 중인 파일시스템에 따라 달라져요. FAT 파일시스템은 전형적으로 "접근 시간" 필드를 지원하지 않고, 타임스탬프를 2초 단위로 제한할 수 있어요.

wait

waitpid

(Win32) system(1, ...)으로 생성된 프로세스나 fork로 만들어진 의사 프로세스에 대해 반환된 프로세스 핸들에만 적용할 수 있어요.

(RISC OS) 유용하지 않아요.

지원 플랫폼 (Supported Platforms)

다음 플랫폼은 표준 소스 코드 배포판 http://www.cpan.org/src에서 Perl 5.12(2010년 4월, 릴리스 날짜)를 빌드하는 것으로 알려져 있어요.

Linux (x86, ARM, IA64)

HP-UX

AIX

Win32

Windows 2000

Windows XP

Windows Server 2003

Windows Vista

Windows Server 2008

Windows 7

Cygwin

일부 테스트는 실패하는 것으로 알려져 있어요:

Solaris (x86, SPARC)

OpenVMS

Alpha (7.2 and later)

I64 (8.2 and later)

NetBSD

FreeBSD

Debian GNU/kFreeBSD

Haiku

Irix (6.5. What else?)

OpenBSD

Dragonfly BSD

Midnight BSD

QNX Neutrino RTOS (6.5.0)

MirOS BSD

Stratus OpenVOS (17.0 or later)

주의사항:

time_t 이슈(고쳐졌을 수도 있고 아닐 수도 있음)

Stratus VOS / OpenVOS

AIX

Android

FreeMINT

Perl은 이제 FreeMiNT/Atari로 빌드돼요. 몇몇 테스트에서 실패하는데, 조사가 필요해요.

FreeMiNT 포트는 로드 가능한 모듈 기능에 GNU dld를 사용해요. 따라서 perl을 빌드할 때 그 라이브러리가 설치되어 있는지 확인하세요.

EOL 플랫폼 (EOL Platforms)

(Perl 5.37.1)

다음 플랫폼은 이전 버전의 Perl이 지원했지만 5.37.1부터 Perl 소스에서 공식적으로 제거됐어요:

Ultrix

(Perl 5.36)

다음 플랫폼은 이전 버전의 Perl이 지원했지만 5.36부터 Perl 소스에서 공식적으로 제거됐어요:

NetWare

DOS/DJGPP

AT&T UWIN

(Perl 5.20)

다음 플랫폼은 이전 버전의 Perl이 지원했지만 5.20부터 Perl 소스에서 공식적으로 제거됐어요:

AT&T 3b1

(Perl 5.14)

다음 플랫폼은 5.10까지 지원되었어요. 5.12에서도 동작했을지 모르지만, 5.14에서 지원 코드가 제거됐어요:

Windows 95

Windows 98

Windows ME

Windows NT4

(Perl 5.12)

다음 플랫폼은 이전 버전의 Perl이 지원했지만 5.12부터 Perl 소스에서 공식적으로 제거됐어요:

Atari MiNT

Apollo Domain/OS

Apple Mac OS 8/9

Tenon Machten

지원 플랫폼 (Perl 5.8) (Supported Platforms (Perl 5.8))

2002년 7월(Perl 릴리스 5.8.0) 시점에, 다음 플랫폼은 표준 소스 코드 배포판 http://www.cpan.org/src/에서 Perl을 빌드할 수 있었어요:

AIX
BeOS
BSD/OS          (BSDi)
Cygwin
DG/UX
DOS DJGPP       1)
DYNIX/ptx
EPOC R5
FreeBSD
HI-UXMPP        (Hitachi) (5.8.0 worked but we didn't know it)
HP-UX
IRIX
Linux
Mac OS Classic
Mac OS X        (Darwin)
MPE/iX
NetBSD
NetWare
NonStop-UX
ReliantUNIX     (formerly SINIX)
OpenBSD
OpenVMS         (formerly VMS)
Open UNIX       (Unixware) (since Perl 5.8.1/5.9.0)
OS/2
OS/400          (using the PASE) (since Perl 5.8.1/5.9.0)
POSIX-BC        (formerly BS2000)
QNX
Solaris
SunOS 4
SUPER-UX        (NEC)
Tru64 UNIX      (formerly DEC OSF/1, Digital UNIX)
UNICOS
UNICOS/mk
UTS
VOS / OpenVOS
Win95/98/ME/2K/XP 2)
WinCE
z/OS            (formerly OS/390)
VM/ESA

1) in DOS mode either the DOS or OS/2 ports can be used
2) compilers: Borland, MinGW (GCC), VC6

다음 플랫폼은 이전 릴리스(5.6과 5.7)에서 동작했지만, 5.8.0 릴리스 시간에 맞춰 고치거나 테스트하지는 못했어요. 이 중 많은 것이 5.8.0에서 잘 동작할 가능성이 아주 높아요:

BSD/OS
DomainOS
Hurd
LynxOS
MachTen
PowerMAX
SCO SV
SVR4
Unixware
Windows 3.1

5.8.0에서 깨진 것으로 알려짐(하지만 5.6.1과 5.7.2는 사용할 수 있음):

AmigaOS 3

다음 플랫폼은 과거에 소스에서 Perl을 빌드한 것으로 알려져 있지만(5.005_03과 그 이전), 현재 릴리스에 대한 상태는 확인하지 못했어요. 하드웨어/소프트웨어 플랫폼이 드물거나 그 플랫폼의 적극적인 챔피언이 없거나 둘 다이기 때문이에요. 하지만 과거에는 동작했으므로, 컴파일을 시도해 보고 어떤 문제든 https://github.com/Perl/perl5/issues에 알려 주세요:

3b1
A/UX
ConvexOS
CX/UX
DC/OSx
DDE SMES
DOS EMX
Dynix
EP/IX
ESIX
FPS
GENIX
Greenhills
ISC
MachTen 68k
MPC
NEWS-OS
NextSTEP
OpenSTEP
Opus
Plan 9
RISC/os
SCO ODT/OSR
Stellar
SVR2
TI1500
TitanOS
Unisys Dynix

다음 플랫폼은 http://www.cpan.org/ports/를 통해 사용 가능한 자체 소스 코드 배포판과 바이너리가 있어요:

                        Perl release

OS/400 (ILE)            5.005_02
Tandem Guardian         5.004

다음 플랫폼은 http://www.cpan.org/ports/index.html을 통해서만 바이너리를 사용할 수 있어요:

                        Perl release

Acorn RISCOS            5.005_02
AOS                     5.002
LynxOS                  5.004_02

최대 구성성과 보안을 위해 항상 소스에서 자신만의 Perl을 빌드하는 걸 제안하지만, 급한 경우 바이너리 배포를 위해 http://www.cpan.org/ports/index.html을 확인할 수 있어요.

기타 보기 (SEE ALSO)

perlaix, perlamiga, perlbs2000, perlcygwin, perlebcdic, perlfreebsd, perlhurd, perlhpux, perlirix, perlmacosx, perlos2, perlos390, perlos400, perlplan9, perlqnx, perlsolaris, perltru64, perlunicode, perlvms, perlvos, perlwin32, 그리고 Win32.

AUTHORS / CONTRIBUTORS

Abigail, Charles Bailey, Graham Barr, Tom Christiansen, Nicholas Clark, Thomas Dorner, Andy Dougherty, Dominic Dunlop, Neale Ferguson, David J. Fiander, Paul Green, M.J.T. Guy, Jarkko Hietaniemi, Luther Huffman, Nick Ing-Simmons, Andreas J. König, Markus Laker, Andrew M. Langmead, Lukas Mai, Larry Moore, Paul Moore, Chris Nandor, Matthias Neeracher, Philip Newton, Gary Ng, Tom Phoenix, André Pirard, Peter Prymmer, Hugo van der Sanden, Gurusamy Sarathy, Paul J. Schinder, Michael G Schwern, Dan Sugalski, Nathan Torkington, John Malmberg.