C(ubuntu)多重定义中的Makefile [英] Makefile in C (ubuntu) multiple definition

查看:88
本文介绍了C(ubuntu)多重定义中的Makefile的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am learning c and trying to build using makefile. I am stuck on the following error and don't know what to do next.

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

the build command is gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o

如果我同时需要file_utils.o和cmdargutils.o,但是如果我同时添加,则会出现以下错误.

If I need both file_utils.o and cmdargutils.o but if I add both I get the following error.

错误屏幕截图

错误

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

推荐答案

阅读文档!

首先,花几个小时阅读 GNU make ,并了解如何调用GCC .您还需要进一步了解预处理器,因此请阅读答案.您可以使用重新制作(作为remake -x)来调试Makefile.您显然不了解应该如何使用makegcc,因此您需要阅读更多内容.另请阅读 C教程,查看一些 C11 标准 n1570 .当然,请阅读您使用的每个函数的文档(例如, ALP 之类的书以及来自 syscalls(2)

read documentation!

First, take a few hours to read documentation of GNU make, and read how to invoke GCC. You also need to understand more about the preprocessor, so read documentation of cpp. You want to take advantage of builtin GNU make rules (so run make -p to understand them) and variables. See also this answer. You could use remake (as remake -x) to debug your Makefile. You apparently don't understand how make and how gcc should be used, so you need to read more. Read also a C tutorial, look into some C reference, and glance when needed into the C11 standard n1570. Of course, read the documentation of every function you use (e.g. printf(3) etc..). For Linux system programming, read a book like ALP and relevant man pages from syscalls(2) and intro(3) etc...

然后阅读 如何调试小型程序 .您当然想编译所有警告和调试信息.

Then read How to debug small programs. You certainly want to compile with all warnings and debug info.

您可以尝试以下方法:

# 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 *~

当然,您需要目标文件与头文件的依赖关系.您可以自动计算它们,但是显式它们更简单,因此添加如下内容:

Of course, you need dependencies for object files on header files. You could compute them automatically, but it is simpler to explicit them, so add something like:

strutils.o: strutils.c strutils.h

以此类推,以获取其他目标文件.

and so on for each other object files.

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

BTW my HelloWorld/ directory on github is a tutorial example for using make

您正在获取multiple definition of MAX_LINE,因为它是由定义 ="nofollow noreferrer">翻译单元,因此有多个翻译单元对其进行定义.

You are getting multiple definition of MAX_LINE because it is defined in a header file included by several translation units, hence several translation units define it.

因此,可以在标头file_utils.h中将其设置为预处理器常量#define MAX_LINE 1024,或仅在其中放置一次声明(例如extern const int MAX_LINE; define )单个翻译单元,如file_utils.c

So either make it a preprocessor constant #define MAX_LINE 1024 in your header file_utils.h, or put there only a declaration like extern const int MAX_LINE; and define it only once in a single translation unit, as const int MAX_LINE=1024; in file_utils.c

我强烈建议您进行一些迭代和增量开发:仅编写一两行代码一次,然后对其进行编译,对其进行改进以使其不产生任何警告,然后使用 GDB调试器并对其进行测试.最后重复所有这些直到满意为止.我确实建议您也使用版本控制系统(例如

I strongly recommend doing some iterative and incremental development: code only one or two dozen lines at once, then compile them, improve them to get no warnings, debug them with the GDB debugger and test them. At last repeat all this till satisfied. I do recommend using also a version control system (like git) even for school homework.

您可能想使用 valgrind 来狩猎动态内存分配错误.

You might want to use valgrind to hunt memory leaks and other dynamic memory allocation bugs.

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

You could also use some static source analyzer like clang-analyzer or even Frama-C.

一旦调试了程序,就可以在您的计算机中添加优化标志 CFLAGS(特别是如果您使用 time(1)).

Once your program is debugged, you might add optimization flags like -O2 into your CFLAGS (in particular if you benchmark it with time(1)).

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

这篇关于C(ubuntu)多重定义中的Makefile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆