Objective-C: How is ARC Enabled Within GNUStep?
Asked Answered
L

1

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!

Libyan answered 10/11, 2013 at 22:1 Comment(7)
Is -fobj-arc a typo here or in your actual script?Meissner
No, it's in the script. I assumed the compiler would complain if its arguments were invalid...Libyan
Seems like a reasonable assumption to me, but it should definitely be -fobjc-arcMeissner
I'll try it now and get back to you :)Libyan
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.Libyan
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.Meissner
I'll answer it myself since an erroneous compiler flags being ignored is pretty hard to catch it seems... something others could trip on.Libyan
L
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.

Libyan answered 10/11, 2013 at 22:23 Comment(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.Belting

© 2022 - 2024 — McMap. All rights reserved.