Hi Andreas,

thanks again for trying to help. I really appreciate it!

Find feedback inlined.

Best,
Andreas

Am 15.10.21 um 17:56 schrieb Andreas Fink:
> i have done precompiled libraries for debian10 and 11 and they work fine
> for me.
Just to avoid misunderstandings: I do _not_ have a general issue using 
pre-compiled static libs. Its only about Objective-C Categories that 
cause issues.

The behaviour is expected when linking a static lib containing 
Categories without the `-ObjC` linker flag.

 From theApple Docs <#Objective-C,,The dynamic nature of Objective-C 
complicates things slightly. Because the code that implements a method 
is not determined until the method is actually called, Objective-C does 
not define linker symbols for methods. Linker symbols are only defined 
for classes.,,For example, if main.m includes the code [[FooClass alloc] 
initWithBar:nil]; then main.o will contain an undefined symbol for 
FooClass, but no linker symbols for the -initWithBar: method will be in 
main.o.,,Since categories are a collection of methods, using a 
category's method does not generate an undefined symbol. This means the 
linker does not know to load an object file defining the category, if 
the class itself is already defined. This causes the same "selector not 
recognized" runtime exception you would see for any unimplemented 
method.,,#The -ObjC Linker Flag,,Passing the -ObjC option to the linker 
causes it to load all members of static libraries that implement any 
Objective-C class or category. This will pickup any category method 
implementations. But it can make the resulting executable larger, and 
may pickup unnecessary objects. For this reason it is not on by default>:
"
# Objective-C

The dynamic nature of Objective-C complicates things slightly. Because 
the code that implements a method is not determined until the method is 
actually called, Objective-C does not define linker symbols for methods. 
Linker symbols are only defined for classes.

For example, if main.m includes the code [[FooClass alloc] 
initWithBar:nil]; then main.o will contain an undefined symbol for 
FooClass, but no linker symbols for the -initWithBar: method will be in 
main.o.

Since categories are a collection of methods, using a category's method 
does not generate an undefined symbol. This means the linker does not 
know to load an object file defining the category, if the class itself 
is already defined. This causes the same "selector not recognized" 
runtime exception you would see for any unimplemented method.

# The -ObjC Linker Flag

Passing the -ObjC option to the linker causes it to load all members of 
static libraries that implement any Objective-C class or category. This 
will pickup any category method implementations. But it can make the 
resulting executable larger, and may pickup unnecessary objects. For 
this reason it is not on by default
"
The problem seems to be that the `-ObjC` flag is used by the compiler 
(who doesn't know and thus ignores it) instead of the linker using the 
GNUstep make system.

I have created a simple project to reproduce, showing the issue, taking 
your advice into account.

*## HowTo Reproduce*

```
# clone
git clone 
http://pep-security.lu/gitlab/andreas/category-linking-problem-sample.git

# build
cd category-linking-problem-sample
sh build.sh
# note: compiler output "clang: warning: argument unused during 
compilation: '-ObjC' [-Wunused-command-line-argument]"

# run
./obj/LinkFailSample
```

*Expected:*

Console output is
```
myDebugPrint
myDebugPrintCategory
```

*Actual:*
Console output is
```
myDebugPrint
./obj/LinkFailSample: Uncaught exception NSInvalidArgumentException, 
reason: MyClass(instance) does not recognize myDebugPrintCategory
```

*Additional Info:*

`nm` shows the Category _is_ contained in the lib:

```
nm static-lib/obj/libmyLib.a | grep myDebugPrint
0000000000000000 t _i_MyClass__myDebugPrint
0000000000000000 V .objc_selector_myDebugPrint_v160:8
0000000000000000 V .objc_sel_name_myDebugPrint
0000000000000000 V .objc_str_myDebugPrint
0000000000000000 t _i_MyClass_Extension_myDebugPrintCategory #HERE
0000000000000000 V .objc_selector_myDebugPrintCategory_v160:8
0000000000000000 V .objc_sel_name_myDebugPrintCategory
0000000000000000 V .objc_str_myDebugPrintCategory
```

`nm` shows it's _not_ in the excecutable:

```
nm obj/LinkFailSample | grep myDebugPrint
0000000000400b40 t _i_MyClass__myDebugPrint
0000000000403220 d .objc_selector_myDebugPrintCategory_v160:8
0000000000403210 d .objc_selector_myDebugPrint_v160:8
0000000000400bf0 r .objc_sel_name_myDebugPrint
0000000000400c10 r .objc_sel_name_myDebugPrintCategory
0000000000403330 d .objc_str_myDebugPrint
```


Attachment: sender_key.asc
Description: application/pgp-keys

Reply via email to