Implémenter des méthodes pour des versions antérieures de MacOS

ChachaChacha Membre
23:50 modifié dans API AppKit #1
Salut,

Sous MacOS 10.4, la méthode objectsAtIndexes: de NSArray est bien pratique.
Elle n'existe pas sous MacOS 10.3. Elle est facile à  réimplémenter.
Je pourrais faire un wrapper myObjectsAtIndexes: (dans une catégorie de NSArray) qui appelle objectsAtIndexes: sous 10.4 et mon code sous 10.3, mais je trouve ça un peu dommage de devoir utiliser un autre nom.
Y a-t-il moyen de faire en sorte qu'une (re)définition de objectsAtIndexes ne soit "vue" que sous 10.3, sans faire des tests à  chaque appel ? Et que ça compile sans warnings ?

+
Chacha

Réponses

  • schlumschlum Membre
    avril 2007 modifié #2
    MyArray.h (catégorie de NSArray) :

    #if MAC_OS_X_VERSION_MAX_ALLOWED &lt; MAC_OS_X_VERSION_10_4<br />- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes;<br />#endif
    



    MyArray.m :

    #if MAC_OS_X_VERSION_MAX_ALLOWED &lt; MAC_OS_X_VERSION_10_4<br />- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes<br />{<br />    // [...]<br />}<br />#endif
    
  • ChachaChacha Membre
    avril 2007 modifié #3
    Oui, je suis d'accord (http://www.objective-cocoa.org/forum/index.php/topic,1079.0.html). C'est d'ailleurs ce que je fais actuellement. Cependant, je voudrais maintenant non pas résoudre le problème à  la compilation, mais au run-time.
    En effet, mon but est de ne générer qu'un exécutable, compilé avec le MacOSX10.4u.sdk, mais qui fonctionne sous Panther.

    +
    Chacha
  • schlumschlum Membre
    avril 2007 modifié #4
    dans 1176973114:

    Oui, je suis d'accord (http://www.objective-cocoa.org/forum/index.php/topic,1079.0.html. Cependant, je ne veux pas résoudre le problème à  la compilation, mais au run-time !
    En effet, je veux ne générer qu'un exécutable, compilé avec le MacOSX10.4u.sdk, mais qui fonctionne sous Panther.

    +
    Chacha

    ??

    Un exécutable compilé avec "MacOSX10.4u.sdk" n'est pas vraiment fait pour tourner sous Panther... C'est assez hasardeux comme technique
    Si tu veux générer un seul exécutable, c'est compilé avec "MacOSX10.3.9.sdk", ce qui donnera un exécutable PPC qui tournera avec Rosetta sur les Mac Intel

    Une bonne configuration 10.3/10.4 Intel/PPC, c'est :
    SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk
    SDKROOT_ppc = /Developer/SDKs/MacOSX10.3.9.sdk

    Si tu as un seul exécutable, il sera soit PPC, soit Intel, non ??
  • ChachaChacha Membre
    23:50 modifié #5
    dans 1176973371:

    Un exécutable compilé avec "MacOSX10.4u.sdk" n'est pas vraiment fait pour tourner sous Panther...
    C'est assez hasardeux comme technique

    Je pense que ça doit marcher du moment qu'on n'appelle que des méthodes disponibles sous Panther. Apparemment, MacOS 10.3 lit la partie PPC des binaires universels sans problème (c'est ce que j'ai fait pour RubyCalc
    http://www.objective-cocoa.org/forum/index.php/topic,2101.0.html)

    +
    Chacha
  • schlumschlum Membre
    23:50 modifié #6
    dans 1176973901:

    dans 1176973371:

    Un exécutable compilé avec "MacOSX10.4u.sdk" n'est pas vraiment fait pour tourner sous Panther...
    C'est assez hasardeux comme technique

    Je pense que ça doit marcher du moment qu'on n'appelle que des méthodes disponibles sous Panther. Apparemment, MacOS 10.3 lit la partie PPC des binaires universels sans problème (c'est ce que j'ai fait pour RubyCalc
    http://www.objective-cocoa.org/forum/index.php/topic,2101.0.html)

    +
    Chacha


    Oui, mais c'est hasardeux et dangereux...

    De toute manière, si tu as un binaire universel, tu as deux compilation et deux exécutables, donc je ne vois pas l'intérêt de créer la partie PPC avec /Developer/SDKs/MacOSX10.4u.sdk au lieu de la créer avec /Developer/SDKs/MacOSX10.3.9.sdk  ???
  • schlumschlum Membre
    23:50 modifié #7
    dans 1176974023:

    Oui, mais c'est hasardeux et dangereux...


    Je vais expliciter plus...

    Là , tu penses ne pas utiliser des fonctions "10.4", mais il est possible que certaines fonctions du SDK 10.3.9 aient été mises à  jour dans le SDK 10.4u en appelant des fonctions 10.4u tout en gardant le même nom.
    Que se passe-il dans ces cas là  ?

    Utiliser le SDK 10.3.9 permet justement de garder une cohérence tout le long et d'éviter ça !
  • ChachaChacha Membre
    23:50 modifié #8
    dans 1176974023:

    Oui, mais c'est hasardeux et dangereux...

    Qu'est-ce qui risque de se passer ?
    [grillé]


    De toute manière, si tu as un binaire universel, tu as deux compilation et deux exécutables, donc je ne vois pas l'intérêt de créer la partie PPC avec /Developer/SDKs/MacOSX10.4u.sdk au lieu de la créer avec /Developer/SDKs/MacOSX10.3.9.sdk  ???

    Si je compile avec le 10.3.9.sdk, le code PPC peut-il bénéficier des méthodes de l'AppKit 10.4 ?
  • schlumschlum Membre
    avril 2007 modifié #9
    dans 1176974371:


    De toute manière, si tu as un binaire universel, tu as deux compilation et deux exécutables, donc je ne vois pas l'intérêt de créer la partie PPC avec /Developer/SDKs/MacOSX10.4u.sdk au lieu de la créer avec /Developer/SDKs/MacOSX10.3.9.sdk  ???

    Si je compile avec le 10.3.9.sdk, le code PPC peut-il bénéficier des méthodes de l'AppKit 10.4 ?


    C'est là  que ça devient complexe...  :crackboom:-
    À priori... non. Après, il y a peut-être moyen de bidouiller, mais à  mon avis c'est grosse prise de tête !

    En général, les développeurs qui veulent faire profiter des nouveautés à  leur application maintiennent deux versions (voire plus).

    (en agrémentant le code source de quelques #if et en créant plusieurs "targets")
  • ChachaChacha Membre
    23:50 modifié #10
    dans 1176974851:

    En général, les développeurs qui veulent faire profiter des nouveautés à  leur application maintiennent deux versions (voire plus).

    Ben alors c'est pas aujourd'hui que je vais unifier LaTeXiT ! Bah, tant pis.

    Merci quand même

    +
    Chacha
  • avril 2007 modifié #11
    Hasardeux et dangereux, tu peux avancer des docs qui le montrent?

    À ce qu'il me semble Mach-O est prévu (depuis OpenStep) pour contenir des exécutables pour plusieurs platteformes différentes (OpenStep tournait sur i386, 68k, sparc, dec-alpha et j'en passe). La possibilité a donc toujours existé sous OS X, mais n'a pas été "dévoilée" parce que OS X ne tournait jusqu'il y a peu que sur une platteforme. Maintenant, lorsqu'on fait un UB on fait 2 compils différentes, donc je ne vois pas où est le souci d'en faire une pour 10.3/ppc et une pour 10.4/intel (je ne vois pas d'autre solution "propre"). C'est en tous cas ce qui est suggéré ici:
    http://www.zengobi.com/blog/2006/03/details-on-our-universal-binary-port.html

    Mais l'inconvénient de cette méthode est que les 10.4/ppc ne peuvent pas "profiter" de l'implémentation Apple des méthodes que tu as réimplémenté. Il te faut ensuite faire des "lazy bindings" des framework qui ont été ajoutés dans Tiger, les charger à  la volée et faire des tests au run time pour que les 10.4/ppc puissent profiter des nouveautés de 10.4.
  • schlumschlum Membre
    23:50 modifié #12
    dans 1176975152:

    Hasardeux et dangereux, tu peux avancer des docs qui le montrent?

    À ce qu'il me semble Mach-O est prévu (depuis OpenStep) pour contenir des exécutables pour plusieurs platteformes différentes (OpenStep tournait sur i386, 68k, sparc, dec-alpha et j'en passe). La possibilité a donc toujours existé sous OS X, mais n'a pas été "dévoilée" parce que OS X ne tournait jusqu'il y a peu que sur une platteforme. Maintenant, lorsqu'on fait un UB on fait 2 compils différentes, donc je ne vois pas où est le souci d'en faire une pour 10.3/ppc et une pour 10.4/intel (je ne vois pas d'autre solution "propre"). C'est en tous cas ce qui est suggéré ici:
    http://www.zengobi.com/blog/2006/03/details-on-our-universal-binary-port.html



    Oui da, c'est exactement ce que j'ai dit  ;)
    Pas plus, pas moins...

    Ce qui est dangereux, c'est de laisser 10.3 taper dans du code PPC généré avec le SDK 10.4u, donc un tout autre sujet !
    (ça contient des exécutables pour plusieurs "plates-formes" différentes, mais pas pour plusieurs "OS" différents !)
  • schlumschlum Membre
    avril 2007 modifié #13
    dans 1176975152:

    Mais l'inconvénient de cette méthode est que les 10.4/ppc ne peuvent pas "profiter" de l'implémentation Apple des méthodes que tu as réimplémenté.


    D'où l'intérêt de maintenir éventuellement des versions avec des fonctionnalités ajoutées venant des SDK récents avec une "target" spéciale 10.4 par exemple...
    (par contre, il faut barder le code de #if au niveau de ces fonctionnalités supplémentaires...)
  • schlumschlum Membre
    avril 2007 modifié #14
    dans 1176974289:

    dans 1176974023:

    Oui, mais c'est hasardeux et dangereux...


    Je vais expliciter plus...

    Là , tu penses ne pas utiliser des fonctions "10.4", mais il est possible que certaines fonctions du SDK 10.3.9 aient été mises à  jour dans le SDK 10.4u en appelant des fonctions 10.4u tout en gardant le même nom.
    Que se passe-il dans ces cas là  ?

    Utiliser le SDK 10.3.9 permet justement de garder une cohérence tout le long et d'éviter ça !


    En y réfléchissant plus, en faisant super-attention, ça devrait pouvoir fonctionner car il appellera ces fonctions sur le code Framework de la machine, donc pas de risque qu'il tape dans une fonction mise à  jour.
    À voir... Un peu hasardeux quand même je pense.

    À voir déjà  si 10.3 accepte sans sourciller un code compilé avec le SDK 10.4u
  • Eddy58Eddy58 Membre
    23:50 modifié #15
    dans 1176976819:

    En y réfléchissant plus, en faisant super-attention, ça devrait pouvoir fonctionner car il appellera ces fonctions sur le code Framework de la machine, donc pas de risque qu'il tape dans une fonction mise à  jour.
    À voir... Un peu hasardeux quand même je pense.

    À voir déjà  si 10.3 accepte sans sourciller un code compilé avec le SDK 10.4u


    Oui, j'ai fais ainsi pour mon GPB et ça fonctionne très bien, il se porte comme un charme sur les deux versions. :)
  • schlumschlum Membre
    23:50 modifié #16
    OK, donc on en revient à  la question de départ pour gérer ça dans le run-time...

    Peut-être en sous-classant NSArray, en redéfinissant "objectsAtIndexes" de manière à  appeler la classe mère sous 10.4 et l'implémenter sous 10.3, puis utiliser "poseAsClass"...
  • BruBru Membre
    23:50 modifié #17
    M'ouais...

    En fait, je pense à  une autre méthode qui mélange la fonction sel_registerName et le method swizzling...

    Premièrement, via une catégorie, faut créer une méthode simulant la méthode manquante (mais avec un autre nom) : par exemple objectsAtIndexes_10_3:.

    Secondo, au tout début du programme (soit dans le main, soit dans un delegate de fin de chargement de NSApplication), il faut tester la présence de la méthode objectsAtIndexes:, et si elle n'existe pas, alors faire un sel_registerName("objectsAtIndexes:");.

    Enfin via le truc du method swizzling de Chacha (voir ce post), récupérer le pointeur de la méthode objectsAtIndexes_10_3: pour l'injecter dans la méthode créée par sel_registerName.

    Bon, ce n'est que de la théorie, mais ça vaut le coup d'essayer.

    .
  • laurrislaurris Membre
    23:50 modifié #18
    Ca devient franchement intéressant ce fil !
    J'attends avec impatience les conclusions. Au passage, je signale que le poseAsClass: marche bien et devrait marcher dans ce cas. La seule limitation est qu'on ne peut pas ajouter d'ivar dans la classe de substitution.

    Quand on aura trouvé comment rétro-implémenter une méthode , on pourra alors essayer de le faire mais pour une classe entière. Je me casse les octets  depuis des semaines en essayant de ré-implémenter NSPredicate pour 10.3, sans succes. Alors je pose une option dès à  présent sur ce problème, sachant que la solution devrait découler de celle au problème de ce fil.

  • BruBru Membre
    avril 2007 modifié #19
    A tête reposée et sur mon mac, voici une solution :
    <br />#import &lt;/usr/include/objc/objc-class.h&gt;<br /><br />int main(int argc, char *argv&#91;])<br />{<br />&nbsp; &nbsp; NSAutoreleasePool *pool;<br />&nbsp; &nbsp; Method mth;<br /><br />&nbsp; &nbsp; // création d&#39;un autorelasepool au cas où...<br />&nbsp; &nbsp; pool=[[NSAutoreleasePool alloc] init];<br /><br />&nbsp; &nbsp; // test si la méthode n&#39;est pas implémentée<br />&nbsp; &nbsp; if (![NSArray instancesRespondToSelector:@selector(objectsAtIndexes:)])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // récupération de la structure Method de la méthode de ré-implantation de la méthode manquante<br />&nbsp; &nbsp; &nbsp; &nbsp; mth=class_getInstanceMethod([NSArray class], @selector(objectsAtIndexes_10_3:));<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; // on &quot;remplace&quot; le nom de cette méthode de ré-implantion par la méthode manquante<br />&nbsp; &nbsp; &nbsp; &nbsp; mth-&gt;method_name=sel_registerName(&quot;objectsAtIndexes:&quot;);<br />&nbsp; &nbsp; }<br /><br />&nbsp; &nbsp; // nettoyage<br />&nbsp; &nbsp; [p release];<br /><br />&nbsp; &nbsp; // appel de NSApplication<br />&nbsp; &nbsp; return NSApplicationMain(argc,&nbsp; (const char **) argv);<br />}<br />
    


    objectsAtIndexes_10_3: est la méthode de remplacement de objectsAtIndexes:. Elle doit être définie dans une catégorie de NSArray. Bien sûr, la méthode remplaçante doit avoir exactement la même signature que la méthode à  ré-implanter.

    Voilà , en fait c'est plus simple que je le pensais.
    Vraiment, le runtime de ObjC est incroyablement flexible !

    .
  • MalaMala Membre, Modérateur
    23:50 modifié #20
    dans 1177010645:

    Vraiment, le runtime de ObjC est incroyablement flexible !


    Cela m'amène une question. Cette souplesse n'est-elle pas potentiellement dangereuse niveau sécurité?
  • schlumschlum Membre
    23:50 modifié #21
    dans 1177024124:

    dans 1177010645:

    Vraiment, le runtime de ObjC est incroyablement flexible !


    Cela m'amène une question. Cette souplesse n'est-elle pas potentiellement dangereuse niveau sécurité?


    À priori pas... Les droits sont bien cloisonnés dans un système basé "Unix".
  • ChachaChacha Membre
    23:50 modifié #22
    dans 1177010645:

    objectsAtIndexes_10_3: est la méthode de remplacement de objectsAtIndexes:.


    Salut,
    Effectivement, même si j'avais pensé sortir le swizzle, je n'avais pas vraiment trouvé comment m'en servir. Ta solution est intéressante !
    Merci

    +
    Chacha
Connectez-vous ou Inscrivez-vous pour répondre.