Как написать «Makefile» для игры «Угадай правильный номер!» На C? - PullRequest
0 голосов
/ 07 декабря 2018

Я выполнил код для запуска коробки внутри игры.Это называется Угадай правильный номер!Это означает, что вы можете выбрать число от 0 до 10, если это неправильное число, будет отображено сообщение для повторной попытки, в противном случае появится сообщение, которое вы выиграли, с вариантами выхода или перезапуска.Когда я пытаюсь использовать gcc для его компиляции, но, похоже, мне нужно создать makefile, как мне сказали, но я никогда не делал make-файл для одного файла, или второй файл будет называться answer?

Я занимаюсь программированием на С уже 4 месяца.Мое имя программы game.c для создания Game (./Game) для запуска программы (игры).Как я могу написать make-файл для этого?

Я понятия не имею, что такое "проклятия", поэтому я хотел научиться использовать с проклятиями (<ncurses.h>) для себя, когда я до сих пор проводил много исследованийЯ не вижу различий между проклятиями и курсами.Я создал ошибку компиляции после использования gcc в приведенном ниже.

Фрагмент:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <time.h>

// PREDEFINED VALUES FOR DEFINING NON CHANGING VALUES IN CODE THIS CASE
#define WINDOWHEIGHT 20
#define WINDOWWIDTH 60
#define WINDOWSTARTX 0
#define WINDOWSTARTY 0
#define CORRECT 1
#define INCORRECT 0
#define START 2
#define WRONGFORMAT 3
#define MAXVALUE 10//You may change MAXVALUE to any num, i.e. `100` = (0-100).
#define MINVALUE 0
// PREDEFINED VALUES FOR DEFINING NON CHANGING VALUES IN THIS CASE


// initialising global structure for saving amount of right and wrong guesses and number to compare with.
struct game {
        int rightGuesses;
        int wrongGuesses;
        int rightNumber;
} myGame;

void initializeGame()
{

        // Returns a pseudo-random integer between 0 and MAXVALUE.
        int randomNumber = rand() % MAXVALUE;
        myGame.rightGuesses=0;
        myGame.rightNumber=randomNumber;
}

WINDOW *create_newwin(int height, int width, int starty, int startx)
{
        WINDOW *local_win;
        local_win = newwin(height, width, starty, startx);
        box(local_win, 0, 0);
        wrefresh(local_win);
        return local_win;
}


int getGuess()
{
        int guess=0;
        char guessString[32];
        scanf("%s", guessString);

        // Read number as string by using scanf, but convert to int for comparison with atoi()
        guess= atoi(guessString);
        size_t allowedEntries = strspn(guessString, "0123456789");

        // Some checking if guess was between allowed range + its a number + checking if answer is correct or not
        if(guess>=MINVALUE && guess<=MAXVALUE && guessString[allowedEntries] == '\0')
        {
                if(guess==myGame.rightNumber)
                        return CORRECT;
                else
                        return INCORRECT;
        }
        else
                return WRONGFORMAT;

}

/**
    Function for updating views regarding the input values...
 **/

void updateWindowTexts(WINDOW* window, int state)
{

        char* greetingsString = "Guess the correct number!";
        char* instructionsString = "Enter number 0-10 and press enter";
        char* correctGuess = "That was correct! Lets play again";
        char* incorrectGuess = "Sorry that was not right";
        char* wrongFormat = "incorrect number, please enter number between 0-10";
        char* correctAnswersString = "Correct answers:";
        char correctAnswers[32];
        char wrongAnswers[32];
        const char rightAnswersBase[] = "Right numbers so far: ";
        sprintf(correctAnswers, "%s%d", rightAnswersBase, myGame.rightGuesses);
        const char wrongAnswersBase[] = "Wrong numbers so far: ";
        sprintf(wrongAnswers, "%s%d", wrongAnswersBase, myGame.wrongGuesses);


        wclear(window);
        box (window, 0, 0);

        mvwprintw (window, 1, (WINDOWWIDTH/2)-(strlen(greetingsString)/2), greetingsString);
        mvwprintw (window, (WINDOWHEIGHT-3), (WINDOWWIDTH/2)-(strlen(correctAnswers)/2), correctAnswers);
        mvwprintw (window, (WINDOWHEIGHT-2), (WINDOWWIDTH/2)-(strlen(wrongAnswers)/2), wrongAnswers);
        mvwprintw (window, (WINDOWHEIGHT/2), (WINDOWWIDTH/2)-(strlen(instructionsString)/2), instructionsString);


        switch (state) {
        case START:
                break;
        case CORRECT:
                mvwprintw (window, WINDOWHEIGHT-5, (WINDOWWIDTH/2)-(strlen(correctGuess)/2), correctGuess);
                myGame.rightGuesses++;
                break;
        case INCORRECT:
                mvwprintw (window, (WINDOWHEIGHT-5), (WINDOWWIDTH/2)-(strlen(incorrectGuess)/2), incorrectGuess);
                myGame.wrongGuesses++;
                break;
        case WRONGFORMAT:
                mvwprintw (window, (WINDOWHEIGHT-5), (WINDOWWIDTH/2)-(strlen(wrongFormat)/2), wrongFormat);
                break;

        }
        wrefresh (window);

}

int main (int argc, char **argv)
{
        WINDOW *my_win;
        initscr();
        // Here we call crea_newwin to make new window, paremeters are static and defined at the top of file
        // You can try to play with these numbers
        my_win = create_newwin(WINDOWHEIGHT, WINDOWWIDTH, WINDOWSTARTY, WINDOWSTARTX);
        // Initialization of random generator, should only be called once.
        srand(time(NULL));

        initializeGame();
        // Update window once before enteringing loop
        updateWindowTexts(my_win,START);
        while(1)
        {
                updateWindowTexts(my_win,getGuess());
        }
        return 0;
}

gcc версия:

/u1/stuff/C/projectFinal> gcc game.c
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `create_newwin':
game.c:(.text+0x73): undefined reference to `newwin'
/usr/bin/ld: game.c:(.text+0xa8): undefined reference to `wborder'
/usr/bin/ld: game.c:(.text+0xb8): undefined reference to `wrefresh'
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `updateWindowTexts':
game.c:(.text+0x251): undefined reference to `wclear'
/usr/bin/ld: game.c:(.text+0x285): undefined reference to `wborder'
/usr/bin/ld: game.c:(.text+0x2c5): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x301): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x33d): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x379): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x3f4): undefined reference to `mvwprintw'
/usr/bin/ld: /tmp/ccOy8YhK.o:game.c:(.text+0x444): more undefined references to `mvwprintw' follow
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `updateWindowTexts':
game.c:(.text+0x4a3): undefined reference to `wrefresh'
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `main':
game.c:(.text+0x4ba): undefined reference to `initscr'
collect2: error: ld returned 1 exit status

1 Ответ

0 голосов
/ 07 декабря 2018

Прежде всего, вы не можете создать Makefile для чего-либо, если вы не знаете, как сделать это вручную.Итак, давайте сначала исправим ваши проблемы компиляции и компоновки.Чтобы скомпилировать тип вашей программы:

gcc -c game.c

Опция -c сообщает gcc, что вы просто хотите скомпилировать, а не ссылаться.Эта команда создает объектный файл с именем game.o.Для автоматизации этого с make вам ничего не нужно: make уже знает, как это сделать.Без Makefile просто наберите:

make game.o CC=gcc

и make сделает эту работу.Обратите внимание, что мы сообщаем make, какой компилятор использовать, передавая ему в командной строке значение для его стандартной переменной make CC.

Далее мы хотим связать все объектные файлы нашего проекта (только game.o вв нашем случае, но у нас может быть несколько, соответствующих нескольким различным исходным файлам) и генерировать исполняемый файлЗдесь важно понимать, что вы используете библиотеку уже существующих функций (ncurses), которая по умолчанию не связана ни с каким исполняемым файлом, поскольку большинство программ не используют ее.Вы должны указать gcc связать ваши объектные файлы с этой библиотекой, используя параметр -lncurses:

gcc game.o -o game -lncurses

Обратите внимание, что в очень простом примере, подобном этому, вы можете скомпилировать и связать в одномпозвоните по номеру gcc:

gcc game.c -o game -lncurses

И снова, make уже знает, как все это сделать.Просто нужно передать параметр связывания -lncurses благодаря другой стандартной переменной make LDLIBS:

make game CC=gcc LDLIBS=-lncurses

И все, вы должны быть в состоянии играть в свою игру.Если вы хотите обрабатывать все детали в реальном Makefile, то все должно быть в порядке:

game: game.c
    gcc game.c -o game -lncurses

Но гораздо более подходящим решением было бы:

CC     := gcc
LDLIBS := -lncurses

game: game.c
    $(CC) $^ -o $@ $(LDLIBS)

InЧтобы понять это, вам придется потратить некоторое время с GNU make manual , но вот краткое и минимальное объяснение.В обеих версиях:

<target>: <prerequisite>
    <recipe>

говорит make, что для сборки <target> необходимо иметь <prerequisite> и запустить <recipe>.Это также говорит make, что если <target> новее <prerequisite>, то нет необходимости перестраивать <target>.В первой версии выше, с:

game: game.c
    gcc game.c -o game -lncurses

make знает, что:

  • , если game.c не существует, он не может собрать game;если его так попросят, то возникнет ошибка
  • , если game существует и новее game.c, то для сборки game
  • делать нечегоесли game не существует или если он старше game.c, он должен работать:

    gcc game.c -o game -lncurses
    

Во второй версии:

VARNAME := <value>

это синтаксис make для установки переменной make с именем VARNAME в значение <value>, в то время как $(VARNAME) является синтаксисом make для получения значения make variable VARNAME.$@ и $^ - это две автоматические переменные , значения которых являются, соответственно, целью и списком всех предпосылок правила, в рецепте которых они появляются.

...