1

I want to take a brief moment that I'm aware SO is littered with these questions and I've looked at many:

I'm currently building a disassembler for a school project using C++ and I'm getting blasted with duplicate symbol errors when I run my make file. I fear my issue is a little more complicated than the examples cited above. I apologize for the duplicate question but I can't figure it out after hours of searching and attempting to fix the issue and I appreciate any constructive, complete, and positive feedback anyone has.

  • g++ version 3.4.6 (yes, I know, it's old – school server)
  • make version 3.81

Here's my makefile:

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

all: dasm

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

clean:
    rm *.o dasm

It looks like Make is able to convert all files to their respective object files but the linking into the single executable is what's failing:

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

I'm definitely not a C++ expert nor am I a Makefile guru so any help is appreciated. Here are the relevant files:

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

main.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;
}
Community
  • 1
  • 1
djthoms
  • 3,026
  • 2
  • 31
  • 56
  • what do you mean by $^ in make file? I know for $< which goes back to the beginning of stack? –  Apr 20 '15 at 05:04
  • No idea tbh. I found the Makefile on SO and it works. I haven't had time to look at what it actually does. – djthoms Apr 20 '15 at 05:05
  • @GRC. $< and $^ are two different variables. See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html. – R Sahu Apr 20 '15 at 05:26
  • @RSahu thank you!!! :) Learning something new every day :) –  Apr 20 '15 at 05:27

2 Answers2

2

This line in optab.h is a problem:

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

Every .cpp file that includes this .h file defines optab as a global variable. That would result in the symbol defined multiple times.

Same errors will result from the lines:

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

in record_tokenizer.h.

You can fix them by:

  1. By making them extern variables and defining them in only one .cpp file.

  2. By making them static variables.

  3. By making them const. This would work for the strings but not optab. I imagine you will need to change its value.

    const char* const HEADER_RECORD_REGEX =  ...;
    const char* const END_RECORD_REGEX = ...;
    const char* const TEXT_RECORD_REGEX = ...;
    const char* const MOD_RECORD_REGEX = ...;
    
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    Which of the three options is best practice? – djthoms Apr 20 '15 at 05:04
  • 2
    For `optab`, I would use (1). For the `***_REGEX`, I would use (3). – R Sahu Apr 20 '15 at 05:05
  • What exactly does `const char* const ...` do? That seems overly confusing – djthoms Apr 20 '15 at 05:07
  • 1
    It means, you cannot change where the pointers point and you cannot change the values of what they point to. – R Sahu Apr 20 '15 at 05:08
  • Whoa, that's a trip! I didn't know you had that much control over pointers and values. So my definition in the header file would be what exactly? – djthoms Apr 20 '15 at 05:11
  • `const char* HEADER_RECORDS_REGES` is actually referring to constant pointer, would `char* constant HEADER_RECORDS_REGES` which says that what is stored inside memory is constant, be enough for him? We do not care if pointer changes but content should not? –  Apr 20 '15 at 05:11
  • The reference to the regex string shouldn't change so it seems fitting for it to be constant – djthoms Apr 20 '15 at 05:13
  • @djthoms, see [my answer to another SO post](http://stackoverflow.com/a/27739028/434551) that talks little bit more about `const` qualifiers and pointers. – R Sahu Apr 20 '15 at 05:20
  • Okay, I'm just wondering because no combination seems to be working in the header and cpp file. Says I can't redefine it. – djthoms Apr 20 '15 at 05:20
0

This was the first result in google for "duplicate symbol cerr", so I think it'd help to respond here.

New gcc/clang (v10, v11) versions are by default more strict about duplicate symbols, but this behavior can be adjusted with the -fcommon flag

clang main.c -fcommon
Christopher Mauney
  • 459
  • 1
  • 5
  • 10