Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de linker

Sujet résolu
    17 juin 2023 à 15:43:59

    Bonjour / bonsoir à tous,

    J'ai un programme composé de plusieurs .c qui avaient étés compilé en 32bits. J'ai maintenant installé un compilateur 64bits, mais si la compilation se passe bien, le linker (ld) me met des erreurs. Je comprends bien le message qu'il met, mais ce que je comprends pas, c'est le pourquoi.

    J'utilise cette version de gcc

    gcc (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders) 12.2.0
    Copyright (C) 2022 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    J'exécute make

    GNU Make 4.2
    This program is built by Equation Solution <http://www.Equation.com>.
    Copyright (C) 1988-2016 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

    avec le makefile suivant (old school)

    OBJS=clrt.o clrt_sdl.o clrt_products.o clrt_display.o clrt_doit.o clrt_commands.o clrt_printlist.o clrt_ico.o
    CFLAGS=-c -Wall -Wextra -std=c11 -Wunused -Wno-parentheses -Wswitch-default -fno-diagnostics-color
    LFLAGS=-Wl,--subsystem=windows
    LIBS=-lmingw32 -lsdl2main -lsdl2 -lsdl2_ttf -lsdl2_image -lGdi32 -lwinspool -lpg
    EXEC=bin/clrt.exe
    H=*.h
    
    $(EXEC): $(OBJS) $(H)
    	gcc $(LFLAGS) -o$(EXEC) $(OBJS) ..\pglib\pgprint.o $(LIBS)
    
    clrt.o: clrt.c $(H)
    	gcc clrt.c $(CFLAGS)
    
    clrt_sdl.o: clrt_sdl.c $(H)
    	gcc clrt_sdl.c $(CFLAGS)
    
    clrt_doit.o: clrt_doit.c $(H)
    	gcc clrt_doit.c $(CFLAGS)
    
    clrt_products.o: clrt_products.c $(H)
    	gcc clrt_products.c $(CFLAGS)
    
    clrt_display.o: clrt_display.c $(H)
    	gcc clrt_display.c $(CFLAGS)
    
    clrt_commands.o: clrt_commands.c $(H)
    	gcc clrt_commands.c $(CFLAGS)
    	
    clrt_printlist.o: clrt_printlist.c $(H)
    	gcc clrt_printlist.c $(CFLAGS)
    
    clrt_ico.o: clrt_ico.rc
    	windres -i clrt_ico.rc -o clrt_ico.o

    et j'obtiens ces messages d'erreur

    gcc -Wl,--subsystem=windows -obin/clrt.exe clrt.o clrt_sdl.o clrt_products.o clrt_display.o clrt_doit.o clrt_commands.o clrt_printlist.o clrt_ico.o ..\pglib\pgprint.o -lmingw32 -lsdl2main -lsdl2 -lsdl2_ttf -lsdl2_image -lGdi32 -lwinspool -lpg
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_sdl.o:clrt_sdl.c:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_products.o:clrt_products.:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_display.o:clrt_display.c:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_doit.o:clrt_doit.c:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_commands.o:clrt_commands.:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    d:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: clrt_printlist.o:clrt_printlist:(.bss+0x0): multiple definition of `clrt'; clrt.o:clrt.c:(.bss+0x0): first defined here
    collect2.exe: error: ld returned 1 exit status
    make: *** [makefile:9: bin/clrt.exe] Error 1
    

    Merci d'avance pour votre aide.

    Edgar;

    NB: supprimer LFLAGS ne change rien, et pg est une lib personnelle.

    -
    Edité par edgarjacobs 17 juin 2023 à 15:51:10

    • Partager sur Facebook
    • Partager sur Twitter

    On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

      17 juin 2023 à 17:27:02

      J'ai réussi à reproduire ton problème : J'ai créé une variable global dans un fichier entête que j'ai inclus dans 2 fichier sources et que j'ai compilé ensemble :

      Avec les anciennes versions de minGW ça passe sans erreur (32 comme 64 bits)

      Puis j'ai compilé avec minGW (gcc12) et là j'ai bien l'erreur ! La même que toi.

      EDIT : J'ai testé sous Visual studio C  ça compile, ce qui semblerait normal puisque si elles ne sont pas initialisées. 

      EDIT : J'ai testé aussi sous clang et la ça ne passe pas !

      Il y aurait donc de divergences selon les compilateurs ?

      PS : j'ai trouvé ça sur la norme :  If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

      -
      Edité par rouIoude 17 juin 2023 à 18:53:56

      • Partager sur Facebook
      • Partager sur Twitter
      ...
        17 juin 2023 à 20:00:14

        rouIoude a écrit:

        J'ai réussi à reproduire ton problème : J'ai créé une variable global dans un fichier entête que j'ai inclus dans 2 fichier sources et que j'ai compilé ensemble :

        Avec les anciennes versions de minGW ça passe sans erreur (32 comme 64 bits)

        Puis j'ai compilé avec minGW (gcc12) et là j'ai bien l'erreur ! La même que toi.


        Waouuw ! Je me demande comment tu as pensé à ça en voyant le message d'erreur, car il faut avouer qu'il n'est pas très explicite !

        J'ai en effet dans un common.h (inclus dans tous les .c) une variable globale, struct clrt *clrt; (ça évite de devoir la trimbaler de fonction en fonction). Et dans le main(), j'ai struct clrt sclrt={0}; clrt=&sclrt;

        Avec minGW v9 (ou v6 ?), ça passe, mais avec v12 (comme tu l'as testé), ça casse.

        La solution: dans common.h, déclarer extern struct clrt *clrt; et dans le .c qui contient le main() **, mettre struct clrt *clrt; en variable globale, et l'initialiser dans le main() (comme écrit plus haut, p.ex.)

        rouloude, je te remercie énormément. Tu me sors d'une bien mauvaise passe. Ça vaut plus qu'un +1

        Edgar;

        PS: clang et minGW ont apparement raison, si je comprends bien.

        ** en fait, après test, en variable globale dans n'importe quel fichier .c du projet et initialisée n'importe où avant de l'utiliser.



        -
        Edité par edgarjacobs 17 juin 2023 à 20:53:18

        • Partager sur Facebook
        • Partager sur Twitter

        On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

          18 juin 2023 à 12:05:56

          Après recherche, apparemment c'est comme cela depuis la version 10 de gcc.

          On peut garder l'ancien comportement avec l'option -fcommon   (idem pour clang).

          -
          Edité par rouIoude 18 juin 2023 à 12:07:13

          • Partager sur Facebook
          • Partager sur Twitter
          ...
            18 juin 2023 à 15:41:30

            Après avoir corrigé l' "erreur", je me suis dit "je plains le bonhomme qui doit faire des modifications dans un pgm compilé avec ancien gcc, et le compiler avec un gcc récent".

            Avec ta remarque, je me souviens d'avoir lu un article dans lequel l'auteur expliquait que les développeurs de compilateurs conservaient les éventuels "bugs" d'une version à l'autre, pour que les programmes utilisant la nouvelle version aient toujours le même comportement. L'option -fcommon me semble donc logique.

            -
            Edité par edgarjacobs 18 juin 2023 à 15:42:02

            • Partager sur Facebook
            • Partager sur Twitter

            On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

              18 juin 2023 à 17:50:24

              > J'ai créé une variable globale [dans 2 fichiers]

              Le problème c'est l'emploi de "creer".

              Avec un petit effort de vocabulaire

              • Soit tu définis
              • Soit tu déclares.

              Et le linker te dit qu'il y'a des définitions multiples du même symbole.

              Donc le problème est clair, et la solution aussi : déclarer autant que tu veux (Avec extern), et définir une et une seule fois (sans).

              En general, pour une variable globale commune

              • Elle est déclarée dans un .h (Comme ça on en hérite par include)
              • Elle est définie dans le .c qui va avec

              Éviter de "définir dans n'importe quel fichier", autant que d'avoir un .h fourre-tout.

              -
              Edité par michelbillaud 18 juin 2023 à 17:53:03

              • Partager sur Facebook
              • Partager sur Twitter
                18 juin 2023 à 18:15:50

                michelbillaud a écrit:

                Le problème c'est l'emploi de "creer".

                On est d'accord que "créer" n'est pas le mot approprié. Pour le reste je suis aussi d'accord, mais ici j'essayer de reproduire une erreur et non pas de faire un code fonctionnel.

                michelbillaud a écrit:

                Avec un petit effort de vocabulaire

                • Soit tu définis
                • Soit tu déclares.

                Dans ce sujet on serait dans ce qu'ils appellent une définition provisoire 'A tentative definition '.

                -
                Edité par rouIoude 18 juin 2023 à 19:34:22

                • Partager sur Facebook
                • Partager sur Twitter
                ...
                  18 juin 2023 à 20:00:16

                  michelbillaud a écrit:

                  Éviter de "définir dans n'importe quel fichier", autant que d'avoir un .h fourre-tout.

                  Le "Éviter de définir ...." c'était juste par souci de précision, mais d'accord avec toi.

                  Le common.h n'est pas un fourre-tout, il contient les define nécessaires au programme, et une structure qui retient les paramètres nécessaires au fonctionnement de l'application, style taille de la fenêtre etc, et un pointeur sur cette structure pour éviter de devoir se le coltiner de fonction en fonction, certaines n'en ayant pas besoin mais celles qu'elles appellent, oui.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                  Problème de linker

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown