.cpp または .h ファイルに #includes (例: #include "ready.h") がある場合、これらのファイル名を含むテキスト ファイルを作成する必要があります。ready.h には独自の #includes がある可能性があるため、呼び出しは再帰的に行う必要があります。これを行う方法がわからない。
3 に答える
@OneSolitaryNoob の解決策は問題なく機能する可能性がありますが、問題があります。再帰ごとに別のプロセスが開始され、非常に無駄です。サブルーチンを使用して、より効率的に行うことができます。すべてのヘッダー ファイルが作業ディレクトリにあると仮定します。
sub collect_recursive_includes {
# Unpack parameter from subroutine
my ($filename, $seen) = @_;
# Open the file to lexically scoped filehandle
# In your script, you'll probably have to transform $filename to correct path
open my $fh, "<", $filename or do {
# On failure: Print a warning, and return. I.e. go on with next include
warn "Can't open $filename: $!";
return;
};
# Loop through each line, recursing as needed
LINE: while(<$fh>) {
if (/^\s*#include\s+"([^"]+)"/) {
my $include = $1;
# you should probably normalize $include before testing if you've seen it
next LINE if $seen->{$include}; # skip seen includes
$seen->{$include} = 1;
collect_recursive_includes($include, $seen);
}
}
}
このサブルーチンは、どのファイルが既に表示されているかを記憶し、再帰を回避します。各ファイルは 1 回だけアクセスされます。
トップレベルでは、サブルーチンの実行後にすべてのファイル名をキーとして保持するハッシュリファレンスを 2 番目の引数として指定する必要があります。
my %seen = ( $start_filename => 1 );
collect_recursive_includes($start_filename, \%seen);
my @files = sort keys %seen;
# output @files, e.g. print "$_\n" for @files;
コードのコメントで、おそらくファイル名を正規化する必要があることをほのめかしました。./foo/bar/baz.h
たとえば、 を指す開始ファイル名を考えてみましょうqux.h
。次に、再帰したくない実際のファイル名は./foo/bar/qux.h
ではなく./qux.h
です。このCwd
モジュールは、現在の場所を見つけて、絶対パスから相対的に変換するのに役立ちます。このFile::Spec
モジュールはより複雑ですが、プラットフォームに依存しないファイル名と -path 操作を適切にサポートしています。
Perl では、再帰は単純です。
sub factorial
{
my $n = shift;
if($n <= 1)
{ return 1; }
else
{ return $n * factorial($n - 1); }
}
print factorial 7; # prints 7 * 6 * 5 * 4 * 3 * 2 * 1
率直に言って、注意が必要なことは 2 つしか思い浮かびません。
- Perl では、変数はデフォルトでグローバルであるため、デフォルトで静的です。ある関数呼び出しの変数が別の関数呼び出しの変数を踏みにじるのを避けるため、変数をローカライズする必要があります
my
。 - プロトタイプと再帰にはいくつかの制限があります。プロトタイプを使用したい場合 (たとえば、
sub factorial($)
の代わりに)、関数定義の前sub factorial
にプロトタイプを提供して、関数本体内で使用できるようにする必要があります。(または、関数を再帰的に呼び出すときに使用できます。これにより、プロトタイプが適用されなくなります。)&
表示をどのように表示したいかは完全には明確ではありませんが、基本は follow_includes.pl というスクリプトです。
#!/usr/bin/perl -w
while(<>) {
if(/\#include "(\S+)\"/) {
print STDOUT $1 . "\n";
system("./follow_includes.pl $1");
}
}
次のように実行します。
% follow_includes.pl somefile.cpp
重複したインクルードを非表示にする場合は、次のように実行します。
% follow_includes.pl somefile.cpp | sort -u
通常、これは何らかのツリー プリントで表示する必要があります。