- 名前
- 説明
- ソースコード静的解析
- Perl をデバッグするための外部ツール
- 結び
- 作者
- SEE ALSO
名前¶
perlhack - How to hack at the Perl internals
perlhack - Perl の内部をハックする方法
説明¶
This document attempts to explain how Perl development takes place, and ends with some suggestions for people wanting to become bona fide porters.
この文書は、Perl 開発がどのように行われているかを説明しようと試み、最後に 正真正銘の porters になりたい人々に対する提案が付いています。
The perl5-porters mailing list is where the Perl standard distribution is maintained and developed. The list can get anywhere from 10 to 150 messages a day, depending on the heatedness of the debate. Most days there are two or three patches, extensions, features, or bugs being discussed at a time.
perl5-porters メーリングリストは Perl 標準配布の保守と開発を行っている 場所です。 リストには議論の白熱度に応じて一日に 10 から 150 のメッセージが流れます。 ほとんどの場合 2 または 3 のパッチ、エクステンション、機能、バグが 同時に議論されています。
A searchable archive of the list is at either:
メーリングリストの検索可能なアーカイブは以下の場所か:
http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/
or
または
http://archive.develooper.com/[email protected]/
List subscribers (the porters themselves) come in several flavours. Some are quiet curious lurkers, who rarely pitch in and instead watch the ongoing development to ensure they're forewarned of new changes or features in Perl. Some are representatives of vendors, who are there to make sure that Perl continues to compile and work on their platforms. Some patch any reported bug that they know how to fix, some are actively patching their pet area (threads, Win32, the regexp engine), while others seem to do nothing but complain. In other words, it's your usual mix of technical people.
リスト登録者(porters 自身)にはいくつかの種類があります。 中には静かで好奇心旺盛な人もいて、めったに協力しない代わりに進行中の開発を 監視して、Perl の新しい変更や機能について事前に警告されていることを 確認している人もいます。 中にはベンダーの代表者もいて、Perl が自分たちのプラットフォームで コンパイルと作業を継続していることを確認している人もいます。 報告されたバグの修正方法を知っているパッチを当てる人もいれば、 自分たちの得意分野(スレッド、Win32、正規表現エンジン)に 積極的にパッチを当てる人もいれば、文句ばかり言っている人もいます。 言い換えれば、これは通常の技術者の組み合わせです。
Over this group of porters presides Larry Wall. He has the final word in what does and does not change in the Perl language. Various releases of Perl are shepherded by a "pumpking", a porter responsible for gathering patches, deciding on a patch-by-patch, feature-by-feature basis what will and will not go into the release. For instance, Gurusamy Sarathy was the pumpking for the 5.6 release of Perl, and Jarkko Hietaniemi was the pumpking for the 5.8 release, and Rafael Garcia-Suarez holds the pumpking crown for the 5.10 release.
Larry Wall は、Perl 言語で何が変更され、何が変更されないかについて 最終的な決定権を持っています。 Perl のさまざまなリリースでは、パッチを収集し、パッチ上ごとに、機能ごとに、 リリースで何が変更され、何が変更されないかを決定する責任を負う "pumpking" によって管理されています。 たとえば、Gurusamy Sarthy は 5.6 のPerlリリースの pumpking を務め、 Jarkko Hietaniemi は 5.8 のリリースの pumpking を務め、 Rafael Garcia-Suarez は 5.10 のリリースの pumpking を務めています。
In addition, various people are pumpkings for different things. For instance, Andy Dougherty and Jarkko Hietaniemi did a grand job as the Configure pumpkin up till the 5.8 release. For the 5.10 release H.Merijn Brand took over.
また、いろいろな人がいろいろなことで pumpking になっています。 例えば、Andy Dougherty と Jarkko Hietaniemi は、5.8 リリースまでは Configure pumpking として大きな仕事をしていました。 5.10 リリースでは H.Merijn Brand が引き継ぎました。
Larry sees Perl development along the lines of the US government: there's the Legislature (the porters), the Executive branch (the pumpkings), and the Supreme Court (Larry). The legislature can discuss and submit patches to the executive branch all they like, but the executive branch is free to veto them. Rarely, the Supreme Court will side with the executive branch over the legislature, or the legislature over the executive branch. Mostly, however, the legislature and the executive branch are supposed to get along and work out their differences without impeachment or court cases.
Larry は、Perl 開発は米国政府の方針に沿ったものだと考えています。 議会(porters)、行政府(pumpking)、そして最高裁判所(Larry)があります。 議会は行政府に対して好きなだけ議論してパッチを提出することができますが、 行政府は自由に拒否権を行使することができます。 まれに、最高裁判所が立法府おyり行政府に味方したり、行政府より立法府に 味方することがあります。 しかし、ほとんどの場合、立法府と行政府は、弾劾や裁判なしに 意見の相違を調整することになっています。
You might sometimes see reference to Rule 1 and Rule 2. Larry's power as Supreme Court is expressed in The Rules:
Rule 1 と Rule 2 を参照しているのをみたことがあるかもしれません。 Larry の最高裁としての権力は、The Rules で次のように表現されています。
-
Larry is always by definition right about how Perl should behave. This means he has final veto power on the core functionality.
Larry は、定義上、Perl がどのように振る舞うべきかについて常に正しいです。 これは、彼がコア機能に対する最終的な拒否権を持っていることを意味します。
-
Larry is allowed to change his mind about any matter at a later date, regardless of whether he previously invoked Rule 1.
Larry は、以前に Rule 1 を発動したかどうかにかかわらず、 いかなる問題についても後で考えを変えることが許されます。
Got that? Larry is always right, even when he was wrong. It's rare to see either Rule exercised, but they are often alluded to.
わかりましたか? Larry は、たとえ間違っていても、常に正しいです。 どちらのルールが実行されているのを見ることはまれですが、 それらはしばしば暗に言及されます。
New features and extensions to the language are contentious, because the criteria used by the pumpkings, Larry, and other porters to decide which features should be implemented and incorporated are not codified in a few small design goals as with some other languages. Instead, the heuristics are flexible and often difficult to fathom. Here is one person's list, roughly in decreasing order of importance, of heuristics that new features have to be weighed against:
pumpking や Larry、その他の porters がどの機能を実装して組み込むかを 決定するために使った基準が、他の言語のようにいくつかの小さな設計目標に 成文化されていないため、新しい機能や言語の拡張には議論の余地があります。 代わりに、ヒューリスティックスは柔軟性があり、多くの場合、理解するのが 困難です。 ここでは、ある個人が、新しい機能を比較検討する必要がある ヒューリスティックスを、重要度の高い順にまとめたリストを示します。
- Does concept match the general goals of Perl?
-
These haven't been written anywhere in stone, but one approximation is:
これらはどこにも明文化されていませんが、次のような近似があります:
1. Keep it fast, simple, and useful. 2. Keep features/concepts as orthogonal as possible. 3. No arbitrary limits (platforms, data sizes, cultures). 4. Keep it open and exciting to use/patch/advocate Perl everywhere. 5. Either assimilate new technologies, or build bridges to them.
- Where is the implementation?
-
All the talk in the world is useless without an implementation. In almost every case, the person or people who argue for a new feature will be expected to be the ones who implement it. Porters capable of coding new features have their own agendas, and are not available to implement your (possibly good) idea.
実装なしでは、世界のすべての話は役に立ちません。 ほとんどすべての場合、新機能を主張する人は、それを実装する人であることが 期待されます。 新機能をコーディングできる porters は独自のアジェンダを持っており、 あなたの(おそらく良い)アイデアを実装するためには利用できません。
- Backwards compatibility
-
It's a cardinal sin to break existing Perl programs. New warnings are contentious--some say that a program that emits warnings is not broken, while others say it is. Adding keywords has the potential to break programs, changing the meaning of existing token sequences or functions might break programs.
既存の Perl プログラムを破壊することは重大な罪です。 新しい警告については議論の余地があります -- 警告を発するプログラムは破壊されないとする人もいれば、 破壊されるとする人もいます。 キーワードを追加するとプログラムが破壊される可能性があり、 既存のトークンシーケンスや関数の意味を変更すると プログラムが破壊される可能性があります。
- Could it be a module instead?
-
Perl 5 has extension mechanisms, modules and XS, specifically to avoid the need to keep changing the Perl interpreter. You can write modules that export functions, you can give those functions prototypes so they can be called like built-in functions, you can even write XS code to mess with the runtime data structures of the Perl interpreter if you want to implement really complicated things. If it can be done in a module instead of in the core, it's highly unlikely to be added.
Perl 5 には、 特に Perl インタプリタを変更し続ける必要がないようにするための、 拡張メカニズム、モジュール、XS があります。 関数をエクスポートするモジュールを書くこともできますし、 組み込み関数のように呼び出すことができるように 関数にプロトタイプを与えることもできますし、 非常に複雑なことを実装したい場合には、 Perl インタプリタの実行時データ構造をいじる XS コードを書くこともできます。 コアではなくモジュールで行うことができる場合は、 追加される可能性は非常に低くなります。
- Is the feature generic enough?
-
Is this something that only the submitter wants added to the language, or would it be broadly useful? Sometimes, instead of adding a feature with a tight focus, the porters might decide to wait until someone implements the more generalized feature. For instance, instead of implementing a "delayed evaluation" feature, the porters are waiting for a macro system that would permit delayed evaluation and much more.
これは投稿者だけが言語に追加したいと思っているものなのでしょうか、 それとも広く有用なものなのでしょうか? 時には、焦点を絞った機能を追加する代わりに、 porters は誰かがより一般的な機能を実装するまで待つことに決めるかもしれません。 例えば、「遅延評価」機能を実装する代わりに、 porters は遅延評価などを可能にするマクロシステムを待っています。
- Does it potentially introduce new bugs?
-
Radical rewrites of large chunks of the Perl interpreter have the potential to introduce new bugs. The smaller and more localized the change, the better.
Perl インタプリタの大きな部分を大幅に書き換えてしまうと、 新しいバグが発生する可能性があります。 変化が小さく、局所的であればあるほど良いです。
- Does it preclude other desirable features?
-
A patch is likely to be rejected if it closes off future avenues of development. For instance, a patch that placed a true and final interpretation on prototypes is likely to be rejected because there are still options for the future of prototypes that haven't been addressed.
パッチが将来の開発の道を閉ざす場合、 パッチは却下される可能性が高いです。 例えば、プロトタイプに真の最終解釈を置いたパッチは、 まだ対処されていないプロトタイプの将来の選択肢がまだあるため、 却下される可能性が高いです。
- Is the implementation robust?
-
Good patches (tight code, complete, correct) stand more chance of going in. Sloppy or incorrect patches might be placed on the back burner until the pumpking has time to fix, or might be discarded altogether without further notice.
優れたパッチ(厳密なコード、完全なパッチ、正しいパッチ)は、 入り込む可能性が高くなります。 ずさんなパッチや正しくないパッチは、pumpking が修正する時間があるまで 後回しにされたり、通知なしに完全に廃棄されたりします。
- Is the implementation generic enough to be portable?
-
The worst patches make use of a system-specific features. It's highly unlikely that non-portable additions to the Perl language will be accepted.
最悪のパッチは、システム固有の機能を利用しています。 移植性のない Perl 言語への追加が受け入れられる可能性はほとんどありません。
- Is the implementation tested?
-
Patches which change behaviour (fixing bugs or introducing new features) must include regression tests to verify that everything works as expected. Without tests provided by the original author, how can anyone else changing perl in the future be sure that they haven't unwittingly broken the behaviour the patch implements? And without tests, how can the patch's author be confident that his/her hard work put into the patch won't be accidentally thrown away by someone in the future?
動作を変更するパッチ(バグの修正や新機能の導入)には、 すべてが期待通りに動作することを検証するための 回帰テストを含める必要があります。 元の著者が提供したテストがなければ、将来 Perl を変更する他の人が、 パッチが実装している動作を無意識のうちに破壊していないことを 確認するにはどうすればよいでしょうか? また、テストがなければ、パッチの作成者は、 パッチに加えた自分の苦労が将来誰かによって誤って捨てられないと 確信するにはどうすればよいでしょうか?
- Is there enough documentation?
-
Patches without documentation are probably ill-thought out or incomplete. Nothing can be added without documentation, so submitting a patch for the appropriate manpages as well as the source code is always a good idea.
文書のないパッチは、おそらく間違っているか不完全です。 文書なしでは何も追加できないので、ソースコードとともに適切な man ページのパッチを提出することは常に良い考えです。
- Is there another way to do it?
-
Larry said "Although the Perl Slogan is There's More Than One Way to Do It, I hesitate to make 10 ways to do something". This is a tricky heuristic to navigate, though--one man's essential addition is another man's pointless cruft.
Larry は、「Perl のスローガンはThere's More Than one way to Do It ですが、 何かを行うための 10 の方法を作ることにはためらいがあります」と述べています。 しかし、これは運営のための巧妙なヒューリスティックです -- ある人の 本質的な追加は、別の人の無意味なたわごとです。
- Does it create too much work?
-
Work for the pumpking, work for Perl programmers, work for module authors, ... Perl is supposed to be easy.
pumpking の仕事、Perl プログラマーの仕事、モジュール作成者の仕事…。 Perl は簡単なはずです。
- Patches speak louder than words
-
Working code is always preferred to pie-in-the-sky ideas. A patch to add a feature stands a much higher chance of making it to the language than does a random feature request, no matter how fervently argued the request might be. This ties into "Will it be useful?", as the fact that someone took the time to make the patch demonstrates a strong desire for the feature.
動作するコードは、絵に描いた餅のアイデアよりも常に好まれます。 機能を追加するパッチは、ランダムな機能リクエストよりも、 そのリクエストがどんなに熱心に議論されたとしても、 言語に取り入れられる可能性がはるかに高くなります。 誰かが時間をかけてパッチを作成したという事実は、 その機能に対する強い欲求を示しているため、 これは "Will it be useful?" と結びついています。
If you're on the list, you might hear the word "core" bandied around. It refers to the standard distribution. "Hacking on the core" means you're changing the C source code to the Perl interpreter. "A core module" is one that ships with Perl.
リストに参加している人は、あちこちで「コア」という言葉を 耳にするかもしれません。 これは標準配布を指しています。 「コアをハッキングする」とは、Perl インタプリタ のC ソースコードを 変更することを意味します。 「コアモジュール」とは、Perl に同梱されているモジュールです。
同期し続ける¶
The source code to the Perl interpreter, in its different versions, is kept in a repository managed by the git revision control system. The pumpkings and a few others have write access to the repository to check in changes.
複数のバージョンの Perl インタプリタのソースコードは、 git リビジョン管理システムによって管理されるリポジトリに保存されています。 pumpking とその他の数人は、変更をチェックインするための リポジトリへの書き込みアクセス権を持っています。
How to clone and use the git perl repository is described in perlrepository.
git perl リポジトリを複製して使う方法は、perlrepository に 説明されています。
You can also choose to use rsync to get a copy of the current source tree for the bleadperl branch and all maintenance branches :
rsync を使って、bleadperlブランチとすべての保守ブランチの 現在のソースツリーのコピーを取得することもできます:
$ rsync -avz rsync://perl5.git.perl.org/APC/perl-current .
$ rsync -avz rsync://perl5.git.perl.org/APC/perl-5.10.x .
$ rsync -avz rsync://perl5.git.perl.org/APC/perl-5.8.x .
$ rsync -avz rsync://perl5.git.perl.org/APC/perl-5.6.x .
$ rsync -avz rsync://perl5.git.perl.org/APC/perl-5.005xx .
(Add the --delete
option to remove leftover files)
(残ったファイルを削除するために --delete
オプションを追加します)
You may also want to subscribe to the perl5-changes mailing list to receive a copy of each patch that gets submitted to the maintenance and development "branches" of the perl repository. See http://lists.perl.org/ for subscription information.
perl5-changes メーリングリストに登録して、perl リポジトリーの保守および 開発「ブランチ」に送信される各パッチのコピーを受け取ることもできます。 登録のための情報については、http://lists.perl.org/ を参照してください。
If you are a member of the perl5-porters mailing list, it is a good thing to keep in touch with the most recent changes. If not only to verify if what you would have posted as a bug report isn't already solved in the most recent available perl development branch, also known as perl-current, bleading edge perl, bleedperl or bleadperl.
perl5-porters メーリングリストのメンバーであれば、最新の変更点を 把握しておくとよいでしょう。 バグレポートとして投稿したであろうものが、最新の perl 開発ブランチ (perl-current, leading edge perl, bleedperl, bleadperl としても 知られています)でまだ解決されていないかどうかを 確認するためだけではありません。
Needless to say, the source code in perl-current is usually in a perpetual state of evolution. You should expect it to be very buggy. Do not use it for any purpose other than testing and development.
言うまでもなく、perl-current のソースコードは通常、永続的な進化の 状態にあります。 非常にバグが多いことを想定する必要があります。 テストと開発以外の目的では 使わない でください。
perlbug 管理¶
There is a single remote administrative interface for modifying bug status, category, open issues etc. using the RT bugtracker system, maintained by Robert Spier. Become an administrator, and close any bugs you can get your sticky mitts on:
Robert Spier が管理する RT バグトラッカーシステムを使って、 バグステータス、カテゴリ、未解決の問題などを変更するための単一の リモート管理インターフェイスがあります。 管理者になって、スティッキーミットで捕まえられるバグをすべて閉じてください:
http://bugs.perl.org/
To email the bug system administrators:
バグシステム管理者に電子メールを送信するには:
"perlbug-admin" <[email protected]>
パッチを投稿する¶
Always submit patches to [email protected]. If you're patching a core module and there's an author listed, send the author a copy (see "Patching a core module"). This lets other porters review your patch, which catches a surprising number of errors in patches. Please patch against the latest development version. (e.g., even if you're fixing a bug in the 5.8 track, patch against the blead
branch in the git repository.)
パッチは常に [email protected] に送信してください。 コアモジュールにパッチを適用していて、著者がリストされている場合は、その 著者にコピーを送信してください("Patching a core module" を参照してください)。 これにより、他の porters がパッチをレビューすることができ、パッチに驚くほど 多くのエラーが見つかります。 最新の 開発 バージョンにパッチを当ててください (例えば、5.8 トラックのバグを修正している場合でも、git リポジトリの blead
ブランチにパッチを当ててください)。
If changes are accepted, they are applied to the development branch. Then the maintenance pumpking decides which of those patches is to be backported to the maint branch. Only patches that survive the heat of the development branch get applied to maintenance versions.
変更が受け入れられた場合、それらは開発ブランチに適用されます。 次に、メンテナンスパンプキンが、それらのパッチのどれをメンテナンスブランチに バックポートするかを決定します。 開発ブランチの熱に耐えたパッチのみが、メンテナンス版に適用されます。
Your patch should update the documentation and test suite. See "Writing a test". If you have added or removed files in the distribution, edit the MANIFEST file accordingly, sort the MANIFEST file using make manisort
, and include those changes as part of your patch.
パッチで文書とテストスイートを更新する必要があります。 "Writing a test" を参照してください。 ディストリビューションにファイルを追加または削除した場合は、 MANIFEST ファイルを適宜編集し、make manisort
を使って MANIFEST ファイルをソートし、それらの変更をパッチの一部として含めます。
Patching documentation also follows the same order: if accepted, a patch is first applied to development, and if relevant then it's backported to maintenance. (With an exception for some patches that document behaviour that only appears in the maintenance branch, but which has changed in the development version.)
パッチの文書も同じ順序で作成されます: パッチが受け入れられた場合、 まず development に適用され、関連する場合は maintenance に バックポートされます。 (例外として、メンテナンスブランチにのみ現れるけれども、 開発バージョンで変更されていいる振る舞いを 文書化するパッチがあります。)
To report a bug in Perl, use the program perlbug which comes with Perl (if you can't get Perl to work, send mail to the address [email protected] or [email protected]). Reporting bugs through perlbug feeds into the automated bug-tracking system, access to which is provided through the web at http://rt.perl.org/rt3/ . It often pays to check the archives of the perl5-porters mailing list to see whether the bug you're reporting has been reported before, and if so whether it was considered a bug. See above for the location of the searchable archives.
Perl のバグを報告するには、Perl に付属のプログラム perlbug を 使います(Perl を動作させることができない場合は、アドレス [email protected] または [email protected] にメールを送信してください)。 perlbug を通じてバグを報告すると、自動バグ追跡システムにフィードされます; このシステムへのアクセスは http://rt.perl.org/rt3/ のウェブから 提供されています。 Perl5-porter メーリングリストのアーカイブをチェックして、 あなたが報告しているバグが以前に報告されたことがあるかどうか、 もしそうであれば、それがバグとみなされたかどうかを調べるとよいでしょう。 検索可能なアーカイブの場所については上記を参照してください。
The CPAN testers ( http://testers.cpan.org/ ) are a group of volunteers who test CPAN modules on a variety of platforms. Perl Smokers ( http://www.nntp.perl.org/group/perl.daily-build and http://www.nntp.perl.org/group/perl.daily-build.reports/ ) automatically test Perl source releases on platforms with various configurations. Both efforts welcome volunteers. In order to get involved in smoke testing of the perl itself visit http://search.cpan.org/dist/Test-Smoke. In order to start smoke testing CPAN modules visit http://search.cpan.org/dist/CPANPLUS-YACSmoke/ or http://search.cpan.org/dist/minismokebox/ or http://search.cpan.org/dist/CPAN-Reporter/.
CPAN testers (http://testers.cpan.org/) は、さまざまな プラットフォームで CPAN モジュールをテストするボランティアのグループです。 Perl Smoker ( http://www.nntp.perl.org/group/perl.daily-build と http://www.nntp.perl.org/group/perl.daily-build.reports/ ) は、 さまざまな構成のプラットフォームでPerlソースリリースを自動的にテストします。 どちらの取り組みもボランティアを歓迎しています。 Perl 自体のスモークテストに参加するには、 http://search.cpan.org/dist/Test-Smoke を訪れてください。 CPAN モジュールのスモークテストを開始するには、 http://search.cpan.org/dist/CPANPLUS-YACSmoke/ または http://search.cpan.org/dist/minismokebox/ または http://search.cpan.org/dist/CPAN-Reporter/ を訪れてください。
It's a good idea to read and lurk for a while before chipping in. That way you'll get to see the dynamic of the conversations, learn the personalities of the players, and hopefully be better prepared to make a useful contribution when do you speak up.
参加する前に、しばらくぶらぶらするのは良い考えです。 そうすれば、会話のダイナミックさを見ることができ、 プレーヤーの性格を知ることができ、うまくいけば、 あなたが発言したときに役に立つ貢献をするための準備が整うでしょう。
If after all this you still think you want to join the perl5-porters mailing list, send mail to [email protected]. To unsubscribe, send mail to [email protected].
以上のことを行ってもなお perl5-porters メーリングリストに 参加したいと思うなら、 [email protected] にメールを送ってください。 登録を解除するには、 [email protected] にメールを送ってください。
To hack on the Perl guts, you'll need to read the following things:
Perl の本質をハックするためには、以下を読む必要があります:
- perlguts
-
This is of paramount importance, since it's the documentation of what goes where in the Perl source. Read it over a couple of times and it might start to make sense - don't worry if it doesn't yet, because the best way to study it is to read it in conjunction with poking at Perl source, and we'll do that later on.
これは、Perl ソースのどこに何があるかを記述した文書なので、非常に重要です。 この文書を何度か読んでみると、分かりはじめてくるかもしれませんが、 まだでも心配する必要はありません; なぜなら、この文書を学ぶ最善の方法は、Perl ソースを調べながら 読むことであり、これは後で行いますから。
Gisle Aas's "illustrated perlguts", also known as illguts, has very helpful pictures:
Gisle Aas の、 illguts としても知られる "illustrated perlguts" には、 とても役に立つ絵があります。
- perlxstut and perlxs
-
A working knowledge of XSUB programming is incredibly useful for core hacking; XSUBs use techniques drawn from the PP code, the portion of the guts that actually executes a Perl program. It's a lot gentler to learn those techniques from simple examples and explanation than from the core itself.
XSUB プログラミングの実用的な知識は、コアハッキングに非常に役立ちます; XSUBs では、Perl プログラムを実際に実行するコア部分である PP コードから引き出されたテクニックを使います。 これらのテクニックをコア自体から学ぶよりも、 簡単な例や説明から学ぶ方がはるかにやさしいです。
- perlapi
-
The documentation for the Perl API explains what some of the internal functions do, as well as the many macros used in the source.
Perl API の文書では、内部関数の機能や、ソースで使われる多くのマクロについて 説明しています。
- Porting/pumpkin.pod
-
This is a collection of words of wisdom for a Perl porter; some of it is only useful to the pumpkin holder, but most of it applies to anyone wanting to go about Perl development.
これは、Perl porters のための英知を集めたものです; その中にはパンプキンを持っている人にしか役に立たないものもありますが、 そのほとんどは Perl 開発を行おうとする人にも当てはまります。
- The perl5-porters FAQ
-
This should be available from http://dev.perl.org/perl5/docs/p5p-faq.html . It contains hints on reading perl5-porters, information on how perl5-porters works and how Perl development in general works.
http://dev.perl.org/perl5/docs/p5p-faq.html から入手できます。 perl5-porters を読むためのヒント、perl5-porters がどのように動作するか、 そして Perl 開発がどのように一般的に動作するかについての情報が 含まれています。
回避方法を見つける¶
Perl maintenance can be split into a number of areas, and certain people (pumpkins) will have responsibility for each area. These areas sometimes correspond to files or directories in the source kit. Among the areas are:
Perl の保守はいくつかの領域に分割することができ、それぞれの領域に対して 特定の人(パンプキン)が責任を持ちます。 これらの領域は、ソースキット内のファイルやディレクトリに対応する 場合があります。 次の領域があります:
- Core modules
-
(コアモジュール)
Modules shipped as part of the Perl core live in various subdirectories, where two are dedicated to core-only modules, and two are for the dual-life modules which live on CPAN and may be maintained separately with respect to the Perl core:
Perl コアの一部として出荷されるモジュールは、様々なサブディレクトリにあります; 二つはコア専用モジュール用で、二つは二重管理モジュール用です; これは CPAN にあって、Perl コアとは独立して保守されているものです:
lib/ is for pure-Perl modules, which exist in the core only. ext/ is for XS extensions, and modules with special Makefile.PL requirements, which exist in the core only. cpan/ is for dual-life modules, where the CPAN module is canonical (should be patched first). dist/ is for dual-life modules, where the blead source is canonical.
- Tests
-
(テスト)
There are tests for nearly all the modules, built-ins and major bits of functionality. Test files all have a .t suffix. Module tests live in the lib/ and ext/ directories next to the module being tested. Others live in t/. See "Writing a test"
ほとんどすべてのモジュール、組み込み関数、主要な機能に対する テストがあります。 テストファイルにはすべて .t 拡張子が付いています。 モジュールテストは、テスト対象モジュールの隣の lib/ ディレクトリと ext/ ディレクトリにあります。 その他は t/ ディレクトリにあります。 "Writing a test" を参照してください。
- Documentation
-
(文書)
Documentation maintenance includes looking after everything in the pod/ directory, (as well as contributing new documentation) and the documentation to the modules in core.
文書のメンテナンスには、pod/ ディレクトリのすべての管理(新しい文書の 提供も含む)と、コアのモジュールへの文書が含まれます。
- Configure
-
The Configure process is the way we make Perl portable across the myriad of operating systems it supports. Responsibility for the Configure, build and installation process, as well as the overall portability of the core code rests with the Configure pumpkin - others help out with individual operating systems.
Configure プロセスは、Perl がサポートする無数のオペレーティングシステムに 対して Perl が移植性があるようにするための方法です。 Configure、構築、インストールプロセス、およびコアコードの全体的な 移植性に対する責任は、Configure パンプキンにあります - 他の人は個々のオペレーティングシステムを支援します。
The three files that fall under his/her responsibility are Configure, config_h.SH, and Porting/Glossary (and a whole bunch of small related files that are less important here). The Configure pumpkin decides how patches to these are dealt with. Currently, the Configure pumpkin will accept patches in most common formats, even directly to these files. Other committers are allowed to commit to these files under the strict condition that they will inform the Configure pumpkin, either on IRC (if he/she happens to be around) or through (personal) e-mail.
Configure パンプキンの責任下にある三つのファイルは Configure, config_h.SH, Porting/Glossary (およびこれらよりは重要でない、 大量の小さい関連ファイル) です。 Configure パンプキンはパッチをどのように扱うかを決定します。 現在の所、Configure パンプキンはほとんどの一般的な形式や、 それらのファイルを直接でも、受け入れています。 その他のコミッタは、(本人がいる) IRC または (個人の) 電子メールによって Configure パンプキンに知らせるという厳密な条件の下で これらのファイルのコミットを許されています。
The files involved are the operating system directories, (win32/, os2/, vms/ and so on) the shell scripts which generate config.h and Makefile, as well as the metaconfig files which generate Configure. (metaconfig isn't included in the core distribution.)
関連するファイルは、オペレーティングシステムのディレクトリ (win32/, os2/, vms/ など)、config.h と Makefile を生成する シェルスクリプト、および Configure を生成する metaconfig ファイルです。 (metaconfig はコアディストリビューションには含まれていません。)
See http://perl5.git.perl.org/metaconfig.git/blob/HEAD:/README for a description of the full process involved.
関連する完全なプロセスに関する技術については http://perl5.git.perl.org/metaconfig.git/blob/HEAD:/README を 参照してください。
- Interpreter
-
(インタプリタ)
And of course, there's the core of the Perl interpreter itself. Let's have a look at that in a little more detail.
もちろん、Perl インタプリタ自体の中核部分もあります。 これについてもう少し詳しく見てみましょう。
Before we leave looking at the layout, though, don't forget that MANIFEST contains not only the file names in the Perl distribution, but short descriptions of what's in them, too. For an overview of the important files, try this:
レイアウトを見る前に、MANIFEST には Perl 配布物のファイル名だけでなく、 その中にあるものの簡単な説明も含まれていることを忘れないでください。 重要なファイルの概要を知るには、以下を試してみてください:
perl -lne 'print if /^[^\/]+\.[ch]\s+/' MANIFEST
インタプリタの要素¶
The work of the interpreter has two main stages: compiling the code into the internal representation, or bytecode, and then executing it. "Compiled code" in perlguts explains exactly how the compilation stage happens.
インタプリタの動作には二つの主要なステージがあります: コードを内部表現(バイトコード)にコンパイルし、それを実行します。 "Compiled code" in perlguts は、コンパイルステージがどのように起こるかを 正確に説明しています。
Here is a short breakdown of perl's operation:
perl の操作について簡単に説明します:
- Startup
-
(開始)
The action begins in perlmain.c. (or miniperlmain.c for miniperl) This is very high-level code, enough to fit on a single screen, and it resembles the code found in perlembed; most of the real action takes place in perl.c
アクションは perlmain.c で始まります(miniperl の場合は miniperlmain.c)。 これは非常に高レベルのコードで、一つの画面に収まります; また、perlembed のコードに似ています; 実際のアクションのほとんどは perl.c で行われます。
perlmain.c is generated by writemain from miniperlmain.c at make time, so you should make perl to follow this along.
perlmain.c は writemain によって miniperlmain.c から make 時に生成されますので、perl はこれに従うようにしてください。
First, perlmain.c allocates some memory and constructs a Perl interpreter, along these lines:
まず、perlmain.c はメモリを割り当て、次の行に従って Perl インタプリタを 構築します:
1 PERL_SYS_INIT3(&argc,&argv,&env); 2 3 if (!PL_do_undump) { 4 my_perl = perl_alloc(); 5 if (!my_perl) 6 exit(1); 7 perl_construct(my_perl); 8 PL_perl_destruct_level = 0; 9 }
Line 1 is a macro, and its definition is dependent on your operating system. Line 3 references
PL_do_undump
, a global variable - all global variables in Perl start withPL_
. This tells you whether the current running program was created with the-u
flag to perl and then undump, which means it's going to be false in any sane context.1 行目はマクロで、その定義はオペレーティングシステムによって異なります。 3 行目はグローバル変数
PL_do_undump
を参照しています; Perl のグローバル変数はすべてPL_
で始まります。 これにより、現在実行中のプログラムが perl に対して-u
フラグを付けて 作成され、次に undump フラグを付けて作成されたかどうかがわかります。 これは、まともなコンテキストでは偽になることを意味します。Line 4 calls a function in perl.c to allocate memory for a Perl interpreter. It's quite a simple function, and the guts of it looks like this:
4 行目では、Perl インタプリタにメモリを割り当てるために perl.c の関数を呼び出しています。 これは非常に単純な関数で、その中身は次のようになります:
my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
Here you see an example of Perl's system abstraction, which we'll see later:
PerlMem_malloc
is either your system'smalloc
, or Perl's ownmalloc
as defined in malloc.c if you selected that option at configure time.PerlMem_malloc
は、システムのmalloc
か、または malloc.c で 定義されている Perl 自身のmalloc
(設定時にこのオプションを選択した場合)の いずれかです。Next, in line 7, we construct the interpreter using perl_construct, also in perl.c; this sets up all the special variables that Perl needs, the stacks, and so on.
次に、7 行目で、同じく perl.c で perl_construct を使って インタプリタを作成します; これにより、Perl が必要とするすべての特殊変数やスタックなどが設定されます。
Now we pass Perl the command line options, and tell it to go:
次に、Perl にコマンドラインオプションを渡し、実行するように指示します:
exitstatus = perl_parse(my_perl, xs_init, argc, argv, (char **)NULL); if (!exitstatus) perl_run(my_perl); exitstatus = perl_destruct(my_perl); perl_free(my_perl);
perl_parse
is actually a wrapper aroundS_parse_body
, as defined in perl.c, which processes the command line options, sets up any statically linked XS modules, opens the program and callsyyparse
to parse it.perl_parse
は実際には、perl.c で定義されているS_parse_body
の ラッパーです; このラッパーはコマンドラインオプションを処理し、静的にリンクされた XS モジュールを設定し、プログラムを開き、yyparse
を 呼び出して構文解析します。 - Parsing
-
(パース)
The aim of this stage is to take the Perl source, and turn it into an op tree. We'll see what one of those looks like later. Strictly speaking, there's three things going on here.
このステージの目的は、Perl ソースを取得し、それを op 木に変換することです。 これらのうちの一つがどのように見えるかについては、後で説明します。 厳密に言えば、ここでは三つのことが起こっています。
yyparse
, the parser, lives in perly.c, although you're better off reading the original YACC input in perly.y. (Yes, Virginia, there is a YACC grammar for Perl!) The job of the parser is to take your code and "understand" it, splitting it into sentences, deciding which operands go with which operators and so on.パーサである
yyparse
は perly.c にありますが、 元の YACC 入力を perly.y で読んだ方が良いでしょう。 (そう、バージニア、これが Perl のための YACC 文法です!)。 パーサの仕事は、コードを「理解」し、それを文に分割し、 どのオペランドがどの演算子と合うかなどを決定することです。The parser is nobly assisted by the lexer, which chunks up your input into tokens, and decides what type of thing each token is: a variable name, an operator, a bareword, a subroutine, a core function, and so on. The main point of entry to the lexer is
yylex
, and that and its associated routines can be found in toke.c. Perl isn't much like other computer languages; it's highly context sensitive at times, it can be tricky to work out what sort of token something is, or where a token ends. As such, there's a lot of interplay between the tokeniser and the parser, which can get pretty frightening if you're not used to it.パーサは字句解析器の支援を受けます; 字句解析器は入力をトークンに分割し、変数名、演算子、裸の単語、サブルーチン、 コア関数など、各トークンがどのような種類のものであるかを判断します。 字句解析器への主なエントリポイントは
yylex
です; 字句解析器とそれに関連するルーチンは toke.c にあります。 Perl は他のコンピュータ言語とはあまり似ていません; コンテキストに非常に敏感な場合があり、トークンがどのような種類の ものであるか、トークンがどこで終わるかを理解するのは難しい場合があります。 そのため、トークン解析器とパーサの間には多くの相互作用があり、 これに慣れていないと非常に恐ろしくなります。As the parser understands a Perl program, it builds up a tree of operations for the interpreter to perform during execution. The routines which construct and link together the various operations are to be found in op.c, and will be examined later.
パーサは Perl プログラムを理解すると、実行中にインタプリタが 実行するための操作木を構築します。 さまざまな操作を構築してリンクするルーチンは op.cにあり、 これは後で検討します。
- Optimization
-
(最適化)
Now the parsing stage is complete, and the finished tree represents the operations that the Perl interpreter needs to perform to execute our program. Next, Perl does a dry run over the tree looking for optimisations: constant expressions such as
3 + 4
will be computed now, and the optimizer will also see if any multiple operations can be replaced with a single one. For instance, to fetch the variable$foo
, instead of grabbing the glob*foo
and looking at the scalar component, the optimizer fiddles the op tree to use a function which directly looks up the scalar in question. The main optimizer ispeep
in op.c, and many ops have their own optimizing functions.これで構文解析段階が完了し、完成した木は Perl インタプリタが プログラムを実行するために実行する必要のある操作を表します。 次に、Perl は木を仮ここで走査して最適化を探します:
3 + 4
のような定数式はここで計算され、オプティマイザは複数の操作が 単一の操作に置き換えられるかどうかも調べます。 例えば、変数$foo
をフェッチするために、glob*foo
を取得して スカラ成分を調べる代わりに、オプティマイザは、問題のスカラを 直接検索する関数を使うように op 木を操作します。 メインオプティマイザは op.c のpeep
であり、多くの op は 独自の最適化関数を持っています。 - Running
-
(実行)
Now we're finally ready to go: we have compiled Perl byte code, and all that's left to do is run it. The actual execution is done by the
runops_standard
function in run.c; more specifically, it's done by these three innocent looking lines:Perl バイトコードをコンパイルし、あとはそれを実行するだけです。 実際の実行は、run.c の
runops_standard
関数によって行われます; 具体的には、次の三つの無邪気に見える行によって行われます:while ((PL_op = CALL_FPTR(PL_op->op_ppaddr)(aTHX))) { PERL_ASYNC_CHECK(); }
You may be more comfortable with the Perl version of that:
次のような Perl バージョンの方が使いやすいかもしれません:
PERL_ASYNC_CHECK() while $Perl::op = &{$Perl::op->{function}};
Well, maybe not. Anyway, each op contains a function pointer, which stipulates the function which will actually carry out the operation. This function will return the next op in the sequence - this allows for things like
if
which choose the next op dynamically at run time. ThePERL_ASYNC_CHECK
makes sure that things like signals interrupt execution if required.ええと、違うかも知れません。 とにかく、各 op には関数ポインタが含まれていて、実際に操作を実行する関数を 指定します。 この関数は、シーケンス内の次の op を返します - これにより、
if
のようなものが実行時に動的に次の op を選択することができます。PERL_ASYNC_CHECK
は、シグナルのようなものが必要に応じて実行を 中断するようにします。The actual functions called are known as PP code, and they're spread between four files: pp_hot.c contains the "hot" code, which is most often used and highly optimized, pp_sys.c contains all the system-specific functions, pp_ctl.c contains the functions which implement control structures (
if
,while
and the like) and pp.c contains everything else. These are, if you like, the C code for Perl's built-in functions and operators.実際に呼び出される関数は PP コードと呼ばれ、四つのファイルに分散されます。 pp_hot.c には最も頻繁に使われ高度に最適化された "hot"コードが含まれ、 pp_sys.c にはシステム固有の関数がすべて含まれ、 pp_ctl.c には制御構造を実装する関数(
if
、while
など)が含まれ、 pp.cにはその他のすべてが含まれます。 これらは、言ってみれば、Perl の組み込み関数と演算子の C コードです。Note that each
pp_
function is expected to return a pointer to the next op. Calls to perl subs (and eval blocks) are handled within the same runops loop, and do not consume extra space on the C stack. For example,pp_entersub
andpp_entertry
just push aCxSUB
orCxEVAL
block struct onto the context stack which contain the address of the op following the sub call or eval. They then return the first op of that sub or eval block, and so execution continues of that sub or block. Later, app_leavesub
orpp_leavetry
op pops theCxSUB
orCxEVAL
, retrieves the return op from it, and returns it.各
pp_
関数は、次の op へのポインタを返すことが期待されていることに 注意してください。 perl サブルーチン (および eval ブロック)への呼び出しは、同じ runops ループ内で処理され、C スタック上の余分なスペースを消費しません。 たとえば、pp_entersub
とpp_entertry
は、CxSUB
またはCxEVAL
ブロック構造体を、サブルーチン呼び出しまたは eval に続く op のアドレスを含むコンテキストスタックにプッシュします。 次に、それらはそのサブルーチンまたは eval ブロックの最初の op を返すので、 そのサブルーチンまたはブロックの実行が継続されます。 その後、pp_leavesub
またはpp_leavetry
op がCxSUB
またはCxEVAL
をポップし、そこから return op を取得して返します。 - Exception handing
-
(例外処理)
Perl's exception handing (i.e.
die
etc.) is built on top of the low-levelsetjmp()
/longjmp()
C-library functions. These basically provide a way to capture the current PC and SP registers and later restore them; i.e. alongjmp()
continues at the point in code where a previoussetjmp()
was done, with anything further up on the C stack being lost. This is why code should always save values usingSAVE_FOO
rather than in auto variables.Perl の例外処理(
die
など)は、低レベルのsetjmp()
/longjmp()
C ライブラリ関数の上に構築されています。 これらは基本的に、現在の PC と SP レジスタを取得し、後で復元する方法を 提供します; つまり、longjmp()
は、コード内で前のsetjmp()
が実行された時点で 継続され、C スタック上の上位のものは失われます。 これが、コードが常に自動変数ではなくSAVE_FOO
を使って 値を保存すべき理由です。The perl core wraps
setjmp()
etc in the macrosJMPENV_PUSH
andJMPENV_JUMP
. The basic rule of perl exceptions is thatexit
, anddie
(in the absence ofeval
) perform aJMPENV_JUMP(2)
, whiledie
withineval
does aJMPENV_JUMP(3)
.perl コアは、マクロ
JMPENV_PUSH
とJMPENV_JUMP
でsetjmp()
などをラップします。 perl 例外の基本的なルールは、exit
とdie
(eval
がない場合)はJMPENV_JUMP(2)
を実行し、eval
内のdie
はJMPENV_JUMP(3)
を 実行するということです。At entry points to perl, such as
perl_parse()
,perl_run()
andcall_sv(cv, G_EVAL)
each does aJMPENV_PUSH
, then enter a runops loop or whatever, and handle possible exception returns. For a 2 return, final cleanup is performed, such as popping stacks and callingCHECK
orEND
blocks. Amongst other things, this is how scope cleanup still occurs during anexit
.perl_parse()
,perl_run()
,call_sv(cv, G_EVAL)
などの perl へのエントリポイントでは、それぞれJMPENV_PUSH
を実行し、 runops ループなどに入り、考えられる例外リターンを処理します。 2 リターンの場合は、スタックをポップしたり、CHECK
またはEND
ブロックを呼び出すなど、最終的なクリーンアップが実行されます。 とりわけ、exit
の実行中にスコープのクリーンアップが行われる方法は このようになっています。If a
die
can find aCxEVAL
block on the context stack, then the stack is popped to that level and the return op in that block is assigned toPL_restartop
; then aJMPENV_JUMP(3)
is performed. This normally passes control back to the guard. In the case ofperl_run
andcall_sv
, a non-nullPL_restartop
triggers re-entry to the runops loop. The is the normal way thatdie
orcroak
is handled within aneval
.die
がコンテキストスタック上にCxEVAL
ブロックを見つけることが できる場合、スタックはそのレベルにポップされ、そのブロック内の return op がPL_restartop
に割り当てられます; 次にJMPENV_JUMP(3)
が実行されます。 これにより、通常は制御がガードに戻されます。perl_run
とcall_sv
の場合、非 NULL のPL_restartop
が runops ループへの再エントリを引き起こします。 これは、eval
内でdie
またはcroak
を処理する通常の方法です。Sometimes ops are executed within an inner runops loop, such as tie, sort or overload code. In this case, something like
内部 runops ループ(tie、sort、overload コードなど)内で op が 実行されることがあります。 この場合、以下のようになります:
sub FETCH { eval { die } }
would cause a longjmp right back to the guard in
perl_run
, popping both runops loops, which is clearly incorrect. One way to avoid this is for the tie code to do aJMPENV_PUSH
before executingFETCH
in the inner runops loop, but for efficiency reasons, perl in fact just sets a flag, usingCATCH_SET(TRUE)
. Thepp_require
,pp_entereval
andpp_entertry
ops check this flag, and if true, they calldocatch
, which does aJMPENV_PUSH
and starts a new runops level to execute the code, rather than doing it on the current loop.これは、
perl_run
のガードに対して longjmp を引き起こし、両方の runops ループをポップさせますが、これは明らかに正しくありません。 これを回避する一つの方法は、内部 runops ループでFETCH
を実行する前に、 tie コードがJMPENV_PUSH
を実行することですが、効率性の理由から、 perl は実際にはCATCH_SET(TRUE)
を使ってフラグを設定するだけです。pp_require
,pp_entereval
,pp_entertry
op はこのフラグをチェックし、 真の場合はdocatch
を呼び出します; これはJMPENV_PUSH
を実行し、新しい runops レベルを開始して コードを実行します; 現在のループでは実行されません。As a further optimisation, on exit from the eval block in the
FETCH
, execution of the code following the block is still carried on in the inner loop. When an exception is raised,docatch
compares theJMPENV
level of theCxEVAL
withPL_top_env
and if they differ, just re-throws the exception. In this way any inner loops get popped.さらなる最適化として、
FETCH
の eval ブロックを終了すると、 ブロックに続くコードの実行は依然として内側のループで実行されます。 例外が発生すると、docatch
はCxEVAL
のJMPENV
レベルとPL_top_env
を比較し、両者が異なる場合は例外を再スローします。 このようにして、内側のループはポップされます。Here's an example.
以下は例です:
1: eval { tie @a, 'A' }; 2: sub A::TIEARRAY { 3: eval { die }; 4: die; 5: }
To run this code,
perl_run
is called, which does aJMPENV_PUSH
then enters a runops loop. This loop executes the eval and tie ops on line 1, with the eval pushing aCxEVAL
onto the context stack.このコードを実行するために、
perl_run
が呼び出され、JMPENV_PUSH
を 実行して runops ループに入ります。 このループは 1 行目の eval と tie op を実行します; eval はCxEVAL
をコンテキストスタックにプッシュします。The
pp_tie
does aCATCH_SET(TRUE)
, then starts a second runops loop to execute the body ofTIEARRAY
. When it executes the entertry op on line 3,CATCH_GET
is true, sopp_entertry
callsdocatch
which does aJMPENV_PUSH
and starts a third runops loop, which then executes the die op. At this point the C call stack looks like this:pp_tie
はCATCH_SET(TRUE)
を実行し、2 番目の runops ループを開始してTIEARRAY
の本体を実行します。 3 行目の entertry op を実行すると、CATCH_GET
は真であるため、pp_entertry
はdocatch
を呼び出してJMPENV_PUSH
を実行し、 3 番目の runops ループを開始して die op を実行します。 この時点で、C コールスタックは次のようになります。Perl_pp_die Perl_runops # third loop S_docatch_body S_docatch Perl_pp_entertry Perl_runops # second loop S_call_body Perl_call_sv Perl_pp_tie Perl_runops # first loop S_run_body perl_run main
and the context and data stacks, as shown by
-Dstv
, look like:コンテキストスタックとデータスタックは、
-Dstv
で示すように、 次のようになります:STACK 0: MAIN CX 0: BLOCK => CX 1: EVAL => AV() PV("A"\0) retop=leave STACK 1: MAGIC CX 0: SUB => retop=(null) CX 1: EVAL => * retop=nextstate
The die pops the first
CxEVAL
off the context stack, setsPL_restartop
from it, does aJMPENV_JUMP(3)
, and control returns to the topdocatch
. This then starts another third-level runops level, which executes the nextstate, pushmark and die ops on line 4. At the point that the secondpp_die
is called, the C call stack looks exactly like that above, even though we are no longer within an inner eval; this is because of the optimization mentioned earlier. However, the context stack now looks like this, ie with the top CxEVAL popped:die はコンテキストスタックから最初の
CxEVAL
をポップし、そこからPL_restartop
をセットし、JMPENV_JUMP(3)
を実行し、制御はトップのdocatch
に戻ります。 これにより、もう一つの第 3 レベルの runops レベルが開始され、 4 行目の nextstate、pushmark、die ops が実行されます。 2 番目のpp_die
が呼び出された時点で、C のコールスタックは上記と まったく同じように見えますが、内側の eval 内ではありません; これは前述の最適化のためです。 しかし、コンテキストスタックは次のように見えます; つまり、トップ CxEVAL がポップされます:STACK 0: MAIN CX 0: BLOCK => CX 1: EVAL => AV() PV("A"\0) retop=leave STACK 1: MAGIC CX 0: SUB => retop=(null)
The die on line 4 pops the context stack back down to the CxEVAL, leaving it as:
4 行目の die は、コンテキストスタックを CxEVAL にポップダウンし、 次のように残します:
STACK 0: MAIN CX 0: BLOCK =>
As usual,
PL_restartop
is extracted from theCxEVAL
, and aJMPENV_JUMP(3)
done, which pops the C stack back to the docatch:いつものように、
CxEVAL
からPL_restartop
が抽出され、JMPENV_JUMP(3)
が実行されて C スタックが docatch に戻されます:S_docatch Perl_pp_entertry Perl_runops # second loop S_call_body Perl_call_sv Perl_pp_tie Perl_runops # first loop S_run_body perl_run main
In this case, because the
JMPENV
level recorded in theCxEVAL
differs from the current one,docatch
just does aJMPENV_JUMP(3)
and the C stack unwinds to:この場合、
CxEVAL
に記録されているJMPENV
レベルが現在のレベルと 異なるため、docatch
はJMPENV_JUMP(3)
を実行し、C スタックは 以下のように巻き戻します:perl_run main
Because
PL_restartop
is non-null,run_body
starts a new runops loop and execution continues.PL_restartop
は NULL でないため、run_body
は新しい runops ループを 開始し、実行が継続されます。
内部変数型¶
You should by now have had a look at perlguts, which tells you about Perl's internal variable types: SVs, HVs, AVs and the rest. If not, do that now.
perlguts を見ると、Perl の内部変数型(SV、HV、AVなど)について 知ることができます。 そうでない場合は、今すぐ見てください。
These variables are used not only to represent Perl-space variables, but also any constants in the code, as well as some structures completely internal to Perl. The symbol table, for instance, is an ordinary Perl hash. Your code is represented by an SV as it's read into the parser; any program files you call are opened via ordinary Perl filehandles, and so on.
これらの変数は、Perl スペース変数だけでなく、コード内の任意の定数や、 完全に Perl 内部の構造体を表すためにも使われます。 例えば、シンボルテーブルは通常の Perl ハッシュです。 コードはパーサに読み込まれるときに SV によって表されます; 呼び出したプログラムファイルは通常の Perl ファイルハンドルを 介して開かれます; といったことです。
The core Devel::Peek module lets us examine SVs from a Perl program. Let's see, for instance, how Perl treats the constant "hello"
.
コア Devel::Peek モジュールを使うと、Perl プログラムから SV を調べることができます。 例えば、Perl が定数 "hello"
をどのように処理するかを見てみましょう。
% perl -MDevel::Peek -e 'Dump("hello")'
1 SV = PV(0xa041450) at 0xa04ecbc
2 REFCNT = 1
3 FLAGS = (POK,READONLY,pPOK)
4 PV = 0xa0484e0 "hello"\0
5 CUR = 5
6 LEN = 6
Reading Devel::Peek
output takes a bit of practise, so let's go through it line by line.
Devel::Peek
の出力を読むには少し練習が必要なので、1 行ずつ 見ていきましょう。
Line 1 tells us we're looking at an SV which lives at 0xa04ecbc
in memory. SVs themselves are very simple structures, but they contain a pointer to a more complex structure. In this case, it's a PV, a structure which holds a string value, at location 0xa041450
. Line 2 is the reference count; there are no other references to this data, so it's 1.
1 行目は、メモリ内の 0xa04ecbc
に存在する SV を見ていることを示しています。 SV 自体は非常に単純な構造ですが、より複雑な構造へのポインタを含んでいます。 この場合は、それは PV で、場所 0xa041450
にある文字列値を保持する構造です。 2 行目は参照カウントです; このデータへの他の参照はないので 1 です。
Line 3 are the flags for this SV - it's OK to use it as a PV, it's a read-only SV (because it's a constant) and the data is a PV internally. Next we've got the contents of the string, starting at location 0xa0484e0
.
3 行目はこの SV のフラグです - これをPVとして使っても問題ありません; これは読み取り専用の SV (定数であるため)であり、データは内部的に PV です。 次に、位置 0xa0484e0
から始まる文字列の内容を取得します。
Line 5 gives us the current length of the string - note that this does not include the null terminator. Line 6 is not the length of the string, but the length of the currently allocated buffer; as the string grows, Perl automatically extends the available storage via a routine called SvGROW
.
5 行目は、文字列の現在の長さを示しています - これは ヌル終端文字が含まれて いない ことに注意してください。 6 行目は文字列の長さではなく、現在割り当てられているバッファの長さです; 文字列が大きくなると、Perl は自動的に SvGROW
というルーチンを使って 利用可能な記憶域を拡張します。
You can get at any of these quantities from C very easily; just add Sv
to the name of the field shown in the snippet, and you've got a macro which will return the value: SvCUR(sv)
returns the current length of the string, SvREFCOUNT(sv)
returns the reference count, SvPV(sv, len)
returns the string itself with its length, and so on. More macros to manipulate these properties can be found in perlguts.
これらの値は C から非常に簡単に得ることができます; スニペットに示されているフィールドの名前に Sv
を追加するだけで、 その値を返すマクロができます: SvCUR(sv)
は文字列の現在の長さを返し、SvREFCOUNT(sv)
は 参照カウントを返し、SvPV(sv, len)
は文字列そのものとその長さを返します。 これらのプロパティを操作するもっと多くのマクロは perlguts にあります。
Let's take an example of manipulating a PV, from sv_catpvn
, in sv.c
sv.c の sv_catpvn
から PV を操作する例を見てみましょう。
1 void
2 Perl_sv_catpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
3 {
4 STRLEN tlen;
5 char *junk;
6 junk = SvPV_force(sv, tlen);
7 SvGROW(sv, tlen + len + 1);
8 if (ptr == junk)
9 ptr = SvPVX(sv);
10 Move(ptr,SvPVX(sv)+tlen,len,char);
11 SvCUR(sv) += len;
12 *SvEND(sv) = '\0';
13 (void)SvPOK_only_UTF8(sv); /* validate pointer */
14 SvTAINT(sv);
15 }
This is a function which adds a string, ptr
, of length len
onto the end of the PV stored in sv
. The first thing we do in line 6 is make sure that the SV has a valid PV, by calling the SvPV_force
macro to force a PV. As a side effect, tlen
gets set to the current value of the PV, and the PV itself is returned to junk
.
これは、長さ len
の文字列 ptr
を、sv
に保存されている PV の末尾に 追加する関数です。 6 行目で最初に行うことは、SvPV_force
マクロを呼び出して PV を 強制することによって、SV が有効な PV を 持っている ことを確認することです。 副作用として、tlen
は PV の現在の値に設定され、PV 自体は junk
に 戻されます。
In line 7, we make sure that the SV will have enough room to accommodate the old string, the new string and the null terminator. If LEN
isn't big enough, SvGROW
will reallocate space for us.
7 行目では、SV に古い文字列、新しい文字列、ヌルターミネータを収容する 十分なスペースがあることを確認しています。 LEN
が十分に大きくない場合は、SvGROW
がスペースを再割り当てします。
Now, if junk
is the same as the string we're trying to add, we can grab the string directly from the SV; SvPVX
is the address of the PV in the SV.
junk
が追加しようとしている文字列と同じであれば、その文字列を SV から 直接取得できます; SvPVX
は SV 内の PV のアドレスです。
Line 10 does the actual catenation: the Move
macro moves a chunk of memory around: we move the string ptr
to the end of the PV - that's the start of the PV plus its current length. We're moving len
bytes of type char
. After doing so, we need to tell Perl we've extended the string, by altering CUR
to reflect the new length. SvEND
is a macro which gives us the end of the string, so that needs to be a "\0"
.
10 行目で実際の結合が行われます: Move
マクロはメモリの塊を移動します: 文字列 ptr
を PV の末尾に移動します - これは PV の先頭に現在の長さを加えたものです。 char
型の len
バイトを移動します。 その後、新しい長さを反映するように CUR
を変更して文字列を拡張したことを Perl に伝える必要があります。 SvEND
は文字列の末尾を与えるマクロなので、"\0"
である必要があります。
Line 13 manipulates the flags; since we've changed the PV, any IV or NV values will no longer be valid: if we have $a=10; $a.="6";
we don't want to use the old IV of 10. SvPOK_only_utf8
is a special UTF-8-aware version of SvPOK_only
, a macro which turns off the IOK and NOK flags and turns on POK. The final SvTAINT
is a macro which launders tainted data if taint mode is turned on.
13 行目はフラグを操作します; PV を変更したため、IV や NV の値は無効になります: $a=10; $a.="6";
があれば、古い IV の 10 は使いたくありません。 SvPOK_only_utf8
は SvPOK_only
の特別な UTF-8 対応バージョンで、 IOK と NOK フラグをオフにし、POK をオンにするマクロです。 最後の SvTAINT
は、汚染チェックモードがオンになっていれば、汚染された データを洗浄するマクロです。
AVs and HVs are more complicated, but SVs are by far the most common variable type being thrown around. Having seen something of how we manipulate these, let's go on and look at how the op tree is constructed.
AV と HV はもっと複雑ですが、SV は群を抜いて最も一般的な変数型です。 これらを操作する方法を見てきたので、次に op 木がどのように構築されるかを 見ていきましょう。
op 木¶
First, what is the op tree, anyway? The op tree is the parsed representation of your program, as we saw in our section on parsing, and it's the sequence of operations that Perl goes through to execute your program, as we saw in "Running".
まず、op 木とは何でしょうか? op 木は、構文解析のセクションで説明したように、プログラムを構文解析した 表現であり、"Running" で説明したように、Perl がプログラムを実行するために 行う一連の操作です。
An op is a fundamental operation that Perl can perform: all the built-in functions and operators are ops, and there are a series of ops which deal with concepts the interpreter needs internally - entering and leaving a block, ending a statement, fetching a variable, and so on.
op は Perl が実行できる基本的な操作です: すべての組み込み関数と演算子は op であり、ブロックの出入り、文の 終了、変数のフェッチなど、インタプリタが内部的に必要とする概念を処理する 一連の op があります。
The op tree is connected in two ways: you can imagine that there are two "routes" through it, two orders in which you can traverse the tree. First, parse order reflects how the parser understood the code, and secondly, execution order tells perl what order to perform the operations in.
op 木は二つの方法で接続されています: op 木には二つの「ルート」があり、ツリーをトラバースできる二つの 順序があると想像できます。 第 1 に、構文解析順序はパーサがコードをどのように理解したかを反映し、 第 2 に、実行順序は perl に操作を実行する順序を指示します。
The easiest way to examine the op tree is to stop Perl after it has finished parsing, and get it to dump out the tree. This is exactly what the compiler backends B::Terse, B::Concise and B::Debug do.
op 木を調べる最も簡単な方法は、Perl が構文解析を完了した後で Perl を停止し、 Perl に木をダンプさせることです。 これはまさに、コンパイラのバックエンド B::Terse、 B::Concise、B::Debug が行うことです。
Let's have a look at how Perl sees $a = $b + $c
:
Perl が $a = $b + $c
をどのように見るかを見てみましょう。
% perl -MO=Terse -e '$a=$b+$c'
1 LISTOP (0x8179888) leave
2 OP (0x81798b0) enter
3 COP (0x8179850) nextstate
4 BINOP (0x8179828) sassign
5 BINOP (0x8179800) add [1]
6 UNOP (0x81796e0) null [15]
7 SVOP (0x80fafe0) gvsv GV (0x80fa4cc) *b
8 UNOP (0x81797e0) null [15]
9 SVOP (0x8179700) gvsv GV (0x80efeb0) *c
10 UNOP (0x816b4f0) null [15]
11 SVOP (0x816dcf0) gvsv GV (0x80fa460) *a
Let's start in the middle, at line 4. This is a BINOP, a binary operator, which is at location 0x8179828
. The specific operator in question is sassign
- scalar assignment - and you can find the code which implements it in the function pp_sassign
in pp_hot.c. As a binary operator, it has two children: the add operator, providing the result of $b+$c
, is uppermost on line 5, and the left hand side is on line 10.
真ん中の 4 行目から始めましょう。 これは BINOP (二項演算子)で、位置 0x8179828
にあります。 問題となっている特定の演算子は sassign
- スカラ代入 - です; この演算子を実装するコードは、pp_hot.c の関数 pp_sassign
にあります。 二項演算子としては二つの子があります: $b+$c
の結果を与える加算演算子は 5 行目の一番上にあり、左側は 10 行目にあります。
Line 10 is the null op: this does exactly nothing. What is that doing there? If you see the null op, it's a sign that something has been optimized away after parsing. As we mentioned in "Optimization", the optimization stage sometimes converts two operations into one, for example when fetching a scalar variable. When this happens, instead of rewriting the op tree and cleaning up the dangling pointers, it's easier just to replace the redundant operation with the null op. Originally, the tree would have looked like this:
10 行目は null op です: これは何もしません。 そこで何をしているのでしょう? null op が表示された場合は、解析後に何かが最適化されたことを示しています。 "Optimization" で説明したように、最適化ステージでは、スカラ変数を フェッチする場合など、二つの演算が一つに変換されることがあります。 このような場合は、op 木を書き直して相手がいないポインタを クリーンアップする代わりに、冗長な演算を null op に置き換える方が簡単です。 本来、木は次のように表示されます:
10 SVOP (0x816b4f0) rv2sv [15]
11 SVOP (0x816dcf0) gv GV (0x80fa460) *a
That is, fetch the a
entry from the main symbol table, and then look at the scalar component of it: gvsv
(pp_gvsv
into pp_hot.c) happens to do both these things.
つまり、メインシンボルテーブルから a
エントリを取得し、その スカラコンポーネントを調べます: gsvsv
(pp_hot.c の pp_gsvsv
)は、これらの両方を実行します。
The right hand side, starting at line 5 is similar to what we've just seen: we have the add
op (pp_add
also in pp_hot.c) add together two gvsv
s.
5 行目から始まる右側は、先ほど見たものと似ています: add
op (pp_add
も pp_hot.c にあります) が二つの gsvsv
を 加算します。
Now, what's this about?
ここで、これは何でしょう?
1 LISTOP (0x8179888) leave
2 OP (0x81798b0) enter
3 COP (0x8179850) nextstate
enter
and leave
are scoping ops, and their job is to perform any housekeeping every time you enter and leave a block: lexical variables are tidied up, unreferenced variables are destroyed, and so on. Every program will have those first three lines: leave
is a list, and its children are all the statements in the block. Statements are delimited by nextstate
, so a block is a collection of nextstate
ops, with the ops to be performed for each statement being the children of nextstate
. enter
is a single op which functions as a marker.
enter
と leave
はスコープ op であり、それらの仕事は、ブロックに 入ったり出たりするたびにハウスキーピングを実行することです: レキシカル変数は整理され、参照されていない変数は破棄され、などです。 すべてのプログラムには最初の 3 行があります: leave
はリストであり、その子はブロック内のすべての文です。 文は nextstate
で区切られているため、ブロックは nextstate
op の集合であり、各文に対して実行される op は nextstate
の子となります。 enter
はマーカーとして機能する単一の op です。
That's how Perl parsed the program, from top to bottom:
このようにして、Perl はプログラムを上から下まで構文解析しました:
Program
|
Statement
|
=
/ \
/ \
$a +
/ \
$b $c
However, it's impossible to perform the operations in this order: you have to find the values of $b
and $c
before you add them together, for instance. So, the other thread that runs through the op tree is the execution order: each op has a field op_next
which points to the next op to be run, so following these pointers tells us how perl executes the code. We can traverse the tree in this order using the exec
option to B::Terse
:
しかし、この順序で操作を 実行 することは不可能です: 例えば、$b
と $c
の値を見つけてから、それらを一緒に追加する 必要があります。 そのため、op 木を通るもう一つの糸は実行順序です: 各 op には、次に実行される op を指すフィールド op_next
があるので、 これらのポインタに従って perl がどのようにコードを実行するかを 知ることができます。 exec
オプションを B::Terse
に指定すると、この順序で木を走査できます:
% perl -MO=Terse,exec -e '$a=$b+$c'
1 OP (0x8179928) enter
2 COP (0x81798c8) nextstate
3 SVOP (0x81796c8) gvsv GV (0x80fa4d4) *b
4 SVOP (0x8179798) gvsv GV (0x80efeb0) *c
5 BINOP (0x8179878) add [1]
6 SVOP (0x816dd38) gvsv GV (0x80fa468) *a
7 BINOP (0x81798a0) sassign
8 LISTOP (0x8179900) leave
This probably makes more sense for a human: enter a block, start a statement. Get the values of $b
and $c
, and add them together. Find $a
, and assign one to the other. Then leave.
これはおそらく人間にとってより分かりやすいでしょう: ブロックにを入り、文を開始します。 $b
と $c
の値を取得し、それらを加算します。 $a
を検索し、一方をもう一方に代入します。 そして離れます。
The way Perl builds up these op trees in the parsing process can be unravelled by examining perly.y, the YACC grammar. Let's take the piece we need to construct the tree for $a = $b + $c
Perl が構文解析プロセスでこれらの op 木を構築する方法は、YACC 文法である perly.y を調べることによって解明できます。 $a = $b + $c
の木を構築するために必要な部分を取り上げましょう:
1 term : term ASSIGNOP term
2 { $$ = newASSIGNOP(OPf_STACKED, $1, $2, $3); }
3 | term ADDOP term
4 { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
If you're not used to reading BNF grammars, this is how it works: You're fed certain things by the tokeniser, which generally end up in upper case. Here, ADDOP
, is provided when the tokeniser sees +
in your code. ASSIGNOP
is provided when =
is used for assigning. These are "terminal symbols", because you can't get any simpler than them.
BNF 文法を読むことに慣れていない人は、次のように動作します: ある種のものをトークナイザによって供給されます; それは通常大文字になります。 ここでは、ADDOP
は、トークナイザがコード内で +
が検出したときに 提供されます。 ASSIGNOP
は、代入のために =
が使われたときに提供されます。 これらは「終端記号」です; これ以上単純なものは得られないからです。
The grammar, lines one and three of the snippet above, tells you how to build up more complex forms. These complex forms, "non-terminal symbols" are generally placed in lower case. term
here is a non-terminal symbol, representing a single expression.
上のスニペットの1 行目と3 行目の文法では、より複雑な形式を 構築する方法が説明されています。 これらの複合形式である「非終端記号」は、通常は小文字で配置されます。 ここで term
は、単一の式を表す非終端記号です。
The grammar gives you the following rule: you can make the thing on the left of the colon if you see all the things on the right in sequence. This is called a "reduction", and the aim of parsing is to completely reduce the input. There are several different ways you can perform a reduction, separated by vertical bars: so, term
followed by =
followed by term
makes a term
, and term
followed by +
followed by term
can also make a term
.
文法は次の規則を与えます: 右側のすべてのものを順番に見れば、 コロンの左側のものを作ることができます。 これは「還元」(reduction)と呼ばれ、構文解析の目的は入力を完全に 還元することです。 還元を実行するにはいくつかの異なる方法があり、縦棒で区切られています: つまり、term
の後に =
と term
が続くと term
を作成し、 term
の後に +
と term
が続いても term
を作成できます。
So, if you see two terms with an =
or +
, between them, you can turn them into a single expression. When you do this, you execute the code in the block on the next line: if you see =
, you'll do the code in line 2. If you see +
, you'll do the code in line 4. It's this code which contributes to the op tree.
それで、二つの項の間に =
または +
がある場合、それらを一つの式に 変換できます。 これを行うときは、次の行のブロック内のコードを実行します: =
がある場合は 2 行目のコードを実行します。 +
がある場合は 4 行目のコードを実行します。 このコードが op 木に貢献しています。
| term ADDOP term
{ $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
What this does is creates a new binary op, and feeds it a number of variables. The variables refer to the tokens: $1
is the first token in the input, $2
the second, and so on - think regular expression backreferences. $$
is the op returned from this reduction. So, we call newBINOP
to create a new binary operator. The first parameter to newBINOP
, a function in op.c, is the op type. It's an addition operator, so we want the type to be ADDOP
. We could specify this directly, but it's right there as the second token in the input, so we use $2
. The second parameter is the op's flags: 0 means "nothing special". Then the things to add: the left and right hand side of our expression, in scalar context.
これにより、新しいバイナリ op が作成され、多数の変数が渡されます。 変数はトークンを参照します: $1
は入力の最初のトークン、$2
は 2 番目のトークン、という形です - 正規表現の後方参照を考えてみてください。 $$
はこの還元から返される op です。 そこで、newBINOP
を呼び出して新しい二項演算子を作成します。 op.c にある関数である newBINOP
の最初の引数は op 型です。 これは加算演算子なので、型が ADDOP
になってほしいです。 これを直接指定することもできますが、これは入力の 2 番目のトークンとして すぐそこにあるので、$2
を使います。 2 番目の引数は op のフラグです: 0 は「特別なものがない」ことを意味します。 次に追加すべきものは、スカラコンテキストでの式の左辺と右辺です。
スタック¶
When perl executes something like addop
, how does it pass on its results to the next op? The answer is, through the use of stacks. Perl has a number of stacks to store things it's currently working on, and we'll look at the three most important ones here.
perl が addop
のようなものを実行した場合、その結果をどのように 次の op に渡すのでしょうか? 答えは、スタックを使うことです。 Perl には、現在作業中のものを保存するためのスタックが数多くありますが、 ここでは最も重要な三つのスタックについて説明します。
- Argument stack
-
(引数スタック)
Arguments are passed to PP code and returned from PP code using the argument stack,
ST
. The typical way to handle arguments is to pop them off the stack, deal with them how you wish, and then push the result back onto the stack. This is how, for instance, the cosine operator works:引数は PP コードに渡され、引数スタック
ST
を使って PP コードから 返されます。 引数を処理する一般的な方法は、引数をスタックから取り出し、 必要に応じて処理した後、結果をスタックにプッシュします。 たとえば、余弦演算子は次のように動作します:NV value; value = POPn; value = Perl_cos(value); XPUSHn(value);
We'll see a more tricky example of this when we consider Perl's macros below.
POPn
gives you the NV (floating point value) of the top SV on the stack: the$x
incos($x)
. Then we compute the cosine, and push the result back as an NV. TheX
inXPUSHn
means that the stack should be extended if necessary - it can't be necessary here, because we know there's room for one more item on the stack, since we've just removed one! TheXPUSH*
macros at least guarantee safety.以下に示す Perl のマクロを考えると、もっと巧妙な例を見ることになります。
POPn
はスタック上の最上位 SV の NV (浮動小数点値)を与えます:cos($x)
の$x
です。 次にコサインを計算し、その結果を NV としてプッシュします。XPUSHn
のX
は、必要に応じてスタックを拡張する 必要があることを意味します - ここでは必要ありません; なぜなら、スタック上にもう一つの項目のためのスペースがあることが わかっているからです; なぜなら、一つを削除したばかりなのです!XPUSH*
マクロは少なくとも安全性を保証します。Alternatively, you can fiddle with the stack directly:
SP
gives you the first element in your portion of the stack, andTOP*
gives you the top SV/IV/NV/etc. on the stack. So, for instance, to do unary negation of an integer:あるいは、スタックを直接操作することもできます:
SP
は スタックのあなたの部分の最初の要素を与え、TOP*
はスタック上の最上位の SV/IV/NV などを与えます。 たとえば、整数の単項否定を行うには、次のようにします:SETi(-TOPi);
Just set the integer value of the top stack entry to its negation.
最上位スタックエントリの整数値をその否定に設定するだけです。
Argument stack manipulation in the core is exactly the same as it is in XSUBs - see perlxstut, perlxs and perlguts for a longer description of the macros used in stack manipulation.
コアでの引数スタック操作は、XSUBs とまったく同じです - スタック操作で 使われるマクロのより長い説明については、 perlxstut、perlxs、perlguts を参照してください。
- Mark stack
-
(マークスタック)
I say "your portion of the stack" above because PP code doesn't necessarily get the whole stack to itself: if your function calls another function, you'll only want to expose the arguments aimed for the called function, and not (necessarily) let it get at your own data. The way we do this is to have a "virtual" bottom-of-stack, exposed to each function. The mark stack keeps bookmarks to locations in the argument stack usable by each function. For instance, when dealing with a tied variable, (internally, something with "P" magic) Perl has to call methods for accesses to the tied variables. However, we need to separate the arguments exposed to the method to the argument exposed to the original function - the store or fetch or whatever it may be. Here's roughly how the tied
push
is implemented; seeav_push
in av.c:上で「スタックのあなたの部分」と言ったのは、PP コードが必ずしも スタック全体を自分自身に取得する必要はないからです: 関数が別の関数を呼び出す場合は、呼び出された関数を対象とした引数を 公開するだけで、(必ずしも)自分自身のデータを取得させるわけではありません。 これを行う方法は、各関数に公開される「仮想的な」スタックの最下位を 持つことです。 マークスタックは、各関数が使える引数スタック内の場所への ブックマークを保持します。 例えば、tie された変数を扱う場合(内部では "P" マジックのようなもの)、 Perl は tie された変数にアクセスするためにメソッドを呼び出す必要があります。 ただし、メソッドに公開される引数を、元の関数に公開される引数(store や fetch など)に分離する必要があります。 tie された
push
がどのように実装されるかを大まかに説明します; av.c のav_push
を参照してください。1 PUSHMARK(SP); 2 EXTEND(SP,2); 3 PUSHs(SvTIED_obj((SV*)av, mg)); 4 PUSHs(val); 5 PUTBACK; 6 ENTER; 7 call_method("PUSH", G_SCALAR|G_DISCARD); 8 LEAVE;
Let's examine the whole implementation, for practice:
実践のために、実装全体を調べてみましょう:
1 PUSHMARK(SP);
Push the current state of the stack pointer onto the mark stack. This is so that when we've finished adding items to the argument stack, Perl knows how many things we've added recently.
スタックポインタの現在の状態をマークスタックにプッシュします。 これは、引数スタックへの項目の追加が完了したときに、Perl が最近追加した 項目の数を知るためです。
2 EXTEND(SP,2); 3 PUSHs(SvTIED_obj((SV*)av, mg)); 4 PUSHs(val);
We're going to add two more items onto the argument stack: when you have a tied array, the
PUSH
subroutine receives the object and the value to be pushed, and that's exactly what we have here - the tied object, retrieved withSvTIED_obj
, and the value, the SVval
.引数スタックにさらに二つの項目を追加します: tie された配列がある場合、
PUSH
サブルーチンはオブジェクトと プッシュされる値を受け取ります; そしてこれがここで得られるものです -SvTIED_obj
で取得された tie されたオブジェクトと、 その値である SVval
です。5 PUTBACK;
Next we tell Perl to update the global stack pointer from our internal variable:
dSP
only gave us a local copy, not a reference to the global.次に、内部変数からグローバルスタックポインタを更新するように Perl に指示します:
dSp
はローカルコピーだけを提供し、グローバルへの参照は提供しません。6 ENTER; 7 call_method("PUSH", G_SCALAR|G_DISCARD); 8 LEAVE;
ENTER
andLEAVE
localise a block of code - they make sure that all variables are tidied up, everything that has been localised gets its previous value returned, and so on. Think of them as the{
and}
of a Perl block.ENTER
とLEAVE
はコードブロックをローカル化します - すべての変数が 整理されていること、ローカル化されたすべてのものが以前の値を返すことなどを 確認します。 これらは Perl ブロックの{
と}
と考えてください。To actually do the magic method call, we have to call a subroutine in Perl space:
call_method
takes care of that, and it's described in perlcall. We call thePUSH
method in scalar context, and we're going to discard its return value. The call_method() function removes the top element of the mark stack, so there is nothing for the caller to clean up.マジックメソッド呼び出しを実際に行うためには、Perl 空間でサブルーチンを 呼び出す必要があります:
call_method
がこれを処理します; これについては perlcall で説明しています。PUSH
メソッドをスカラコンテキストで呼び出し、その戻り値を破棄します。 call_method() 関数はマークスタックの最上位要素を削除するため、 呼び出し側がクリーンアップするものはありません。 - Save stack
-
C doesn't have a concept of local scope, so perl provides one. We've seen that
ENTER
andLEAVE
are used as scoping braces; the save stack implements the C equivalent of, for example:C にはローカルスコープという概念がないので、perl が提供しています。
ENTER
とLEAVE
がスコープを作る中かっことして 使われていることを見てきました; 保存スタックは以下のような C に相当するものを実装しています:{ local $foo = 42; ... }
See "Localising Changes" in perlguts for how to use the save stack.
保存スタックの使い方については、 "Localising Changes" in perlguts を参照してください。
大量のマクロ¶
One thing you'll notice about the Perl source is that it's full of macros. Some have called the pervasive use of macros the hardest thing to understand, others find it adds to clarity. Let's take an example, the code which implements the addition operator:
Perl ソースに関して気付くかも知れない一つのことは、Perl ソースには マクロが豊富に含まれているということです。 マクロが広く使われていることを理解するのが最も難しいとする人もいれば、 マクロが明快さを増すと考える人もいます。 例えば、加算演算子を実装するコードを例にとりましょう:
1 PP(pp_add)
2 {
3 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
4 {
5 dPOPTOPnnrl_ul;
6 SETn( left + right );
7 RETURN;
8 }
9 }
Every line here (apart from the braces, of course) contains a macro. The first line sets up the function declaration as Perl expects for PP code; line 3 sets up variable declarations for the argument stack and the target, the return value of the operation. Finally, it tries to see if the addition operation is overloaded; if so, the appropriate subroutine is called.
ここの各行(もちろん中かっこを除く)にはマクロが含まれています。 最初の行は、Perl が PP コードに期待する関数宣言を設定します。 3 行目は、引数スタックと操作の戻り値であるターゲットの変数宣言を設定します。 最後に、加算操作がオーバーロードされているかどうかを調べます; オーバーロードされている場合は、適切なサブルーチンが呼び出されます。
Line 5 is another variable declaration - all variable declarations start with d
- which pops from the top of the argument stack two NVs (hence nn
) and puts them into the variables right
and left
, hence the rl
. These are the two operands to the addition operator. Next, we call SETn
to set the NV of the return value to the result of adding the two values. This done, we return - the RETURN
macro makes sure that our return value is properly handled, and we pass the next operator to run back to the main run loop.
5 行目はもう一つの変数宣言です - すべての変数宣言は d
で始まります - これは引数スタックの先頭から二つの NV(つまり nn
)を取り出し、それらを 変数 right
と left
(つまり rl
)に入れます。 これらは加算演算子に対する二つのオペランドです。 次に、SETn
を呼び出して、戻り値の NV を二つの値を加算した結果に 設定します。 これが終われば、返ります - RETURN
マクロは返り値が適切に処理されていることを確認し、 メインの実行ループに戻るために次の演算子を渡します。
Most of these macros are explained in perlapi, and some of the more important ones are explained in perlxs as well. Pay special attention to "Background and PERL_IMPLICIT_CONTEXT" in perlguts for information on the [pad]THX_?
macros.
これらのマクロのほとんどは perlapi で説明されていますし、 より重要なマクロのいくつかは perlxs でも説明されています。 [pad]THX_?
マクロに関する情報については、 "Background and PERL_IMPLICIT_CONTEXT" in perlguts に特に注意してください。
.i ターゲット¶
You can expand the macros in a foo.c file by saying
以下のようにすることで、foo.c ファイルのマクロを展開できます
make foo.i
which will expand the macros using cpp. Don't be scared by the results.
これは cpp を使ってマクロを展開します。 結果によって怯えないでください。
ソースコード静的解析¶
Various tools exist for analysing C source code statically, as opposed to dynamically, that is, without executing the code. It is possible to detect resource leaks, undefined behaviour, type mismatches, portability problems, code paths that would cause illegal memory accesses, and other similar problems by just parsing the C code and looking at the resulting graph, what does it tell about the execution and data flows. As a matter of fact, this is exactly how C compilers know to give warnings about dubious code.
C ソースコードを 静的 に、つまり 動的 とは対照的に、コードを実行せずに 分析するためのさまざまなツールが存在します。 リソースリーク、未定義動作、型の不一致、移植性の問題、不正なメモリアクセスを 引き起こすコードパス、その他同様の問題は、単に C コードを解析して結果の グラフを見るだけで、実行とデータフローについて何がわかるかを 検出することができます。 実際のところ、 C コンパイラが疑わしいコードについて警告を発する方法は まさにこれです。
lint, splint¶
The good old C code quality inspector, lint
, is available in several platforms, but please be aware that there are several different implementations of it by different vendors, which means that the flags are not identical across different platforms.
古き良き C コード品質インスペクタである lint
は、いくつかの プラットフォームで利用できますが、異なるベンダーによるいくつかの 異なる実装があることに注意してください; つまり、フラグは異なるプラットフォーム間で同一ではありません。
There is a lint variant called splint
(Secure Programming Lint) available from http://www.splint.org/ that should compile on any Unix-like platform.
http://www.splint.org/ から利用可能な splint
(Secure Programming Lint) と呼ばれる lint の亜種があり、 どんな Unix 風のプラットフォームでもコンパイルできるはずです。
There are lint
and <splint> targets in Makefile, but you may have to diddle with the flags (see above).
Makefile には lint
と <splint> ターゲットがありますが、フラグ(上記参照)を いじってみる必要があるかもしれません。
Coverity¶
Coverity (http://www.coverity.com/) is a product similar to lint and as a testbed for their product they periodically check several open source projects, and they give out accounts to open source developers to the defect databases.
Coverity (http://www.coverity.com/) は lint に似た製品で、彼らの製品の テストベッドとして、彼らは定期的にいくつかのオープンソースプロジェクトを チェックし、オープンソース開発者に欠陥データベースのアカウントを 提供しています。
cpd (コピペ検出器)¶
The cpd tool detects cut-and-paste coding. If one instance of the cut-and-pasted code changes, all the other spots should probably be changed, too. Therefore such code should probably be turned into a subroutine or a macro.
cpd ツールはカットアンドペーストのコーディングを検出します。 カットアンドペーストされたコードの一つのインスタンスが変更されると、 他のすべてのスポットも変更される必要があります。 したがって、そのようなコードはサブルーチンまたはマクロに変換される 必要があります。
cpd (http://pmd.sourceforge.net/cpd.html) is part of the pmd project (http://pmd.sourceforge.net/). pmd was originally written for static analysis of Java code, but later the cpd part of it was extended to parse also C and C++.
cpd (http://pmd.sourceforge.net/cpd.html) は pmd プロジェクトの一部です (http://pmd.sourceforge.net/)。 pmd はもともと Java コードの静的解析のために書かれましたが、後に cpd 部分が拡張されて C と C++ も解析できるようになりました。
Download the pmd-bin-X.Y.zip () from the SourceForge site, extract the pmd-X.Y.jar from it, and then run that on source code thusly:
SourceForge のサイトからpmd-bin-X.Y.zip()をダウンロードし、そこから pmd-X.Y.jar を抽出し、次のようにソースコードに対して実行します:
java -cp pmd-X.Y.jar net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /some/where/src --language c > cpd.txt
You may run into memory limits, in which case you should use the -Xmx option:
メモリ制限に到達する場合があります。 その場合は-Xmxオプションを使ってください:
java -Xmx512M ...
gcc の警告¶
Though much can be written about the inconsistency and coverage problems of gcc warnings (like -Wall
not meaning "all the warnings", or some common portability problems not being covered by -Wall
, or -ansi
and -pedantic
both being a poorly defined collection of warnings, and so forth), gcc is still a useful tool in keeping our coding nose clean.
(-Wall
が「全ての警告」を意味しなかったり、-Wall
が基本的な移植性問題に 対応していなかったり、-ansi
と -pedantic
の両方は対応する警告が 貧弱であったり、というような) gcc の警告に関する非一貫性と対応範囲についての 問題点はたくさん書かれてはいますが、gcc は未だにコードをきれいに保つのに 有用なツールです。
The -Wall
is by default on.
-Wall
はデフォルトでオンです。
The -ansi
(and its sidekick, -pedantic
) would be nice to be on always, but unfortunately they are not safe on all platforms, they can for example cause fatal conflicts with the system headers (Solaris being a prime example). If Configure -Dgccansipedantic
is used, the cflags
frontend selects -ansi -pedantic
for the platforms where they are known to be safe.
-ansi
(およびその親類である -pedantic
) も常にオンにしたいですが、 残念ながら全てのプラットフォームで安全というわけではありません; 例えば システムヘッダと致命的な衝突を引き起こすことがあります (Solaris が 第一の例です)。 Configure で -Dgccansipedantic
を使うと、cflags
フロントエンドは 安全と分かっているプラットフォームでだけ -ansi -pedantic
を選択します。
Starting from Perl 5.9.4 the following extra flags are added:
Perl 5.9.4 から以下のフラグが追加されました:
-Wendif-labels
-Wextra
-Wdeclaration-after-statement
The following flags would be nice to have but they would first need their own Augean stablemaster:
以下のフラグがあると便利ですが、最初に整理が必要です:
-Wpointer-arith
-Wshadow
-Wstrict-prototypes
The -Wtraditional
is another example of the annoying tendency of gcc to bundle a lot of warnings under one switch (it would be impossible to deploy in practice because it would complain a lot) but it does contain some warnings that would be beneficial to have available on their own, such as the warning about string constants inside macros containing the macro arguments: this behaved differently pre-ANSI than it does in ANSI, and some C compilers are still in transition, AIX being an example.
-Wtraditional
は、gcc が一つのスイッチに多数の警告をバンドルするという 厄介な傾向のもう一つの例です (多くの警告が 出るので、実際に展開することは不可能です) しかし、-Wtraditional
には、 マクロ引数を含むマクロ内の文字列定数に関する警告など、単独で 利用できるようにしておくと有益な警告がいくつか含まれています: これは ANSI 以前と ANSI では動作が異なり、いくつかのCコンパイラは まだ移行中で、AIX がその一例です。
その他の C コンパイラの警告¶
Other C compilers (yes, there are other C compilers than gcc) often have their "strict ANSI" or "strict ANSI with some portability extensions" modes on, like for example the Sun Workshop has its -Xa
mode on (though implicitly), or the DEC (these days, HP...) has its -std1
mode on.
他の C コンパイラ(もちろん、gcc 以外の C コンパイラも あります)はしばしば 「厳密な ANSI」 や 「厳密な ANSI といくつかの移植性の拡張」モードを オンにしています; 例えば、Sun Workshop では -Xa
モードが(暗黙的ですが)オンになっていたり、 DEC (最近では HP…)では -std1
モードがオンになっていたりします。
デバッグ¶
You can compile a special debugging version of Perl, which allows you to use the -D
option of Perl to tell more about what Perl is doing. But sometimes there is no alternative than to dive in with a debugger, either to see the stack trace of a core dump (very useful in a bug report), or trying to figure out what went wrong before the core dump happened, or how did we end up having wrong or unexpected results.
Perlの -D
オプションを使って、Perl が何をしているのかを詳しく 知ることができるように、Perl の特別なデバッグバージョンを コンパイルすることができます。 しかし、場合によっては、デバッガを使って、コアダンプのスタックトレースを 調べたり(バグレポートで非常に役立ちます)、コアダンプが発生する前に何が 間違っていたのかを調べたり、どのようにして間違った結果や予期しない結果に なったのかを調べたりする以外に方法がないこともあります。
Perl をつつく¶
To really poke around with Perl, you'll probably want to build Perl for debugging, like this:
実際に Perl をつつくためには、おそらく以下のようにデバッグ用の Perl を ビルドしたいでしょう:
./Configure -d -D optimize=-g
make
-g
is a flag to the C compiler to have it produce debugging information which will allow us to step through a running program, and to see in which C function we are at (without the debugging information we might see only the numerical addresses of the functions, which is not very helpful).
-g
は、C コンパイラに対して、実行中のプログラムをステップ実行するため、 そしてどの C 関数にいるのかを調べるためのデバッグ情報を生成させるための フラグです(デバッグ情報がなければ、関数の数値アドレスだけが表示されますが、 あまり役に立ちません)。
Configure will also turn on the DEBUGGING
compilation symbol which enables all the internal debugging code in Perl. There are a whole bunch of things you can debug with this: perlrun lists them all, and the best way to find out about them is to play about with them. The most useful options are probably
Configure は DEBUGGING
コンパイルシンボルも有効にします; これは Perl の全ての内部デバッグコードを有効にします。 これでデバッグできるものはたくさんあります: perlrunはそれらをすべてリストしています; それらについて知るための最良の方法は、それらをいじってみることです。 最も有用なオプションはおそらく次のようになります:
l Context (loop) stack processing
t Trace execution
o Method and overloading resolution
c String/numeric conversions
Some of the functionality of the debugging code can be achieved using XS modules.
コードのデバッグの機能の一部は XS モジュールを使って実現できます。
-Dr => use re 'debug'
-Dx => use O 'Debug'
ソースレベルデバッガを使う¶
If the debugging output of -D
doesn't help you, it's time to step through perl's execution with a source-level debugger.
-D
のデバッグ出力が役に立たない場合は、ソースレベルのデバッガを使って perl の実行を順に追ってみましょう。
-
We'll use
gdb
for our examples here; the principles will apply to any debugger (many vendors call their debuggerdbx
), but check the manual of the one you're using.ここでは例として
gdb
を使います; この原則はどのデバッガにも適用されます(多くのベンダーではデバッガをdbx
と呼んでいます)が、使っているデバッガのマニュアルを 確認してください。
To fire up the debugger, type
デバッガを起動するには、以下のようにタイプします:
gdb ./perl
Or if you have a core dump:
あるいはコアダンプがあるなら:
gdb ./perl core
You'll want to do that in your Perl source tree so the debugger can read the source code. You should see the copyright message, followed by the prompt.
Perl ソースツリーで行い、デバッガがソースコードを読み取ることが できるようにします。 copyrightメッセージに続いてプロンプトが表示されます。
(gdb)
help
will get you into the documentation, but here are the most useful commands:
help
で文書を参照できますが、最も便利なコマンドは以下のとおりです:
- run [args]
-
Run the program with the given arguments.
引数を指定してプログラムを実行します。
- break function_name
- break source.c:xxx
-
Tells the debugger that we'll want to pause execution when we reach either the named function (but see "Internal Functions" in perlguts!) or the given line in the named source file.
指定された関数 (ただし "Internal Functions" in perlguts を参照!)または 指定されたソースファイル内の指定された行に到達したときに、実行を 一時停止するようデバッガに指示します。
- step
-
Steps through the program a line at a time.
一度に 1 行、プログラムをステップ実行します。
- next
-
Steps through the program a line at a time, without descending into functions.
一度に 1 行、関数を下っていかずにプログラムをステップ実行します。
- continue
-
Run until the next breakpoint.
次のブレークポイントまで実行します。
- finish
-
Run until the end of the current function, then stop again.
現在の関数の末尾まで実行して、もう一度停止します。
- 'enter'
-
Just pressing Enter will do the most recent operation again - it's a blessing when stepping through miles of source code.
単に Enter キーを押すと、直前の操作をもう一度実行します - これは 大量のソースコードをステップ実行するときに助けになります。
-
Execute the given C code and print its results. WARNING: Perl makes heavy use of macros, and gdb does not necessarily support macros (see later "gdb macro support"). You'll have to substitute them yourself, or to invoke cpp on the source code files (see "The .i Targets") So, for instance, you can't say
指定された C コードを実行し、その結果を出力します。 警告: Perl はマクロを多用していますが、gdb は必ずしもマクロを サポートしていません(後述の "gdb macro support" を参照してください)。 それらを自分で置き換えるか、ソースコードファイルで cpp を起動する 必要があります("The .i Targets" を参照してください)。 ですから例えばこのようにはできず:
print SvPV_nolen(sv)
but you have to say
以下のように書く必要があります
print Perl_sv_2pv_nolen(sv)
You may find it helpful to have a "macro dictionary", which you can produce by saying cpp -dM perl.c | sort
. Even then, cpp won't recursively apply those macros for you.
cpp -dM perl.c | sort
として生成できる「マクロ辞書」があると 便利かもしれません。 それでも、cpp はこれらのマクロを再帰的に適用しません。
gdb マクロ対応¶
Recent versions of gdb have fairly good macro support, but in order to use it you'll need to compile perl with macro definitions included in the debugging information. Using gcc version 3.1, this means configuring with -Doptimize=-g3
. Other compilers might use a different switch (if they support debugging macros at all).
gdb の最近のバージョンはかなり良いマクロサポートを持っていますが、 それを使うためにはデバッグ情報にマクロ定義が含まれている perl を コンパイルする必要があります。 gcc バージョン 3.1 を使うと、-Doptimize=-g3
で設定することになります。 他のコンパイラは(もしデバッグマクロをサポートしていれば)別のスイッチを 使うかもしれません。
Perl データ構造体をダンプする¶
One way to get around this macro hell is to use the dumping functions in dump.c; these work a little like an internal Devel::Peek, but they also cover OPs and other structures that you can't get at from Perl. Let's take an example. We'll use the $a = $b + $c
we used before, but give it a bit of context: $b = "6XXXX"; $c = 2.3;
. Where's a good place to stop and poke around?
このマクロ地獄を回避する一つの方法は、dump.c のダンプ関数を 使うことです; これらの関数は、内部の Devel::Peek と少し似た動作ですが、 Perl からは得られない OP やその他の構造体もカバーしています。 例を挙げてみましょう。 前に使った $a = $b + $c
を使いますが、$b = "6XXXX"; $c = 2.3;
という コンテキストを少し説明します。 立ち止まって歩き回るのに良い場所はどこでしょう?
What about pp_add
, the function we examined earlier to implement the +
operator:
先ほど +
演算子を実装するために検討した関数 pp_add
については どうでしょう:
(gdb) break Perl_pp_add
Breakpoint 1 at 0x46249f: file pp_hot.c, line 309.
Notice we use Perl_pp_add
and not pp_add
- see "Internal Functions" in perlguts. With the breakpoint in place, we can run our program:
pp_add
ではなく Perl_pp_add
を使っていることに注意してください - "Internal Functions" in perlgutsを参照してください。 ブレークポイントを設定すると、プログラムを実行できます:
(gdb) run -e '$b = "6XXXX"; $c = 2.3; $a = $b + $c'
Lots of junk will go past as gdb reads in the relevant source files and libraries, and then:
gdb が関連するソースファイルやライブラリを読み込むので 多くのガラクタが通り過ぎ、それから:
Breakpoint 1, Perl_pp_add () at pp_hot.c:309
309 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
(gdb) step
311 dPOPTOPnnrl_ul;
(gdb)
We looked at this bit of code before, and we said that dPOPTOPnnrl_ul
arranges for two NV
s to be placed into left
and right
- let's slightly expand it:
前にこのコードを見ましたが、dPOPTOPnnrl_ul
は二つの NV
を left
と right
に配置するようにアレンジしていると言いました - 少し拡張してみましょう:
#define dPOPTOPnnrl_ul NV right = POPn; \
SV *leftsv = TOPs; \
NV left = USE_LEFT(leftsv) ? SvNV(leftsv) : 0.0
POPn
takes the SV from the top of the stack and obtains its NV either directly (if SvNOK
is set) or by calling the sv_2nv
function. TOPs
takes the next SV from the top of the stack - yes, POPn
uses TOPs
- but doesn't remove it. We then use SvNV
to get the NV from leftsv
in the same way as before - yes, POPn
uses SvNV
.
POPn
はスタックの先頭から SV を取得し、直接(SvNOK
が設定されている 場合)または sv_2nv
関数を呼び出すことによって NV を取得します。 TopS
はスタックの先頭から次の SV を取得します - はい、POPn
は TopS
を使います - ただし、SV は削除されません。 次に SvNV
を使って、以前と同じ方法で leftsv
から NV を取得します - はい、POPn
は SvNV
を使います。
Since we don't have an NV for $b
, we'll have to use sv_2nv
to convert it. If we step again, we'll find ourselves there:
$b
には NV がないので、sv_2nv
を使って変換する必要があります。 もう一度ステップ実行すると、そこにいることがわかるでしょう:
Perl_sv_2nv (sv=0xa0675d0) at sv.c:1669
1669 if (!sv)
(gdb)
We can now use Perl_sv_dump
to investigate the SV:
次に、Perl_sv_dump
を使って SV を調査します:
SV = PV(0xa057cc0) at 0xa0675d0
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0xa06a510 "6XXXX"\0
CUR = 5
LEN = 6
$1 = void
We know we're going to get 6
from this, so let's finish the subroutine:
ここから 6
が得られることはわかっているので、サブルーチンを 終了しましょう:
(gdb) finish
Run till exit from #0 Perl_sv_2nv (sv=0xa0675d0) at sv.c:1671
0x462669 in Perl_pp_add () at pp_hot.c:311
311 dPOPTOPnnrl_ul;
We can also dump out this op: the current op is always stored in PL_op
, and we can dump it with Perl_op_dump
. This'll give us similar output to B::Debug.
この op をダンプすることもできます: 現在の op は常に PL_op
に保存されており、Perl_op_dump
で ダンプすることができます。 これにより、B::Debug と同様の出力が得られます。
{
13 TYPE = add ===> 14
TARG = 1
FLAGS = (SCALAR,KIDS)
{
TYPE = null ===> (12)
(was rv2sv)
FLAGS = (SCALAR,KIDS)
{
11 TYPE = gvsv ===> 12
FLAGS = (SCALAR)
GV = main::b
}
}
# finish this later #
パッチを当てる¶
All right, we've now had a look at how to navigate the Perl sources and some things you'll need to know when fiddling with them. Let's now get on and create a simple patch. Here's something Larry suggested: if a U
is the first active format during a pack
, (for example, pack "U3C8", @stuff
) then the resulting string should be treated as UTF-8 encoded.
ここまでで、Perl ソースをナビゲートする方法と、ソースを操作するときに 知っておく必要があることについて説明しました。 では、簡単なパッチを作成してみましょう。 Larry が提案したことは、U
が pack
中で最初に アクティブなフォーマットである場合(たとえば、pack "U3C8", @stuff
)、 結果の文字列は UTF-8 エンコードとして扱われるべきであるということです。
If you are working with a git clone of the Perl repository, you will want to create a branch for your changes. This will make creating a proper patch much simpler. See the perlrepository for details on how to do this.
Perl リポジトリの git クローン上で作業しているなら、 あなたの変更のためのブランチを作成した方が良いでしょう。 これにより適切なパッチの作成がを大幅に簡単になります。 この方法に関する詳細については perlrepository を参照してください。
How do we prepare to fix this up? First we locate the code in question - the pack
happens at runtime, so it's going to be in one of the pp files. Sure enough, pp_pack
is in pp.c. Since we're going to be altering this file, let's copy it to pp.c~.
この問題を解決するための準備はどうすればいいでしょう? まず問題のコードを見つけます - pack
は実行時に発生するので、 pp ファイルの一つにあるはずです。 pp_pack
は pp.c にあります。 このファイルを変更するので、pp.c~ にコピーします。
[Well, it was in pp.c when this tutorial was written. It has now been split off with pp_unpack
to its own file, pp_pack.c]
[そうですね、このチュートリアルが書かれたときは pp.c に書かれていました。 現在は pp_unpack
とともに独自のファイル pp_pack.c に分割されています]
Now let's look over pp_pack
: we take a pattern into pat
, and then loop over the pattern, taking each format character in turn into datum_type
. Then for each possible format character, we swallow up the other arguments in the pattern (a field width, an asterisk, and so on) and convert the next chunk input into the specified format, adding it onto the output SV cat
.
pp_pack
を見てみましょう: パターンを pat
に取り込み、そのパターンをループして、各フォーマット文字を 順番に datum_type
に取り込みます。 次に、可能なフォーマット文字ごとに、パターン内の他の引数 (フィールド幅やアスタリスクなど)を取り込み、 次のチャンク入力を指定されたフォーマットに変換し、 出力 SV cat
に追加します。
How do we know if the U
is the first format in the pat
? Well, if we have a pointer to the start of pat
then, if we see a U
we can test whether we're still at the start of the string. So, here's where pat
is set up:
U
が pat
の最初のフォーマットであるかどうかはどうすれば わかるでしょう? さて、pat
の先頭へのポインタがあれば、U
が見つかったら、 まだ文字列の先頭にいるかどうかをテストできます。 ここで pat
が設定されています:
STRLEN fromlen;
register char *pat = SvPVx(*++MARK, fromlen);
register char *patend = pat + fromlen;
register I32 len;
I32 datumtype;
SV *fromstr;
We'll have another string pointer in there:
ここには別の文字列ポインタがあります:
STRLEN fromlen;
register char *pat = SvPVx(*++MARK, fromlen);
register char *patend = pat + fromlen;
+ char *patcopy;
register I32 len;
I32 datumtype;
SV *fromstr;
And just before we start the loop, we'll set patcopy
to be the start of pat
:
ループを開始する直前に、patcopy
を pat
の開始点に設定します。
items = SP - MARK;
MARK++;
sv_setpvn(cat, "", 0);
+ patcopy = pat;
while (pat < patend) {
Now if we see a U
which was at the start of the string, we turn on the UTF8
flag for the output SV, cat
:
文字列の先頭に U
がある場合、出力 SV である cat
に対して UTF8
フラグをオンにします。
+ if (datumtype == 'U' && pat==patcopy+1)
+ SvUTF8_on(cat);
if (datumtype == '#') {
while (pat < patend && *pat != '\n')
pat++;
Remember that it has to be patcopy+1
because the first character of the string is the U
which has been swallowed into datumtype!
文字列の最初の文字は datumtype
に飲み込まれたU
なので、 これは patcopy+1
でなければならないことを覚えておいてください!
Oops, we forgot one thing: what if there are spaces at the start of the pattern? pack(" U*", @stuff)
will have U
as the first active character, even though it's not the first thing in the pattern. In this case, we have to advance patcopy
along with pat
when we see spaces:
おっと、ひとつ忘れていました: パターンの先頭にスペースがあったら? pack(" U*", @stuff)
は、パターンの先頭ではないにもかかわらず、 最初のアクティブな文字として U
を持ちます。 この場合、スペースがあるときは、pat
とともに patcopy
を 進める必要があります:
if (isSPACE(datumtype))
continue;
needs to become
これは次のようにする必要があります:
if (isSPACE(datumtype)) {
patcopy++;
continue;
}
OK. That's the C part done. Now we must do two additional things before this patch is ready to go: we've changed the behaviour of Perl, and so we must document that change. We must also provide some more regression tests to make sure our patch works and doesn't create a bug somewhere else along the line.
OK。 これで C の部分は完了です。 次に、このパッチを準備する前に、次の二つのことを行う必要があります: Perlの動作を変更したので、その変更を文書化する必要があります。 また、パッチが動作し、他の場所でバグが発生しないことを確認するために、 さらに回帰テストを提供する必要があります。
The regression tests for each operator live in t/op/, and so we make a copy of t/op/pack.t to t/op/pack.t~. Now we can add our tests to the end. First, we'll test that the U
does indeed create Unicode strings.
各演算子の退行テストは t/op/ に存在するため、 t/op/pack.t から t/op/pack.t~ へのコピーを作成します。 これで、テストを最後に追加できます。 まず、U
が実際に Unicode 文字列を作成することをテストします。
t/op/pack.t has a sensible ok() function, but if it didn't we could use the one from t/test.pl.
t/op/pack.t には適切な ok() 関数がありますが、そうでなければ t/test.pl の関数を使うことができます。
require './test.pl';
plan( tests => 159 );
so instead of this:
それで次のようにする代わりに:
print 'not ' unless "1.20.300.4000" eq sprintf "%vd", pack("U*",1,20,300,4000);
print "ok $test\n"; $test++;
we can write the more sensible (see Test::More for a full explanation of is() and other testing functions).
より実用的な関数を書くことができます (is() やその他のテスト関数の詳細については Test::More を参照してください)。
is( "1.20.300.4000", sprintf "%vd", pack("U*",1,20,300,4000),
"U* produces Unicode" );
Now we'll test that we got that space-at-the-beginning business right:
では、私たちが最初の場所でビジネスの権利を得たことを テストしてみましょう:
is( "1.20.300.4000", sprintf "%vd", pack(" U*",1,20,300,4000),
" with spaces at the beginning" );
And finally we'll test that we don't make Unicode strings if U
is not the first active format:
最後に、U
が not である場合、Unicode 文字列を作成しないことを テストします:
isnt( v1.20.300.4000, sprintf "%vd", pack("C0U*",1,20,300,4000),
"U* not first isn't Unicode" );
Mustn't forget to change the number of tests which appears at the top, or else the automated tester will get confused. This will either look like this:
一番上にあるテストの数を変更することを忘れないでください; さもないと、自動化されたテスターが混乱します。 これは以下のようになります:
print "1..156\n";
or this:
または次のようになります:
plan( tests => 156 );
We now compile up Perl, and run it through the test suite. Our new tests pass, hooray!
今度は Perl をコンパイルして、テストスイートで実行します。 新しいテストに合格しました、万歳!
Finally, the documentation. The job is never done until the paperwork is over, so let's describe the change we've just made. The relevant place is pod/perlfunc.pod; again, we make a copy, and then we'll insert this text in the description of pack
:
最後に、文書です。 事務処理が終わるまで仕事は終わらないので、 今行った変更について説明しましょう。 関連する場所は pod/perlfunc.pod です; ここでもコピーを作成し、pack
の説明に次のテキストを挿入します:
=item *
If the pattern begins with a C<U>, the resulting string will be treated
as UTF-8-encoded Unicode. You can force UTF-8 encoding on in a string
with an initial C<U0>, and the bytes that follow will be interpreted as
Unicode characters. If you don't want this to happen, you can begin your
pattern with C<C0> (or anything else) to force Perl not to UTF-8 encode your
string, and then follow this with a C<U*> somewhere in your pattern.
コアモジュールにパッチを当てる¶
This works just like patching anything else, with an extra consideration. Many core modules also live on CPAN. If this is so, patch the CPAN version instead of the core and send the patch off to the module maintainer (with a copy to p5p). This will help the module maintainer keep the CPAN version in sync with the core version without constantly scanning p5p.
これは他のパッチと同じように動作しますが、特別な注意が必要です。 多くのコアモジュールは CPAN 上にもあります。 その場合は、コアではなく CPAN バージョンにパッチを適用し、 モジュールメンテナにパッチを送ります(p5p へのコピーと共に)。 これは、モジュールメンテナが p5p を絶えずスキャンすることなく、 CPAN バージョンをコアバージョンと同期させるのに役立ちます。
The list of maintainers of core modules is usefully documented in Porting/Maintainers.pl.
コアモジュールのメンテナのリストは、Porting/Maintainers.pl に 記載されています。
コアに新しい関数を追加する¶
If, as part of a patch to fix a bug, or just because you have an especially good idea, you decide to add a new function to the core, discuss your ideas on p5p well before you start work. It may be that someone else has already attempted to do what you are considering and can give lots of good advice or even provide you with bits of code that they already started (but never finished).
バグを修正するためのパッチの一部として、または単に特別に優れたアイデアが あるという理由で、コアに新しい関数を追加することに決めた場合は、 作業を始める前に p5p でアイデアについて十分に議論してください。 あなたが考えていることを他の誰かがすでに実行しようとしており、多くの 優れたアドバイスを与えてくれたり、彼らがすでに開始している (まだ完了していない)コードの一部を提供したりしている可能性すらあります。
You have to follow all of the advice given above for patching. It is extremely important to test any addition thoroughly and add new tests to explore all boundary conditions that your new function is expected to handle. If your new function is used only by one module (e.g. toke), then it should probably be named S_your_function (for static); on the other hand, if you expect it to accessible from other functions in Perl, you should name it Perl_your_function. See "Internal Functions" in perlguts for more details.
パッチ適用については、前述のすべてのアドバイスに従う必要があります。 追加を徹底的にテストし、新しいテストを追加して、新しい関数が処理すると 予想されるすべての境界条件を調べることが非常に重要です。 新しい関数が一つのモジュール(toke など)のみで使われる場合は、 (static から) S_your_function という名前にする必要があります; 一方、Perl の他の関数からアクセスできると予想される場合は、 Perl_your_function という名前にする必要があります。 更なる詳細については、"Internal Functions" in perlguts を参照してください。
The location of any new code is also an important consideration. Don't just create a new top level .c file and put your code there; you would have to make changes to Configure (so the Makefile is created properly), as well as possibly lots of include files. This is strictly pumpking business.
新しいコードの場所も重要な考慮事項です。 単に新しい最上位レベルの .c ファイルを作成してそこにコードを 置かないでください; Configure を変更し(Makefile が正しく作成されるように)、 多くのインクルードファイルも変更する必要があります。 これはまさにパンプキンの仕事です。
It is better to add your function to one of the existing top level source code files, but your choice is complicated by the nature of the Perl distribution. Only the files that are marked as compiled static are located in the perl executable. Everything else is located in the shared library (or DLL if you are running under WIN32). So, for example, if a function was only used by functions located in toke.c, then your code can go in toke.c. If, however, you want to call the function from universal.c, then you should put your code in another location, for example util.c.
既存のトップレベルソースコードファイルの一つに関数を追加することを お薦めしますが、Perl 配布の性質上、選択が複雑になります。 コンパイル済み静的としてマークされたファイルのみが perl 実行可能ファイルに 配置されます。 その他はすべて共有ライブラリ(または WIN32 で実行している場合は DLL)に 配置されます。 たとえば、ある関数が toke.c にある関数によってのみ使われていた場合、 コードは toke.c に配置できます。 ただし、universal.c から関数を呼び出す場合は、util.c などの別の場所に コードを配置する必要があります。
In addition to writing your c-code, you will need to create an appropriate entry in embed.pl describing your function, then run 'make regen_headers' to create the entries in the numerous header files that perl needs to compile correctly. See "Internal Functions" in perlguts for information on the various options that you can set in embed.pl. You will forget to do this a few (or many) times and you will get warnings during the compilation phase. Make sure that you mention this when you post your patch to P5P; the pumpking needs to know this.
c コードを書くことに加えて、embed.pl に関数を記述する適切なエントリを 作成する必要があります。 そして 'make regen_headers' を実行して、perl が正しくコンパイルするために 必要な多数のヘッダファイルにエントリを作成します。 embed.pl に設定できるさまざまなオプションについては、 "Internal Functions" in perlguts を参照してください。 これを何回か(あるいは何回も)行うことを忘れ、コンパイル時に 警告が表示されることになるでしょう。 P5Pに パッチを投稿する際には、このことを必ず伝えてください; パンプキンはこのことを知る必要があります。
When you write your new code, please be conscious of existing code conventions used in the perl source files. See perlstyle for details. Although most of the guidelines discussed seem to focus on Perl code, rather than c, they all apply (except when they don't ;). Also see perlrepository for lots of details about both formatting and submitting patches of your changes.
新しいコードを作成する際には、perl ソースファイルで使われている既存の コード規則に従ってください。 詳細は perlstyle を参照してください。 議論されているガイドラインのほとんどは、c ではなく Perl コードに焦点を 当てているようですが、それらはすべて適用されます(適用されない場合を 除きます ;)。 また、変更のパッチの書式設定と送信の詳細については perlrepository も参照してください。
Lastly, TEST TEST TEST TEST TEST any code before posting to p5p. Test on as many platforms as you can find. Test as many perl Configure options as you can (e.g. MULTIPLICITY). If you have profiling or memory tools, see "EXTERNAL TOOLS FOR DEBUGGING PERL" below for how to use them to further test your code. Remember that most of the people on P5P are doing this on their own time and don't have the time to debug your code.
最後に、p5p に投稿する前に、全てのコードを テストテストテストテストテストします。 可能な限り多くのプラットフォームでテストします。 可能な限り多くの perl Configure オプションでテストします (例: MULTIPLICITY)。 プロファイルツールやメモリツールをお持ちの場合は、以下の "EXTERNAL TOOLS FOR DEBUGGING PERL" を参照して、これらのツールを使って コードをさらにテストする方法を確認してください。 p5p のほとんどの人は、自分の時間でこれを行っており、あなたのコードを デバッグする時間がないことを覚えておいてください。
テストを書く¶
Every module and built-in function has an associated test file (or should...). If you add or change functionality, you have to write a test. If you fix a bug, you have to write a test so that bug never comes back. If you alter the docs, it would be nice to test what the new documentation says.
すべてのモジュールおよび組み込み関数には関連付けられたテストファイルが あります。 (または そうあるべきです…)。 機能を追加または変更する場合は、テストを記述する必要があります。 バグを修正する場合は、バグが再発しないようにテストを記述する必要があります。 文書を変更する場合は、新しい文書に記載されている内容を テストするとよいでしょう。
In short, if you submit a patch you probably also have to patch the tests.
つまり、パッチを送信する場合は、おそらくテストにもパッチを 当てる必要があります。
For modules, the test file is right next to the module itself. lib/strict.t tests lib/strict.pm. This is a recent innovation, so there are some snags (and it would be wonderful for you to brush them out), but it basically works that way. Everything else lives in t/.
モジュールの場合、テストファイルはモジュール自体のすぐ隣にあります。 lib/strict.t は lib/strict.pm をテストします。 これは最近のイノベーションなので、いくつかの障害があります (そしてそれらを取り除くことは素晴らしいことです)が、 基本的にはそのように機能します。 他のすべては t/ に存在します。
If you add a new test directory under t/, it is imperative that you add that directory to t/HARNESS and t/TEST.
t/ の下に新しいテストディレクトリを追加する場合は、そのディレクトリを t/HARNESS と t/TEST に追加する必要があります。
- t/base/
-
Testing of the absolute basic functionality of Perl. Things like
if
, basic file reads and writes, simple regexes, etc. These are run first in the test suite and if any of them fail, something is really broken.Perl の絶対的な基本機能のテスト。
if
、基本的なファイルの読み書き、単純な正規表現など。 これらはテストスイートで最初に実行され、それらのいずれかが失敗した場合、 何かが 本当に 壊れていることになります。 - t/cmd/
-
These test the basic control structures,
if/else
,while
, subroutines, etc.これらは、基本制御構造、
if/else
、while
、サブルーチンなどを テストします。 - t/comp/
-
Tests basic issues of how Perl parses and compiles itself.
Perl の構文解析およびコンパイル方法に関する基本的な問題をテストします。
- t/io/
-
Tests for built-in IO functions, including command line arguments.
コマンドライン引数を含む組み込み IO 関数をテストします。
- t/lib/
-
The old home for the module tests, you shouldn't put anything new in here. There are still some bits and pieces hanging around in here that need to be moved. Perhaps you could move them? Thanks!
モジュールテストの古いホームです; ここに新しいものを置くべきではありません。 ここにはまだ動かす必要のあるいくつかの断片が残っています。 それらを動かすことはできますか? ありがとう!
- t/mro/
-
Tests for perl's method resolution order implementations (see mro).
perl のメソッド解決順序実装(mro を参照)をテストします。
- t/op/
-
Tests for perl's built in functions that don't fit into any of the other directories.
perl に組み込まれている関数のうち、他のどのディレクトリにも適合しない 関数をテストします。
- t/re/
-
Tests for regex related functions or behaviour. (These used to live in t/op).
正規表現関係の関数や振る舞いに関するテストをします。 (これらは以前は t/op にありました)。
- t/run/
-
Testing features of how perl actually runs, including exit codes and handling of PERL* environment variables.
終了コードや PERL* 環境変数の処理など、perl が 実際にどのように実行されるかをテストします。
- t/uni/
-
Tests for the core support of Unicode.
Unicode のコア対応をテストします。
- t/win32/
-
Windows-specific tests.
Windows 固有のテスト。
- t/x2p
-
A test suite for the s2p converter.
s2p コンバータ用のテストスイート。
The core uses the same testing style as the rest of Perl, a simple "ok/not ok" run through Test::Harness, but there are a few special considerations.
コアは Perl の他の部分と同じテストスタイルを使っており、 Test::Harness を通して単純な「ok/not ok」を実行しますが、 いくつか特別な考慮事項があります。
There are three ways to write a test in the core. Test::More, t/test.pl and ad hoc print $test ? "ok 42\n" : "not ok 42\n"
. The decision of which to use depends on what part of the test suite you're working on. This is a measure to prevent a high-level failure (such as Config.pm breaking) from causing basic functionality tests to fail.
コアにテストを記述する方法は三つあります。 Test::More, t/test.pl, アドホックな print $test ? "ok 42\n" : "not ok 42\n"
です。 どれを使うかは、テストスイートのどの部分で 作業しているかによって決まります。 これは、高レベルの障害(Config.pm の破損など)によって基本的な機能テストが 失敗しないようにするための手段です。
- t/base t/comp
-
Since we don't know if require works, or even subroutines, use ad hoc tests for these two. Step carefully to avoid using the feature being tested.
require が動作するのか、あるいはサブルーチンでさえも分からないので、 この二つに対してはアドホックテストを使ってください。 テスト中の機能を使わないように注意してください。
- t/cmd t/run t/io t/op
-
Now that basic require() and subroutines are tested, you can use the t/test.pl library which emulates the important features of Test::More while using a minimum of core features.
これで基本的な require() とサブルーチンがテストされたので、最小限のコア機能を 使いながら Test::More の重要な機能をエミュレートする t/test.pl ライブラリを 使うことができます。
You can also conditionally use certain libraries like Config, but be sure to skip the test gracefully if it's not there.
Config のような特定のライブラリを条件付きで使うこともできますが、 テストがない場合にはテストを省略するようにしてください。
- t/lib ext lib
-
Now that the core of Perl is tested, Test::More can be used. You can also use the full suite of core modules in the tests.
Perl のコアがテストされたので、Test::More を使うことができます。 また、コアモジュールの完全なスイートをテストで使うこともできます。
When you say "make test" Perl uses the t/TEST program to run the test suite (except under Win32 where it uses t/harness instead.) All tests are run from the t/ directory, not the directory which contains the test. This causes some problems with the tests in lib/, so here's some opportunity for some patching.
"make test" とすれば、Perl は t/TEST プログラムを使って テストスイートを実行します(Win32 では、代わりに t/harness を使います)。 すべてのテストは t/ ディレクトリから実行され、テストを含む ディレクトリでは ありません。 このため、lib/ 内のテストで問題が発生するので、パッチを適用する 機会があります。
You must be triply conscious of cross-platform concerns. This usually boils down to using File::Spec and avoiding things like fork()
and system()
unless absolutely necessary.
クロスプラットフォームに関する懸念を 3 倍意識する必要があります。 これは通常、File::Spec を使い、絶対に必要でない限り fork()
や system()
のようなものを避けることに要約されます。
特殊 make test ターゲット¶
There are various special make targets that can be used to test Perl slightly differently than the standard "test" target. Not all them are expected to give a 100% success rate. Many of them have several aliases, and many of them are not available on certain operating systems.
標準の "test" ターゲットとは若干異なる方法で Perl をテストするために 使える特殊な make ターゲットがいくつかあります。 すべての make ターゲットが 100% の成功率を示すとは限りません。 これらの多くには複数の別名があり、その多くは特定の オペレーティングシステムでは使えません。
- coretest
-
Run perl on all core tests (t/* and lib/[a-z]* pragma tests).
全てのコアテスト (t/* と lib/[a-z]* プラグマテスト) で perl を 実行します。
(Not available on Win32)
(Win32 では利用できません)
- test.deparse
-
Run all the tests through B::Deparse. Not all tests will succeed.
全てのテストを B::Deparse を通して実行します。 全てのテストが成功するわけではありません。
(Not available on Win32)
(Win32 では利用できません)
- test.taintwarn
-
Run all tests with the -t command-line switch. Not all tests are expected to succeed (until they're specifically fixed, of course).
全てのテストを -t コマンドラインスイッチ付きで実行します。 全てのテストが成功するとは想定されません(もちろん具体的に修正するまでです)。
(Not available on Win32)
(Win32 では利用できません)
- minitest
-
Run miniperl on t/base, t/comp, t/cmd, t/run, t/io, t/op, t/uni and t/mro tests.
t/base, t/comp, t/cmd, t/run, t/io, t/op, t/uni, t/mro テストで miniperl を実行します。
- test.valgrind check.valgrind utest.valgrind ucheck.valgrind
-
(Only in Linux) Run all the tests using the memory leak + naughty memory access tool "valgrind". The log files will be named testname.valgrind.
(Linux のみ) 全てのテストをメモリリーク+メモリアクセスツール "valgrind" を使って実行します。 ログファイルの名前は testname.valgrind です。
- test.third check.third utest.third ucheck.third
-
(Only in Tru64) Run all the tests using the memory leak + naughty memory access tool "Third Degree". The log files will be named perl.3log.testname.
(Tru64 のみ) 全てのテストをメモリリーク+メモリアクセスツール "Third Degree" を使って実行します。 ログファイルの名前は perl.3log.testname です。
- test.torture torturetest
-
Run all the usual tests and some extra tests. As of Perl 5.8.0 the only extra tests are Abigail's JAPHs, t/japh/abigail.t.
全ての通常のテストといくつかの追加のテストを実行します。 Perl 5.8.0 から、追加のテストは Abigail の JAPHs, t/japh/abigail.t だけです。
You can also run the torture test with t/harness by giving
-torture
argument to t/harness.t/harness に
-torture
引数を与えることでも t/harness で耐久テストを 実行できます。 - utest ucheck test.utf8 check.utf8
-
Run all the tests with -Mutf8. Not all tests will succeed.
全てのテストを -Mutf8 で実行します。 全てのテストが成功するわけではありません。
(Not available on Win32)
(Win32 では利用できません)
- minitest.utf16 test.utf16
-
Runs the tests with UTF-16 encoded scripts, encoded with different versions of this encoding.
UTF-16 の様々なバージョンでエンコードされたスクリプトでテストを 実行します。
make utest.utf16
runs the test suite with a combination of-utf8
and-utf16
arguments to t/TEST.make utest.utf16
は t/TEST へ-utf8
と-utf16
引数を組み合わせて テストスイートを実行します。(Not available on Win32)
(Win32 では利用できません)
- test_harness
-
Run the test suite with the t/harness controlling program, instead of t/TEST. t/harness is more sophisticated, and uses the Test::Harness module, thus using this test target supposes that perl mostly works. The main advantage for our purposes is that it prints a detailed summary of failed tests at the end. Also, unlike t/TEST, it doesn't redirect stderr to stdout.
t/TEST ではなく、t/harness 制御プログラムでテストスイートを実行します。 t/harness はより洗練されており、Test::Harness モジュールを使います; したがって、このテストターゲットを使うと、perl はほとんど動作すると 想定されます。 私たちの目的にとっての主な利点は、失敗したテストの詳細な要約が最後に 出力されることです。 また、t/TEST とは異なり、stderr を stdout にリダイレクトしません。
Note that under Win32 t/harness is always used instead of t/TEST, so there is no special "test_harness" target.
Win32 では、t/TEST の代わりに常に t/harness が使われるので、特別な "test_harness" ターゲットはありません。
Under Win32's "test" target you may use the TEST_SWITCHES and TEST_FILES environment variables to control the behaviour of t/harness. This means you can say
Win32の "test" ターゲットでは、環境変数 TEST_SWITCHES とTEST_FILES を 使って t/harness の動作を制御することができます。 これは次のようにできるということです:
nmake test TEST_FILES="op/*.t" nmake test TEST_SWITCHES="-torture" TEST_FILES="op/*.t"
- Parallel tests
-
(並列テスト)
The core distribution can now run its regression tests in parallel on Unix-like platforms. Instead of running
make test
, setTEST_JOBS
in your environment to the number of tests to run in parallel, and runmake test_harness
. On a Bourne-like shell, this can be done asコア配布は、Unix 風のプラットフォームでは退行テストを並列に 実行できるようになりました。
make test
を実行する代わりに、並列に実行するテストの数を 環境変数TEST_JOBS
に設定して、make test_harness
を実行してください。 Bourne 風のシェルでは、これは次のようになります:TEST_JOBS=3 make test_harness # Run 3 tests in parallel
An environment variable is used, rather than parallel make itself, because TAP::Harness needs to be able to schedule individual non-conflicting test scripts itself, and there is no standard interface to
make
utilities to interact with their job schedulers.並列 make 自身ではなく環境変数が使われます; TAP::Harness は衝突しないテストスクリプトを自身でスケジュールできる 必要があり、
make
ユーティリティとこれらのジョブスケジューラを 相互作用させる標準的なインターフェースはないからです。Note that currently some test scripts may fail when run in parallel (most notably
ext/IO/t/io_dir.t
). If necessary run just the failing scripts again sequentially and see if the failures go away.現在の所、並列に実行すると失敗するかもしれないテストがいくつか あることに注意してください (もっとも顕著なものは
ext/IO/t/io_dir.t
)。 もし必要なら、失敗したスクリプトを単に直列に再び実行して、 失敗しなくなるかを見てください。 - test-notty test_notty
-
Sets PERL_SKIP_TTY_TEST to true before running normal test.
通常のテストを実行する前に PERL_SKIP_TTY_TEST を真に設定します。
手動でテストを実行する¶
You can run part of the test suite by hand by using one the following commands from the t/ directory :
t/ ディレクトリで以下のコマンドの一つを使うことでテストスイートの一部を 手動で実行できます:
./perl -I../lib TEST list-of-.t-files
or
または
./perl -I../lib harness list-of-.t-files
(if you don't specify test scripts, the whole test suite will be run.)
(テストスクリプトを指定しないと、テストスイート全体が実行されます。)
テストに t/harness を使う¶
If you use harness
for testing you have several command line options available to you. The arguments are as follows, and are in the order that they must appear if used together.
テストに harness
を使う場合は、いくつかのコマンドラインオプションを 使えます。 引数は次のとおりで、一緒に使った場合に現れなければならない 順序になっています:
harness -v -torture -re=pattern LIST OF FILES TO TEST
harness -v -torture -re LIST OF PATTERNS TO MATCH
If LIST OF FILES TO TEST
is omitted the file list is obtained from the manifest. The file list may include shell wildcards which will be expanded out.
LIST OF FILES TO TEST
が省略された場合、ファイルリストは マニフェストから取得されます。 ファイルリストにはシェルワイルドカードが含まれている可能性があります。
- -v
-
Run the tests under verbose mode so you can see what tests were run, and debug output.
テストを詳細モードで実行するので、実行されたテストとデバッグ出力を 確認できます。
- -torture
-
Run the torture tests as well as the normal set.
通常のセットと同様に拷問テストを実行します。
- -re=PATTERN
-
Filter the file list so that all the test files run match PATTERN. Note that this form is distinct from the -re LIST OF PATTERNS form below in that it allows the file list to be provided as well.
すべてのテストファイルが PATTERN にマッチングするようにファイルリストを フィルタリングします。 この形式は、ファイルリストも指定できるという点で、次の -re LIST OF PATTERNS 形式とは異なることに注意してください。
- -re LIST OF PATTERNS
-
Filter the file list so that all the test files run match /(LIST|OF|PATTERNS)/. Note that with this form the patterns are joined by '|' and you cannot supply a list of files, instead the test files are obtained from the MANIFEST.
実行するすべてのテストファイルが match/(LIST OF PATTERNS)/ に マッチングするようにファイルリストをフィルタリングします。 この形式では、パターンは''で結合され、ファイルのリストを指定できません。 かわりに、テストファイルは MANIFEST から取得されます。
You can run an individual test by a command similar to
次のようなコマンドで、個々のテストを実行できます:
./perl -I../lib patho/to/foo.t
except that the harnesses set up some environment variables that may affect the execution of the test :
ただし、ハーネスは、テストの実行に影響を与える可能性のあるいくつかの 環境変数を設定します:
- PERL_CORE=1
-
indicates that we're running this test part of the perl core test suite. This is useful for modules that have a dual life on CPAN.
これは、perl コアテストスイートのこのテスト部分を実行していることを示します。 これは、CPAN上で二重管理されているモジュールに役立ちます。
- PERL_DESTRUCT_LEVEL=2
-
is set to 2 if it isn't set already (see "PERL_DESTRUCT_LEVEL")
まだ設定されていない場合は 2 に設定されます("PERL_DESTRUCT_LEVEL" を参照)。
- PERL
-
(used only by t/TEST) if set, overrides the path to the perl executable that should be used to run the tests (the default being ./perl).
(t/TEST でのみ使用)設定されている場合、テストの実行に使う perl 実行可能ファイルへのパスを上書きします(デフォルトは ./perl)。
- PERL_SKIP_TTY_TEST
-
if set, tells to skip the tests that need a terminal. It's actually set automatically by the Makefile, but can also be forced artificially by running 'make test_notty'.
設定すると、ターミナルが必要なテストを飛ばします。 これは実際には Makefile で自動的に設定されますが、 'make test_notty' を実行して人為的に設定することもできます。
テストに影響を与えるかも知れないその他の環境変数¶
- PERL_TEST_Net_Ping
-
Setting this variable runs all the Net::Ping modules tests, otherwise some tests that interact with the outside world are skipped. See perl58delta.
この変数を設定すると、すべての Net::Ping モジュールテストが実行されます; そうでない場合、外部世界と対話する一部のテストはスキップされます。 perl58delta を参照してください。
- PERL_TEST_NOVREXX
-
Setting this variable skips the vrexx.t tests for OS2::REXX.
この変数を設定すると、OS2::REXX の vrexx.t テストがスキップされます。
- PERL_TEST_NUMCONVERTS
-
This sets a variable in op/numconvert.t.
op/numconvert.t に変数を設定します。
See also the documentation for the Test and Test::Harness modules, for more environment variables that affect testing.
テストに影響を与える環境変数については、Test および Test::Harness モジュールの文書も参照してください。
Perl ソースコードにパッチを当てるときに良くある問題¶
Perl source plays by ANSI C89 rules: no C99 (or C++) extensions. In some cases we have to take pre-ANSI requirements into consideration. You don't care about some particular platform having broken Perl? I hear there is still a strong demand for J2EE programmers.
Perl ソースは ANSI C89 の規則に従って動作します: C99(または C++)拡張はありません。 場合によっては、ANSI 以前の要件を考慮する必要があります。 特定のプラットフォームが Perl を壊したことに関心はありませんか? J2EE プログラマーに対する需要は依然として強いと聞いています。
Perl 環境の問題¶
-
Not compiling with threading
スレッドでコンパイルできない
Compiling with threading (-Duseithreads) completely rewrites the function prototypes of Perl. You better try your changes with that. Related to this is the difference between "Perl_-less" and "Perl_-ly" APIs, for example:
スレッド化(-Duseithreads) でコンパイルすると、Perl の関数プロトタイプが 完全に書き直されます。 それを使って変更を試してみるとよいでしょう。 これに関連して、"Perl_-less" API と "Perl_-ly" API の違いがあります; 例えば:
Perl_sv_setiv(aTHX_ ...); sv_setiv(...);
The first one explicitly passes in the context, which is needed for e.g. threaded builds. The second one does that implicitly; do not get them mixed. If you are not passing in a aTHX_, you will need to do a dTHX (or a dVAR) as the first thing in the function.
最初のものはコンテキストに明示的に渡すもので、 スレッド化ビルドなどに必要です。 2 番目のものは暗黙的に渡します; 混在させないでください。 aTHX_ を渡していない場合は、関数の最初に dTHX(または dVAR) を 行う必要があります。
See "How multiple interpreters and concurrency are supported" in perlguts for further discussion about context.
コンテキストの詳細については、 "How multiple interpreter and concurrency is supported" in perlguts を 参照してください。
-
Not compiling with -DDEBUGGING
-DDEBUGGING と一緒にコンパイルできません
The DEBUGGING define exposes more code to the compiler, therefore more ways for things to go wrong. You should try it.
DEBUGGING 定義は、より多くのコードをコンパイラに公開するため、問題が 発生する可能性が高くなります。 やってみるといいですよ。
-
Introducing (non-read-only) globals
(読み取り専用でない)グローバル変数の導入
Do not introduce any modifiable globals, truly global or file static. They are bad form and complicate multithreading and other forms of concurrency. The right way is to introduce them as new interpreter variables, see intrpvar.h (at the very end for binary compatibility).
真のグローバルやファイル静的など、変更可能なグローバル変数を 導入しないでください。 これらは誤ったな形式であり、マルチスレッドや他の形式の並行性を複雑にします。 正しい方法は、これらを新しいインタプリタ変数として導入することです; intrpvar.hを参照してください(バイナリ互換性については最後にあります)。
Introducing read-only (const) globals is okay, as long as you verify with e.g.
nm libperl.a|egrep -v ' [TURtr] '
(if yournm
has BSD-style output) that the data you added really is read-only. (If it is, it shouldn't show up in the output of that command.)例えば
nm libperl.a egrep-v'[TURtr]'
(nm
がBSD スタイルの出力を 持っている場合)で、追加したデータが本当に読み取り専用であることを 確認すれば、読み取り専用(const)グローバルを導入しても問題ありません (もしそうであれば、このコマンドの出力には現れないはずです。)If you want to have static strings, make them constant:
静的文字列が必要な場合は、定数にします:
static const char etc[] = "...";
If you want to have arrays of constant strings, note carefully the right combination of
const
s:定数文字列の配列が必要な場合は、
const
の正しい組み合わせに 注意してください:static const char * const yippee[] = {"hi", "ho", "silver"};
There is a way to completely hide any modifiable globals (they are all moved to heap), the compilation setting
-DPERL_GLOBAL_STRUCT_PRIVATE
. It is not normally used, but can be used for testing, read more about it in "Background and PERL_IMPLICIT_CONTEXT" in perlguts.変更可能なグローバル変数を完全に隠す方法があります(すべてヒープに 移動されます); コンパイル設定は
-DPERL_GLOBAL_STRUCT_PRIVATE
です。 通常は使われませんが、テストに使うことができます; 詳細は "Background and PERL_IMPLICIT_CONTEXT" in perlguts を読んでください。 -
Not exporting your new function
新しい機能をエクスポートしない
Some platforms (Win32, AIX, VMS, OS/2, to name a few) require any function that is part of the public API (the shared Perl library) to be explicitly marked as exported. See the discussion about embed.pl in perlguts.
一部のプラットフォーム(Win32、AIX、VMS、OS/2 など)では、パブリック API (共有 Perl ライブラリ)の一部である関数を明示的にエクスポート済みとして マークする必要があります。 perlguts の embed.pl に関する説明を参照してください。
-
Exporting your new function
新規関数のエクスポート
The new shiny result of either genuine new functionality or your arduous refactoring is now ready and correctly exported. So what could possibly go wrong?
これで、真の新機能または困難なリファクタリングによる新しい輝きのある結果が 準備でき、正しくエクスポートされます。 では、何がうまくいかない可能性があるのでしょうか?
Maybe simply that your function did not need to be exported in the first place. Perl has a long and not so glorious history of exporting functions that it should not have.
関数をエクスポートする必要がなかったという単純な理由かもしれません。 Perl には、そうするべきでない関数をエクスポートするという、長くあまり 輝かしくない歴史があります。
If the function is used only inside one source code file, make it static. See the discussion about embed.pl in perlguts.
関数が一つのソースコードファイル内でのみ使われる場合は、関数を静的にします。 perlguts の embed.pl に関する説明を参照してください。
If the function is used across several files, but intended only for Perl's internal use (and this should be the common case), do not export it to the public API. See the discussion about embed.pl in perlguts.
関数が複数のファイルにまたがって使われているが、Perl 内部での使用のみを 意図している場合(これは一般的なケースです)は、パブリック API に エクスポートしないでください。 perlguts の embed.pl に関する説明を参照してください。
移植性の問題¶
The following are common causes of compilation and/or execution failures, not common to Perl as such. The C FAQ is good bedtime reading. Please test your changes with as many C compilers and platforms as possible; we will, anyway, and it's nice to save oneself from public embarrassment.
以下は、コンパイルや実行の失敗の一般的な原因であり、Perl で 一般的というわけではありません。 C FAQは、寝る前に読むのに適しています。 できるだけ多くの C コンパイラとプラットフォームで変更をテストしてください; とにかく、私たちはそうしますし、公の場で恥をかかないようにするのは 良いことです。
If using gcc, you can add the -std=c89
option which will hopefully catch most of these unportabilities. (However it might also catch incompatibilities in your system's header files.)
gcc を使っている場合は、-std=c89
オプションを追加することができます。 このオプションはこれらの移植性の問題のほとんどをキャッチすることを 期待しています。 (ただし、システムのヘッダファイルの非互換性もキャッチする可能性があります。)
Use the Configure -Dgccansipedantic
flag to enable the gcc -ansi -pedantic
flags which enforce stricter ANSI rules.
より厳密な ANSI 規則を矯正するために gcc の -ansi -pedantic
フラグを 有効にするには、Configure の -Dgccansipedantic
フラグを使います。
If using the gcc -Wall
note that not all the possible warnings (like -Wunitialized
) are given unless you also compile with -O
.
gcc -Wall
を使っている場合は、-O
も付けてコンパイルしない限り、 (-Wunitialized
のような)考えられるすべての警告が 表示されるわけではないことに注意してください。
Note that if using gcc, starting from Perl 5.9.5 the Perl core source code files (the ones at the top level of the source code distribution, but not e.g. the extensions under ext/) are automatically compiled with as many as possible of the -std=c89
, -ansi
, -pedantic
, and a selection of -W
flags (see cflags.SH).
gcc を使っている場合、Perl 5.9.5 以降では、Perl コアソースコードファイル (ソースコード配布物の最上位レベルにあるもので、ext/ の下の拡張部分などは 含まれません)は、自動的に、できるだけ多くの -std=c89
、-ansi
、-pedantic
、そしていくつかの -W
フラグ (cflags.SH を参照) とともにコンパイルされます。
Also study perlport carefully to avoid any bad assumptions about the operating system, filesystems, and so forth.
また、perlport を注意深く研究して、オペレーティングシステムや ファイルシステムなどに関する誤った仮定を避けるようにしてください。
You may once in a while try a "make microperl" to see whether we can still compile Perl with just the bare minimum of interfaces. (See README.micro.)
必要最小限のインターフェースで Perl をコンパイルできるかどうか、 "make microperl" を試してみてください(README.microを参照。)。
Do not assume an operating system indicates a certain compiler.
あるオペレーティングシステムが特定のコンパイラを示すことを 仮定しないでください。
-
Casting pointers to integers or casting integers to pointers
ポインタを整数にキャストしたり整数をポインタにキャストしたりする
void castaway(U8* p) { IV i = p;
or
または
void castaway(U8* p) { IV i = (IV)p;
Both are bad, and broken, and unportable. Use the PTR2IV() macro that does it right. (Likewise, there are PTR2UV(), PTR2NV(), INT2PTR(), and NUM2PTR().)
どちらも悪く、壊れていて、移植性がありません。 これを正しく行うためには PTR2IV() マクロを使ってください。 (同様に、PTR2UV(), PTR2NV(), INT2PTR(), NUM2PTR() があります。)
-
Casting between data function pointers and data pointers
データ関数ポインタとデータポインタの間でキャストする
Technically speaking casting between function pointers and data pointers is unportable and undefined, but practically speaking it seems to work, but you should use the FPTR2DPTR() and DPTR2FPTR() macros. Sometimes you can also play games with unions.
関数ポインタとデータポインタの間のキャストは、技術的には移植性がなく 定義されていませんが、実際には動作しているように見えますが、 FPTR2DPTR() と DPTR2FPTR() マクロを使うべきです。 共用体とゲームをすることもできます。
-
Assuming sizeof(int) == sizeof(long)
sizeof(int) == sizeof(long) と仮定する
There are platforms where longs are 64 bits, and platforms where ints are 64 bits, and while we are out to shock you, even platforms where shorts are 64 bits. This is all legal according to the C standard. (In other words, "long long" is not a portable way to specify 64 bits, and "long long" is not even guaranteed to be any wider than "long".)
long が 64 ビットであるプラットフォームと int が 64 ビットである プラットフォームがあり、私たちは驚かされますが、short が 64 ビットである プラットフォームもあります。 これは C 標準に従ってすべて合法です(言い換えれば、"long long" は 64 ビットを 指定する移植可能な方法ではなく、"long long"は"long"よりも広いことさえ 保証されません)。
Instead, use the definitions IV, UV, IVSIZE, I32SIZE, and so forth. Avoid things like I32 because they are not guaranteed to be exactly 32 bits, they are at least 32 bits, nor are they guaranteed to be int or long. If you really explicitly need 64-bit variables, use I64 and U64, but only if guarded by HAS_QUAD.
代わりに、IV, UV, IVSIZE, I32SIZE などの定義を使ってください。 I32 のようなものは、正確に 32 ビットであること、 少なくとも 32ビットであることが保証されて いません; int や long であることも保証されていません。 本当に明示的に 64 ビット変数が必要な場合は、HAS_QUAD で 保護されている場合に限り、I64 と U64 を使ってください。
-
Assuming one can dereference any type of pointer for any type of data
任意の型のデータのために任意の型のポインタをデリファレンスできると仮定する
char *p = ...; long pony = *p; /* BAD */
Many platforms, quite rightly so, will give you a core dump instead of a pony if the p happens not be correctly aligned.
多くのプラットフォームでは、それが正しいのですが、p が正しい アライメントでなければ、pony ではなくコアダンプを出力します。
-
Lvalue casts
左辺値をキャストする
(int)*p = ...; /* BAD */
Simply not portable. Get your lvalue to be of the right type, or maybe use temporary variables, or dirty tricks with unions.
単に移植性がありません。 左辺値を適切な型にするか、あるいは一時的な変数を使うか、または 共用体で汚いトリックを使うかもしれません。
-
Assume anything about structs (especially the ones you don't control, like the ones coming from the system headers)
構造体について (特にシステムヘッダのような制御できないものについて) 何かを 仮定する
-
That a certain field exists in a struct
構造体にある特定のフィールドがある
-
That no other fields exist besides the ones you know of
わかっているものの他にフィールドがない
-
That a field is of certain signedness, sizeof, or type
あるフィールドの符号有り無し、sizeof、型
-
That the fields are in a certain order
フィールドが特定の順序で並んでいる
-
While C guarantees the ordering specified in the struct definition, between different platforms the definitions might differ
C は struct 定義で指定された順に並んでいることを保証していますが、異なった プラットフォーム絵は定義が異なるかもしれません
-
-
That the sizeof(struct) or the alignments are the same everywhere
sizeof(struct) やアライメントがどこでも同じである
-
There might be padding bytes between the fields to align the fields - the bytes can be anything
フィールドの位置合わせにフィールドの間にパッディングのバイトが あるかもしれません - バイトはなんでもかまいません
-
Structs are required to be aligned to the maximum alignment required by the fields - which for native types is for usually equivalent to sizeof() of the field
構造体は、フィールドで要求される最大のアラインメントに合わせる必要があります - ネイティブ型では、これは通常、フィールドの sizeof() に相当します
-
-
-
Assuming the character set is ASCIIish
文字集合が ASCII 風であると仮定する
Perl can compile and run under EBCDIC platforms. See perlebcdic. This is transparent for the most part, but because the character sets differ, you shouldn't use numeric (decimal, octal, nor hex) constants to refer to characters. You can safely say 'A', but not 0x41. You can safely say '\n', but not \012. If a character doesn't have a trivial input form, you can create a #define for it in both
utfebcdic.h
andutf8.h
, so that it resolves to different values depending on the character set being used. (There are three different EBCDIC character sets defined inutfebcdic.h
, so it might be best to insert the #define three times in that file.)Perl は EBCDIC プラットフォームでコンパイルおよび実行できます。 perlebcdic を参照してください。 これはほとんどの部分で透過的ですが、文字集合が異なるため、文字を 参照するために数値定数(10 進数、8 進数、16 進数)を使うべきではありません。 'A' は安全に言うことはできますが、0x41 はできません。 '\n' は安全に言うことはできますが、\012 はできません。 文字に簡単な入力形式がない場合は、
utfebcdic.h
とutf8.h
の両方で #define を作成して、使われている文字集合に応じて異なる値に 解決することができます。 (utfebcdic.h
では三つの異なる EBCDIC 文字集合が定義されているので、 そのファイルに #define を 3 回挿入することをお勧めします。)Also, the range 'A' - 'Z' in ASCII is an unbroken sequence of 26 upper case alphabetic characters. That is not true in EBCDIC. Nor for 'a' to 'z'. But '0' - '9' is an unbroken range in both systems. Don't assume anything about other ranges.
また、ASCII の 'A'-'Z' の範囲は、26 個の大文字アルファベット文字の 連続したものです。 EBCDIC ではそうではありません。 また、'a' か ら'z' も同様です。 しかし、'0'-'9' は両方のシステムで連続した範囲です。 他の範囲について何も仮定しないでください。
Many of the comments in the existing code ignore the possibility of EBCDIC, and may be wrong therefore, even if the code works. This is actually a tribute to the successful transparent insertion of being able to handle EBCDIC without having to change pre-existing code.
既存のコードのコメントの多くは EBCDIC の可能性を無視しているため、コードが 動作しても間違っている可能性があります。 これは実際には、既存のコードを変更することなく EBCDIC を処理できる 透過的な挿入が成功したことへの賛辞です。
UTF-8 and UTF-EBCDIC are two different encodings used to represent Unicode code points as sequences of bytes. Macros with the same names (but different definitions) in
utf8.h
andutfebcdic.h
are used to allow the calling code to think that there is only one such encoding. This is almost always referred to asutf8
, but it means the EBCDIC version as well. Again, comments in the code may well be wrong even if the code itself is right. For example, the concept ofinvariant characters
differs between ASCII and EBCDIC. On ASCII platforms, only characters that do not have the high-order bit set (i.e. whose ordinals are strict ASCII, 0 - 127) are invariant, and the documentation and comments in the code may assume that, often referring to something like, say,hibit
. The situation differs and is not so simple on EBCDIC machines, but as long as the code itself uses theNATIVE_IS_INVARIANT()
macro appropriately, it works, even if the comments are wrong.UTF-8 と UTF-EBCDIC は、Unicode 符号位置をバイト列として 表現するために使われる二つの異なるエンコーディングです。
utf8.h
とutfebcdic.h
で同じ名前(ただし定義が異なる)を持つマクロは、 呼び出し側のコードにそのようなエンコーディングが一つしかないと 認識させるために使われます。 これはほとんど常にutf8
と呼ばれていますが、EBCDIC 版も意味します。 繰り返しますが、コード内のコメントは、コード自体が正しい場合でも 間違っている可能性があります。 たとえば、invariant characters
の概念は ASCII と EBCDIC で異なります。 ASCII プラットフォームでは、上位ビットセットを持たない文字(つまり、その序数が 厳密な ASCII、0-127)のみが不変であり、コード内の文書とコメントは、 しばしばhibit
のようなものを参照していると想定することができます。 状況は異なり、EBCDIC マシンではそれほど単純ではありませんが、コード自体がNATIVE_IS_INVARIANT()
マクロを適切に使っている限り、コメントが 間違っていても機能します。 -
Assuming the character set is just ASCII
文字集合が単に ASCII であると仮定する
ASCII is a 7 bit encoding, but bytes have 8 bits in them. The 128 extra characters have different meanings depending on the locale. Absent a locale, currently these extra characters are generally considered to be unassigned, and this has presented some problems. This is being changed starting in 5.12 so that these characters will be considered to be Latin-1 (ISO-8859-1).
ASCII は 7 ビットエンコーディングですが、バイトには 8 ビットが含まれています。 128 個の余分な文字は、ロケールによって異なる意味を持ちます。 ロケールが存在しない場合、現在これらの余分な文字は一般的に 割り当てられていないと考えられているため、いくつかの問題が発生しています。 これは 5.12 に変更され、これらの文字は Latin-1(ISO-8859-1) と 見なされるようになります。
-
Mixing #define and #ifdef
#define と #ifdef を混ぜる
#define BURGLE(x) ... \ #ifdef BURGLE_OLD_STYLE /* BAD */ ... do it the old way ... \ #else ... do it the new way ... \ #endif
You cannot portably "stack" cpp directives. For example in the above you need two separate BURGLE() #defines, one for each #ifdef branch.
移植性のある方法で cpp 指示子を「スタック」させることはできません。 上述の例では、#ifdef の分岐毎に一つ、計二つの別々の BURGLE() の #define が 必要です。
-
Adding non-comment stuff after #endif or #else
#endif または #else の後にコメント以外の内容を追加する
#ifdef SNOSH ... #else !SNOSH /* BAD */ ... #endif SNOSH /* BAD */
The #endif and #else cannot portably have anything non-comment after them. If you want to document what is going (which is a good idea especially if the branches are long), use (C) comments:
#endif と #else は、その後ろにコメント以外のものを書くと移植性がありません。 何をしているかを書いておきたい場合(これは特に分岐が長いときにはよい 考えです)、(C の)コメントを使います:
#ifdef SNOSH ... #else /* !SNOSH */ ... #endif /* SNOSH */
The gcc option
-Wendif-labels
warns about the bad variant (by default on starting from Perl 5.9.4).gcc オプション
-Wendif-labels
は悪い変形について警告します (Perl 5.9.4 からこれはデフォルトです)。 -
Having a comma after the last element of an enum list
enum リストの最後の要素の後ろにカンマを付ける
enum color { CERULEAN, CHARTREUSE, CINNABAR, /* BAD */ };
is not portable. Leave out the last comma.
は移植性はありません。 最後のカンマは省いてください。
Also note that whether enums are implicitly morphable to ints varies between compilers, you might need to (int).
また、enum が暗黙に int に変換されるかどうかはコンパイラによって異なることに 注意してください; (int) する必要があるかもしれません。
-
Using //-comments
// コメントを使う
// This function bamfoodles the zorklator. /* BAD */
That is C99 or C++. Perl is C89. Using the //-comments is silently allowed by many C compilers but cranking up the ANSI C89 strictness (which we like to do) causes the compilation to fail.
これは C99 または C++ です。 Perl は C89 です。 //-コメントを使うことは多くの C コンパイラで暗黙的に許可されていますが、 ANSI C89 の厳密さを強化してしまうと(私たちがやりたいことですが) コンパイルが失敗します。
-
Mixing declarations and code
宣言とコードを混ぜる
void zorklator() { int n = 3; set_zorkmids(n); /* BAD */ int q = 4;
That is C99 or C++. Some C compilers allow that, but you shouldn't.
これは C99 または C++ です。 一部の C コンパイラはこれを使えますが、するべきではありません。
The gcc option
-Wdeclaration-after-statements
scans for such problems (by default on starting from Perl 5.9.4).gcc オプション
-Wdeclaration-after-statements
はこのような問題を スキャンします (Perl 5.9.4 からデフォルトです)。 -
Introducing variables inside for()
for() 内部の変数を導入する
for(int i = ...; ...; ...) { /* BAD */
That is C99 or C++. While it would indeed be awfully nice to have that also in C89, to limit the scope of the loop variable, alas, we cannot.
これは C99 または C++ です。 ループ変数を制限するために C89 でもできれば本当にとてもよいことなのですが、 悲しいかなそれはできません。
-
Mixing signed char pointers with unsigned char pointers
符号付き char ポインタと符号なし char ポインタを混ぜる
int foo(char *s) { ... } ... unsigned char *t = ...; /* Or U8* t = ... */ foo(t); /* BAD */
While this is legal practice, it is certainly dubious, and downright fatal in at least one platform: for example VMS cc considers this a fatal error. One cause for people often making this mistake is that a "naked char" and therefore dereferencing a "naked char pointer" have an undefined signedness: it depends on the compiler and the flags of the compiler and the underlying platform whether the result is signed or unsigned. For this very same reason using a 'char' as an array index is bad.
これは法的慣行ではありますが、確かに疑わしく、少なくとも一つの プラットフォームでは致命的です: 例えばVMS cc はこれを致命的エラーと 見なします。 人々がこの間違いを頻繁にする原因の一つは、"naked char"、したがって "naked char pointer" を逆参照する場合の符号が未定義であることです: 結果が符号付きか符号なしかは、コンパイラとコンパイラ基盤となる プラットフォームのフラグに依存します。 これとまったく同じ理由で、'char' を配列インデックスとして使うのは 不適切です。
-
Macros that have string constants and their arguments as substrings of the string constants
文字列定数とその引数を文字列定数の部分文字列として持つマクロ
#define FOO(n) printf("number = %d\n", n) /* BAD */ FOO(10);
Pre-ANSI semantics for that was equivalent to
このための ANSI 以前の構文は次のものです:
printf("10umber = %d\10");
which is probably not what you were expecting. Unfortunately at least one reasonably common and modern C compiler does "real backward compatibility" here, in AIX that is what still happens even though the rest of the AIX compiler is very happily C89.
これはおそらくあなたが期待していたものではありません。 残念ながら、少なくとも一つの合理的に一般的で最新のCコンパイラが、 ここでは「真の後方互換性」を実現しています; AIX では、AIX コンパイラの残りの部分が非常に幸せに C89 であっても、これが 依然として行われています。
-
Using printf formats for non-basic C types
基本 C 型以外の printf のフォーマットを使う
IV i = ...; printf("i = %d\n", i); /* BAD */
While this might by accident work in some platform (where IV happens to be an
int
), in general it cannot. IV might be something larger. Even worse the situation is with more specific types (defined by Perl's configuration step in config.h):これはいくつかの(IV がたまたま
int
であるような)プラットフォームでは 偶然動作するかもしれませんが、一般的にはこれはできません。 IV はもっと大きいかもしれません。 もっと悪いことに、この状況はより特定の (config.h にある Perl の設定 ステップで定義される)型です:Uid_t who = ...; printf("who = %d\n", who); /* BAD */
The problem here is that Uid_t might be not only not
int
-wide but it might also be unsigned, in which case large uids would be printed as negative values.ここでの問題は、Uid_t が
int
幅でないだけでなく、符号なしでもある 可能性があることであり、その場合、大きな uid は負の値として出力されます。There is no simple solution to this because of printf()'s limited intelligence, but for many types the right format is available as with either 'f' or '_f' suffix, for example:
printf() のインテリジェンスが限られているため、これに対する簡単な解決策は ありませんが、多くの型では 'f' または '_f' 接尾辞のような適切な フォーマットが利用できます; 例えば:
IVdf /* IV in decimal */ UVxf /* UV is hexadecimal */ printf("i = %"IVdf"\n", i); /* The IVdf is a string constant. */ Uid_t_f /* Uid_t in decimal */ printf("who = %"Uid_t_f"\n", who);
Or you can try casting to a "wide enough" type:
または、「十分に広い」型にキャストすることもできます:
printf("i = %"IVdf"\n", (IV)something_very_small_and_signed);
Also remember that the
%p
format really does require a void pointer:%p
フォーマットは実際は void ポインタが必要であることも 忘れないでください:U8* p = ...; printf("p = %p\n", (void*)p);
The gcc option
-Wformat
scans for such problems.gcc オプション
-Wformat
はこのような問題をスキャンします。 -
Blindly using variadic macros
可変マクロの盲目的な使用
gcc has had them for a while with its own syntax, and C99 brought them with a standardized syntax. Don't use the former, and use the latter only if the HAS_C99_VARIADIC_MACROS is defined.
gcc には独自の構文があり、C99 には標準化された構文があります。 前者は使わず、後者は HAS_C99_VARIADIC_MACROS が定義されている場合にのみ 使ってください。
-
Blindly passing va_list
盲目的に va_list を渡す
Not all platforms support passing va_list to further varargs (stdarg) functions. The right thing to do is to copy the va_list using the Perl_va_copy() if the NEED_VA_COPY is defined.
すべてのプラットフォームが va_list を他の varargs(stdarg) 関数に渡すことを サポートしているわけではありません。 NEED_VA_COPY が定義されている場合は、Perl_va_copy() を使って va_list を コピーするのが適切です。
-
Using gcc statement expressions
gcc 文表現を使う
val = ({...;...;...}); /* BAD */
While a nice extension, it's not portable. The Perl code does admittedly use them if available to gain some extra speed (essentially as a funky form of inlining), but you shouldn't.
よい拡張ではありますが、移植性がありません。 Perl コードでは(本質的には変わった形のインラインとして)より速度が 得られる場合には使っているのは確かですが、あなたはするべきではありません。
-
Binding together several statements in a macro
マクロの中で複数の文を結び付ける
Use the macros STMT_START and STMT_END.
マクロ STMT_START と STMT_END を使ってください。
STMT_START { ... } STMT_END
-
Testing for operating systems or versions when should be testing for features
機能をテストするべきところでオペレーティングシステムやバージョンをテストする
#ifdef __FOONIX__ /* BAD */ foo = quux(); #endif
Unless you know with 100% certainty that quux() is only ever available for the "Foonix" operating system and that is available and correctly working for all past, present, and future versions of "Foonix", the above is very wrong. This is more correct (though still not perfect, because the below is a compile-time check):
quux() が "Foonix" オペレーティングシステムでのみ利用可能であり、かつ これが "Foonix"の過去、現在、将来の 全ての バージョンで利用可能で、 かつ 正しく動作することを 100% 確実に知っていない限り、 上記は非常に間違っています。 次のものはより正確です(これはコンパイル時チェックなので、まだ 完全ではありませんが):
#ifdef HAS_QUUX foo = quux(); #endif
How does the HAS_QUUX become defined where it needs to be? Well, if Foonix happens to be Unixy enough to be able to run the Configure script, and Configure has been taught about detecting and testing quux(), the HAS_QUUX will be correctly defined. In other platforms, the corresponding configuration step will hopefully do the same.
HAS_QUUX は必要な場所でどのように定義されるのでしょうか? まあ、もし Foonix が Configure スクリプトを実行するのに十分ななくらい Unixy であり、Configure が quux() の検出とテストについて教えられているなら、 HAS_QUUX は正しく定義されるでしょう。 他のプラットフォームでは、対応する設定ステップが同じことをすることを 期待しています。
In a pinch, if you cannot wait for Configure to be educated, or if you have a good hunch of where quux() might be available, you can temporarily try the following:
困ったときに、Configure が教育されるのを待てない場合や、quux() が どこで使えるか予感がある場合には、一時的に以下を試すことができます:
#if (defined(__FOONIX__) || defined(__BARNIX__)) # define HAS_QUUX #endif ... #ifdef HAS_QUUX foo = quux(); #endif
But in any case, try to keep the features and operating systems separate.
ただし、いずれの場合でも、機能とオペレーティングシステムを 分離するようにしてください。
問題のあるシステムインターフェース¶
-
malloc(0), realloc(0), calloc(0, 0) are non-portable. To be portable allocate at least one byte. (In general you should rarely need to work at this low level, but instead use the various malloc wrappers.)
malloc(0), realloc(0), calloc(0, 0) は移植性がありません。 移植性を持たせるためには、少なくとも 1 バイトを割り当ててください。 (一般に、この低レベルで作業する必要はほとんどありません; 代わりに さまざまな malloc ラッパーを使ってください。)
-
snprintf() - the return type is unportable. Use my_snprintf() instead.
snprintf() - 返り型は移植性がありません。 代わりに my_snprintf() を使ってください。
セキュリティ問題¶
Last but not least, here are various tips for safer coding.
最後ですが重要な、より安全なコーディングのためのさまざまなヒントを 紹介します。
-
Do not use gets()
gets() を使わない
Or we will publicly ridicule you. Seriously.
さもなければ私たちは公にあなたをからかうことになるでしょう。 本気です。
-
Do not use strcpy() or strcat() or strncpy() or strncat()
strcpy(), strcat(), strncpy(), strncat() を使わない
Use my_strlcpy() and my_strlcat() instead: they either use the native implementation, or Perl's own implementation (borrowed from the public domain implementation of INN).
代わりに my_strlcpy() と my_strlcat() を使ってください: これらはネイティブな実装か、Perl 独自の実装(INN の パブリックドメイン実装から借用したもの)を使います。
-
Do not use sprintf() or vsprintf()
sprintf(), vsprintf() を使わない
If you really want just plain byte strings, use my_snprintf() and my_vsnprintf() instead, which will try to use snprintf() and vsnprintf() if those safer APIs are available. If you want something fancier than a plain byte string, use SVs and Perl_sv_catpvf().
本当にプレーンなバイト文字列だけが必要な場合は、代わりに my_snprintf() と y_vsnprintf() を使ってください; これらは、より安全な API が利用可能であれば、snprintf() と vsnprintf() を 使おうとします。 プレーンなバイト文字列よりも洗練されたものが必要な場合は、 SV と Perl_sv_catpvf() を使ってください。
Perl をデバッグするための外部ツール¶
Sometimes it helps to use external tools while debugging and testing Perl. This section tries to guide you through using some common testing and debugging tools with Perl. This is meant as a guide to interfacing these tools with Perl, not as any kind of guide to the use of the tools themselves.
Perlをデバッグしたりテストしたりするときに、外部ツールを使うと 便利な場合があります。 このセクションでは、一般的なテストツールやデバッグツールを Perl で使う方法を 説明します。 これは、これらのツールを Perl と繋ぐためのガイドであり、 ツール自体を使うためのガイドではありません。
NOTE 1: Running under memory debuggers such as Purify, valgrind, or Third Degree greatly slows down the execution: seconds become minutes, minutes become hours. For example as of Perl 5.8.1, the ext/Encode/t/Unicode.t takes extraordinarily long to complete under e.g. Purify, Third Degree, and valgrind. Under valgrind it takes more than six hours, even on a snappy computer. The said test must be doing something that is quite unfriendly for memory debuggers. If you don't feel like waiting, that you can simply kill away the perl process.
注 1: Purify, Valgrind, Third Degree などのメモリデバッガで実行すると、 実行速度が大幅に低下します: 秒は分になり、分は時間になります。 たとえば、Perl 5.8.1 では、ext/Encode/t/Unicode.t は、Purify, Third Degree, Valgrind などで実行すると非常に時間がかかります。 Valgrind では、高速なコンピュータでも 6 時間以上かかります。 このテストは、メモリデバッガにとって非常に扱いにくいことを 行っているはずです。 待つ気がなければ、perl プロセスを kill するだけで済みます。
NOTE 2: To minimize the number of memory leak false alarms (see "PERL_DESTRUCT_LEVEL" for more information), you have to set the environment variable PERL_DESTRUCT_LEVEL to 2.
注 2: メモリリークの誤通知 (詳細については "PERL_DESTRUCT_LEVEL" を 参照) の数を最小限にするためには、環境変数 PERL_DESTRUCT_LEVEL を 2 に 設定する必要があります。
For csh-like shells:
csh のようなシェルの場合:
setenv PERL_DESTRUCT_LEVEL 2
For Bourne-type shells:
Bourne タイプのシェルの場合:
PERL_DESTRUCT_LEVEL=2
export PERL_DESTRUCT_LEVEL
In Unixy environments you can also use the env
command:
UNIXy 環境では、env
コマンドを使うこともできます:
env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib ...
NOTE 3: There are known memory leaks when there are compile-time errors within eval or require, seeing S_doeval
in the call stack is a good sign of these. Fixing these leaks is non-trivial, unfortunately, but they must be fixed eventually.
注 3: eval または require 内にコンパイル時エラーがある場合、既知の メモリリークがあります; コールスタックに S_doeval
があることは、これらの良い兆候です。 残念ながら、これらのリークを修正することは簡単ではありませんが、最終的には 修正する必要があります。
NOTE 4: DynaLoader will not clean up after itself completely unless Perl is built with the Configure option -Accflags=-DDL_UNLOAD_ALL_AT_EXIT
.
注 4:Perl が Configure オプション -Accflags=-DDL_UNLOAD_ALL_AT_EXIT
で構築されていない限り、 DynaLoader は自分自身を完全にクリーンアップすることはありません。
Rational Software の Purify¶
Purify is a commercial tool that is helpful in identifying memory overruns, wild pointers, memory leaks and other such badness. Perl must be compiled in a specific way for optimal testing with Purify. Purify is available under Windows NT, Solaris, HP-UX, SGI, and Siemens Unix.
Purify は、メモリオーバーラン、ワイルドポインタ、メモリリークなどの不良を 識別するのに役立つ商用ツールです。 Purify で最適なテストを行うためには、Perl を特定の方法でコンパイルする 必要があります。 Purify は Windows NT, Solaris, HP-UX, SGI, Siemens Unix で利用できます。
Unix での Purify¶
On Unix, Purify creates a new Perl binary. To get the most benefit out of Purify, you should create the perl to Purify using:
Unix では、Purify は新しい Perl バイナリを作成します。 Purify を最大限に活用するには、以下を使って Purify 用の perl を作成する 必要があります:
sh Configure -Accflags=-DPURIFY -Doptimize='-g' \
-Uusemymalloc -Dusemultiplicity
where these arguments mean:
これらの引数の意味は次のとおりです:
- -Accflags=-DPURIFY
-
Disables Perl's arena memory allocation functions, as well as forcing use of memory allocation functions derived from the system malloc.
Perl のアリーナメモリ割り当て関数を無効にし、システム malloc から派生した メモリ割り当て関数を強制的に使います。
- -Doptimize='-g'
-
Adds debugging information so that you see the exact source statements where the problem occurs. Without this flag, all you will see is the source filename of where the error occurred.
デバッグ情報を追加して、問題が発生したソース文を正確に表示します。 このフラグがなければ、エラーが発生したソースファイル名だけが表示されます。
- -Uusemymalloc
-
Disable Perl's malloc so that Purify can more closely monitor allocations and leaks. Using Perl's malloc will make Purify report most leaks in the "potential" leaks category.
Perl の malloc を無効にして、Purify が割り当てとリークをより厳密に 監視できるようにします。 Perl の malloc を使うと、Purify は「潜在的な」リークのカテゴリで最も多くの リークをレポートします。
- -Dusemultiplicity
-
Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter shuts down, which reduces the number of bogus leak reports from Purify.
multiplicity オプションを有効にすると、perl はインタプリタが シャットダウンしたときに完全にクリーンアップすることができ、 Purify からの偽のリークレポートの数を減らすことができます。
Once you've compiled a perl suitable for Purify'ing, then you can just:
Purify に適した Perl をコンパイルしたら、次のようにします:
make pureperl
which creates a binary named 'pureperl' that has been Purify'ed. This binary is used in place of the standard 'perl' binary when you want to debug Perl memory problems.
Purify された "pureperl" という名前のバイナリを作成します。 このバイナリは、Perl メモリの問題をデバッグしたい場合に、標準の "perl" バイナリの代わりに使われます。
As an example, to show any memory leaks produced during the standard Perl testset you would create and run the Purify'ed perl as:
たとえば、標準的な Perl テストセットで生成されたメモリリークを 表示するには、Purify の perl を次のように作成して実行します:
make pureperl
cd t
../pureperl -I../lib harness
which would run Perl on test.pl and report any memory problems.
test.pl で Perl を実行し、メモリの問題を報告します。
Purify outputs messages in "Viewer" windows by default. If you don't have a windowing environment or if you simply want the Purify output to unobtrusively go to a log file instead of to the interactive window, use these following options to output to the log file "perl.log":
デフォルトでは、Purify は "Viewer" ウィンドウにメッセージを出力します。 ウィンドウ環境がない場合、または Purify 出力を対話式ウィンドウではなく 控えめなログファイルに出力する場合は、次のオプションを使ってログファイル "perl.log" に出力します:
setenv PURIFYOPTIONS "-chain-length=25 -windows=no \
-log-file=perl.log -append-logfile=yes"
If you plan to use the "Viewer" windows, then you only need this option:
"Viewer" ウィンドウを使う場合は、次のオプションのみが必要です:
setenv PURIFYOPTIONS "-chain-length=25"
In Bourne-type shells:
Bourne タイプのシェルの場合:
PURIFYOPTIONS="..."
export PURIFYOPTIONS
or if you have the "env" utility:
"env" ユーティリティを使っている場合:
env PURIFYOPTIONS="..." ../pureperl ...
NT での Purify¶
Purify on Windows NT instruments the Perl binary 'perl.exe' on the fly. There are several options in the makefile you should change to get the most use out of Purify:
Purify on Windows NT では、Perl バイナリ 'perl.exe' をオンザフライで 計測します。 Purify を最大限に活用するためには、makefile のいくつかのオプションを 変更する必要があります。
- DEFINES
-
You should add -DPURIFY to the DEFINES line so the DEFINES line looks something like:
DEFINES 行に -DPURIFY を追加して、DEFINES 行が次のようになるようにします。
DEFINES = -DWIN32 -D_CONSOLE -DNO_STRICT $(CRYPT_FLAG) -DPURIFY=1
to disable Perl's arena memory allocation functions, as well as to force use of memory allocation functions derived from the system malloc.
Perl のアリーナメモリアロケーション関数を無効にしたり、malloc システムから 派生したメモリアロケーション関数を強制的に使わせたりします。
- USE_MULTI = define
-
Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter shuts down, which reduces the number of bogus leak reports from Purify.
multiplicity オプションを有効にすると、perl はインタプリタが シャットダウンしたときに完全にクリーンアップすることができ、 Purify からの偽のリークレポートの数を減らすことができます。
- #PERL_MALLOC = define
-
Disable Perl's malloc so that Purify can more closely monitor allocations and leaks. Using Perl's malloc will make Purify report most leaks in the "potential" leaks category.
Perl の malloc を無効にして、Purify が割り当てとリークをより厳密に 監視できるようにします。 Perl の malloc を使うと、Purify は「潜在的な」リークのカテゴリで最も多くの リークをレポートします。
- CFG = Debug
-
Adds debugging information so that you see the exact source statements where the problem occurs. Without this flag, all you will see is the source filename of where the error occurred.
デバッグ情報を追加して、問題が発生したソース文を正確に表示します。 このフラグがなければ、エラーが発生したソースファイル名だけが表示されます。
As an example, to show any memory leaks produced during the standard Perl testset you would create and run Purify as:
例として、標準 Perl テストセット中に生成されたメモリリークを表示するために、 Purify を次のように作成して実行します:
cd win32
make
cd ../t
purify ../perl -I../lib harness
which would instrument Perl in memory, run Perl on test.pl, then finally report any memory problems.
メモリに Perl を構築し、test.pl 上で Perl を実行し、最後にメモリの問題を 報告します。
valgrind¶
The excellent valgrind tool can be used to find out both memory leaks and illegal memory accesses. As of version 3.3.0, Valgrind only supports Linux on x86, x86-64 and PowerPC. The special "test.valgrind" target can be used to run the tests under valgrind. Found errors and memory leaks are logged in files named testfile.valgrind.
優れた valgrind ツールは、メモリリークと不正なメモリアクセスの両方を 見つけるために使えます。 バージョン 3.3.0 では、Valgrind は x86、x86-64、および PowerPC 上の Linux のみをサポートしています。 特別な "test.valgrind" ターゲットを使って、valgrind 下でテストを実行できます。 検出されたエラーとメモリリークは、testfile.valgrind という名前の ファイルに記録されます。
Valgrind also provides a cachegrind tool, invoked on perl as:
Valgrind は cachegrind ツールも提供しており、perl で以下のように 呼び出されます:
VG_OPTS=--tool=cachegrind make test.valgrind
As system libraries (most notably glibc) are also triggering errors, valgrind allows to suppress such errors using suppression files. The default suppression file that comes with valgrind already catches a lot of them. Some additional suppressions are defined in t/perl.supp.
システムライブラリ(最も顕著な glibc)もエラーを引き起こすので、valgrind は 抑制ファイルを使ってそのようなエラーを抑制することができます。 valgrind に付属のデフォルトの抑制ファイルはすでに多くのエラーを捕捉しています。 いくつかの追加の抑制は t/perl.supp で定義されています。
To get valgrind and for more information see
詳細については、以下を参照してください:
http://developer.kde.org/~sewardj/
Compaq/Digital/HP の Third Degree¶
Third Degree is a tool for memory leak detection and memory access checks. It is one of the many tools in the ATOM toolkit. The toolkit is only available on Tru64 (formerly known as Digital UNIX formerly known as DEC OSF/1).
Third Degree は、メモリリーク検出とメモリアクセスチェックのためのツールです。 これは ATOM ツールキットに含まれる多くのツールの一つです。 このツールキットは (以前は DEC OSF/1 として知られていた Digital UNIX として 知られていた) Tru64 でのみ使えます。
When building Perl, you must first run Configure with -Doptimize=-g and -Uusemymalloc flags, after that you can use the make targets "perl.third" and "test.third". (What is required is that Perl must be compiled using the -g
flag, you may need to re-Configure.)
Perl を構築するときは、まず -Doptimize=-g フラグと -Uusemymalloc フラグを 指定して Configure を実行する必要があります; その後、make ターゲット "perl.third" と "test.third" を使えます。 (Perl は -g
フラグを使ってコンパイルする必要があります; 再 Configure が必要になる場合もあります。)
The short story is that with "atom" you can instrument the Perl executable to create a new executable called perl.third. When the instrumented executable is run, it creates a log of dubious memory traffic in file called perl.3log. See the manual pages of atom and third for more information. The most extensive Third Degree documentation is available in the Compaq "Tru64 UNIX Programmer's Guide", chapter "Debugging Programs with Third Degree".
簡単に言うと、"atom" を使えば、Perl の実行可能ファイルを 調整して、perl.third という名前の新しい 実行可能ファイルを作成することができます。 調整された実行可能ファイルが実行されると、 疑わしいメモリトラフィックのログが perl.3log という名前のファイルに 作成されます。 詳細については、atom と third のマニュアルページを参照してください。 Compaq の "Tru64 UNIX Programmer's Guide" の "Debugging Programs with Third Degree" の章に、Third Degree の最も広範な 文書があります。
The "test.third" leaves a lot of files named foo_bar.3log in the t/ subdirectory. There is a problem with these files: Third Degree is so effective that it finds problems also in the system libraries. Therefore you should used the Porting/thirdclean script to cleanup the *.3log files.
"test.third" は t/ サブディレクトリに foo_bar.3log という名前の 多数のファイルを残します。 これらのファイルには問題があります: Third Degree は非常に効果的なため、 システムライブラリにも問題が見つかります。 したがって、Porting/thirdclean スクリプトを使って *.3log ファイルを クリーンアップする必要があります。
There are also leaks that for given certain definition of a leak, aren't. See "PERL_DESTRUCT_LEVEL" for more information.
定義によってはリークと言えないリークもあります; 詳細は "PERL_DESTRUCT_LEVEL" を参照してください。
PERL_DESTRUCT_LEVEL¶
If you want to run any of the tests yourself manually using e.g. valgrind, or the pureperl or perl.third executables, please note that by default perl does not explicitly cleanup all the memory it has allocated (such as global memory arenas) but instead lets the exit() of the whole program "take care" of such allocations, also known as "global destruction of objects".
例えば valgrind や pureperl や perl.third の実行可能ファイルを使って 手動でテストを実行したい場合、 デフォルトでは perl は (グローバルメモリ領域のような)割り当てられた全てのメモリを明示的に クリーンアップ しません が、代わりにプログラム全体の exit() がそのような 割り当てを"処理"します; これは"グローバルなオブジェクト破壊"としても知られています。
There is a way to tell perl to do complete cleanup: set the environment variable PERL_DESTRUCT_LEVEL to a non-zero value. The t/TEST wrapper does set this to 2, and this is what you need to do too, if you don't want to see the "global leaks": For example, for "third-degreed" Perl:
perl に完全なクリーンアップを行うように指示する方法があります: 環境変数 PERL_DESTRUCT_LEVEL を 0 以外の値に設定します。 t/TEST ラッパーはこれを 2 に設定しますが、"global leaks" を 見たくない場合にはこれも行う必要があります。 例えば "third-degree" Perl の場合:
env PERL_DESTRUCT_LEVEL=2 ./perl.third -Ilib t/foo/bar.t
(Note: the mod_perl apache module uses also this environment variable for its own purposes and extended its semantics. Refer to the mod_perl documentation for more information. Also, spawned threads do the equivalent of setting this variable to the value 1.)
(注: mod_perl apache モジュールも独自の目的でこの環境変数を使い、その セマンティクスを拡張しています。 詳細については、mod_perl の文書を参照してください。 また、生成されたスレッドは、この変数を値 1 に設定するのと同じことを 行います。)
If, at the end of a run you get the message N scalars leaked, you can recompile with -DDEBUG_LEAKING_SCALARS
, which will cause the addresses of all those leaked SVs to be dumped along with details as to where each SV was originally allocated. This information is also displayed by Devel::Peek. Note that the extra details recorded with each SV increases memory usage, so it shouldn't be used in production environments. It also converts new_SV()
from a macro into a real function, so you can use your favourite debugger to discover where those pesky SVs were allocated.
実行の最後にメッセージ N scalars leaked が表示された場合は、 -DDEBUG_LEAKING_SCALARS
で再コンパイルすることができます; これにより、リークされたすべての SV のアドレスが、各 SV が最初に 割り当てられた場所の詳細とともにダンプされます。 この情報は、Devel::Peek でも表示されます。 各 SV に追加の詳細が記録されると、メモリ使用量が増加するため、本番環境では 使わないでください。 また、マクロから new_SV()
を実関数に変換するため、お気に入りのデバッガを 使って、これらの SV が割り当てられた場所を検出できます。
If you see that you're leaking memory at runtime, but neither valgrind nor -DDEBUG_LEAKING_SCALARS
will find anything, you're probably leaking SVs that are still reachable and will be properly cleaned up during destruction of the interpreter. In such cases, using the -Dm
switch can point you to the source of the leak. If the executable was built with -DDEBUG_LEAKING_SCALARS
, -Dm
will output SV allocations in addition to memory allocations. Each SV allocation has a distinct serial number that will be written on creation and destruction of the SV. So if you're executing the leaking code in a loop, you need to look for SVs that are created, but never destroyed between each cycle. If such an SV is found, set a conditional breakpoint within new_SV()
and make it break only when PL_sv_serial
is equal to the serial number of the leaking SV. Then you will catch the interpreter in exactly the state where the leaking SV is allocated, which is sufficient in many cases to find the source of the leak.
実行時にメモリリークが発生しているが、valgrind も -DDEBUG_LEAKING_SCALARS
も 何も検出しない場合は、おそらく到達可能な SV がリークしており、インタプリタの 破壊時に適切にクリーンアップされている可能性があります。 このような場合、-Dm
スイッチを使うと、リーク元を示すことができます。 実行可能ファイルが -DDEBUG_LEAKING_SCALARS
でビルドされている場合、 -Dm
はメモリ割り当てに加えて SV 割り当てを出力します。 各 SV 割り当てには、SV の作成時と破壊時に書き込まれるシリアル番号があります。 そのため、リークしているコードをループで実行している場合は、各サイクル間に 作成されたが破壊されなかった SV を探す必要があります。 このような SV が見つかった場合は、new_SV()
内に条件付きブレークポイントを 設定し、PL_sv_serial
がリークしている SV のシリアル番号に等しい場合にのみ ブレークするようにします。 これにより、多くの場合リーク元を見つけるのに十分な、リークしている SV が 割り当てられた正確な状態でインタプリタをキャッチできます。
As -Dm
is using the PerlIO layer for output, it will by itself allocate quite a bunch of SVs, which are hidden to avoid recursion. You can bypass the PerlIO layer if you use the SV logging provided by -DPERL_MEM_LOG
instead.
-Dm
は出力に PerlIO レイヤーを使っているため、再帰を避けるために 非表示になっている大量の SV を単独で割り当てます; 代わりに -DPERL_MEM_LOG
が提供する SV ロギングを使う場合は、 PerlIO レイヤーをバイパスできます。
PERL_MEM_LOG¶
If compiled with -DPERL_MEM_LOG
, both memory and SV allocations go through logging functions, which is handy for breakpoint setting.
-DPERL_MEM_LOG
でコンパイルした場合、メモリと SV 割り当ての両方は ロギング関数を通過します; これはブレークポイントの設定に便利です。
Unless -DPERL_MEM_LOG_NOIMPL
is also compiled, the logging functions read $ENV{PERL_MEM_LOG} to determine whether to log the event, and if so how:
-DPERL_MEM_LOG_NOIMPL
は付けずにコンパイルした場合、 ロギング関数は、イベントをロギングするか、およびどうやってするかを 決定するために $ENV{PERL_MEM_LOG} を読み込みます:
$ENV{PERL_MEM_LOG} =~ /m/ Log all memory ops
$ENV{PERL_MEM_LOG} =~ /s/ Log all SV ops
$ENV{PERL_MEM_LOG} =~ /t/ include timestamp in Log
$ENV{PERL_MEM_LOG} =~ /^(\d+)/ write to FD given (default is 2)
Memory logging is somewhat similar to -Dm
but is independent of -DDEBUGGING
, and at a higher level; all uses of Newx(), Renew(), and Safefree() are logged with the caller's source code file and line number (and C function name, if supported by the C compiler). In contrast, -Dm
is directly at the point of malloc()
. SV logging is similar.
メモリのロギングは -Dm
といくらか似ていますが、-DDEBUGGING
とは 独立しており、より高いレベルにあります; Newx(), Renew(), Safefree() の使用は呼び出し基のソースコードファイルと 行番号 (C コンパイラが対応しているなら C 関数名も) がロギングされます。 一方、-Dm
は malloc()
の時点で直接です。 SV のロギングも同様です。
Since the logging doesn't use PerlIO, all SV allocations are logged and no extra SV allocations are introduced by enabling the logging. If compiled with -DDEBUG_LEAKING_SCALARS
, the serial number for each SV allocation is also logged.
ログには PerlIO が使われないため、すべての SV の割り当てがログに 記録され、ログを有効にすることによって余分な SV の割り当ては発生しません。 -DDEBUG_LEAKING_SCALARS
でコンパイルすると、各 SV の割り当ての シリアル番号もログに記録されます。
プロファイリング¶
Depending on your platform there are various of profiling Perl.
プラットフォームによって、Perl をプロファイリングする方法が色々あります。
There are two commonly used techniques of profiling executables: statistical time-sampling and basic-block counting.
一般的に使われる実行ファイルをプロファイリングする技術が二つあります: 統計的タイムサンプリング(statistical time-sampling) と 基本ブロックカウント(basic-block counting) です。
The first method takes periodically samples of the CPU program counter, and since the program counter can be correlated with the code generated for functions, we get a statistical view of in which functions the program is spending its time. The caveats are that very small/fast functions have lower probability of showing up in the profile, and that periodically interrupting the program (this is usually done rather frequently, in the scale of milliseconds) imposes an additional overhead that may skew the results. The first problem can be alleviated by running the code for longer (in general this is a good idea for profiling), the second problem is usually kept in guard by the profiling tools themselves.
一つ目の方法では、CPU プログラムカウンタのサンプルを定期的に取得し、 プログラムカウンタは関数用に生成されたコードと照合させることができるため、 プログラムがどの関数に時間を費やしているかを統計的に把握することができます。 注意すべき点は、非常に小さい/高速な関数はプロファイルに現れる可能性が低く、 プログラムを定期的に中断すると(通常はミリ秒単位で頻繁に行われます)追加の オーバーヘッドが発生し、結果に歪みが生じる可能性があることです。 一つ目の問題は、コードをより長く実行することで軽減できます(一般的に、 これはプロファイリングに適した方法です); 二つ目の問題は、通常はプロファイリングツール自体によってガードされます。
The second method divides up the generated code into basic blocks. Basic blocks are sections of code that are entered only in the beginning and exited only at the end. For example, a conditional jump starts a basic block. Basic block profiling usually works by instrumenting the code by adding enter basic block #nnnn book-keeping code to the generated code. During the execution of the code the basic block counters are then updated appropriately. The caveat is that the added extra code can skew the results: again, the profiling tools usually try to factor their own effects out of the results.
2 番目の方法では、生成されたコードを 基本ブロック に分割します。 基本ブロックは、最初にのみ入力され、最後にのみ終了されるコードの セクションです。 たとえば、条件付きジャンプで基本ブロックが開始されます。 基本ブロックプロファイリングは通常、生成されたコードに enter basic block #nnnn ブックキーピングコードを追加することにより、 コードを 調整 して実行されます。 コードの実行中に、基本ブロックカウンタが適切に更新されます。 追加された余分なコードが結果を歪める可能性があることに注意してください: ここでも、プロファイリングツールは通常、結果から独自の影響を 考慮しようとします。
Gprof によるプロファイリング¶
gprof is a profiling tool available in many Unix platforms, it uses statistical time-sampling.
gprof は多くの Unix プラットフォームで利用できるプロファイルツールで、 統計的タイムサンプリング を使います。
You can build a profiled version of perl called "perl.gprof" by invoking the make target "perl.gprof" (What is required is that Perl must be compiled using the -pg
flag, you may need to re-Configure). Running the profiled version of Perl will create an output file called gmon.out is created which contains the profiling data collected during the execution.
make ターゲット "perl.gprof" を呼び出すことにより、"perl.gprof" という プロファイルバージョンの perl を作成することができます(-pg
フラグを使って Perl をコンパイルする必要があります; 再 Configure が必要な場合もあります)。 プロファイルバージョンの Perl を実行すると、gmon.out という出力ファイルが 作成されます; このファイルには、実行中に収集されたプロファイルデータが含まれています。
The gprof tool can then display the collected data in various ways. Usually gprof understands the following options:
gprof ツールは、収集されたデータをさまざまな方法で表示することができます。 通常 gprof は以下のオプションを理解します:
- -a
-
Suppress statically defined functions from the profile.
静的に定義された関数をプロファイルから抑制します。
- -b
-
Suppress the verbose descriptions in the profile.
プロファイルの詳細な説明を非表示にします。
- -e routine
-
Exclude the given routine and its descendants from the profile.
指定されたルーチンとその子孫をプロファイルから除外します。
- -f routine
-
Display only the given routine and its descendants in the profile.
プロファイル内の指定されたルーチンとその子孫のみを表示します。
- -s
-
Generate a summary file called gmon.sum which then may be given to subsequent gprof runs to accumulate data over several runs.
gmon.sum という名前のサマリーファイルを生成します。 このファイルは、後続のgprof実行に渡され、複数の実行にわたってデータを 蓄積します。
- -z
-
Display routines that have zero usage.
使用率が 0 のルーチンを表示します。
For more detailed explanation of the available commands and output formats, see your own local documentation of gprof.
使用可能なコマンドと出力フォーマットの詳細については、gprof の ローカル文書を参照してください。
quick hint:
ヒント:
$ sh Configure -des -Dusedevel -Doptimize='-pg' && make perl.gprof
$ ./perl.gprof someprog # creates gmon.out in current directory
$ gprof ./perl.gprof > out
$ view out
GCC gcov によるプロファイリング¶
Starting from GCC 3.0 basic block profiling is officially available for the GNU CC.
GCC 3.0 以降では、基本ブロックプロファイリング が GNU CC 用に公式に 利用可能です。
You can build a profiled version of perl called perl.gcov by invoking the make target "perl.gcov" (what is required that Perl must be compiled using gcc with the flags -fprofile-arcs -ftest-coverage
, you may need to re-Configure).
make ターゲット "perl.gcov" を呼び出すことによって、perl.gcov という プロファイルバージョンの perl を構築することができます(Perl は gcc で フラグ -fprofile-arcs -ftest-coverage
を指定してコンパイルする 必要があります; 再 Configure が必要になる場合もあります)。
Running the profiled version of Perl will cause profile output to be generated. For each source file an accompanying ".da" file will be created.
プロファイルバージョンの Perl を実行すると、プロファイル出力が生成されます。 各ソースファイルに付随する ".da" ファイルが作成されます。
To display the results you use the "gcov" utility (which should be installed if you have gcc 3.0 or newer installed). gcov is run on source code files, like this
結果を表示するには、"gcov" ユーティリティ(gcc 3.0 以降が インストールされている場合にインストールされるはずです)を使います。 gcov は以下のようにソースコードファイルで実行されます:
gcov sv.c
which will cause sv.c.gcov to be created. The .gcov files contain the source code annotated with relative frequencies of execution indicated by "#" markers.
sv.c.gcov が作成されます。 .gcov ファイルには、"#" マーカーで示される相対的な実行頻度で注釈が 付けられたソースコードが含まれています。
Useful options of gcov include -b
which will summarise the basic block, branch, and function call coverage, and -c
which instead of relative frequencies will use the actual counts. For more information on the use of gcov and basic block profiling with gcc, see the latest GNU CC manual, as of GCC 3.0 see
gcov の有用なオプションには、基本的なブロック、ブランチ、関数呼び出しの カバレッジを要約する -b
や、相対的な頻度ではなく実際のカウントを使う -c
などがあります。 gcc での gcov と基本的なブロックプロファイリングの使用に関する詳細は、 最新の GNU CC マニュアルを参照してください; GCC 3.0 では最新の GNU CC マニュアルを参照してください:
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc.html
and its section titled "8. gcov: a Test Coverage Program"
およびその "8. gcov: a Test Coverage Program" というタイトルの セクションです:
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc_8.html#SEC132
quick hint:
ヒント:
$ sh Configure -des -Doptimize='-g' -Accflags='-fprofile-arcs -ftest-coverage' \
-Aldflags='-fprofile-arcs -ftest-coverage' && make perl.gcov
$ rm -f regexec.c.gcov regexec.gcda
$ ./perl.gcov
$ gcov regexec.c
$ view regexec.c.gcov
Pixie によるプロファイリング¶
Pixie is a profiling tool available on IRIX and Tru64 (aka Digital UNIX aka DEC OSF/1) platforms. Pixie does its profiling using basic-block counting.
Pixie は、IRIX および Tru64(Digital UNIX または DEC OSF/1)プラットフォームで 利用可能なプロファイリングツールです。 Pixie は 基本ブロックカウント を使ってプロファイリングを行います。
You can build a profiled version of perl called perl.pixie by invoking the make target "perl.pixie" (what is required is that Perl must be compiled using the -g
flag, you may need to re-Configure).
make ターゲット"perl.pixie" を呼び出すことにより、perl.pixie という プロファイルバージョンの perl を構築することができます(必要なのは、 -g
フラグを使って Perl をコンパイルすることです。 再 Configure が必要になる場合もあります)。
In Tru64 a file called perl.Addrs will also be silently created, this file contains the addresses of the basic blocks. Running the profiled version of Perl will create a new file called "perl.Counts" which contains the counts for the basic block for that particular program execution.
Tru64 では、perl.Addrs というファイルも静かに作成されます。 このファイルには基本ブロックのアドレスが含まれています。 プロファイルされたバージョンのPerlを実行すると、"perl.Counts" という 新しいファイルが作成されます。 このファイルには、特定のプログラムを実行するための基本ブロックの カウントが含まれています。
To display the results you use the prof utility. The exact incantation depends on your operating system, "prof perl.Counts" in IRIX, and "prof -pixie -all -L. perl" in Tru64.
結果を表示するには、prof ユーティリティを使います。 正確な決まり文句はオペレーティングシステムによって異なります; IRIX では "prof perl.Counts"、Tru64 では "prof -pixie -all -L. perl" です。
In IRIX the following prof options are available:
IRIX では、次のプロファイルオプションを使えます:
- -h
-
Reports the most heavily used lines in descending order of use. Useful for finding the hotspot lines.
最も頻繁に使われている行を降順でレポートします。 ホットスポットの行を見つけるのに便利です。
- -l
-
Groups lines by procedure, with procedures sorted in descending order of use. Within a procedure, lines are listed in source order. Useful for finding the hotspots of procedures.
プロシージャごとに明細をグループ化します; プロシージャは使用の降順にソートされます。 プロシージャ内では、明細はソース順にリストされます。 プロシージャのホットスポットを検索する場合に便利です。
In Tru64 the following options are available:
Tru64 では、次のオプションを使えます:
- -p[rocedures]
-
Procedures sorted in descending order by the number of cycles executed in each procedure. Useful for finding the hotspot procedures. (This is the default option.)
各プロシージャで実行されたサイクル数の降順にソートされたプロシージャ。 ホットスポットプロシージャを検索するのに便利です。(これはデフォルトの オプションです。)
- -h[eavy]
-
Lines sorted in descending order by the number of cycles executed in each line. Useful for finding the hotspot lines.
各行で実行されたサイクル数の降順にソートされた行。 ホットスポットの行を見つけるのに便利です。
- -i[nvocations]
-
The called procedures are sorted in descending order by number of calls made to the procedures. Useful for finding the most used procedures.
呼び出されたプロシージャは、プロシージャに対して行われたコール数の降順で ソートされます。 最も使われているプロシージャを検索する場合に便利です。
- -l[ines]
-
Grouped by procedure, sorted by cycles executed per procedure. Useful for finding the hotspots of procedures.
プロシージャ別にグループ化され、プロシージャごとに実行されるサイクル別に ソートされます。 プロシージャのホットスポットを見つけるのに便利です。
- -testcoverage
-
The compiler emitted code for these lines, but the code was unexecuted.
コンパイラはこれらの行のコードを出力しましたが、コードは実行されませんでした。
- -z[ero]
-
Unexecuted procedures.
実行されていないプロシージャ。
For further information, see your system's manual pages for pixie and prof.
詳細については、システムのマニュアルページの pixie と prof を 参照してください。
様々な小技¶
-
Those debugging perl with the DDD frontend over gdb may find the following useful:
gdb 上で DDD フロントエンドを使って perl をデバッグする場合は、 次のような方法が便利です:
You can extend the data conversion shortcuts menu, so for example you can display an SV's IV value with one click, without doing any typing. To do that simply edit ~/.ddd/init file and add after:
データ変換ショートカットメニューを拡張できます; たとえば、SV の IV 値を 1 回クリックするだけで表示できます; キーを押す必要はありません。 これを行うには、~/.ddd/init ファイルを編集し、次の部分の後に追加します:
! Display shortcuts. Ddd*gdbDisplayShortcuts: \ /t () // Convert to Bin\n\ /d () // Convert to Dec\n\ /x () // Convert to Hex\n\ /o () // Convert to Oct(\n\
the following two lines:
次の 2 行です:
((XPV*) (())->sv_any )->xpv_pv // 2pvx\n\ ((XPVIV*) (())->sv_any )->xiv_iv // 2ivx
so now you can do ivx and pvx lookups or you can plug there the sv_peek "conversion":
ivx と pvx のルックアップを行うか、sv_peek "conversion" を接続します。
Perl_sv_peek(my_perl, (SV*)()) // sv_peek
(The my_perl is for threaded builds.) Just remember that every line, but the last one, should end with \n\
(my_perl はスレッド化ビルド用です)。 最後の行以外のすべての行は \n\ で終わることを覚えておいてください。
Alternatively edit the init file interactively via: 3rd mouse button -> New Display -> Edit Menu
または、3 番目のマウスボタン-> New Display - Edit Menu を 使って、対話的に init ファイルを編集します。
Note: you can define up to 20 conversion shortcuts in the gdb section.
注: gdb セクションでは、最大 20 の変換ショートカットを定義できます。
-
If you see in a debugger a memory area mysteriously full of 0xABABABAB or 0xEFEFEFEF, you may be seeing the effect of the Poison() macros, see perlclib.
デバッガ内のメモリ領域が 0xABABABAB または 0xEFEFEFEF で神秘的に いっぱいになっている場合は、Poison() マクロの効果が表示されている 可能性があります。 perlclib を参照してください。
-
Under ithreads the optree is read only. If you want to enforce this, to check for write accesses from buggy code, compile with
-DPL_OP_SLAB_ALLOC
to enable the OP slab allocator and-DPERL_DEBUG_READONLY_OPS
to enable code that allocates op memory viammap
, and sets it read-only at run time. Any write access to an op results in aSIGBUS
and abort.ithreads では、op 木は読み取り専用です。 バグのあるコードからの書き込みアクセスを チェックするためにこれを強制したい場合は、
-DPL_OP_SLAB_ALLOC
でコンパイルして OP スラブアロケーターを有効にし、-DPERL_DEBUG_READONLY_OPS
で コンパイルしてmmap
経由で op メモリを割り当てるコードを有効にし、 実行時に読み取り専用に設定します。 op への書き込みアクセスはSIGBUS
で中断されます。This code is intended for development only, and may not be portable even to all Unix variants. Also, it is an 80% solution, in that it isn't able to make all ops read only. Specifically it
このコードは開発のみを目的としており、すべての Unix バリエーションに 移植できるわけではありません。 また、すべての op を読み取り専用にすることができないという点で、80% の ソリューションです。 具体的には:
-
Only sets read-only on all slabs of ops at
CHECK
time, hence ops allocated later viarequire
oreval
will be re-writeCHECK
時に op のすべてのスラブに読み取り専用のみを設定します。 したがって、後でrequire
またはeval
によって割り当てられた op は 再書き込みされます。 -
Turns an entire slab of ops read-write if the refcount of any op in the slab needs to be decreased.
スラブ内の任意の op の refcount を減らす必要がある場合は、op のスラブ全体を 読み書き可能にします。
-
Turns an entire slab of ops read-write if any op from the slab is freed.
スラブから任意の op が解放された場合、op のスラブ全体を 読み書き可能にします。
It's not possible to turn the slabs to read-only after an action requiring read-write access, as either can happen during op tree building time, so there may still be legitimate write access.
読み取り/書き込みアクセスを必要とするアクションの後で、スラブを 読み取り専用にすることはできません; これは、op 木の構築時に発生する可能性があるため、正当な 書き込みアクセスが存在する可能性があります。
However, as an 80% solution it is still effective, as currently it catches a write access during the generation of Config.pm, which means that we can't yet build perl with this enabled.
しかし、80% のソリューションとしてはまだ有効です。 現在のところ、Config.pm の生成中に書き込みアクセスをキャッチしているため、 これを有効にして perl を構築することはできません。
-
結び¶
We've had a brief look around the Perl source, how to maintain quality of the source code, an overview of the stages perl goes through when it's running your code, how to use debuggers to poke at the Perl guts, and finally how to analyse the execution of Perl. We took a very simple problem and demonstrated how to solve it fully - with documentation, regression tests, and finally a patch for submission to p5p. Finally, we talked about how to use external tools to debug and test Perl.
Perl ソースの概要、ソースコードの品質を維持する方法、perl がコードを 実行する段階の概要、デバッガを使って Perl の本質を探る方法、そして最後に Perl の実行を分析する方法について簡単に説明しました。 非常に単純な問題を取り上げ、文書、回帰テスト、そして最後に p5p に 提出するためのパッチを使って、問題を完全に解決する方法を説明しました。 最後に、外部ツールを使って Perl をデバッグおよびテストする方法について 説明しました。
I'd now suggest you read over those references again, and then, as soon as possible, get your hands dirty. The best way to learn is by doing, so:
これらのリファレンスをもう一度読み通して、それから、できるだけ早く、 手を汚すことを提案します。 学ぶための最良の方法はやってみることです; 従って:
-
Subscribe to perl5-porters, follow the patches and try and understand them; don't be afraid to ask if there's a portion you're not clear on - who knows, you may unearth a bug in the patch...
perl5-porters を購読して、パッチを追いかけ、試してみて理解します; はっきりしない部分を訊ねるのを恐れないでください - あなたがパッチのバグを 掘り出すかも知れないことを知っています…
-
Keep up to date with the bleeding edge Perl distributions and get familiar with the changes. Try and get an idea of what areas people are working on and the changes they're making.
Perl 配布の最新を追いかけ続けて、変更に慣れ親しみます。 どの分野で人々が作業していて変更が行われているかを理解しようとします。
-
Do read the README associated with your operating system, e.g. README.aix on the IBM AIX OS. Don't hesitate to supply patches to that README if you find anything missing or changed over a new OS release.
オペレーティングシステムに関連づけられた README (例えば IBM AIX OS なら README.aix) を読みます。 新しい OS のリリースで抜けていたり変更されていることに気付いたら、 その README へのパッチを提供することを遠慮しないでください。
-
Find an area of Perl that seems interesting to you, and see if you can work out how it works. Scan through the source, and step over it in the debugger. Play, poke, investigate, fiddle! You'll probably get to understand not just your chosen area but a much wider range of perl's activity as well, and probably sooner than you'd think.
自分にとって興味深いと思われる Perl の分野を見つけて、作業をすると どのように動作するかを見ます。 ソースをスキャンして、デバッガでステップ実行します。 遊んでつついて調べていじります! おそらく、選んだ分野だけではなく、perl のもっと広い範囲の動作も 理解する必要があって、それはおそらくあなたが考えているより早いでしょう。
- The Road goes ever on and on, down from the door where it began.
-
(道はつづくよ、先へ先へと、戸口より出て、遠くへつづく。)
If you can do these things, you've started on the long road to Perl porting. Thanks for wanting to help make Perl better - and happy hacking!
これらのことができれば、Perl porting への長い道の開始です。 Perl をよりよくする助けをしようとしてくれてありがとう - そして happy hacking!
比喩的な引用¶
If you recognized the quote about the Road above, you're in luck.
上述の道に関する引用に気付いたなら、運があります。
Most software projects begin each file with a literal description of each file's purpose. Perl instead begins each with a literary allusion to that file's purpose.
ほとんどのソフトウェアプロジェクトでは、それぞれのファイルは、ファイルの 目的の文字通りの説明で始まります。 Perl はそうではなく、ファイルの目的の文学的な言及で始まります。
Like chapters in many books, all top-level Perl source files (along with a few others here and there) begin with an epigramic inscription that alludes, indirectly and metaphorically, to the material you're about to read.
多くの本の章のように、トップレベル (およびあちこちにあるいくつかの) Perl ソースファイルは、今から読もうとしているものへの暗示的、間接的、 隠喩的な警句的碑文で始まります。
Quotations are taken from writings of J.R.R Tolkien pertaining to his Legendarium, almost always from The Lord of the Rings. Chapters and page numbers are given using the following editions:
引用は J.R.R Tolkien の著作とそれに付随する世界から取られます; ほとんど常に The Lord of the Rings (指輪物語) からです。 章と頁番号は以下の版から取られています:
-
The Hobbit, by J.R.R. Tolkien. The hardcover, 70th-anniversary edition of 2007 was used, published in the UK by Harper Collins Publishers and in the US by the Houghton Mifflin Company.
J.R.R. Tolkien による The Hobbit (ホビットの冒険)。 イギリスでは Harper Collins Publishers から、アメリカでは the Houghton Mifflin Company から出版された、2007 年の 70 周年記念ハードカバー版が 使われています。
-
The Lord of the Rings, by J.R.R. Tolkien. The hardcover, 50th-anniversary edition of 2004 was used, published in the UK by Harper Collins Publishers and in the US by the Houghton Mifflin Company.
J.R.R. Tolkien による The Lord of the Rings (指輪物語)。 イギリスでは Harper Collins Publishers から、アメリカでは the Houghton Mifflin Company から出版された、2004 年の 50 周年記念ハードカバー版が 使われています。
-
The Lays of Beleriand, by J.R.R. Tolkien and published posthumously by his son and literary executor, C.J.R. Tolkien, being the 3rd of the 12 volumes in Christopher's mammoth History of Middle Earth. Page numbers derive from the hardcover edition, first published in 1983 by George Allen & Unwin; no page numbers changed for the special 3-volume omnibus edition of 2002 or the various trade-paper editions, all again now by Harper Collins or Houghton Mifflin.
J.R.R. Tolkien による The Lays of Beleriand; 死後、息子であり 遺著管理者である C.J.R. Tolkien によって出版された 12 巻からなる巨大な History of Middle Earth の第 3 巻。 頁番号は George Allen & Unwin から 1983 年に出版されたハードカバー版に 依っています; Harper Collins や Houghton Mifflin による、2002 年の特別 3 巻 オムニバス版や様々な trade-paper 版でも頁番号は変わっていません。
Other JRRT books fair game for quotes would thus include The Adventures of Tom Bombadil, The Silmarillion, Unfinished Tales, and The Tale of the Children of Hurin, all but the first posthumously assembled by CJRT. But The Lord of the Rings itself is perfectly fine and probably best to quote from, provided you can find a suitable quote there.
その他の JRRT の本である The Adventures of Tom Bombadil (トム・ボンバディルの冒険)、The Silmarillion(シルマリルの物語)、 Unfinished Tales(終わらざりし物語)、 The Tale of the Children of Hurin も引用の元となります (最初のもの以外は 死後 CJRT によって編纂されたものです)。 しかし、適切な引用が見つけられるなら、The Lord of the Rings は引用元として 完全によく、おそらく最良のものです。
So if you were to supply a new, complete, top-level source file to add to Perl, you should conform to this peculiar practice by yourself selecting an appropriate quotation from Tolkien, retaining the original spelling and punctuation and using the same format the rest of the quotes are in. Indirect and oblique is just fine; remember, it's a metaphor, so being meta is, after all, what it's for.
それで、Perl に追加するための新しくて完全なトップレベルソースファイルを 提供しようとしているなら、Tolkien から適切な引用を自分で選択して、 元の綴りと句読点を残して他の引用と同じ形式を使うという、特有の慣例に 従うべきです。 間接的で遠回しでもかまいません; これはメタファーであり、メタであると いうことは、結局、ためにするものであるということを忘れないでください。
作者¶
This document was written by Nathan Torkington, and is maintained by the perl5-porters mailing list.
この文書は Nathan Torkington によって書かれ、perl5-porters メーリングリストで 管理されています。