web-dev-qa-db-fra.com

Comment lier des fichiers d'objet en C? Echec avec "Symboles non définis pour l'architecture x86_64"

J'essaye donc d'utiliser une fonction définie dans un autre fichier C (fichier1.c) de mon fichier (fichier2.c). J'inclus l'en-tête de fichier1 (fichier1.h) afin de faire cela.

Cependant, je continue à avoir l'erreur suivante chaque fois que j'essaie de compiler mon fichier avec gcc:

Undefined symbols for architecture x86_64:
  "_init_filenames", referenced from:
      _run_worker in cc8hoqCM.o
  "_read_list", referenced from:
      _run_worker in cc8hoqCM.o
ld: symbol(s) not found for architecture x86_64

On m'a dit que je devais "lier les fichiers d'objet ensemble" afin d'utiliser les fonctions de file1 dans file2, mais je n'ai aucune idée de ce que cela signifie :(

45
adi

Je suppose que vous utilisez gcc, simplement pour lier des fichiers objet:

$ gcc -o output file1.o file2.o

Pour obtenir les fichiers objets simplement compiler en utilisant

$ gcc -c file1.c

cela donne file1.o et ainsi de suite.

Si vous souhaitez lier vos fichiers à un exécutable, faites

$ gcc -o output file1.c file2.c
79
bash.d

Les réponses existantes couvrent déjà le "comment", mais je voulais juste élaborer sur le "quoi" et le "pourquoi" pour ceux qui pourraient se demander.

Qu'est-ce qu'un compilateur (gcc) fait: Le terme "compiler" est un terme surchargé, car il est utilisé à un niveau élevé pour signifier "convertir le code source en programme", mais signifie techniquement "convertir le code source en code objet". Un compilateur comme gcc exécute en réalité deux fonctions liées, mais discutablement distinctes, pour transformer votre code source en programme: compiler (comme dans la dernière définition de la conversion du code source en code objet) et la liaison (processus consistant à combiner les fichiers de code objet nécessaires en un exécutable complet).

L'erreur originale que vous avez vue est techniquement une "erreur de lien" et est renvoyée par "ld", l'éditeur de liens. Contrairement aux erreurs de compilation (strictes), il n'y a aucune référence aux lignes de code source, car l'éditeur de liens est déjà dans l'espace objet.

Par défaut, lorsque gcc reçoit du code source en entrée, il tente de les compiler, puis de les lier. Comme indiqué dans les autres réponses, il est possible d’utiliser des indicateurs pour indiquer à gcc de tout d’abord compiler, puis d’utiliser les fichiers objet plus tard pour créer un lien dans une étape distincte. Ce processus en deux étapes peut sembler inutile (et probablement pour de très petits programmes), mais il est très important lors de la gestion d'un très grand programme, où la compilation de l'ensemble du projet à chaque fois que vous effectuez un petit changement vous ferait perdre un temps considérable.

21
SeKa

Vous pouvez compiler et lier en une seule commande:

gcc file1.c file2.c -o myprogram

Et courir avec:

./myprogram

Mais pour répondre à la question, posez simplement les fichiers objet à gcc:

gcc file1.o file2.o -o myprogram
8
Johnsyweb

Ajouter foo1.c, foo2.c, foo3.c et makefile dans un dossier du type make in bash

si vous ne voulez pas utiliser le makefile, vous pouvez lancer la commande

gcc -c foo1.c foo2.c foo3.c

puis

gcc -o output foo1.o foo2.o foo3.o

foo1.c

#include <stdio.h>
#include <string.h>

void funk1();

void funk1() {
    printf ("\nfunk1\n");
}


int main(void) {

    char *arg2;
    size_t nbytes = 100;

    while ( 1 ) {

        printf ("\nargv2 = %s\n" , arg2);
        printf ("\n:> ");
        getline (&arg2 , &nbytes , stdin);
        if( strcmp (arg2 , "1\n") == 0 ) {
            funk1 ();
        } else if( strcmp (arg2 , "2\n") == 0 ) {
            funk2 ();
        } else if( strcmp (arg2 , "3\n") == 0 ) {
            funk3 ();
        } else if( strcmp (arg2 , "4\n") == 0 ) {
            funk4 ();
        } else {
            funk5 ();
        }
    }
}

foo2.c

#include <stdio.h>
void funk2(){
    printf("\nfunk2\n");
}
void funk3(){
    printf("\nfunk3\n");
}

foo3.c

#include <stdio.h>

void funk4(){
    printf("\nfunk4\n");
}
void funk5(){
    printf("\nfunk5\n");
}

makefile

outputTest: foo1.o foo2.o foo3.o
    gcc -o output foo1.o foo2.o foo3.o
    make removeO

outputTest.o: foo1.c foo2.c foo3.c
    gcc -c foo1.c foo2.c foo3.c

clean:
    rm -f *.o output

removeO:
    rm -f *.o
5
Ar maj

Comme il n'y a aucune mention sur la façon de compiler un fichier .c avec un tas de fichiers .o, et ce commentaire le demande:

où est le main.c dans cette réponse? :/si file1.c est le fichier principal, comment le relier à d’autres fichiers .o déjà compilés? - Tom Brito 12 Oct 14 à 19:45

$ gcc main.c lib_obj1.o lib_obj2.o lib_objN.o -o x0rbin

Ici, main.c est le fichier C avec la fonction main () et les fichiers objets (* .o) sont précompilés. GCC sait comment les gérer ensemble et appelle le lieur en conséquence, ce qui donne un exécutable final, qui dans notre cas est x0rbin.

Vous pourrez utiliser des fonctions non définies dans le fichier main.c mais en utilisant une référence externe aux fonctions définies dans les fichiers objets (* .o).

Vous pouvez également établir une liaison avec .obj ou d'autres extensions si les fichiers objet ont le format correct (tel que COFF).

2
ashmew2