Clang NSTask с потоками

Не обращайте внимания на все комментарии «почему?», «бесполезно?» и «не беспокойтесь». Я хочу скомпилировать программу внутри другой программы, используя clang. Я могу создать NSTask и настроить аргументы, и он будет работать, если файл существует (т.е. нет потока) и записывает в физический файл. Я не смог получить то, что мне действительно хотелось бы, - использовать потоки как для ввода, так и для вывода. Я знаю, что и clang, и gcc позволяют компилировать стандартный ввод, если вы используете параметры -xc и -, но я не могу реализовать эту функцию с помощью каналов. Я также не уверен, как перенаправить вывод 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 просто ждет закрытия стандартного ввода. Есть ли способ закрыть канал, когда данные были прочитаны?

Для вывода я попытался использовать fileHandleForWriting NSPipe в качестве параметра -o, что дает ошибку [NSConcretePipe fileSystemRepresentation] нераспознанного селектора. Я попытался создать дескриптор файла с файловым дескриптором stdout с той же ошибкой. Я не знаю ни одного аргумента командной строки, который перенаправляет его. Я пытался использовать | для перенаправления, но не смог заставить его работать. Если есть какая-то магия unix для перенаправления, я могу дублировать stdout куда захочу.

Итак, есть ли способ закрыть канал, когда все данные будут прочитаны? И перенаправить лязг выход? Если есть какой-либо другой способ сделать то же самое проще или чище, я открыт для любой реализации. Любая помощь по этим двум пунктам была бы очень кстати.


person utahwithak    schedule 06.06.2012    source источник


Ответы (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]];
}
person CRD    schedule 08.06.2012