2012-06-06 112 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]]; 
}