10

Objective-C/ARC/memory managements questions have been done to death on SO, but this one seems slightly different to the existing ones.

I've been trying to use Objective-C with GNUStep and Clang. I've downloaded the libraries apparently required for modern Objective-C features like ARC; blocks work and @autoreleasepools are accepted by the compiler along with the associated compiler flag. The AppKit GUI toolkit works, and so does the queue dispatcher.

My understanding, if correct, is that alloced objects are automatically set up to release upon the exiting of a @autoreleasepool of a 'parent' stack frame, and that releasing decrements a reference count. Yet the compiler doesn't bemoan a manual [super dealloc] and tolerates manual autoreleases and releases, which implies that ARC isn't even switched on.

One might imagine that Googling GNUStep ARC ~enable would yield some compiler flag that I'm missing out, but it doesn't.

Here's some example code. It's an object wrapper around a multiple dimensional array of C99 bools, which is malloced in init and freed within dealloc, which I gather is one of the few legitimate uses of dealloc within ARC code. Notice that dealloc's puts is not called after the @autoreleasepool finishes, despite there only being a single reference created within it. A manual release or autorelease, however, works great.

#import <stdbool.h>
#import <stdio.h>
#import <stdlib.h>

#import <Foundation/Foundation.h>

@interface Area : NSObject {
    bool *area;
    size_t width, height;
}

- (id) initWithWidth:(size_t)aWidth height:(size_t)aHeight;
- (void) dealloc;
- (void) display;
@end

@implementation Area

- (id) initWithWidth:(size_t)aWidth height:(size_t)aHeight {
    self = [super init];
    width = aWidth;
    height = aHeight;
    area = malloc((sizeof *area) * aWidth * aHeight);

    for (size_t y = 0; y < aHeight; ++y) {
        for (size_t x = 0; x < aWidth; ++x) {
            area[(aHeight * y) + (aWidth * x)] = true;
        }
    }

    return self;
}

- (void) dealloc {
    free(area);
    puts("DEALLOCATED");
}

- (void) display {
    for (size_t y = 0; y < height; ++y) {
        putchar('|');
        for (size_t x = 0; x < width; ++x) {
            putchar(area[(height * y) + (width * x)]
                    ? '#'
                    : ' ');
        }
        puts("|");
    }
}

@end

int main(void)
{
    @autoreleasepool {
        id area = [[Area alloc] initWithWidth:10 height:10];
        [area display];
    }
    return EXIT_SUCCESS;
}

My compiling script (I'll use a proper makefile once I've got this working):-

#!/bin/sh

INC_FLAG=`gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`
LIB_FLAG=`gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`

clang -o main main.m \
    -I $INC_FLAG \
    -L $LIB_FLAG \
    \
    -fblocks \
    -fobj-arc \
    -fconstant-string-class=NSConstantString \
    -D_NATIVE_OBJC_EXCEPTIONS \
    \
    -pthread \
    -lgnustep-base \
    -ldispatch \
    -lgnustep-gui \
    -lobjc

I've been under the assumption that autorelease should be inferred for objects created within @autoreleasepool.

Thanks in advance!

Louis Jackman
  • 1,001
  • 6
  • 16
  • 4
    Is `-fobj-arc` a typo here or in your actual script? – jscs Nov 10 '13 at 22:05
  • 1
    No, it's in the script. I assumed the compiler would complain if its arguments were invalid... – Louis Jackman Nov 10 '13 at 22:06
  • 6
    Seems like a reasonable assumption to me, but it should definitely be `-fobjc-arc` – jscs Nov 10 '13 at 22:08
  • I'll try it now and get back to you :) – Louis Jackman Nov 10 '13 at 22:09
  • 2
    Aha! I now completely works. I'm amazed that I could pass invalid crap as arguments to clang and it just silently ignored them rather than warning me. Now it's enabled, it complains about manual `alloc`. I've also had to enable a 'non fragile ABI' via a flag. Thanks for the help; solved in the comments section... I've no answer to accept now. – Louis Jackman Nov 10 '13 at 22:13
  • 2
    Glad you sorted it out! It doesn't seem likely to me that this question is going to be particularly findable if someone else does the same thing. I'd suggest just sending it to the bit bucket, but if you want to, you can answer it yourself. – jscs Nov 10 '13 at 22:18
  • I'll answer it myself since an erroneous compiler flags being ignored is pretty hard to catch it seems... something others could trip on. – Louis Jackman Nov 10 '13 at 22:21

1 Answers1

8

Solution: Josh Caswell pointed out that my compiler flag fobj-arc should be fobjc-arc. Given that Clang gave no indicator of this flag being invalid, I'll leave this answer up for anyone else.

Louis Jackman
  • 1,001
  • 6
  • 16
  • 1
    Debian clang version 3.5.0-10 based on LLVM 3.5.0 does indicate that -fobj-arc is invalid: it throws an error, while -fobjc-arc is accepted. – Chris Hatton May 09 '15 at 08:07