Search code examples
c++objective-ccmodularity

Objective-C build system that can do modules


I'm working on a small hobby project of mine where I have a big structure that takes care of all core tasks. This core won't do much by itself, it needs a dozen subsystems that actually do the hard work. I've currently written only one subsystem so it's still easy to change things.

I have a lot of code locations where the core interfaces with the subsystems, and I don't want to have to change the core every time I add a new subsystem. My idea was to make it modular.

A long time I saw something similar in a game engine, where a new console command could be defined by using some preprocessor macro. That was all you had to do - after compiling it instantly worked in the game.

So let's take the game engine as an example for my case. I've placed comments in the code below that should make my question more obvious.

My question: How do I implement a modular system in Objective-C, that's built at compile time, and does not involve changing anything other than the modules themselves?

And now some code

-(void)interpretCommand:(NSString*)command {
    // Find the space in the command
    NSRange pos = [command rangeOfString:@" "];
    if (pos.length == 0) return; // No space found
    
    NSString *theCommand = [command substringToIndex:pos.location];
    
    // !!! Here comes the important code !!!
    // Get all the available commands - this is what my question is about!
    NSDictionary *allCommands = nil;
    
    // Find the command in the dictionary
    NSString *foundCommand = [allCommands objectForKey:theCommand];
    
    // Execute the command
    if (foundCommand != nil) {
        [[NSClassFromString(foundCommand) new] execute];
    }
}

I want to be able to add a new command with something like :

REGISTER_COMMAND(MyClassName, "theCommand")

Remember, the above code isn't my specific case. Also, I don't want external modules, they have to be compiled as if they were implemented natively. Objective-C is fine, so is C++ or C.

Update
Clarification: I know how to do this with a plist file, but if I chose that I might just as well store them in my actual code. I'm looking for a C/C++/Objective-C solution that allows me to simply add the module with a preprocessor macro.

Update 2
Adding a bounty - I'd really like some good ideas for this.


Solution

  • Ok, if it must be by macro, this solution works:

        // the macro:
    #define REGISTER_COMMAND( __THE_CLASS, __COMMAND )\
    @interface __THE_CLASS##Registration @end\
    @implementation __THE_CLASS##Registration \
    +(void)load { [ Commands registerHandler:NSClassFromString(@""#__THE_CLASS) command:(__COMMAND) ] ; } \
    @end
    
        // Bookkeeping/lookup class:
    @interface Commands 
    @end
    
    @implementation Commands
    static NSMutableDictionary * __commands = nil ;
    
    +(void)load
    {
        __commands = [[ NSMutableDictionary alloc ] init ] ;
    }
    
    +(void)registerHandler:(Class)theClass command:(NSString*)command
    {
        if ( theClass && command.length > 0 )
        {
            [ __commands setObject:theClass forKey:command ] ;
        }
    }
    
    +(id)handlerForCommand:(NSString*)command
    {
        Class theClass = [ __commands objectForKey:command ] ;
        return [ [ [ theClass alloc ] init ] autorelease ] ;
    }
    
    @end
    
        // map the command 'doit' to handler 'MyCommand', below
    REGISTER_COMMAND( MyCommand, @"doit" )
    
        // one of our command handling objects, 'MyCommand'
    @interface MyCommand : NSObject
    @end
    
    @implementation MyCommand
    @end
    
        // test it out:
    int main (int argc, const char * argv[])
    {   
        @autoreleasepool 
        {
            NSLog(@"command %@ found for 'doit'\n", [ Commands handlerForCommand:@"doit" ] ) ;
    
        }
        return 0;
    }