Makefile в C (Ubuntu) множественное определение - PullRequest
0 голосов
/ 15 декабря 2018

Я учусь c и пытаюсь собрать, используя makefile.Я застрял на следующей ошибке и не знаю, что делать дальше.

команда сборки: gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o

Если мне нужны оба файла file_utils.o и cmdargutils.o, но если ядобавить оба я получаю следующую ошибку.

скриншот ошибки

ОШИБКА

file_utils.o:(.rodata+0x0): multiple definition of `MAX_LINE'
logfind.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'logfind' failed
make: *** [logfind] Error 1

Источник: Makefile

logfind: clean logfind.o
    gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o

logfind.o: logfind.c cmdargutils.o file_utils.o filesystem_utils.o strutils.o error_codes.h
    gcc -c logfind.c

cmdargutils.o: cmdargutils.c cmdargutils.h
    gcc -c cmdargutils.c

file_utils.o: file_utils.c file_utils.h
    gcc -c file_utils.c

filesystem_utils.o: filesystem_utils.c filesystem_utils.h
    gcc -c filesystem_utils.c

strutils.o: strutils.c strutils.h
    gcc -c strutils.c

clean:
    rm -f *.o logfind

cmdargutils.h

#ifndef CMD_ARG_UTILS
#define CMD_ARG_UTILS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include "error_codes.h"
#include "strutils.h"

struct Argument {
    bool is_and_operation;
    int count;
    char **search_terms;
};

struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation);
void argument_destroy(struct Argument *argument);
struct Argument *parse_arguments(int argc, char **argv);

#endif

error_codes.h

#ifndef ERROR_CODES
#define ERROR_CODES

enum error_codes {
    MEMORY_ERROR,
    INPUT_ERROR
};

#endif

file_utils.h

#ifndef FILE_UTILS
#define FILE_UTILS

#define _GNU_SOURCE

#include <stdio.h>
#include <stdbool.h>
#include <string.h> 
#include <stdlib.h>
#include "cmdargutils.h"

const size_t MAX_LINE = 1024;

bool is_match(char *, struct Argument *); 
bool scan_file(char *, struct Argument *);

#endif

filesystem_utils.h

#ifndef FILESYSTEM_UTILS
#define FILESYSTEM_UTILS

#include <glob.h>
#include <string.h>
#include "strutils.h"

struct SearchFiles {
    int count;
    char **paths;
};

struct SearchFiles *search_files_create(int count, char** paths);
void search_files_destroy(struct SearchFiles *search_files);
struct SearchFiles *scan_directory(char *directory_path, char *pattern);

#endif

strutils.h

#ifndef STRUTILS
#define STRUTILS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error_codes.h"

char *strdup(const char *source);
char **copy_string_array(char **source, int start, int end);

#endif

logfind.c

#include <stdio.h>
#include <stdlib.h>
#include <glob.h>
#include "cmdargutils.h"
#include "filesystem_utils.h"
#include "file_utils.h"

int main(int argc, char **argv) {
    struct Argument *argument = parse_arguments(argc, argv);
    int i = 0;

    struct SearchFiles *search_files = scan_directory(".", "*.*");
    for(i = 0; i < search_files->count; i++) {
        scan_file(search_files->paths[i], argument);
    }

    search_files_destroy(search_files);
    argument_destroy(argument);
    return 0;    
}

cmdargutils.c

#include "cmdargutils.h"

struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation){
    struct Argument *argument = (struct Argument *)malloc(sizeof(struct Argument));

    if(!argument) {
        printf("Could not initialize arguments.\n"); 
        exit(MEMORY_ERROR);
    }
    argument->count =  argc - start;
    argument->is_and_operation = is_and_operation;
    argument->search_terms = copy_string_array(argv, start, argc);

    return argument; 
}

void argument_destroy(struct Argument *argument){
    int i = 0;

    for(i = 0; i < argument->count; i++) {
        free(argument->search_terms[i]);
    }

    free(argument->search_terms); 
    free(argument);
    argument = NULL;    
}

struct Argument *parse_arguments(int argc, char **argv) {

    struct Argument *argument = NULL;
    bool is_and_operation = true;
    int start = 0;

    if(argc < 2) {
        printf("Not enough arguments\n");
        exit(INPUT_ERROR);
    }

    char *operation = argv[1];
    if(strcmp(operation, "-o") == 0) {
        is_and_operation = false;

        if(argc < 3) {
            printf("Not enough arguments\n");
            exit(INPUT_ERROR);
        }
    }

    start = is_and_operation ? 1 : 2;

    argument = argument_create(argc, argv, start, is_and_operation); 

    return argument;
}

file_utils.c

#include "file_utils.h"

bool is_match(char *line, struct Argument *argument) {
    int i = 0;
    bool isMatch = false;
    for(i = 0; i < argument->count; i++) {
        char *found = strcasestr(line, argument->search_terms[i]);
        if(!found) {
            if(argument->is_and_operation) {
                isMatch = false;
                break;
            } else {
                continue;
            }
        } else {
            isMatch = true;
            if(argument->is_and_operation) {
                continue;
            } else {
                break;
            }
        }
    }
    return isMatch;
}

bool scan_file(char *path, struct Argument *argument) {
    FILE *file = fopen(path, "r");

    int line_number = 0;
    char *line = malloc(MAX_LINE);

    while(fgets(line, MAX_LINE - 1, file)!= NULL) {
        ++line_number;
        if(is_match(line, argument)) {
            printf("%s:%d\n", path, line_number);
            printf("\t%s\n", line);
        }
    }

    free(line);
    fclose(file);
} 

filesystem_utils.c

#include "filesystem_utils.h"

struct SearchFiles *search_files_create(int count, char** paths) {
    struct SearchFiles *search_files = (struct SearchFiles *)malloc(sizeof(struct SearchFiles));

    search_files->count = count;
    search_files->paths = copy_string_array(paths, 0, count); 

    return search_files;    
}

void search_files_destroy(struct SearchFiles *search_files) {
    int i = 0;

    for(i = 0; i < search_files->count; i++) {
        free(search_files->paths[i]);    
    }

    free(search_files->paths);
    free(search_files);
    search_files = NULL;
}

struct SearchFiles *scan_directory(char *directory_path, char *pattern) {
    glob_t globbuf;
    int error = glob(pattern, GLOB_MARK, NULL, &globbuf);

    if(!error) {
        struct SearchFiles *search_files = search_files_create(globbuf.gl_pathc, globbuf.gl_pathv);
        globfree(&globbuf);
        return search_files;
    }
    return NULL;
}

strutils.c

#include "strutils.h"

char *strdup(const char *source) {
    char *dest = malloc(strlen(source) + 1);
    if(!dest) {
        printf("Memory allocation error\n");
        exit(MEMORY_ERROR);
    }
    strcpy(dest, source);
    return dest;
}

char **copy_string_array(char **source, int start, int end) {
    char **dest = (char **)malloc(sizeof(char *) * (end - start));
    int di = 0;
    int si = start;

    for(di = 0, si = start; si < end; 
        si++, di++) {
        dest[di] = strdup(source[si]);        
    }

    return dest;
}

1 Ответ

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

читать документацию!

Сначала потратьте несколько часов, чтобы прочитать документацию GNU make и прочитать, как вызывает GCC .Вам также нужно больше узнать о препроцессоре , поэтому прочитайте документацию cpp.Вы хотите воспользоваться встроенными правилами GNU make (поэтому запустите make -p, чтобы понять их) и переменными.Смотрите также этот ответ.Вы можете использовать римейк (как remake -x) для отладки вашего Makefile.Вы, очевидно, не понимаете, как make и как gcc следует использовать, поэтому вам нужно прочитать больше.Прочтите также учебник C , посмотрите справочный материал C и, при необходимости, загляните в C11 стандарт n1570 .Конечно, прочитайте документацию по каждой используемой вами функции (например, printf (3) и т. Д.).Для системного программирования Linux прочитайте книгу типа ALP и соответствующие man страницы из системных вызовов (2) и intro (3) и т.д ...

Затем прочитайте Как отлаживать небольшие программы .Вы наверняка захотите скомпилировать все предупреждения и информацию отладки.


лучше Makefile

Вы можете попробовать что-то вроде:

# a better Makefile
# your C compiler
CC= gcc

# the verbose remove
RM= rm -vf

# your C compilation flags
CFLAGS= -Wall -Wextra -g

# your C source files
MY_CSOURCES= logfind.c cmdargutils.c filesystem_utils.c file_utils.c strutils.c

# the corresponding object files
MY_OBJECTS= $(patsubst %.c, %.o, $(MY_CSOURCES))

# the conventional phony targets
.PHONY: all clean

# the only program is for the default target all
all: logfind
logfind: $(MY_OBJECTS)
     $(LINK.c) $< -o $@

# cleaning the mess
clean: 
     $(RM) logfind *.o *~

Конечно,вам нужны зависимости для объектных файлов в заголовочных файлах.Вы можете вычислить их автоматически, но их проще явно указать, поэтому добавьте что-то вроде:

strutils.o: strutils.c strutils.h

и т. Д. Для друг друга объектных файлов.

BTW my HelloWorld /Каталог на github - это учебный пример использования make


вашего множественного определения ошибка

Вы получаете multiple definition of MAX_LINE, потому что это определено в заголовочном файле, включенном в несколько единиц перевода , следовательно, несколько единиц перевода определяют его.

Так что либо сделайте его постоянной препроцессора #define MAX_LINE 1024 в своем заголовке file_utils.h или поместите туда только объявление , например extern const int MAX_LINE; и , определите только один раз в одной единице перевода, как const int MAX_LINE=1024; в file_utils.c


общие советы

Я настоятельно рекомендую сделать итеративную и инкрементальную разработку : кодировать только одну или две дюжины строк одновременно, затем компилировать их, улучшать их, чтобы не получать предупреждений, отлаживать их с помощью GDB отладчик и тест tрубчик.Наконец, повторяйте все это, пока не будете удовлетворены.Я также рекомендую использовать систему контроля версий (например, git ) даже для школьных домашних заданий.

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

Вы также можете использовать некоторый статический анализатор источника, например clang-analyzer или даже Frama-C .

После того, как ваша программа отлажена, вы можете добавить флаги оптимизации как -O2 в CFLAGS (в частности, если вы сравните ее с время (1) ).

Вас может заинтересовать ntfw (3) .

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