Error while creating Makefile

Asked

Viewed 1,457 times

5

When I am trying to use Makefile with the following content:

all: teste
teste: arp_discover.o arp_poisoning.o 
        gcc -o teste arp_discover.o arp_poisoning.o
arp_discover.o: arp_discover.c arp_discover.h
        gcc -o arp_discover.o -c arp_discover.c -W -lpthread -Wall
arp_poisoning.o: arp_poisoning.c 
        gcc -o arp_poisoning.o -c arp_poisoning.c -W -lpthread -Wall
clean:
        rm -rf *.o
mrproper: clean
        rm -rf teste

The following error is shown:

gcc -o teste arp_discover.o arp_poisoning.o
arp_poisoning.o:(.data+0x0): múltipla definição de `capacidade'
arp_discover.o:(.data+0x0): definido primeiramente aqui
arp_poisoning.o:(.bss+0x0): múltipla definição de `posicao'
arp_discover.o:(.bss+0x0): definido primeiramente aqui
arp_poisoning.o: na função `sendRequests':
arp_poisoning.c:(.text+0x0): múltipla definição de `sendRequests'
arp_discover.o:arp_discover.c:(.text+0x0): definido primeiramente aqui
arp_poisoning.o: na função `receiveReplies':
arp_poisoning.c:(.text+0x2e2): múltipla definição de `receiveReplies'
arp_discover.o:arp_discover.c:(.text+0x2e2): definido primeiramente aqui
arp_poisoning.o: na função `getHosts':
arp_poisoning.c:(.text+0x553): múltipla definição de `getHosts'
arp_discover.o:arp_discover.c:(.text+0x553): definido primeiramente aqui
collect2: error: ld returned 1 exit status
Makefile:3: recipe for target 'teste' failed
make: *** [teste] Error 1

Since in the arp_poisoning file there is the following dependency:

/* utilizando os utilitarios */
#include "arp_discover.c"
  • 1

    Makefile looks right. It can show the files you are compiling?

  • Oops, well they’re giant hehehe, but basically what there is is a file. h that defines the arp_discover and this dependency declared inside the arp_poisoning file with #include "arp_discover. c"

  • by Makefile was able to know this. By the errors shown, you are declaring capacidade, posicao, sendRequests, receiveReplies and getHosts more than once.

  • it is, but it shouldn’t, because my code is declaring this only in a file, you will be able to take a look at the code by following the link from github: https://github.com/emanoelvianna/work-networks, the Makefile code is different and the dependency on arp_poisoning is commented, the rest is the same I am using.

  • @Emanoel, do not include files .c

1 answer

10


Repeat after me: never include .c for no other reason

We can use yours more efficiently Makefile using automatic variables. See that answer explaining a little about the variable $<. For an extensive and more focused explanation for C/C file compilation++, see this other answer.

About the use of files .h, I disagree a little bit about forward declaration in that other answer.

Now, let’s focus. The archive arp_poisoning.c does not depend on the arp_discover.c, but it depends on his statements. It depends on the forward declarations which are contained in .h. To explain what is really going on, I now need to go into details of how the compilation of a C source file works.

Compilation of C file

Amazingly, the C compiler works only one entry at a time. It takes this input from the so-called C pre-processor. In the next section I’ll tell you what the pre-processor is.

C is a language that in practice is parsed in a single pass, like most programming languages. The compiler will identify every definition + open references and will put your results in so-called object files (files .o in the world of GCC).

What would be considered definition in this case? A body function is definitely defined. A global variable is also defined.

What about open reference? This is a concept for things that should exist but don’t exist in the context of compiled code. It may exist on the outside, but the compiler is not able to close which implementation is actually being used.

When an open reference happens? It happens when you say the variable exists, but the file is not "owner" of it; the variable is external (extern). This happens with the variable errno. Another open point of reference? Functions they had forward declaration.

You can and should create object files with open references. But you can only create executable after closing all static references, after making all the links, all the Binds. And who does that? The linker.

The linker

The role of the linker is to resolve all open references on top of the set of available objects and libraries.

How does it do that? With a protocol. A C function will have a name, and that name is recognized by the linker and generated by the compiler. GCC generates this value by placing _ in front of the function name C. For example, the function capacidade would have your link name _capacidade.

The linker will search for any open reference and, if it has not found the function to close this reference, it will keep this open reference pointed. If you find a function definition, it will add to the set of known functions; if that function has an open reference to it, the linker will close the reference. If a second definition is found, the linker aborts with error: definition duplicity.

The pre-processor C

The C preprocessor is a word processor in general; it is also known as CPP. It has emerged to work with C files, but can be used to process other textual files.

In general, everything contained # C code line will be interpreted by CPP. After a #, will come a CPP command. CPP will also replace textual everything that is set for preprocessing.

Some commands:

  • #define MACRO val: defines MACRO with the value val; this means that every string in the text, from the moment of the definition of MACRO will be replaced Verbatim for val; if the value is not defined, an empty string is assumed; arguments can be used for the definition;
  • #include "abcde": considers that, the exact point of this include it should take into consideration as continuation of the entire file content entry abcde, preprocessing abcde also; all previous definitions remain valid.

What happens when you include another .c at my source?

Come on. Let’s take as an example a simpler file. I’ll call hello.c and the say_hello.c.

hello.c:

#include <stdio.h>
void hello() {
    printf("hello\n");
}

say_hello.c

#include <stdio.h>
#include "hello.c"

int main() {
    hello();
    return 0;
}

Let’s see what will be the output of the CPP, which is the input of the compiler itself? I will ignore the standard library part because it is not the case:

/* coisas do stdio.h */
void hello() {
    printf("hello\n");
}

int main() {
    hello();
    return 0;
}

Okay. So, when compiling say_hello.c, we will have two properly implemented definitions and an open reference in the say_hello.o. The definitions are:

  1. _hello
  2. _main

The open reference is:

  1. printf

By having the GCC join the say_hello.o with the hello.o, we will have two definitions for _hello. Which means you won’t be rolling the compilation.

How to proceed?

Simple: include the headers/.h. Compile the files .cindividually. Put it all together in one large executable. The C++ compilation response takes care of that very well. In general, this can also be done in the makefile:

.PHONY: all

all : teste

teste : arp_discover.o arp_poisoning.o
    gcc -o $@ $^

%.o : %.c
     gcc -o $@ $< -c

arp_discover.o : arp_discover.h

arp_poisoning.o : arp_discover.h
  • 1

    very nice your explanation, thank you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.