叮叮当当



不要介意所有的"为什么?","无用?"和"不要打扰"的评论。我想使用 clang 在另一个程序中编译一个程序。我可以创建NSTask并设置参数,如果文件存在(即没有流)并写入物理文件,它将起作用。我无法得到我真正想要的,即对输入和输出使用流。我知道如果您使用 -xc 和 - 选项,则 clang 和 gcc 都允许编译 stdin,但无法使用管道实现该功能。我也不确定如何将 clang 的输出重定向到文件句柄或流。

这是我拥有的代码,可以编译它并在输出文件中生成正确的输出

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]无法识别的选择器的错误。我尝试使用标准输出的文件描述符创建文件句柄,但出现相同的错误。我不知道有任何命令行参数可以重定向它。我尝试使用|重定向,但无法使其正常工作。如果有任何 unix 魔法可以重定向它,我可以将标准输出发送到我想要的任何地方。

那么,当读取所有数据时,有没有办法关闭管道呢?和重定向叮当声输出?如果有任何其他方法可以更容易或更干净地完成同样的事情,我对任何实现都持开放态度。对这两个项目的任何帮助都会很棒。

我不清楚你的问题是什么或你尝试过什么。但是,如果您要使用通知从主线程上的管道读取输出,并且还希望写入管道,则一种选择是写入另一个线程中的管道。下面的代码根据您的代码使用 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]];
}

最新更新