Makefile 重复符号

Posted

技术标签:

【中文标题】Makefile 重复符号【英文标题】:Makefile duplicate symbol 【发布时间】:2015-04-20 04:47:29 【问题描述】:

我想花一点时间,我知道 SO 充斥着这些问题,而且我看过很多:

Xcode C++ :: Duplicate Symbols for Architecture x86_64 Duplicate symbols for architecture x86_64 under Xcode ld: 1 duplicate symbol for architecture x86_64

我目前正在使用 C++ 为一个学校项目构建一个反汇编程序,当我运行我的 make 文件时,我遇到了重复符号错误。我担心我的问题比上面引用的例子要复杂一些。对于重复的问题,我深表歉意,但经过数小时的搜索和尝试解决问题后我无法弄清楚,我感谢任何人提供的任何建设性、完整和积极的反馈。

g++ 3.4.6 版(是的,我知道,它很旧——学校服务器) make 3.81版

这是我的生成文件:

CC=g++
CFLAGS=-Wall -O0 -c

all: dasm

dasm: main.o optab.o record_tokenizer.o regex.o
    $(CC) -o $@ $^

clean:
    rm *.o dasm

看起来 Make 能够将所有文件转换为各自的目标文件,但链接到单个可执行文件是失败的:

c++    -c -o main.o main.cpp
c++    -c -o optab.o optab.cpp
c++    -c -o record_tokenizer.o record_tokenizer.cpp
c++    -c -o regex.o regex.cpp
g++ -o dasm main.o optab.o record_tokenizer.o regex.o
duplicate symbol _optab in:
    main.o
    optab.o
duplicate symbol _optab in:
    main.o
    record_tokenizer.o
duplicate symbol _HEADER_RECORD_REGEX in:
    main.o
    record_tokenizer.o
duplicate symbol _END_RECORD_REGEX in:
    main.o
    record_tokenizer.o
duplicate symbol _TEXT_RECORD_REGEX in:
    main.o
    record_tokenizer.o
duplicate symbol _MOD_RECORD_REGEX in:
    main.o
    record_tokenizer.o
ld: 6 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [dasm] Error 1

我绝对不是 C++ 专家,也不是 Makefile 专家,因此不胜感激。以下是相关文件:

optab.h

#ifndef __dasm__optab__
#define __dasm__optab__

#include <map>
#include <string>

std::map<short, const char*> optab;

void init_optab();
const char* get_instruction(int n);

#endif

regex.h

#ifndef __dasm__regex__
#define __dasm__regex__

#include <regex.h>

bool match(const char* pattern, const char* string);

#endif

record_tokenizer.h

#ifndef __dasm__record_tokenizer__
#define __dasm__record_tokenizer__

#include <vector>
#include <cstdlib>
#include <sstream>
#include "regex.h"
#include "optab.h"

const char* HEADER_RECORD_REGEX = "^H[a-zA-Z|[:space:]]6[:digit:]12";
const char* END_RECORD_REGEX = "^E([:digit:]6)?";
const char* TEXT_RECORD_REGEX = "^T[:digit:]6[0-1][0-E][:digit:],60"; // TODO: improve on this
const char* MOD_RECORD_REGEX = "^M[:digit:]8";

struct Record 
    char record_type;
    std::string name;
    std::string address;
    std::vector<std::string> addresses; // used for T records only
;


bool is_valid_record(const char* record, const char* pattern);
const int to_i(std::string n);
const Record tokenize_record(std::string record);

#endif

ma​​in.cpp

#include <iostream>
#include "record_tokenizer.h"

using namespace std;

int main(int args, const char* argv[]) 
    if(args > 2) 
        std::cerr << "Usage: dasm sample.obj" << std::endl;
        exit(EXIT_FAILURE);
    
    tokenize_record("T0000001E^050000^032003^3F^69101791^1BA0131BC0002F200A3B2FF40F102F014F0000");

    return 0;

【问题讨论】:

make 文件中的 $^ 是什么意思?我知道 $ 不知道。我在 SO 上找到了 Makefile,它可以工作。我还没来得及看它到底做了什么。 @GRC。 $gnu.org/software/make/manual/html_node/Automatic-Variables.html。 @RSahu 谢谢!!! :) 每天学习新东西 :) 【参考方案1】:

optab.h 中的这一行有问题:

std::map<short, const char*> optab;

每个包含此 .h 文件的 .cpp 文件都将 optab 定义为全局变量。这会导致符号被多次定义。

以下几行也会产生同样的错误:

const char* HEADER_RECORD_REGEX = "^H[a-zA-Z|[:space:]]6[:digit:]12";
const char* END_RECORD_REGEX = "^E([:digit:]6)?";
const char* TEXT_RECORD_REGEX = "^T[:digit:]6[0-1][0-E][:digit:],60";
const char* MOD_RECORD_REGEX = "^M[:digit:]8";

record_tokenizer.h.

您可以通过以下方式修复它们:

    通过将它们设为extern 变量并仅在一个.cpp 文件中定义它们。

    通过将它们设为static 变量。

    将它们设为const。这适用于字符串,但不适用于optab。我想你需要改变它的价值。

    const char* const HEADER_RECORD_REGEX =  ...;
    const char* const END_RECORD_REGEX = ...;
    const char* const TEXT_RECORD_REGEX = ...;
    const char* const MOD_RECORD_REGEX = ...;
    

【讨论】:

三个选项中哪一个是最佳实践? 对于optab,我会使用 (1)。对于***_REGEX,我会使用 (3)。 const char* const ... 到底是做什么的?这似乎过于混乱 这意味着,您无法更改指针指向的位置,也无法更改它们指向的值。 哇,这是一次旅行!我不知道您对指针和值有这么多的控​​制权。那么我在头文件中的定义到底是什么?【参考方案2】:

这是 google 中“duplicate symbol cerr”的第一个结果,所以我认为在这里回复会有所帮助。

新的 gcc/clang (v10, v11) 版本默认对重复符号更加严格,但可以使用 -fcommon 标志调整此行为

clang main.c -fcommon

【讨论】:

以上是关于Makefile 重复符号的主要内容,如果未能解决你的问题,请参考以下文章

STM32CubeMX 正在生成带有重复 C_SOURCES 的 Makefile

@: (在符号冒号处)在 Makefile 中是啥意思?

错误 LNK2019:Visual Studio 中未解析的外部符号 [重复]

makefile中一些符号的含义

Makefile 中的四个美元符号

makefile中加入了-g选项,但是在dbx调试的时候却提示找不到文件或符号表