1

「なぜ?」、「役に立たない?」、「気にしないで」というコメントは気にしないでください。clang を使用して、別のプログラム内でプログラムをコンパイルしたいと考えています。を作成NSTaskして引数を設定すると、ファイルが存在する (つまり、ストリームがない) 場合に機能し、物理ファイルに書き込みます。入力と出力の両方にストリームを使用するという、本当に欲しいものを手に入れることができませんでした。-xc オプションと - オプションを使用しても、パイプを使用してその機能を実装できない場合、clang と gcc の両方で stdin をコンパイルできることを私は知っています。また、clang の出力をファイル ハンドルまたはストリームにリダイレクトする方法もわかりません。

これをコンパイルしてoutfileに正しい出力を生成するコードを次に示します

task = [[NSTask alloc] init];

NSPipe* outputPipe = [[NSPipe alloc] init];
[task setStandardOutput:outputPipe ];
[task setStandardError: [task standardOutput]];

NSPipe* inPipe = [NSPipe pipe];
[task setStandardInput:inPipe];


[task setLaunchPath:@"/usr/bin/clang"];
NSString* outfile= [NSString stringWithFormat:@"%@.out",[[filename lastPathComponent] stringByDeletingPathExtension]];

//[data writeToFile:@"file.c" atomically:YES];
[task setArguments:[NSArray arrayWithObjects:filename,@"-S",@"-o",outfile,nil]];


[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(getData:) 
                                             name: NSFileHandleReadCompletionNotification 
                                           object: [[task standardOutput] fileHandleForReading]];

[[[task standardOutput] fileHandleForReading] readInBackgroundAndNotify];

[task launch];

入力ストリームにこれを使用してみました:

/* on pipe creation*/
dup2([[inPipe fileHandleForReading] fileDescriptor], STDIN_FILENO);
NSFileHandle* curInputHandle = [inPipe fileHandleForWriting];
/* tried before launch and after, no output just sits */ 
[curInputHandle writeData:[NSData dataWithContentsOfFile:filename]];

場合によっては、NSTask がまだ存在している間にパイプが閉じると、出力ファイルが作成されて実行されると思います。これは、clangがstdinが閉じるのを待っているだけだと思います。データが読み取られたときにパイプを閉じる方法はありますか?

出力のために、NSPipe の fileHandleForWriting を -o のパラメーターとして使用しようとしましたが、[NSConcretePipe fileSystemRepresentation]認識されないセレクターのエラーが発生します。同じエラーに対して、stdout のファイル記述子を使用してファイル ハンドルを作成しようとしました。それをリダイレクトするコマンドライン引数は知りません。リダイレクトに使用しようとしまし|たが、機能させることができませんでした。リダイレクトするUNIXマジックがあれば、stdoutを好きな場所に複製できます。

すべてのデータが読み取られたときにパイプを閉じる方法はありますか? そして、clangs出力をリダイレクトしますか? 同じことをより簡単にまたはよりクリーンに達成する方法が他にある場合、私はどのような実装にもオープンです。これらの 2 つの項目に関するヘルプは非常に優れています。

4

1 に答える 1

1

あなたの問題が何であるか、またはあなたが試したことは私には明らかではありません。ただし、通知を使用してメイン スレッドのパイプから出力を読み取り、パイプにも書き込みたい場合、1 つのオプションは別のスレッドでパイプに書き込むことです。以下のコードは、コードに基づいて、GCD を使用してこれを行います。この例では簡単にするために、バイナリは /tmp に保存されます。

// send a simple program to clang using a GCD task
- (void)provideStdin:(NSFileHandle *)stdinHandle
{
   dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_async(aQueue, ^{
      [stdinHandle writeData:[@"int main(int argc, char **argv)\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [stdinHandle writeData:[@"{\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [stdinHandle writeData:[@"   write(1, \"hello\\n\", 6);\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [stdinHandle writeData:[@"}\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [stdinHandle closeFile];   // sent the code, close the file (pipe in this case)
   });
}

// read the output from clang and dump to console
- (void) getData:(NSNotification *)notifcation
{
   NSData *dataRead = [[notifcation userInfo] objectForKey:NSFileHandleNotificationDataItem];
   NSString *textRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];
   NSLog(@"read %3ld: %@", (long)[textRead length], textRead);
}

// invoke clang using an NSTask, reading output via notifications
// and providing input via an async GCD task
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   NSTask *task = [NSTask new];

   NSPipe *outputPipe = [NSPipe new];
   [task setStandardOutput:outputPipe];
   [task setStandardError:outputPipe];
   NSFileHandle *outputHandle = [outputPipe fileHandleForReading];

   NSPipe* inPipe = [NSPipe pipe];
   [task setStandardInput:inPipe];

   [task setLaunchPath:@"/usr/bin/clang"];

   [task setArguments:[NSArray arrayWithObjects:@"-o", @"/tmp/clang.out", @"-xc",@"-",nil]];

   [[NSNotificationCenter defaultCenter] addObserver:self 
                                            selector:@selector(getData:) 
                                                name:NSFileHandleReadCompletionNotification 
                                              object:outputHandle];

   [outputHandle readInBackgroundAndNotify];

   [task launch];
   [self provideStdin:[inPipe fileHandleForWriting]];
}
于 2012-06-08T01:39:32.100 に答える