ZBrushCentral

Closing Dynamic Libraries

Hello,

I am writing a dynamic library on Mac OS X and after I have compiled and tested it in ZBrush I make some changes and recompile. Unfortunately I then need to shutdown ZBrush, cancel any “do you want to save” dialogs, start ZBrush again and load my dynamic library activating zscript (the last bit I could probably automate).

I understand why; the dynamic library is loaded into the memory space of the ZBrush process. It would be counter to the dynamic part of dynamic library if it did not. The releasing of said memory space is what I don’t quite understand. I mean Zbrush seemingly does not close the dynamic library before it terminates. At least I get no logs from my library’s destructor. Perhaps ZBrush developers have sided with “let the OS take care of reclaiming the memory, at least our program won’t stall upon termination.” Which is fine and what I also would adhere to. But that does not help me right now :slight_smile:

I guess I could try implementing a build script into Xcode that increments the product filename and having the zscript part check for the latest version. Would probably result in an awful lot of dynamic libraries within the hour :smiley:

How do you all write and test libraries? Does the ZBrush debug/diagnostic mode still exist (holding a certain modifier key upon startup) and does that help? Perhaps pressing Init ZBrush from the Preference palette (just thought of that possibility, will try tomorrow)?

Thanks for any help,

… continued.

I tried Init ZBrush from the Preferences palette but no go. Still need to restart ZBrush to reload the dynamic library.

Looking at the OS X documentation on the various dylib loading mechanisms I suspect ZBrush is calling NSBundle’s load method which in turn calls the low level dyld() and by extension dlopen() and dlclose(). It also appears that NSBundle creates two retains upon loading a dynamic library to prevent normal low level release using dlclose(). As the code comment states:

// dylibs are not allowed to unload
// …except those with image_info and nothing else (5359412)

I would still love to hear how other people go about testing their dll’s and lib’s.

Thank you in advance,

You’re light years ahead of me and on a Mac to boot. You could look at my ‘folder approach’ . As I don’t have or use any .dll or .lib files or even yet the ZFileUtilities (yet), I can’t help you too much :frowning:

Doug, what was your folder approach?

I am going with a compiler based solution, e.g adding an incrementing numerical suffix and checking the available filenames before [FileExecute,…]'ing in ZBrush.

I would still love to hear how other people test their dynamic libraries.

Hi TVEyes.

First, when I made changes to the lib and recompiled it, I exited ZBrush each time. I think (but I’m not sure at all) that if you switch to another plugin ZBrush closes the lib and so you can replace it, but I never really tested that way so I stayed on the safe side.

And for about how to trace debug info, I did the following : (ZAdjustor needed a huge lot of testing)

  • On OSX, I just used printf() and launched ZB from a command shell window so I could read console output.
  • On windows, I used the command OutputDebugString() then used dbgview to read the traces (it’s a very small freeware that reads the debugging output from running processes. It’s a microsoft sysinternals freeware that you can download here)

And as a bonus, here’s a very useful little trick I use :
I set up a #DEFINE directive so I can easily omit debug code from compilation with a simple switch :

|#IFDEF DEBUGMODE//For OSX :
|
#DEFINE DBGTRACE(…) printf(VA_ARGS);
//For windows (you must of course declare a global var tmpStringA) :
//#DEFINE DBGTRACE(…) sprintf(tmpStringA, VA_ARGS);OutputDebugStringA(tmpStringA);

#ELSE#DEFINE DBGTRACE(…)
#ENDIF
|

So to print your debuginfo you just have to use DBGTRACE(); just like you would use printf()/OutputDebugString() and when you’re debugging you #DEFINE DEBUGMODE so that it gets compiled and when you want a clean release version you don’t define it and it doesn’t even gets included in compilation.

Hope it helps :slight_smile:

Yes, I don’t know of a way to close a dynamic library other than by restarting ZBrush. Switching to a different plugin doesn’t seem to make any difference. If you’re incrementing the target file name then I think that will have to be pre-build as renaming post-build won’t be recognised as different by ZBrush.

Thanks KeuPon. It does not look like any opened dynamic libraries are closed until you close ZBrush. On Mac, if you open the Activity Monitor app you can get info on the ZBrushOSX process and see the currently opened files and ports for that process. Libraries are definitely not closed, many (if not all) Pixologic supplied libraries are also opened upon startup (UVMasterDLL.lib, DecimationMasterDLL.lib, etc.).

Thanks for the debug info. I do it similarly except I use NSLog(); instead as that outputs to the Console.app log.

I worked out a simple automatic filename versioning upon each build from Xcode. By setting an initial Current Project Version in the Versioning section of your projects Build Settings, you can use the agvtool command line executable to increase the Current Project Version. To do that go to your target’s Build Phases section and add a new Run Script. The script itself is simply agvtool next-version. Then go to the Packaging section of your targets Build Settings and change the Product Name to your_product_name$(CURRENT_PROJECT_VERSION). This will give you mylib1.lib, mylib2.lib etc. each time you build. Your zscript then needs to [FileExists,…] check until it does not find mylib3.lib, for example, and then use mylib2.lib.

Bit of a hack but it works.

Thanks Marcus. I don’t have Visual Studio installed right now, do you know if the library destructor gets called on ZBrush for Windows? It is not getting called on Mac.