NSTask only returning standardError in release build
Asked Answered
A

3

2

First of all, when debugging and running in Xcode everything works as expected.

But when I try to "share" my app, i.e. make a release build, my NSTask won't output any standardOutput while standardErrors ARE put out. How is that possible?

My code

- (id)initWithWindow:(NSWindow *)window {
    self = [super initWithWindow:window];
    if (self) {
        // Initialization code here.
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readPipe:) name:NSFileHandleReadCompletionNotification object:nil];
    return self;
}


-(void) watchFile:(NSNotification *)notification {
        NSString *path = [[notification userInfo] valueForKey:@"path"];

        task = [[NSTask alloc] init];
        [task setLaunchPath:@"/usr/bin/compass"];
        [task setCurrentDirectoryPath:path];

        NSArray *arguments;
        arguments = [NSArray arrayWithObjects: @"watch",@"--boring", nil];
        [task setArguments: arguments];

        NSPipe *outPipe, *errPipe;
        outPipe = [NSPipe pipe];
        errPipe = [NSPipe pipe];
        [task setStandardOutput: outPipe];
        [task setStandardError: errPipe];
        [task setStandardInput: [NSPipe pipe]];

        standardHandle = [outPipe fileHandleForReading];
        [standardHandle readInBackgroundAndNotify];

        errorHandle = [errPipe fileHandleForReading];
        [errorHandle readInBackgroundAndNotify];

        [self setSplitterPosition:0.0f];

        [task launch];

    }

-(void)readPipe:(NSNotification *)notification {
        NSLog(@"reading pipe");
        NSData *data;
        NSString *text;

        if(!([notification object] == standardHandle) && !([notification object] == errorHandle)) {
            return;
        } 

        data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
        text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

        if ([data length] == 0) {
            //error
            [self setSplitterPosition:150.0f];
            return;
        }

        [terminalViewController updateTerminal:text];    
        if(![text isEqualToString:@"\n"]) [self growlAlert:text title:@"Compapp"];

        [text release];
        if(task) [[notification object] readInBackgroundAndNotify];
    }
Agraphia answered 24/11, 2011 at 9:22 Comment(0)
H
0

/usr/bin/compass is not a binary installed in the standard installation of OSX (I don't have any binary named compass in my /usr/bin on my Mac)

So it seems quite logical that when your app is running on another Mac -- that does not have /usr/bin/compass installed -- and you try to run this task, it can't find it and only output some error on stderr.

Holmes answered 24/11, 2011 at 9:27 Comment(10)
That's not really the problem. I receive custom error messages from the binary itself. Besides I've only tested it on my own computer.Agraphia
Ok you were talking about "when I try to share my app" so I assumed it was on another Mac.Holmes
Did you try to retain the standardHandle and errorHandle variables, to be sure they are still valid in your readPipe: method? The difference between Debug and Release also being code optimization (and sometimes a small increase of execution speed then too) it may explain that in Debug your variables have not been autoreleased yet but in Release they are. Try to add some NSLogs to log the different ivars you use and check they are still valid in Release build.Holmes
Yeah, I just said that cause that's how it's called in XCode. Sorry if that wasn't clear :)Agraphia
Well in the code in my question. The log "reading pipe" is never called for standardOutput, so I'm guessing it has something to do with the NSFileHandleReadCompletionNotification never being fired, or something like that?Agraphia
Can't see where you add yourself as an observer for this NSNotification? You sure you added both pipes to the NSNotificationCenter? (would seem strange anyway that it still works in Debug not in Release)Holmes
It's on the very first line of the code I posted. I updated it a little to show where it's being called. I didn't add "both" pipes, it just listens for the NSFileHandleReadCompletionNotification. And then in the readPipe: method, I check to see which pipe is being handled..Agraphia
Before your edit, the first line of your code was adding the watchFile: selector to the "ConfigAdded" notification, not adding readPipe: to the NSFileHandleReadCompletionNotification, hence my question.Holmes
Ok so then sorry but I don't see what could then possibly be wrong in Release but not in Debug… Maybe try to put your addObserver: method into your watchFile: code for both pipes (specifying the object in the addObserver parameter instead of using nil), possibly also using two different @selectors (even if those selectors just NSLog some trace and then call both the same common method at the end)? I'm not sure why it would change anything but it's worth trying, isn't it?Holmes
Good thinking, but to no avail. Damn, this is driving me crazy. The way I see it, NSFileHandleReadCompletionNotification isn't being fired for reading standardOutput... What the hell is up with that?Agraphia
R
0

If you mean after release you are trying to debug, you need to create a file called Entitlements.plist and set Can be debugged before you build and archive.

Rigid answered 24/11, 2011 at 9:27 Comment(0)
R
0

if this is still an open issue for you, then checkout the answer I posted at this link: How to use a determinate NSProgressIndicator to check on the progress of NSTask? - Cocoa

it provides a good template for creating an async NSTask and for reading from standard output or standard error.

Ranaerancagua answered 7/2, 2012 at 1:9 Comment(5)
Hey, thanks, I just tried your code, but I get the exact same results. My program runs perfect when i build and run in Xcode, but when I Archive and then Share as application, I get no textdata back. My process seems to run fine, but I don't get ANY output..Agraphia
does it work perfectly on your xcode machine when you run the archived version? does the target machine have the same OS command on it that you are using on your xcode machine? I prefer to set a notification for each file handle like this: [nc addObserver:self selector:@selector(notifiedForStdOutput:) name:NSFileHandleReadCompletionNotification object:fhOutput]; where you name the file handle and process it separately rather then a single generic method. I would try logging the data then open console and see what is happening.Ranaerancagua
I am testing on the exact same machine, so everything should be the same. And I already tried to NSLog data, but it's like those notifications are never dispatched (or received).Agraphia
not sure what is going on. I have a couple of apps in prod using the approach I recommended. I'm willing to try and compile your xcode project if you would like another set of eyes.Ranaerancagua
I'd greatly appreciate that! Can I send it to you somehow?Agraphia

© 2022 - 2024 — McMap. All rights reserved.