Как скомпилировать несколько файлов с использованием make-файла в Linux - получение переменных ошибок - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь скомпилировать 5 *.c файлов, используя Makefile (gcc -o prog add.c create.c delete.c display.c main.c), но получаю variable is not declared ошибки.Я поставил main.c первым в приведенной выше команде, но все еще с той же ошибкой.Может кто-то указать, что я делаю не так, и как я могу сделать переменную, чтобы она могла быть прочитана компилятором?

Опять же код ниже разделен на 5 файлов Ошибка:

add.c: In function ‘add’:
add.c:3:2: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
  printf("\n\n\t\t\t\t*****ADD Menu*****");
  ^~~~~~
add.c:3:2: warning: incompatible implicit declaration of built-in function ‘printf’
add.c:3:2: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
add.c:5:6: error: ‘left’ undeclared (first use in this function)
  if (left == SIZE - 1)
      ^~~~
add.c:5:6: note: each undeclared identifier is reported only once for each function it appears in
add.c:5:14: error: ‘SIZE’ undeclared (first use in this function)
  if (left == SIZE - 1)
              ^~~~
add.c:12:3: warning: implicit declaration of function ‘scanf_s’ [-Wimplicit-function-declaration]
   scanf_s("%d", &holder);
   ^~~~~~~
add.c:15:3: error: ‘numarr’ undeclared (first use in this function)
   numarr[left] = holder;
   ^~~~~~
add.c:16:7: error: ‘right’ undeclared (first use in this function)
   if (right == -1)
       ^~~~~
create.c: In function ‘create’:
create.c:3:2: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
  printf("\n\n\t\t\t\tArray has been created with the size of 10 elements");
  ^~~~~~
create.c:3:2: warning: incompatible implicit declaration of built-in function ‘printf’
create.c:3:2: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
delete.c: In function ‘delete’:
delete.c:4:6: error: ‘right’ undeclared (first use in this function)
  if (right == -1)
      ^~~~~
delete.c:4:6: note: each undeclared identifier is reported only once for each function it appears in
delete.c:6:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
   printf("\n\n\t\t\t\tERROR! Queue is empty. Please add element before deleting them");
   ^~~~~~
delete.c:6:3: warning: incompatible implicit declaration of built-in function ‘printf’
delete.c:6:3: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
delete.c:10:12: error: ‘numarr’ undeclared (first use in this function)
   holder = numarr[right];
            ^~~~~~
delete.c:11:3: warning: incompatible implicit declaration of built-in function ‘printf’
   printf("\n\n\t\t\t\tSUCCESS. Deleted item: %d", holder);
   ^~~~~~
delete.c:11:3: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
delete.c:13:15: error: ‘left’ undeclared (first use in this function)
  if (right == left)
               ^~~~
display.c: In function ‘display’:
display.c:4:6: error: ‘right’ undeclared (first use in this function)
  if (right == -1)
      ^~~~~
display.c:4:6: note: each undeclared identifier is reported only once for each function it appears in
display.c:6:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
   printf("\n\n\t\t\t\tEmter elements to array to be displayed here!");
   ^~~~~~
display.c:6:3: warning: incompatible implicit declaration of built-in function ‘printf’
display.c:6:3: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
display.c:10:3: warning: incompatible implicit declaration of built-in function ‘printf’
   printf("\n\n\t\t\t\tDisplay of current elements in queue: ");
   ^~~~~~
display.c:10:3: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
display.c:11:24: error: ‘left’ undeclared (first use in this function)
   for (i = right; i <= left; i++)
                        ^~~~
display.c:12:29: error: ‘numarr’ undeclared (first use in this function)
    printf("\n\n\t\t\t\t%d", numarr[i]);
                             ^~~~~~
main.c:3:10: fatal error: conio.h: No such file or directory
 #include <conio.h>
          ^~~~~~~~~
compilation terminated.

#include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #define SIZE 10
    int numarr[SIZE];
    int right, left;

    //function create is in separate c file named create.c
    void create()
    {
        printf("\n\n\t\t\t\tArray has been created with the size of 10 elements");
    }

    //function add is in separate c file named add.c
    void add()
    {
        printf("\n\n\t\t\t\t*****ADD Menu*****");
        int holder;
        if (left == SIZE - 1)
        {
            printf("\n\n\t\t\t\tQueue is FULL");
        }
        else
        {
            printf("\n\t\t\t\tEnter the element you wish to add into queue: ");
            scanf_s("%d", &holder);
            ++left;

            numarr[left] = holder;
            if (right == -1)
                right = 0;
        }
    }

    //function delete is in separate c file delete.c
    void delete()
    {
        int holder;
        if (right == -1)
        {
            printf("\n\n\t\t\t\tERROR! Queue is empty. Please add element before deleting them");
        }
        else
        {
            holder = numarr[right];
            printf("\n\n\t\t\t\tSUCCESS. Deleted item: %d", holder);
        }
        if (right == left)
        {
            right = left = -1;
        }
        else
        {
            right++;
        }
    }

    //function display is in separate c file named display.c
    void display()
    {
        int i;
        if (right == -1)
        {
            printf("\n\n\t\t\t\tEmter elements to array to be displayed here!");
        }
        else
        {
            printf("\n\n\t\t\t\tDisplay of current elements in queue: ");
            for (i = right; i <= left; i++)
                printf("\n\n\t\t\t\t%d", numarr[i]);
        }
    }

    //function main is in separate c file named main.c
    int main()
    {
        right = left = -1;
        int choice;
        do
        {
            printf("\n\n\t\t\t\tWELCOME TO C PROGRAM ON FIFO \n");
            printf("\t\t\t\t1. CREATE an array \n");
            printf("\t\t\t\t2. ADD to array \n");
            printf("\t\t\t\t3. DELETE from arra \n");
            printf("\t\t\t\t4. DISPLAY the array's content \n");
            printf("\t\t\t\t5. EXIT the program \n");
            printf("\t\t\t\tPlease SELECT from above options: ");
            scanf_s("%d", &choice);
            switch (choice)
            {
            case 1:
                //create
                create();
            break;

            case 2:
                //add
                system("cls");
                add();
                break;

            case 3:
                //delete
                delete();
                break;

            case 4:
                //display
                display();
                break;

            case 5:
                exit(0);
            }
        } while (choice != 5);

        return 0;
    }``

Ответы [ 4 ]

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

Вышеупомянутая программа теперь работает после того, как я внес следующие изменения в соответствии с ответами и предложениями: - Создан файл fundec.h и добавлен во все файлы .c.-Изменен scanf_s в scanf -Добавлен #include ко всем файлам -Удаленный #include

fundec.h содержит

#include <stdio.h>

//Global variables
#define SIZE 10
int numarr[SIZE];
int right, left;

//Declaration of functions
void create();
void add();
void delete();
void display();
0 голосов
/ 20 декабря 2018

Ваш вопрос фактически задает как Makefile, так и процесс компиляции.

Makefile файл содержит правила со следующей структурой:

output: input1 input2
   command_to_obtain_output_from_inputs

Проверка thisссылка , чтобы увидеть, как работает компиляция.Вы увидите другой шаг: предварительная обработка (т.е. замена макросов), компиляция, сборка (генерируйте машинный код из вашего файла, но не подставляя команды из внешних библиотек), связывание (соединение вашего машинного кода с машинным кодом внешних библиотек, чтобы вашфинальные исполняемые файлы).

Файл будет считываться с начала до тех пор, пока не будет найдено первое правило, определяющее конечный результат процесса.

Начиная с конца исполняемый файл является результатом процесса компоновки, для которого требуется *.o файлов.В Makefile это должно быть ваше первое правило (над всеми остальными), которое обычно выглядит примерно так:

исполняемый файл: o1.o o2.o gcc $ ^ -o $ @

где $@ - имя файла цели правила, executable в этом случае и $@ - все входные данные o1.0, o2.o.

, поскольку make хотя бы первоевремя не найдет эти файлы и продолжит сканирование Makefile, чтобы найти другое правило для их создания (файлы *.o).Такое правило может быть что-то вроде:

$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile 
    gcc -MMD -MP -c $< -o $@

, и это будет правильным правилом для создания всех необходимых *.o.

, где $< является первой предпосылкой, то есть соответствующей %.c файл.Также Makefile был добавлен в качестве зависимости для регенерации *.o в случае, если он изменен, но не используется в команде.-MMD создаст *.d файлы для зависимостей, но обычно это не нужно.

Makefile также позволяет вам определять переменные, чтобы вы могли ссылаться на них через весь ваш файл.Просто чтобы привести пример, я выложу Makefile моего.

CXX = gcc

SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=$(SOURCEDIR)/obj
LIBS = ... #your external libraries
CXXFLAGS = ... #your flags
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))

# ADD MORE WARNINGS!
WARNING := -Wall -Wextra

# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean

# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: ruptime

clean:
    $(RM) $(OBJECTS) $(DEPENDS) ruptime

# Linking the executable from the object files
# $^   # "src.c src.h" (all prerequisites)
ruptime: $(OBJECTS)
    $(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $@ $(LIBS)

-include $(DEPENDS)

$(OBJDIR):
    mkdir -p $(OBJDIR)
#Note the dependency from the folder $(OBJDIR) and the
#rule above to generate it. However with the symbol |
# no ricompilation is perform if the folder if it modified
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
    $(CXX) $(WARNING) -MMD -MP -c $< -o $@
0 голосов
/ 20 декабря 2018

Ну, вот как я это делаю,

Предположим, есть 5 .c файлов

main.c

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10

int right,left;
int numarr[SIZE];
extern void create();
extern void add();
extern void delete();
extern void display();
int main()
{
    right = left = -1;
    int choice;
    do
    {
        printf("\n\n\t\t\t\tWELCOME TO C PROGRAM ON FIFO \n");
        printf("\t\t\t\t1. CREATE an array \n");
        printf("\t\t\t\t2. ADD to array \n");
        printf("\t\t\t\t3. DELETE from arra \n");
        printf("\t\t\t\t4. DISPLAY the array's content \n");
        printf("\t\t\t\t5. EXIT the program \n");
        printf("\t\t\t\tPlease SELECT from above options: ");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            //create
            create();
        break;

        case 2:
            //add
            system("cls");
            add();
            break;

        case 3:
            //delete
            delete();
            break;

        case 4:
            //display
            display();
            break;

        case 5:
            exit(0);
        }
    } while (choice != 5);

    return 0;
}

delete.c

#include<stdio.h>
#define SIZE 10
extern int right,left,numarr[SIZE];
//function delete is in separate c file delete.c
void delete()
{
    int holder;
    if (right == -1)
    {
        printf("\n\n\t\t\t\tERROR! Queue is empty. Please add element before deleting them");
    }
    else
    {
        holder = numarr[right];
        printf("\n\n\t\t\t\tSUCCESS. Deleted item: %d", holder);
    }
    if (right == left)
    {
        right = left = -1;
    }
    else
    {
        right++;
    }
}

display.c

#include<stdio.h>
#define SIZE 10
extern int right,left,numarr[SIZE];
//function display is in separate c file named display.c
 void display()
 {
     int i;
     if (right == -1)
     {
         printf("\n\n\t\t\t\tEmter elements to array to be displayed here!");
     }
     else
     {
         printf("\n\n\t\t\t\tDisplay of current elements in queue: ");
         for (i = right; i <= left; i++)
             printf("\n\n\t\t\t\t%d", numarr[i]);
     }
 }

create.c

#include<stdio.h>

//function create is in separate c file named create.c
void create()
{
  printf("\n\n\t\t\t\tArray has been created with the size of 10 elements");
}

add.c

#include<stdio.h>
#define SIZE 10
//function add is in separate c file named add.c
extern int left,right;
extern int numarr[SIZE];
void add()
{
    printf("\n\n\t\t\t\t*****ADD Menu*****");
    int holder;
    if (left == SIZE - 1)
    {
        printf("\n\n\t\t\t\tQueue is FULL");
    }
    else
    {
        printf("\n\t\t\t\tEnter the element you wish to add into queue: ");
        scanf("%d", &holder);
        ++left;

        numarr[left] = holder;
        if (right == -1)
            right = 0;
    }
}

скомпилировать каждый файл .c в соответствующие объектные файлы и связать их вместе.

makefile

compile :
    gcc -c main.c -o main.o
    gcc -c create.c -o create.o
    gcc -c add.c -o add.o
    gcc -c delete.c -o delete.o
    gcc -c display.c -o display.o
    gcc main.o create.o add.o delete.o display.o -o file.o

для терничного типа

$ make compile

Обратите внимание, как я использовал ключевое слово extern для функций, а также для общих переменных.

Это работает так: во время компиляции компилятор видит используемый идентификатор / символ, который не определен в текущем файле.Ключевое слово extern сообщает компилятору, что этот символ был определен где-то еще.Наконец, в процессе компоновки ссылка на этот символ разрешается компоновщиком.

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

Вы разрабатываете программу, которую вы разделили на несколько «модулей».Каждый модуль представляет собой файл .c.

Когда вы компилируете все эти модули, компилятор создает файл .o для каждого файла .c , не зная, что они связаны .Каждая компиляция называется «модулем компиляции».

Чтобы «сообщить» компилятору исходные файлы, вы создаете файлы .h, которые вы можете #include в своих файлах .c и которые содержат информацию одругие модули, которые должен знать каждый файл .c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...