2012-06-06 114 views
1

不要介意所有的「爲什麼?」,「沒用?」和「不要打擾」的評論。我想用clang在另一個程序中編譯一個程序。我可以創建NSTask並設置參數,如果文件存在(即沒有流),並且寫入物理文件,它將工作。我一直無法得到我真正喜歡的是什麼,它將流用於輸入和輸出。我知道,如果使用-xc和 - 選項,clang和gcc都允許編譯stdin,但無法使用管道實現該功能。我也不知道如何將clang的輸出重定向到文件句柄或流。鏗鏘NSTask與流

以下是我,編譯它的代碼,並生成在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仍然存在輸出文件創建並運行。這讓我覺得鏗鏘正在等待stdin關閉。數據讀取後有沒有關閉管道的方法?

對於輸出,我試圖使用NSPipe的fileHandleForWriting作爲參數-o,這給出了一個錯誤[NSConcretePipe fileSystemRepresentation]無法識別的選擇器。我試圖用stdout的文件描述符創建一個文件句柄到相同的錯誤。我不知道任何重定向它的命令行參數。我試過使用|來重定向,但一直未能得到它的工作。如果有任何unix魔法重定向它,我可以將stdout複製到我想要的任何地方。

那麼有什麼方法可以在讀取所有數據時關閉管道?和重定向clangs輸出?如果有任何其他方式可以更容易或更清晰地完成相同的任務,我願意接受任何實施。 這兩個項目的任何幫助將如此之大。

回答

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]]; 
}