Categories and "selector not recognized" error

40 views
Skip to first unread message

tre...@austin.rr.com

unread,
Apr 21, 2012, 12:25:08 PM4/21/12
to Cocotron Developers
I have a working application on OSX that I have Cocotron-ified into a
Windows .exe, along with the DLLs for foundation and cocoa.

When I run the exe on Win7, I get errors of the form:
*** Uncaught exception <NSInvalidArgumentException> *** -
[NSMutableDictionary_CF bindSymbol:toValue:]: selector not recognized

bindSymbol:toValue: is a category method added to NSMutableDictionary.

Any clues as to where to look for what might be amiss, resulting in
different behavior from the Mac version? I searched the forum but
didn't find anything specific.

(Yes I probably need to enable the debug session etc, but I'm not sure
that would help in this case?)

Thanks!
Trenton

Christopher Lloyd

unread,
Apr 21, 2012, 9:12:40 PM4/21/12
to cocotr...@googlegroups.com
So I am going to assume this category method is in one of your own DLL's which the application depends on. If this is the case...

On Windows, if there are no hard dependencies to a DLL it won't get loaded, this would cause the category and its methods to not be in the runtime. 

To fix this, just create at least one hard dependency between your .exe (or another dll) and the .dll where the category exists, the easiest way to do this is to make an unused function or constant and reference it somewhere. 

This is typically not a problem because there are enough hard dependencies between exe's and dll's to force a load, but there are cases where this breaks down (e.g. only dynamically finding classes in a particular DLL). 

Historical note: the YellowBox build system would fabricate these hard dependencies for you, we don't do that in Cocotron (just due to limited engineering time and the reasonable workarounds).

Chris

tre...@austin.rr.com

unread,
Apr 22, 2012, 9:59:03 AM4/22/12
to Cocotron Developers
Hmmm... Its a command line app, and all of my code is just complied
and linked in. I have no frameworks of my own, and so I imagine, no
need of any DLL's of my own. Its possible I misunderstood what needed
doing, of course. But all of my classes and categories are compiled
directly into the application. Perhaps some aspect of it being a
command line tool rather than an actual app? But I'm just guessing; I
need to dig deeper when I get back to the office.
Thanks,
Trenton

Christopher Lloyd

unread,
Apr 22, 2012, 11:07:12 AM4/22/12
to cocotr...@googlegroups.com
Ok, are you doing    NSInitializeProcess(argc,argv); immediately after main(){ ? The runtime may not be fully initialized, particularly with code in your tool.

Chris

tre...@austin.rr.com

unread,
Apr 22, 2012, 12:21:21 PM4/22/12
to Cocotron Developers
Aha. No, I'm not calling that... I will give it a try tomorrow when
I get to the office.
Thanks!
-Trenton

tre...@austin.rr.com

unread,
Apr 23, 2012, 10:14:17 PM4/23/12
to Cocotron Developers
Thanks for the help on this. Having poked at this for a few hours off
and on as time allowed, I finally made time to sit down and work
through it. I did, in fact, get it to work. So I now have a command
line tool using foundation and cocoa building for both MacOS and
Windows.

I have attempted, on several occasions, over the past year or so, to
accomplish this using an alternative development environment, but was
never able to achieve any real success. With Cocotron, I managed it
in what amounts to about 3 full days work, if I added it all up,
including reading the documentation. So, I am quite impressed and
have high regard for Cocotron. I intend to continue working with it,
and hope to become competent to contribute at some point.

For posterity, here are a few things I encountered during my
adventures today. My command line tool uses foundation and cocoa
only, and and I build for OSX with CLANG/LLVM and for Windows with
Cocotron's GCC et al.

(1) build option: Executable Extension .exe appears to have no
effect.

Setting the product name to myapp.exe yields an executable.

(2) Running retargetBundle without removing all frameworks from the
destination folder resutls in this error:

2012-04-23 08:35:27.532 retargetBundle[28472:707] no attributes at
path /Developer/Cocotron/1.0/Windows/i386/Frameworks/
Foundation.framework/Developer/Cocotron/1.0/Windows/i386/Frameworks/
Foundation.framework
Command /bin/sh failed with exit code 255

Removing the frameworks from the final output location and rebuilding
works fine.

(3) Building Cocoa-Windows-i386 fails trying to build Foundation-
Darwin-x86_64 with a dependency issue. This problem first appeared as
a failure to build Foundation-FreeBSD-i386. I somehow changed
something trying to explore the issue, and the report changed to
Darwin, from FreeBSD. In any case, its not clear why it wanted to
build all of this when I chose Cocoa-Windows-i386.

I just ignored the error and carried onwards through the fog.

(4) Is there some symbol that can be checked at compile time to
determine the target? Something similar to __GNUC__, __APPLE_CPP__,
__APPLE_CC__, etc either to detect Cocotron or a Windows build?

I temporarily fabricated __COCOTRON_WINDOWS__ for my various
experiments.

(5) Always Search User Paths does not seem to have the same effect as
when using CLANG etc. Normaly setting this results in the sub folders
of the project being searched for inclusions recursively.

For Cocotron builds I found it "necessary" to specify the project
subdirectories explicitly.

(6) [[NSFileManager defaultManager] removeItemAtPath: path error:
&error]; always seemed to fail at runtime on Windows. But this was an
illusion. It turns out that removeItemAtPath:error: behaves
differently on OSX and Windows. On OSX, if you (admittedly foolishly)
remove a file that has an open handle, it succeeds.

I am guessing, but have not done due diligence, that at the bottom
level of file deletion lies unlink().  If one or more processes have
the file open when the link count decrements to zero then the link is
removed but the actual removal of the file is delayed until all
references have been removed. Hypothesizing further, what likely
happens is that removeItemAtPath: decrements the link to zero, returns
YES, and then new version of the file (the purpose of the removal is
to replace the file with an updated version.) is created as a
different inode even though it has the same name as the unlinked
file.  The unlinked file goes away when the file is closed eventually
by the app. So the potential error of deleting an open file is
arguably non obvious. (But again, I'm guessing.).

On Windows DeleteFileW() apparently won't delete the file if there is
an open handle.  This is a different behavior than OSX it seems. I
don't know if/how that works across processes or CPUs, but at least
within the threads of a single process it seems to be able to do it
and I suppose it manages to avoid the obvious race conditions. In any
case, that bit me.

The solution was of course not to delete the files while I still had
them open (duh).

(7) For the following "not implemented?" items, I was getting runtime
exceptions for "invalid selector" or similar. I don't know if they
are not implemented, or if I am just doing something silly still.
Some had "many not respond to" warnings when compiled.

[[NSProcessInfo processInfo] operatingSystemName] not
implemented? ...I decided I didn't need it.

[[NSProcessInfo processInfo] operatingSystemVersionString] not
implemented? ...I decided I didn't need it.

(9) [NSString stringByExpandingTildePath:] not implemented? ..I
avoided tildes and didn't use it. This was in a category on NSString,
so my erstwhile issues with categories could be involved.

(10) [NSURL fileURLWithPath: path isDirectory: NO]; not
implemented? ...I avoided it for now.

(11) [[NSFileManager defaultManager] removeItemAtURL: url error:
&error]; not implemented? ...I avoided it for now.

(12) [NSString stringByAppendingPathComponent: cmp]; uses / on Windows
instead of \ although it seems benign. ...I ignored it since it
wasn't bothering me.

(13) My original issue of category methods not being found on
NSMutableDictionary was actually a red herring of sorts. My subclass
of NSMutableDictionary, which wraps an NSMutableDictionary and an
NSMutableArray, so as to maintain the keys in a specific order, was
broken in a non obvious (ok, embarrassing) way. I resolved the issue
by making it be a subclass of NSObject, not NSMutableDictionary, and
implmented a handfull of missing methods to resolve the resulting
build issues. After that, things began to work as expected and the
rest of this fell into place.

Anyhow, that's all the more I have at the moment.
Cheers,
Trenton

Christopher Lloyd

unread,
Apr 24, 2012, 10:16:56 AM4/24/12
to cocotr...@googlegroups.com

On Monday, April 23, 2012 10:14:17 PM UTC-4, tre...@austin.rr.com wrote:
Thanks for the help on this.  Having poked at this for a few hours off
and on as time allowed, I finally made time to sit down and work
through it.  I did, in fact, get it to work.  So I now have a command
line tool using foundation and cocoa building for both MacOS and
Windows.

Great!
 
I have attempted, on several occasions, over the past year or so, to
accomplish this using an alternative development environment, but was
never able to achieve any real success.  With Cocotron, I managed it
in what amounts to about 3 full days work, if I added it all up,
including reading the documentation.  So, I am quite impressed and
have high regard for Cocotron.  I intend to continue working with it,
and hope to become competent to contribute at some point.

:) Sounds great.
 
For posterity, here are a few things I encountered during my
adventures today.  My command line tool uses foundation and cocoa
only, and and I build for OSX with CLANG/LLVM and for Windows with
Cocotron's GCC et al.

(1) build option: Executable Extension .exe appears to have no
effect.

Hrm, the variable name for the build setting is EXECUTABLE_SUFFIX  I haven't had any problems with this.
 
Setting the product name to myapp.exe yields an executable.

(2) Running retargetBundle without removing all frameworks from the
destination folder resutls in this error:

2012-04-23 08:35:27.532 retargetBundle[28472:707] no attributes at
path /Developer/Cocotron/1.0/Windows/i386/Frameworks/
Foundation.framework/Developer/Cocotron/1.0/Windows/i386/Frameworks/
Foundation.framework
Command /bin/sh failed with exit code 255

Removing the frameworks from the final output location and rebuilding
works fine.

Yea, this does happen sometimes and clears with a fresh rebuild. I think it's a problem with retargetBundle copying symlinks improperly.

 
(3) Building Cocoa-Windows-i386 fails trying to build Foundation-
Darwin-x86_64 with a dependency issue.  This problem first appeared as
a failure to build Foundation-FreeBSD-i386.  I somehow changed
something trying to explore the issue, and the report changed to
Darwin, from FreeBSD.  In any case, its not clear why it wanted to
build all of this when I chose Cocoa-Windows-i386.

I just ignored the error and carried onwards through the fog.
 
 
Yea, Xcode 4's fault here. 4 introduced a new feature on the schemes, under Build there is a check "Find Implicit Dependencies", which is always on by default and causes this problem. If you turn that off it won't do this.

Solution is to set up some public schemes people can use by default, I have some in there but I see I don't have one for Foundation. 

(4) Is there some symbol that can be checked at compile time to
determine the target?  Something similar to __GNUC__, __APPLE_CPP__,
__APPLE_CC__, etc either to detect Cocotron or a Windows build?

I temporarily fabricated __COCOTRON_WINDOWS__ for my various
experiments.

Yes, __COCOTRON__ is defined if you build from Xcode.
 
(5) Always Search User Paths does not seem to have the same effect as
when using CLANG etc.  Normaly setting this results in the sub folders
of the project being searched for inclusions recursively.

For Cocotron builds I found it "necessary" to specify the project
subdirectories explicitly.

Yea, Apple's compiler supports Header Maps which Xcode generates, this is a list of all the .h locations in a project. Solution is as you point out, to manually -I all your directories. This will probably be fixed with the switch to clang.
Yea, I think this is just a basic difference between Windows and Unix. It should probably be looked at though, there may be API to force a delete.


(7) For the following "not implemented?" items, I was getting runtime
exceptions for "invalid selector" or similar.  I don't know if they
are not implemented, or if I am just doing something silly still.
Some had "many not respond to" warnings when compiled.

[[NSProcessInfo processInfo] operatingSystemName] not
implemented?  ...I decided I didn't need it.

[[NSProcessInfo processInfo] operatingSystemVersionString] not
implemented?  ...I decided I didn't need it.

We can add these. 

(9) [NSString stringByExpandingTildePath:] not implemented?  ..I
avoided tildes and didn't use it.  This was in a category on NSString,
so my erstwhile issues with categories could be involved.

Hrm, this should work.
 

(10) [NSURL fileURLWithPath: path isDirectory: NO]; not
implemented?  ...I avoided it for now.

(11) [[NSFileManager defaultManager] removeItemAtURL: url error:
&error]; not implemented?  ...I avoided it for now.


We can add these.
 
(12) [NSString stringByAppendingPathComponent: cmp]; uses / on Windows
instead of \ although it seems benign.  ...I ignored it since it
wasn't bothering me.

Yea, in general paths should use "/" internally and then formatted for display with a \. The reasons are largely treatment of paths with NSURL.
 

(13) My original issue of category methods not being found on
NSMutableDictionary was actually a red herring of sorts.  My subclass
of NSMutableDictionary, which wraps an NSMutableDictionary and an
NSMutableArray, so as to maintain the keys in a specific order, was
broken in a non obvious (ok, embarrassing) way.  I resolved the issue
by making it be a subclass of NSObject, not NSMutableDictionary, and
implmented a handfull of missing methods to resolve the resulting
build issues.  After that, things began to work as expected and the
rest of this fell into place.

Great!
Reply all
Reply to author
Forward
0 new messages