Static variables reset inside CFPlugin code

  • I'm loading and creating a CFplugin using Core Foundation and running into a strange behavior where all the static variables defined throughout my code get reset to their initialization values when running code inside plugin. For example, I define a static variable and functions in a file foo.c

    static int foo = 0;
    void setFoo(void) { foo = 42;}
    void printFoo(void) {fprintf(stderr, "foo is %d\n",foo);}
    then I install and call the plugin code using

    printFoo();    // <- prints "0"
    setFoo();      // <- sets foo to 42
    printFoo();    // <- prints "42"

    PluginInterfaceRef *iunknown = CFPlugInInstanceCreate(kCFAllocatorDefault, factoryID, kMyPluginTypeUUID);

    printFoo();  // <- prints "42"
    which looks okay, but inside the factory function, called by CFPlugInInstanceCreate,...

    void *myFactory(CFAllocatorRef allocator, CFUUIDRef typeID) {
        if(!CFEqual(typeID, kMyPluginTypeUUID)) return NULL;
        MyPluginRef result = MyPluginCreate(typeID);
        printFoo();  // <- prints "0"  ??
        return result;
    }
    printFoo() returns "0", and not "42".

    I'm using Xcode 4.2.1, and all the functions appear to be running in the main thread.

    Any ideas why this is happening, and suggestions for making static variables available inside the plugin?
  • On Dec 29, 2011, at 12:11 PM, Grandinetti Philip wrote:

    > I'm loading and creating a CFplugin using Core Foundation and running into a strange behavior where all the static variables defined throughout my code get reset to their initialization values when running code inside plugin.

    If you have two binaries — an application and a plugin — then each of those has independent global/static variables, even if those variables are declared in the same source files. The scope of globals is basically defined by the linker, and you've linked two independent binaries that have no magic connection to each other.

    If you want the two to share a variable, you'll need to:
    (a) define it in the plugin code, not the app
    (b) declare it as global not static, so it's visible outside that compilation unit
    (c) tell the linker to export that global from the plugin, e.g. by using an export file
    (d) make the app link against the plugin so it can access the variable

    —Jens
  • Thanks Jens.  With more experimenting and reading around I've now got a better picture, and your reply confirmed that picture.  I think my problem was even trickier, because I defined my static variable (actually a pointer to a array) in a static library linked to the main app, and the plugin is loaded by the static library, not the main app.  Whew!

    Your suggestions make sense, although...

    option (a) doesn't work for me, since the static variables are being used before the plugin is loaded.

    option (b) I tried changing the static variable into a global, and putting the global outside of main in the app, but this didn't work for me.  Not sure what I did wrong here.

    option (c) seems like the solution I need, but I couldn't find how to do this in Xcode.

    option (d) I'm not sure I understand.  If I link the host app against the plugin doesn't that defeat the purpose of making it a plugin?

    Ultimately, a solution I put together was to add an interface function to the plugin that passed the pointer from the host app over to the plugin, and used that to set the plugin's copy of the static variable (pointer in this case).

    If you know where I can read more about implementing option (c) or other suggestions I would be grateful to hear about it.

    Thanks, and happy new year!

    Philip

    On Jan 1, 2012, at 3:42 PM, Jens Alfke wrote:

    >
    > On Dec 29, 2011, at 12:11 PM, Grandinetti Philip wrote:
    >
    >> I'm loading and creating a CFplugin using Core Foundation and running into a strange behavior where all the static variables defined throughout my code get reset to their initialization values when running code inside plugin.
    >
    > If you have two binaries — an application and a plugin — then each of those has independent global/static variables, even if those variables are declared in the same source files. The scope of globals is basically defined by the linker, and you've linked two independent binaries that have no magic connection to each other.
    >
    > If you want the two to share a variable, you'll need to:
    > (a) define it in the plugin code, not the app
    > (b) declare it as global not static, so it's visible outside that compilation unit
    > (c) tell the linker to export that global from the plugin, e.g. by using an export file
    > (d) make the app link against the plugin so it can access the variable
    >
    > —Jens
  • I have to wonder why you're using CFPlugIn in the first place.

    I strongly recommend using NSBundle and Objective-C for your plug-in architecture, or plain CFBundle and functions & structs if you absolutely must use C rather than objects for your plug-in architecture.

      -- Chris
  • Hi Chris,

    I prefer sticking with C for this part of my code.  I just assumed that CFPlugin would be less work, but since you suggested CFBundle, I can see that it might be just as easy/hard.  What would be the advantages?

    Either way, I guess I would still have a problem syncing up static variables once the bundle executable was loaded?

    Thanks,

    Philip

    On Jan 1, 2012, at 7:01 PM, Chris Hanson wrote:

    > I have to wonder why you're using CFPlugIn in the first place.
    >
    > I strongly recommend using NSBundle and Objective-C for your plug-in architecture, or plain CFBundle and functions & structs if you absolutely must use C rather than objects for your plug-in architecture.
    >
    > -- Chris
    >
  • On Jan 1, 2012, at 2:21 PM, Grandinetti Philip wrote:

    > Your suggestions make sense, although...
    > option (a) doesn't work for me, since the static variables are being used before the plugin is loaded.

    They're not options, they're steps. You need to do all of them.

    If you can't put the variable in the plugin, I _think_ you can put it in the app, then export it from the app and link the plugin against the app. Apps don't normally export symbols, but I think you can set this up.

    Maybe you could explain what the plugin does and why it and the app need to share a variable?

    —Jens
  • Sorry Jens,

    I read too quickly.  The app is for the physical and engineering sciences, and will perform a least squares fit of experimental data to different physical models.    The models for the experimental data will be in the plugins, and the user will likely only need to the load a few of the plugin models.  In the host app (actually in one of it's static libraries dedicated to handling SI Units) is a static variable pointing to a singleton library (CFMutableSet) with a growing set of SI units available in the main app (and plugins).  The units are flyweights, so I don't want multiple copies floating around the program.

    So, I can't really define the static variable pointing to my library in the plugin.    It needs to be defined in the library that handles all the SI units.

    Is it still possible to tell the linker to export the static variable pointing to my SI Units library in such a situation?

    Thanks again,

    Philip

    On Jan 1, 2012, at 9:49 PM, Jens Alfke wrote:

    >
    > On Jan 1, 2012, at 2:21 PM, Grandinetti Philip wrote:
    >
    >> Your suggestions make sense, although...
    >> option (a) doesn't work for me, since the static variables are being used before the plugin is loaded.
    >
    > They're not options, they're steps. You need to do all of them.
    >
    > If you can't put the variable in the plugin, I _think_ you can put it in the app, then export it from the app and link the plugin against the app. Apps don't normally export symbols, but I think you can set this up.
    >
    > Maybe you could explain what the plugin does and why it and the app need to share a variable?
    >
    > —Jens
  • At 9:47 AM -0500 1/2/12, Grandinetti Philip wrote:
    > So, I can't really define the static variable pointing to my library
    > in the plugin.    It needs to be defined in the library that handles
    > all the SI units.

    Hi Philip,

    This is dusting off brain cells that I haven't used in awhile but,
    assuming all the plugins run only in your application, you could put
    all of the code/data shared by the plugins into a framework that
    resides in your application bundle.

    Your application and your plugins then link against this framework.

    You could use either CFPlugin or NSBundle as Chris suggests.

    The tough part here is all the Xcode magic to get the targets set up
    correctly -- I'm currently working out something similar, and will
    post results.

    If someone has a recipe for setting this up in Xcode 4 and would be
    willing to post it, I'd be interested as well.

    HTH,

    -Steve
  • Hi Steve,

    You raise a fundamental issue that I admit I don't completely understand.  What are the differences between linking against a static library versus a framework.  If I turned all my static libraries into a framework would the plugin see the static variables in the framework without having to do all the Xcode linking magic?

    Thanks,

    Philip

    On Jan 2, 2012, at 10:26 AM, Steve Sisak wrote:

    > At 9:47 AM -0500 1/2/12, Grandinetti Philip wrote:
    >> So, I can't really define the static variable pointing to my library in the plugin.    It needs to be defined in the library that handles all the SI units.
    >
    > Hi Philip,
    >
    > This is dusting off brain cells that I haven't used in awhile but, assuming all the plugins run only in your application, you could put all of the code/data shared by the plugins into a framework that resides in your application bundle.
    >
    > Your application and your plugins then link against this framework.
    >
    > You could use either CFPlugin or NSBundle as Chris suggests.
    >
    > The tough part here is all the Xcode magic to get the targets set up correctly -- I'm currently working out something similar, and will post results.
    >
    > If someone has a recipe for setting this up in Xcode 4 and would be willing to post it, I'd be interested as well.
    >
    > HTH,
    >
    > -Steve
  • On Jan 2, 2012, at 7:52 AM, Grandinetti Philip wrote:

    > You raise a fundamental issue that I admit I don't completely understand.  What are the differences between linking against a static library versus a framework.  If I turned all my static libraries into a framework would the plugin see the static variables in the framework without having to do all the Xcode linking magic?

    The difference is copying vs. referencing. A static library gets copied into the target at link time, whereas if you link with a dynamic library or framework, the linker just notes down what symbols are referenced, and at load time those get resolved to those symbols in the library.

    For your purposes, the difference is that in a static library, everything that links with it has its own private copy of the library's global variables. In a dylib/framework, everything that links with it shares its global variables. The latter is what you want.

    —Jens
  • Hi Jens,

    Thanks for your patience.  I'm getting a better understanding.  Also, it helped a bit reading through ...

    http://developer.apple.com/library/mac/#documentation/developertools/concep
    tual/MachOTopics

    and
    http://developer.apple.com/library/mac/#documentation/DeveloperTools/Concep
    tual/DynamicLibraries


    However, I'm still not sure what is the right way to do this.  I have made the pointer global (no long declared as "static"),...

    CFMutableSetRef unitsLibrary = NULL;

    in my "Units" static library.  The main app begins using the "Units" library at startup and starts filling this set.  Then, eventually the plugin gets loaded. In the plugin factory function I added ...

        CFBundleRef bundle = CFBundleGetMainBundle();
        CFMutableSetRef *pointer =  CFBundleGetDataPointerForName (bundle,CFSTR("unitsLibrary"));
        PSUnitSetLibrary(*pointer);

    and this works!  The plugin now "knows" about all the previous units that were defined in the main app.

    But I'm troubled by this solution.  If I set debugger break points in the "Units" library the debugger no longer stops at those breakpoints when called by the plugin, but it does stop at those breakpoints when called by the main app.  Makes me think I have two copies of code for my static units library running after the plugin is loaded.  Does that make sense?

    Philip

    On Jan 2, 2012, at 1:22 PM, Jens Alfke wrote:

    >
    > On Jan 2, 2012, at 7:52 AM, Grandinetti Philip wrote:
    >
    >> You raise a fundamental issue that I admit I don't completely understand.  What are the differences between linking against a static library versus a framework.  If I turned all my static libraries into a framework would the plugin see the static variables in the framework without having to do all the Xcode linking magic?
    >
    > The difference is copying vs. referencing. A static library gets copied into the target at link time, whereas if you link with a dynamic library or framework, the linker just notes down what symbols are referenced, and at load time those get resolved to those symbols in the library.
    >
    > For your purposes, the difference is that in a static library, everything that links with it has its own private copy of the library's global variables. In a dylib/framework, everything that links with it shares its global variables. The latter is what you want.
    >
    > —Jens
    >
  • On Jan 2, 2012, at 6:27 PM, Grandinetti Philip wrote:

    > But I'm troubled by this solution.  If I set debugger break points in the "Units" library the debugger no longer stops at those breakpoints when called by the plugin, but it does stop at those breakpoints when called by the main app.  Makes me think I have two copies of code for my static units library running after the plugin is loaded.  Does that make sense?

    Yes. That’s what a static library is. As I said, it gets *copied* into the binary at link time. So you do have two copies of the code for the units library. If you only want one copy of the code, make a dynamic library instead (or a framework, which is just a dynamic library packaged with header files and resources.)

    If you make Units a dynamic library, you won’t have to mess with CFBundleGetDataPointerForName either. Just make sure ‘unitsLibrary’ gets exported from Units, and declare it extern in the code that wants to use it.

    —Jens
previous month december 2011 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Go to today