IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Erreur liaison projet C++ CMake


Sujet :

C++

  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 108
    Points : 143
    Points
    143
    Par défaut Erreur liaison projet C++ CMake
    Bonjour,

    J'ai réussi à configurer mon projet CMake mais j'ai cette erreur lors de l'édition des liens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /usr/bin/ld*: CMakeFiles/testKrpnCore.dir/src/TestKrpnCore.cpp.o*: dans la fonction «*TestKrpnCore::TestKrpnCore()*»*:
    TestKrpnCore.cpp:(.text+0x24)*: référence indéfinie vers «*vtable for TestKrpnCore*»
    /usr/bin/ld*: CMakeFiles/testKrpnCore.dir/src/TestKrpnCore.cpp.o*: dans la fonction «*TestKrpnCore::~TestKrpnCore()*»*:
    TestKrpnCore.cpp:(.text+0x49)*: référence indéfinie vers «*vtable for TestKrpnCore*»
    collect2: error: ld returned 1 exit status
    make[2]: *** [tests/KrpnCore/CMakeFiles/testKrpnCore.dir/build.make:102 : tests/KrpnCore/testKrpnCore] Erreur 1
    make[1]: *** [CMakeFiles/Makefile2:199 : tests/KrpnCore/CMakeFiles/testKrpnCore.dir/all] Erreur 2
    make: *** [Makefile:84 : all] Erreur 2

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Sans info supplémentaire, il va nous être difficile de savoir ce qui ne va pas.

    Tout ce que l'on peut dire à l'heure actuelle, c'est que ld (l'éditeur de liens) se plaint de ne pas trouver la "vtable" (la table des fonctions virtuelles) pour ta classe TestKrpnCore.

    Le plus souvent, c'est du à une fonction déclarée comme virtuelle (voire, virtuelle pure, dans une classe parent) qui n'aurait pas été définie (ou redéfinie dans une classe dérivée).

    Cela nous aiderait beaucoup si tu pouvais nous fournir le code
    1. du fichier d'en-tête dans lequel la classe TestKrpnCore est définie
    2. du fichier src/TestKrpnCore.cpp
    3. du fichier CMakeLists.txt (ou de tout fichier utilisé par CMake) qui prend en charge la compilation du fichier en (2)
    4. (si d'application) du fichier d'en-tête de la classe parent de ta classe TestKrpnCore

    A partir de là, nous devrions commencer à pouvoir travailler, et nous aurions une chance de trouver ce qui ne va pas

    MORALITE : lorsque l'on s'adresse à un forum pour obtenir de l'aide dans la résolution d'un problème, il est très important de garder en tête qu'il faut "aider les gens à nous aider", en leur fournissant tous les renseignements susceptibles de les mettre sur la piste de la solution
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 108
    Points : 143
    Points
    143
    Par défaut
    Voici les fichiers:


    TestKrpnCore.h:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    #ifndef TESTKRPNCORE_H
    #define TESTKRPNCORE_H
     
    #include "KrpnCore.h"
     
    #include <QtTest>
    #include <QObject>
     
    class TestKrpnCore : public QObject
    {
        Q_OBJECT
    public:
     
        TestKrpnCore();
     
        virtual ~TestKrpnCore();
     
    private slots:
     
        void testFoo() {
            QVERIFY(1 == 1);
        }
    };
     
    #endif // TESTKRPNCORE_H
    TestKrpnCore.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "TestKrpnCore.h"
     
    TestKrpnCore::TestKrpnCore()
    {
     
    }
     
    TestKrpnCore::~TestKrpnCore()
    {
     
    }

    Le fichier CMakeLists.txt:
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    cmake_minimum_required(VERSION 3.1)
     
    project(TestKrpnCore)
     
    if (NOT TARGET KrpnCore)
        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/KrpnCore ${CMAKE_CURRENT_BINARY_DIR}/lib/KrpnCore)
    endif()
     
    set(CMAKE_CXX_STANDARD 11)
     
    set(SRCS
        src/TestKrpnCore.cpp
        src/main.cpp
        )
     
    set(HEADERS
        include/TestKrpnCore.h
        )
     
    include_directories(include)
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/KrpnCore/include)
     
    find_package(Qt5Test REQUIRED)
     
    add_executable(testKrpnCore ${SRCS} ${HEADERS})
     
    target_link_libraries(testKrpnCore KrpnCore Qt5::Test)
    add_test(NAME testKrpnCore COMMAND testKrpnCore)

  4. #4
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 108
    Points : 143
    Points
    143
    Par défaut
    Problème résolu,
    j'ai changer le CMakeLists.txt et ça marche.

    Le nouveau CMakeLists.txt:
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    32
    33
    34
    35
    36
    cmake_minimum_required(VERSION 3.1)
     
    project(TestKrpnCore)
     
    if (NOT TARGET KrpnCore)
        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/KrpnCore ${CMAKE_CURRENT_BINARY_DIR}/lib/KrpnCore)
    endif()
     
    set(SRCS
        src/TestKrpnCore.cpp
        src/main.cpp
        )
     
    set(HEADERS
        include/TestKrpnCore.h
        )
     
    include_directories(include)
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/KrpnCore/include)
     
    find_package(Qt5Test REQUIRED)
     
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
     
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
     
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    enable_testing()
     
    add_executable(testKrpnCore ${SRCS} ${HEADERS})
     
    target_link_libraries(testKrpnCore KrpnCore Qt5::Test)
    add_test(NAME testKrpnCore COMMAND testKrpnCore)

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Euhh... j'ai l'impression que tu t'es un peu vautré dans l'organisation de ton projet, car la ligne add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/KrpnCore ${CMAKE_CURRENT_BINARY_DIR}/lib/KrpnCore) n'a pas vraiment beaucoup de sens, surtout qu'elle est suivie par l'ensemble des commandes qui permettent effectivement de générer les tests unitaires (si je comprend bien ton code).

    Si je comprend bien, tu essaye de suivre les indications que je t'ai données dans une autre discussion, à avoir, une organisation (partielle) proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    -<ROOT>     # dossier racine du projet
    |    - lib
    |    |    - KrpnCore                     
    |    |    |    - include                  
    |    |    |     |     -KrpnCore.h
    |    |    |    - src                 
    |    |    |    |    - KrpnCore.cpp
    |    - tests 
    |    |    - testKrpnCore 
    |    |    |    - include    
    |    |    |     |     - TestKrpnCore.h
    |    |    |    - src         
    |    |    |    |    - TestKrpnCore.cpp
    tu devrais donc avoir, en théorie, un fichier CMakeLists.txt :
    • dans le dossier <root>
    • dans le dossier <root>/lib
    • dans le dossier <root>/lib/KrpnCore
    • dans le dossier <root>/tests
    • dans le dossier <root>/tests/testKrpncore

    Et chaque fichier devrait avoir deux objectifs, à savoir:
    1. rester aussi simple que possible
    2. ne fournir que le stricte nécessaire pour que "les suivants" (ceux qui se trouvent dans les sous dossiers) puissent fonctionner correctement et qu'ils puissent respecter le (1)

    Voici donc à quoi il devraient ressembler, selon moi:
    <root>/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    32
    33
    34
    35
    36
    # NOTA: étant donné la version actuelle de cmake,
    # on peut décemment considérer une version 3.8 ou supérieure comme le 
    # "minimum requis" (on pourrait même monter à 3.12 :D )
    # ce qui nous évite d'avoir un test de version supplémentaire plus loin
    cmake_minimum_required(VERSION 3.8)
     
    # parce qu'il faut déclarer un projet pour que certaines vérifications soient faites
    project(KrpnAll VERSION 1.0.0.0 LANGUAGES CXX)
    # le standard de C++ à utiliser
    # NOTA: sauf erreur de ma part, Qt 6.0 demande même le support de C++17
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF)
     
    # quelque valeurs spécifiiques à l'utilisation de Qt
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    set(CMAKE_AUTOUIC ON)
     
    # on aura -- au moins -- besoin de QtWidget ;)
    find_package(Qt5 COMPONENTS Widgets REQUIRED)
     
    # on veut compiler ce qui se trouve dans le dossier lib
    add_subdirectory(lib)
     
    # on laisse le choix de compiler (ou non) ce qui se trouve dans le dossier tests
    option(BUILD_TESTS "Should we build the unit tests?" ON)
    # l'ajout du sous dossier tests ne se fera que si on décide ... de compiler son contenu
    if(BUILD_TESTS)
        add_subdirectory(tests)
    endif()
    # pareil pour ce qui se trouve dans le dossier apps
    option(BUILD_APPS "Should we build the applications ?" OFF)
    if(BUILD_APPS)
        add_subdirectory(apps)
    endif()
    Comme tu peux le voir, même s'il contient déjà pas mal d'informations, il reste ** relativement ** minimaliste en ne contenant que le stricte nécessaire pour permettre "aux autres" de rester eux aussi minimalistes

    Le CMakeLists.txt que l'on trouve dans le dossier lib sera encore plus minimaliste, car il se contentera de faire le lien avec ses sous dossiers, et il ressemblera donc à quelque chose comme
    <root>/lib/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    add_subdirectory(KrpnCore)
    (NOTA: on pourrait s'amuser de plein de manière différentes pour gérer l'augmentation des bibliothèques, mais, ici, cela nous suffit amplement )

    Cela nous amène, tout naturellement, à parler du CMakeLists.txt que l'on trouve dans le dossier <root>/lib/KrpnCore, qui va ressembler à quelque chose comme
    <root>/lib/KrpnCore/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    project(KrpnCore_lib)
     
    # j'aime bien, par facilité, définir quelques variables qui correspond aux sous dossiers utilisés, à savoir
    set(INC_DIR include) # pour le dossier contenant les fichiers d'en-tête
    set(SRC_DIR  src) # pour le dossier contenant les fichiers d'implémentation
    # on dresse la liste des fichiers d'en-tête
     
    set(HEADERS ${INC_DIR}/KrpnCore.h
         # et tous les autres que l'on pourra créer
        )
     
    set(SRCS ${SRC_DIR}/KrpnCore.cpp
         # et tous les autres que l'on pourra créer
        )
    add_library(KrpnCore SHARED "")
    target_sources( KrpnCore PUBLIC ${HEADERS}  # les fichiers d'en-tete sont publiques
                                       PRIVATE ${SRCS}     # les fichiers d'implémentation sont privés
    )
    target_include_directories(KrpnCore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
    target_link_libraries(KrpnCore PUBLIC Qt5::Widgets) # ajoute Qt
    Tu remarqueras au passage que nous sommes dans le dossier lib, et que nous créons bel et bien une bibliothèque, c'est à dire, quelque chose qui n'est même pas encore exécutable à proprement parler, bien qu'elle contienne "toutes les fonctionnalités" qui feront que notre application puisse fonctionner

    Note au passage que dans "l'idéal absolu", KrpnCore ne devrait même pas dépendre de Qt, car c'est ce qui correspond dans l'autre intervention à la bibliothèque que je nomme "business", et à la partie "Modèle" du principe MVC / MVD (model view controler / model view deletate)

    Cette bibliothèque ne devrait donc -- dans "l'idéal absolu" -- contenir que les fonctionnalités qui permettent la manipulation de tes données métiers, et ne dépendre que des fonctionnalités offertes par le C++ "pur" (comme la bibliothèque standard) voire, pour quelques cas très spécifiques, de boost ou de quelques autres bibliothèques externes.

    Quoi qu'il en soit, on est vraiment au niveau du "modèle" des données et de leur traitement. Si tu permet de gérer des images, par exemple, il faudra bien que tu sois en mesure de les charger et de les manipuler. Par contre, il n'est même pas encore question d'espérer les afficher à l'écran sous quelque forme que ce soit à ce niveau-ci.

    Tout ce qui a trait à l'affichage fait partie de la vue, si bien que la dépendance avec Qt ne devrait arriver -- dans l'idéal abolu, toujours -- qu'au travers d'une bibliothèque séparée (appelons-la KrpnUI pour Krpn User Inerface ) qui dépendrait également de KrpnCore, et qui se chargerait de faire la "transition" entre les données telles qu'elles sont gérées par le modèle et la manière dont elles sont affichées (voire modifiée) au niveau de la vue, le tout, en passant par "un filtre" que l'on appelle un "controleur" ou "délégué" (la nuance entre les deux étant subtile )

    Cela étant dit, nous en arrivons "naturellement" à parler des tests unitaires.

    Comme la décision de compiler les tests unitaires a déjà été prise au moment où le CMakeLists.txt qui se trouve dans <root>tests est traité, nous pouvons "assez facilement" le garder très minimaliste, et le faire ressembler à quelque chose comme
    <root>/tests/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #parce que nous n'avons besoin de ce composant de Qt qu'à partir d'ici
    find_package(Qt5Test REQUIRED)
     
    enable_testing()
    add_subdirectory(testKrpncore)
    Encore une fois, il "suffira" de rajouter les nouveaux dossier au fur et à mesure que tu les créeras

    Et voilà qui nous amène au nœud du problème: il faut créer le test unitaire à partir du contenu du dossier testKrpncore

    Mais en fait, il s'agit d'un faux problème, car il "suffit" en réalité de créer une application, dépendante de la bibliothèque KrpnCore (car c'est quand même pas mal de disposer des fonctionnalités que l'on veut tester) et de Qt5Test (car c'est ce qui va nous permettre de les tester), avant de déclarer cette application comme étant un test.

    Le fichier CMakeLists.txt correspondant va donc ressembler à quelque chose comme
    <root>/tests/testKrpncore/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    project(KpnCoreTest)
    # on ne change pas une équipe qui gagne :D
    set(INC_DIR include) # pour le dossier contenant les fichiers d'en-tête
    set(SRC_DIR  src) # pour le dossier contenant les fichiers d'implémentation
    # on dresse la liste des fichiers d'en-tête
     
    set(SRCS
        ${SRC_DIR}/TestKrpnCore.cpp
        ${SRC_DIR}/main.cpp
        )
     
    set(HEADERS
        ${INC_DIR}/TestKrpnCore.h
        )
    add_executable(TestKrpnCore "")
    target_sources(TestKrpnCore ${SRCS}) # seuls les fichiers d'implémentation on vraiment de l'intérêt ici car les tests ne sont pas destinés à être installés
    target_include_directories(TestKrpnCore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) # ce dossier pourrait, à mon sens, être privé sans que cela change grand chose ;)
    target_link_libraries(TestKrpnCore PUBLIC KrpnCore  Qt5::Test) # de même que les dépendances vis-à-vis des bibliothèques
    add_test(NAME testKrpnCore COMMAND TestKrpnCore )

    Enfin, nous aurions le dossier apps, qui contiendrait un sous dossier pour l'application telle qu'elle sera mise en production, qui dépendrait uniquement de KrpnCore (car il n'y a aucune raison de la faire dépendre des tests unitaires) et dont les fichiers CMakeLists.txt pourraient ressembler à quelque chose comme
    <root>/apps/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    add_subdirectory(KrpnApp)
    <root>/apps/KrpnApp/CMakeLists.txt
    Code CMakeLists : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    project(KrpnApp)
    # allez, parce que j'aime pas voir un fichier d'implémentation à coté d'un CMakeLists.txt, 
    # on va dire que fichier main.cpp se trouve dans le sous-dossier src :D
     
    set(SRCS src/main.cpp)
    add_executable(Krpn ${SRCS})
    target_link_library(Krpn PRIVATE KrpnCore )
    Et voilà, tu te retrouve au final avec quatre projets différents, dont le seul objectif de l'un d'eux est de permettre la gestion "centralisée" de tous les autres.

    Les CMakeLists.txt relatifs aux trois autres projets sont, quant à eu "suffisamment simples" que pour n'avoir à s'inquiéter que des évolutions spécifiques aux différents projets.

    Et si -- car cela risque fort d'arriver -- de nouveaux projets devaient venir s'incruster dans cette "solution", il "suffirait", en plus de créer un dossier spécifique pour chaque nouveau projet, de rajouter une ligne contenant l'instruction add_subdirectory dans le dossier "générique" dans lequel le projet devra se placer

    On évite un maxium les répétions, on garde tous les fichiers "aussi simples que possible" tout en s'assurant qu'il fournissent le "stricte minimum requis", qui correspond -- comme bien souvent -- également au maximum "admissible", et l'on s'évite donc un tas de problèmes par la suite.

    DISCLAMER : je n'ai absolument pas pris la peine de créer un projet équivalent dans le but de m'assurer que tout était effectivement en ordre. Le code que je présente ici a donc été écrit "à la volée" et n'a en aucun cas été testé d'une quelconque manière.

    Je ne peux donc absolument pas garantir qu'il ne contienne aucune erreur. Cependant, si erreur il y a, elles devraient rester "assez simples" à résoudre, et surtout, elles ne changent en rien les principes que j'ai essayer d'expliquer au travers du code
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 108
    Points : 143
    Points
    143
    Par défaut
    merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 01/06/2018, 15h40
  2. Réponses: 6
    Dernier message: 16/03/2007, 13h45
  3. [C# 1.1] Erreur création projet Web
    Par diaboloche dans le forum ASP.NET
    Réponses: 4
    Dernier message: 30/10/2006, 10h40
  4. Erreur liaison entre 2 bases
    Par gbuxo dans le forum Access
    Réponses: 3
    Dernier message: 26/06/2006, 11h08
  5. [C#] Erreur génération projet de déploiement web
    Par Giill dans le forum ASP.NET
    Réponses: 3
    Dernier message: 18/02/2005, 10h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo