Sign in to follow this  
Drakkcon

Please help me get rid of another cryptic linker error

Recommended Posts

Drakkcon    612
I know I just asked a similar question a few hours ago, but I feel like throwing my computer across the room right now in anger! *one...two...three* phew Okay, MinGW is NOT giving me the proper information on this linker error. I really hope it isn't something trivial, because I have been working on it for the past hour to no avail. The file I THINK it's happening in is this one:
////////////////////////////////////////////////////////////////////////////////
//instruction is an abstract base class. In order to create instructions, you inherit from
//this abstract base. std::string name is what you have to type in order to access
//this instruction, so if name = "Print", then inside the script you would have to 
//type Print.
////////////////////////////////////////////////////////////////////////////////
//In order to use: add argument variables like so: Variable<whatever> argument1, etc.... 
//as arguments to the overloaded Execute function.
//type is where the instruction is used, like: World Map, or Battle, etc....
//redefine name for. After all of this they should overload Execute with whatever
//they need it to do, and how they want it to interpret arguments.
////////////////////////////////////////////////////////////////////////////////
#include "Variable.h"
#include <string>
#include <vector>

#ifndef STRATUS_INSTRUCTION_H
#define STRATUS_INSTRUCTION_H

namespace aeroscript
{

    class Instruction //virtual base
    {
        protected:
            std::string name;
            //this isn't important, just something like BATTLE or ACTION
            std::string type; 
        
        public:
            friend class InstructionList;
            //sets up the name, type, and uses InstructionList::Add(this)
            virtual void Initialize(){};
            virtual void Execute(){};
    };
    
    
    //this class holds a list of all the instructions for easy parsing by the script
    //the only reason this is in the same file is that if it's not, I become buffetted
    //with linker errors from hell.
    
    //screw you MinGW.
    class InstructionList_
    {
        std::vector<Instruction*> instructions;
        
        public:
            void Add(Instruction* instr_) 
            {
                instructions.push_back(instr_);
            }
    }InstructionList;

}

#endif


This is the error:
Script.o: In function `ZN9__gnu_cxx13new_allocatorIPN10aeroscript11InstructionEEC2ERKS4_':
C:/Dev-Cpp/Bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/ext/new_allocator.h:64: multiple definition of `aeroscript::InstructionList'
main.o:C:/Dev-Cpp/Bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_vector.h:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

make.exe: *** [AeroScript.exe] Error 1

Execution terminated


this is the file the error points to:
// Allocator that wraps operator new -*- C++ -*-

// Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING.  If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.

// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.

#ifndef _NEW_ALLOCATOR_H
#define _NEW_ALLOCATOR_H 1

#include <new>

namespace __gnu_cxx
{
  /**
   *  @brief  An allocator that uses global new, as per [20.4].
   *
   *  This is precisely the allocator defined in the C++ Standard. 
   *    - all allocation calls operator new
   *    - all deallocation calls operator delete
   *
   *  (See @link Allocators allocators info @endlink for more.)
   */
  template<typename _Tp>
    class new_allocator
    {
    public:
      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;

      template<typename _Tp1>
        struct rebind
        { typedef new_allocator<_Tp1> other; };

      new_allocator() throw() { }

      new_allocator(const new_allocator&) throw() { }

      template<typename _Tp1>
        new_allocator(const new_allocator<_Tp1>&) throw() { }

      ~new_allocator() throw() { }

      pointer
      address(reference __x) const { return &__x; }

      const_pointer
      address(const_reference __x) const { return &__x; }

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      pointer
      allocate(size_type __n, const void* = 0)
      { return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }

      // __p is not permitted to be a null pointer.
      void
      deallocate(pointer __p, size_type)
      { ::operator delete(__p); }

      size_type
      max_size() const throw() 
      { return size_t(-1) / sizeof(_Tp); }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      void 
      construct(pointer __p, const _Tp& __val) 
      { ::new(__p) _Tp(__val); }

      void 
      destroy(pointer __p) { __p->~_Tp(); }
    };

  template<typename _Tp>
    inline bool
    operator==(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return true; }
  
  template<typename _Tp>
    inline bool
    operator!=(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return false; }
} // namespace __gnu_cxx

#endif


This is the line the error points to:
Line 64: new_allocator(const new_allocator&) throw() { }
What....the....hell.... Any replies will be rewarded with caek or pi (your choice) and a hearty rating++.

Share this post


Link to post
Share on other sites
Programmer16    2321
Ok, I'm going to copy your code and put it into my computer to see what errors I get. I'll return with the results.

BTW, why don't you switch compilers? (Maybe Code::Blocks with the Microsoft Toolkit 2003?)

My code compiled without any errors. How are you trying to use the code?

Also, I'm looking at this line:

class InstructionList_
{
std::vector<Instruction*> instructions;

public:
void Add(Instruction* instr_)
{
instructions.push_back(instr_);
}
}InstructionList;



With MinGW, do you have to typedef this:

typedef class InstructionList_
{
std::vector<Instruction*> instructions;

public:
void Add(Instruction* instr_)
{
instructions.push_back(instr_);
}
}InstructionList;


I believe that you have to with MSVC++ (I didn't try)?

Share this post


Link to post
Share on other sites
Drakkcon    612
Thank you very much!

As for switching compilers, I don't really hate MinGW. That comment line was in humerous frustration. Code::Bloks is a wonderful IDE, but I just can't use it for some reason. I have just always preferred Dev-C++ (I have Visual C++ .net on my computer right now).

EDIT:
let me try the typedef...hold on.

Share this post


Link to post
Share on other sites
Drakkcon    612
Alright, here's the fixed one:

////////////////////////////////////////////////////////////////////////////////
//instruction is an abstract base class. In order to create instructions, you inherit from
//this abstract base. std::string name is what you have to type in order to access
//this instruction, so if name = "Print", then inside the script you would have to
//type Print.
////////////////////////////////////////////////////////////////////////////////
//In order to use: add argument variables like so: Variable<whatever> argument1, etc....
//as arguments to the overloaded Execute function.
//type is where the instruction is used, like: World Map, or Battle, etc....
//redefine name for. After all of this they should overload Execute with whatever
//they need it to do, and how they want it to interpret arguments.
////////////////////////////////////////////////////////////////////////////////
#include "Variable.h"
#include <string>
#include <vector>

#ifndef STRATUS_INSTRUCTION_H
#define STRATUS_INSTRUCTION_H

namespace aeroscript
{
class InstructionList_;

class Instruction //virtual base
{
protected:
std::string name;
//this isn't important, just something like BATTLE or ACTION
std::string type;

public:
friend class InstructionList_;
//sets up the name, type, and uses InstructionList::Add(this)
virtual void Initialize(){};
virtual void Execute(){};
};


//this class holds a list of all the instructions for easy parsing by the script
//the only reason this is in the same file is that if it's not, I become buffetted
//with linker errors from hell.

//screw you MinGW.
typedef class InstructionList_
{
std::vector<Instruction*> instructions;

public:
void Add(Instruction* instr_)
{
instructions.push_back(instr_);
}
}InstructionList;

}

#endif





This fixed one annoying error, but now I'm getting:
24 C:\Dev-Cpp\Projects\Stratus\AeroScript\Instructions_Test.h expected primary-expression before '.' token

here:

//these are just instructions that test my instruction framework
//They will not appear in the final version
#include "Instruction.h"

#include <string>
#include <iostream>

#ifndef STRATUS_INSTRUCTIONS_TEST_H
#define STRATUS_INSTRUCTIONS_TEST_H

//This instruction will print whatever is in its first argument to the console screen
//Usage: PrintConsole "Whatever" X --where X is the number of times
namespace aeroscript
{
typedef class PrintConsole_ : public Instruction
{
Variable<std::string> argument1; //what to print

public:
void Initialize()
{
name = "PrintConsole";
type = "Test";
InstructionList.Add(this);
}
//overloading what the instruction does, argument1_ can't be const for some reason...
void Execute(Variable<std::string>& argument1_)
{
using namespace std;

argument1 = argument1_;

cout << argument1.GetData() << endl;
}

}PrintConsole;
}

#endif





UPDATE: Now, everywhere InstructionList.Add(...) appears I get the error:
16 C:\Dev-Cpp\Projects\Stratus\AeroScript\main.cpp expected primary-expression before '.' token


It's not minGW I hate, it's its linker :)

Share this post


Link to post
Share on other sites
Programmer16    2321
You forgot your underscore:

cout << argument1.GetData() << endl;
// should be
cout << argument1_.GetData() << endl;





I was only suggesting changing to Code::Blocks. I can't use it either (it doesn't indent the way I'm used to and I can't change the background color like in MSVC++ 6.)

This is the 4th or 5th time I've helped someone with a MinGW problem (thats why I was suggesting switching), but if you like it, then stick with it!

Share this post


Link to post
Share on other sites
Drakkcon    612
No, the underscore wasn't the problem. Look carefully and you'll find that I assign the member argument1 the value of argument1_.

Thanks for helping me out on the earlier problem though, rating++

I'm going to sleep :)

Share this post


Link to post
Share on other sites
Programmer16    2321
Ah, sorry about that (my Grandpa's mouse scrolls like 50 lines at once, I missed that.

Edit: Are you defining an InstructionList somewhere that I don't know about?:

typedef class PrintConsole_ : public Instruction
{
Variable<std::string> argument1; //what to print

public:
void Initialize()
{
name = "PrintConsole";
type = "Test";
InstructionList.Add(this);
}
//overloading what the instruction does, argument1_ can't be const for some reason...
void Execute(Variable<std::string>& argument1_)
{
using namespace std;

argument1 = argument1_;

cout << argument1.GetData() << endl;
}

}PrintConsole;





Of course, this might be in C# (I'm not sure what that supports).

Share this post


Link to post
Share on other sites
Fruny    1658
No, you don't have to typedef. The program is C++, not C. However, the program does take a different meaning whether you put a typedef keyword there or not...

class InstructionList_ {} InstructionList declares a type and a variable of that type, respectively named InstructionList_ and InstructionList

typedef class InstructionList_ {} InstructionList declares a type named InstructionList_ and specifies that InstructionList is an alias for that type.

In C, people use typedefs there because the real name of the type is struct foo, not just foo. So they'll put a typedef so that they don't have to type the struct keyword over and over again.

In C++, unless you are writing code that must be compatible with C, you should refrain to use that typedef-struct idiom. Just do class InstructionList {};

[Edited by - Fruny on August 1, 2005 11:23:17 PM]

Share this post


Link to post
Share on other sites
Programmer16    2321
Everytime I try to do:

class CLASSTAG_
{
}ClassTag;

//It gives me errors, but when I do:
typedef class CLASSTAG_
{
}ClassTag;
// It works fine



This is using the Microsoft Visual C++ 6.0 (I'm going to upgrade to the 2003 Toolkit Compiler)

Edit: Ok, I understand what you're saying now that I've reread your post. So my original fix is what is causing the second problem. :(

Share this post


Link to post
Share on other sites
Fruny    1658
Quote:
Original post by Drakkcon
Alright, thanks for explaining that fruny. Anyway, I removed the typedefs and I'm back to the original problem. Anyone know what to do?


As I mentioned in my post, without the typedef, you are defining a variable. Defining a variable in a header file is a bad idea, because every translation unit that includes the header file will get a copy of the variable, and the linker cannot decide which one to keep and which one to drop.

You need to write your class definition as follow:
class InstructionList 
{
// content goes here
};


And that should be it.

Share this post


Link to post
Share on other sites
Drakkcon    612
Thanks fruny! I got it working! It required a ton of externs, and an initialization function though (you didn't see the rest of the project--it's a mess), so it's time to refactor[depressed]. At least I learned something though.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this