【问题标题】:Makefile in C (ubuntu) multiple definitionC(ubuntu)中的Makefile多重定义
【发布时间】:2019-05-16 08:26:23
【问题描述】:

我正在学习 c 并尝试使用 makefile 进行构建。我被以下错误困住了,不知道下一步该怎么做。

构建命令是 gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o

如果我同时需要 file_utils.o 和 cmdargutils.o 但如果我同时添加两者,则会收到以下错误。

error screenshot

错误

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

来源是: 制作文件

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;
}

【问题讨论】:

  • 您的Makefile 不好,因为它没有利用内置规则(由make -p 获得)。请参阅this 答案。
  • 你真的应该多花几天时间阅读。
  • 不要在你的问题中放截图,复制粘贴错误信息。
  • 你应该多阅读并改善你的编码习惯。祝你好运!

标签: c makefile


【解决方案1】:

阅读文档!

首先,花几个小时阅读GNU make 的文档,并阅读如何阅读invoke GCC。您还需要了解更多关于preprocessor 的信息,请阅读documentation of cpp。你想利用内置的 GNU make 规则(所以运行 make -p 来理解它们)和变量。另请参阅this 答案。您可以使用remake(如remake -x)来调试您的Makefile。你显然不明白makegcc 应该如何使用,所以你需要阅读更多。另请阅读C tutorial,查看一些C reference,并在需要时查看C11 标准n1570。当然,请阅读您使用的 每个 函数的文档(例如 printf(3) 等)。对于Linux系统编程,请阅读ALP之类的书以及syscalls(2)intro(3)等相关的man页面...

然后阅读How to debug small programs。您当然希望在编译时包含所有警告和调试信息。


更好的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

对象文件以此类推。

顺便说一句,我在 github 上的 HelloWorld/ 目录是使用 make 的教程示例


你的多重定义错误

您得到multiple definition of MAX_LINE,因为它定义在几个translation units 包含的头文件中,因此有几个翻译单元定义了它。

所以要么在你的标头file_utils.h 中将其设为预处理器常量#define MAX_LINE 1024,要么只在其中放置一个声明,如extern const int MAX_LINE;定义它只在单个翻译单元,如 const int MAX_LINE=1024; in file_utils.c


一般提示

我强烈建议做一些iterative and incremental development:一次只编写一两行代码,然后编译它们,改进它们以获得不警告,使用GDB debugger 调试它们并测试它们。最后重复所有这些直到满意为止。我也建议使用version control 系统(如git),即使是学校作业。

您可能想使用valgrind 来寻找memory leaks 和其他dynamic memory allocation 错误。

您还可以使用一些静态源分析器,例如 clang-analyzer 甚至 Frama-C

一旦您的程序被调试,您可以将optimization flags-O2 添加到您的CFLAGS 中(特别是如果您使用time(1) 对其进行基准测试)。

您可能对ntfw(3)感兴趣。

【讨论】:

  • 非常感谢。如果您不介意,还有一个问题:我正在通过“Learn C the hard way book”学习 c。它非常好,需要在互联网上进行大量搜索才能学习作者鼓励的概念。我想问你学习 C 的更好方法是什么。我的目标是学习 Linux 系统并最终尝试内核编程?
  • 阅读norvig.com/21-days.html 以获得有用的见解(您需要很多的工作)。顺便说一句,我推荐阅读SICP,这是一本很好的编程入门书(你想成为一名开发人员,而不仅仅是一名 C 编码员)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多