clinuxgccmakefilemultiple-definition-error

How to link all files in C ansi? Error with multiple definition


Good morning

This is big problem for me to link all files (main.c, myFunc.c, myFuncHeaders.h and MakeFile). Problem is multiple definition when I don't know what should I do with it. I used global variables char board[3][3], char board_checked[3][3] and int playersRound. I know that global would be unnecessary and bad designed program, but I wanted try something new. Simple tic tac toe game

In one file(all in one), code works. Here:

#include<stdio.h>
#include <stdlib.h>

char board[3][3] = {{'_', '_', '_'},{'_', '_', '_'},{'_', '_', '_'} };
char board_checked[3][3] = {{'+', '+', '+'},{'+', '+', '+'},{'+', '+', '+'}};
int playersRound = 0;

// It shows board
void show_board(){
    char * space = "          ";
    puts("\tPlansza\n\t==================================");
    for(int i = 1; i < 4; i++)
    {
        printf("%s|%d|", space, i);
    }
        printf("\n");
    for(int i = 0; i < 3; i++){
        printf("\t|%d|",i+1);
        for(int j = 0; j < 3; j++)
        {
            printf("%c  %s", board[i][j], space);
        }
        printf("\n\n");
    }
    puts("\t==================================\n");
}


// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player){
    // If it isn't reserved by other mark
    if(board_checked[p[0]-1][p[1]-1] != '-'){
        // x (p[1]) and y (p[0]) vectors are (1, 2, 3)
        if(1 <= p[0] && p[0] <= 3 && 1 <= p[1] && p[1] <= 3)
        {
            if(player == 1)
            {
                // Add to board 'X'
                board[p[0]-1][p[1]-1] = 'O';
                // and unchecked at the same position 'board_checked'
                board_checked[p[0]-1][p[1]-1] = '-';

            }
            else
            {
                // Add to board 'X'
                board[p[0]-1][p[1]-1] = 'X';
                // and unchecked at the same position 'board_checked'
                board_checked[p[0]-1][p[1]-1] = '-';
            }
            // If Everything is Okey go to next playersRound
            playersRound++;
        }
    }
    else
        // On start variable is position[2] = {0,0}; it's mean that I made exception
        if(!(0 == p[0] && 0 == p[1]))
        {
            puts("Nie podales poprawnych parametrow");
            sleep(2);
        }
}


// This function check every position where any mark have been added
int structure_check(int player){
    //return winner
    for(int i = 0; i < 2; i++){
        // Check horizontal
        for(int level = 0; level < 3; level++)
            if(board[level][0] == board[level][1] && board[level][0] == board[level][2] && board[level][0] != '_')return player;
        // Check vertical
        for(int level = 0; level < 3; level++)
            if(board[0][level] == board[1][level] && board[0][level] == board[2][level] && board[0][level] != '_')return player;
        // Check diagonal left
        if(board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != '_')return player;
        // Check diagonal right
        if(board[2][0] == board[1][1] && board[2][0] == board[0][2] && board[0][2] != '_')return player;
    }
    // Draw - when no one of two players won
    return 0;
}



int main(char argc, char * argv[]){
    int player = 1;
    int position[2] = {0,0};
    int status = 0;



    show_board();


    while(playersRound < 10){
        // Short information
        if(player == 1) puts("Gracz 1:");
        else puts("Gracz 2:");
        // Get position
        printf("\tx:"); scanf("%d", &position[0]);
        printf("\ty:"); scanf("%d", &position[1]);
        // status game, win or draw
        status = structure_check(player);
        // Players movement in playersRounds
        if(playersRound%2 == 0) player = 1;
        else player = 2;
        // This add mark to board by player
        add_mark(position, player);
        // Clear console
        system("cls");
        // Show only board
        show_board();
        // To be sure it works
        status = structure_check(player);
        // It finish when someone won game
        if(status != 0) break;
    }

    if(player == 1)
        printf("Wygrywa gracz: 1 z  'O'");
    else
        printf("Wygrywa gracz: 2 z  'X'");
    puts("  ||| Gratulacje! |||");

    return 0;
}

Problem is here:

main.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "myFunc.c"
#include "myFuncHeaders.h"



int main(char argc, char * argv[]){
    int player = 1;
    int position[2] = {0,0};
    int status = 0;
    
    

    show_board();
    

    while(playersRound < 10){
        // Short information
        if(player == 1) puts("Gracz 1:");
        else puts("Gracz 2:");
        // Get position
        printf("\tx:"); scanf("%d", &position[0]);
        printf("\ty:"); scanf("%d", &position[1]);
        // status game, win or draw
        status = structure_check(player);
        // Players movement in playersRounds
        if(playersRound%2 == 0) player = 1;
        else player = 2;
        // This add mark to board by player
        add_mark(position, player);
        // Clear console
        system("clear");
        // Show only board
        show_board();
        // To be sure it works
        status = structure_check(player);
        // It finish when someone won game
        if(status != 0) break;
    }

    if(player == 1)
        printf("Wygrywa gracz: 1 z  'O'");
    else
        printf("Wygrywa gracz: 2 z  'X'");
    puts("  ||| Gratulacje! |||");

    return 0;
}

myFunc.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // sleep() 
#include "myFuncHeaders.h"

char board[3][3] = {{'_', '_', '_'},{'_', '_', '_'},{'_', '_', '_'} };
char board_checked[3][3] = {{'+', '+', '+'},{'+', '+', '+'},{'+', '+', '+'}};
int playersRound = 0;

// It shows board 
void show_board(){
    char * space = "          ";
    puts("\tPlansza\n\t==================================");
    for(int i = 1; i < 4; i++)
    {
        printf("%s|%d|", space, i);
    }
        printf("\n");
    for(int i = 0; i < 3; i++){
        printf("\t|%d|",i+1);
        for(int j = 0; j < 3; j++)
        {
            printf("%c  %s", board[i][j], space);
        }
        printf("\n\n");
    }
    puts("\t==================================\n");
}


// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player){
    // If it isn't reserved by other mark
    if(board_checked[p[0]-1][p[1]-1] != '-'){
        // x (p[1]) and y (p[0]) vectors are (1, 2, 3)
        if(1 <= p[0] && p[0] <= 3 && 1 <= p[1] && p[1] <= 3)
        {
            if(player == 1)
            {
                // Add to board 'X'
                board[p[0]-1][p[1]-1] = 'O';
                // and unchecked at the same position 'board_checked'
                board_checked[p[0]-1][p[1]-1] = '-';

            }
            else
            {
                // Add to board 'X'
                board[p[0]-1][p[1]-1] = 'X';
                // and unchecked at the same position 'board_checked'
                board_checked[p[0]-1][p[1]-1] = '-';
            }
            // If Everything is Okey go to next playersRound
            playersRound++;
        }
    }
    else
        // On start variable is position[2] = {0,0}; it's mean that I made exception
        if(!(0 == p[0] && 0 == p[1]))
        {
            puts("Nie podales poprawnych parametrow");
            sleep(2);
        }
}


// This function check every position where any mark have been added
int structure_check(int player){
    //return winner
    for(int i = 0; i < 2; i++){
        // Check horizontal
        for(int level = 0; level < 3; level++)
            if(board[level][0] == board[level][1] && board[level][0] == board[level][2] && board[level][0] != '_')return player;
        // Check vertical
        for(int level = 0; level < 3; level++)
            if(board[0][level] == board[1][level] && board[0][level] == board[2][level] && board[0][level] != '_')return player;
        // Check diagonal left
        if(board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != '_')return player;
        // Check diagonal right
        if(board[2][0] == board[1][1] && board[2][0] == board[0][2] && board[0][2] != '_')return player;
    }
    // Draw - when no one of two players won
    return 0;
}

myFuncHeaders.h

void show_board();
// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player);
// This function check every position where any mark have been added
int structure_check(int player);

MakeFile

main:               main.o myFunc.o
                    gcc -o main main.o myFunc.o

myFunc.o:           myFunc.c myFunc.o
                    gcc -c -o myFunc.o myFunc.c

Output:

*my foleder*
~/zadania_domowe/kolko_krzyzyk $ make
cc    -c -o main.o main.c
make: circular version myFunc.o <- myFunc.o lost.
gcc -c -o myFunc.o myFunc.c
gcc -o main main.o myFunc.o
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.data+0x0): multiple definition of `board'; main.o:(.data+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.data+0x10): multiple definition of `board_checked'; main.o:(.data+0x10): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.bss+0x0): multiple definition of `playersRound'; main.o:(.bss+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `show_board':
myFunc.c:(.text+0x0): multiple definition of `show_board'; main.o:main.c:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `add_mark':
myFunc.c:(.text+0xf5): multiple definition of `add_mark'; main.o:main.c:(.text+0xf5): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `structure_check':
myFunc.c:(.text+0x2a6): multiple definition of `structure_check'; main.o:main.c:(.text+0x2a6): first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:2: main] Error 1

I try with extern global, put this globals into the main() and then send to the functions. I had more errors then I expected. If someone have link or source to the same problem I will be glad for this information.


Solution

  • The problem is that you #include "myFunc.c" in main.c so you include the implementations of functions show_board, add_mark, etc. in the main.o compiled object, and those functions are also included in the myFunc.o compiled object, result of compiling the same source file directly. The linker, on seeing this, complaints, as it cannot know which function to use, and when you make a call to e.g. add_mark in main it doesn't know which one is to be called.

    To solve your problem, you just need to take off the line

    #include "myFunc.c"
    

    and include also myFuncHeaders.h in the file myFunc.h, so you can check that the definitions given in the header file are compatible with the implementations you provide in the file myFunc.c.

    There is also an error from make telling that you have included a rule indicating that myFunc.o file depends on myFunc.o which is a circular dependence, and it is an error (make cannot be given dependency rules with loops, as it would never end if it had to allow them) you need to change

    myFunc.o: myFunc.c myFunc.o
        gcc -c -o myFunc.o myFunc.c
    

    into

    myFunc.o: myFunc.c myFuncHeaders.h
        gcc -c -o myFunc.o myFunc.c
    

    and write a similar one for main.o (which has been taken by default with the internal make's version, you will see that make has called cc compiler, to compile main.c instead of gcc)

    main.o: main.c myFuncHeaders.h
        gcc -c -o main.o main.c
    

    The rule is to think that if you touch (edit) any of the files main.c or myFuncHeaders.h (this last because you have modified the interface to the functions defined in myFunc.c, then you need to create a new compilation of main.c to main.o, or the final executable will be inconsistent (and your program will crash).