I am writing a code for a long project that uses at least 15 headers. I'm a lover of inline definitions inside headers, but for such a long project I've run into some problems using this method, so I decided to write a header file .h with a .cpp file for the definitions. Since I'm kind of new to this method, I'm not sure how to write the makefile. I tried my luck but it keeps giving me the famous "Undefined symbols for architecture x86_64" error. What I think is that inside the makefile I should just compile using object files all those headers that use a partner .cpp file, and nothing for inline definitions (.h).. Is this thinking right? Is the following makefile alright or wrong?
Makefile
CC = gcc
G = g++
SDLFLAGS = -lSDL_image -lSDL_ttf -lSDL2
INCS= `sdl2-config --cflags --libs`
AssetManager.o: AssetManager.cpp
${CC} -std=c++17 -c AssetManager.cpp
Collision.o: Collision.cpp
${CC} -std=c++17 -c Collision.cpp
Game.o: Game.cpp
${CC} -std=c++17 -c Game.cpp
Map.o: Map.cpp
${CC} -std=c++17 -c Map.cpp
TextureManager.o: TextureManager.cpp
${CC} -std=c++17 -c TextureManager.cpp
ECS.o: ECS/ECS.cpp
${CC} -std=c++17 -c ECS/ECS.cpp
main: main.cpp *.o ECS/Animation.h ECS/ColliderComponent.h ECS/Components.h ECS/KeyboardController.h ECS/ProjectileComponent.h ECS/SpriteComponent.h ECS/TileComponent.h ECS/TransformComponent.h ECS/UILabel.h colors.h
${G} -std=c++17 main.cpp -o main *.o ${INCS} ${SDLFLAGS}
clean:
rm *.o
cleanmain:
rm main
edit:
vim main.cpp
As I earlier anticipated all the commands using .o are for the headers that come with a .cpp file, all the inline headers .h are included in the line main: main.cpp *.o ECS/Animation.h ECS/ColliderComponent.h etc..
An example of an error it gives me is the following:
Undefined symbols for architecture x86_64:
"Vector2D::Zero()", referenced from:
TransformComponent::init() in AssetManager.o
TransformComponent::TransformComponent() in AssetManager.o
TransformComponent::init() in Game.o
TransformComponent::TransformComponent() in Game.o
TransformComponent::TransformComponent() in Map.o
TransformComponent::init() in Map.o
"Vector2D::Vector2D(float, float)", referenced from:
Game::init(char const*, int, int, bool) in Game.o
"Vector2D::Vector2D()", referenced from:
TransformComponent::TransformComponent(float, float, int, int, int) in AssetManager.o
TransformComponent::TransformComponent() in AssetManager.o
TransformComponent::TransformComponent(float, float, int, int, int) in Game.o
TransformComponent::TransformComponent() in Game.o
TransformComponent::TransformComponent() in Map.o
TileComponent::TileComponent(int, int, int, int, int, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) in Map.o
"operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Vector2D const&)", referenced from:
Game::update() in Game.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
where TransformComponent is actually just a .h header...
Where am I going wrong?
Related
I get the following error when trying to compile my simple program with make all:
❯ make all
clang++ --std=c++11 -Wall main.cpp
Undefined symbols for architecture arm64:
"file_reader::read_file()", referenced from:
_main in main-99040e.o
"file_reader::file_reader(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
_main in main-99040e.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main.o] Error 1
I can compile the program manually if I do clang++ --std=clang++11 main.cpp file_reader.cpp (and the executable works correctly), so I don't think it's an architecture error like it suggests. I think it might be a problem with my makefile, which I will include below, so if anyone has any insight that would be really helpful. I looked up several conventions for makefiles and none of them helped. The structure is pretty basic with main.cpp creating an object of type file_reader and then referencing one of its methods, so I use #include "file_reader.h" in my main.cpp.
makefile:
# compiler
CXX = clang++
# compiler flags:
# --std=clang++11 : verion
CXXFLAGS = --std=c++11 -Wall
all: main.out
main.out: main.o file_reader.o
$(CXX) main.o file_reader.o -o main
main.o: main.cpp file_reader.h
$(CXX) $(CXXFLAGS) main.cpp
file_reader.o: file_reader.cpp file_reader.h
$(CXX) $(CXXFLAGS) file_reader.cpp
clean:
rm -rf *.o restaurant
I would like to use tinyxml. I have used it in the past, and it works great. The only problem is I was developing on my Linux box which is a laptop. I have a mac mini and I have that set up as my desktop, so I would like to use it for a big chunk of development.
I have a simple tinyxml example that one of my instructors gave me. With this example came a Makefile like so:
ifeq ("$(shell whoami)", "malloy")
CXX = clang++
else
CXX = g++
endif
# Warnings frequently signal eventual errors:
CXXFLAGS=`sdl-config --cflags` -g -W -Wall -Weffc++ -Wextra -pedantic -O0
ifeq ("$(shell uname)", "Darwin")
LDFLAGS = -framework Foundation -framework GLUT -framework OpenGL -lm
else
ifeq ("$(shell uname)", "Linux")
LDFLAGS = `sdl-config --libs` -lm -lSDL_ttf -lSDL_image -ltinyxml
endif
endif
OBJS = \
main.o
EXEC = run
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
$(EXEC): $(OBJS)
$(CXX) $(CXXFLAGS) -o $# $(OBJS) $(LDFLAGS)
main.o: main.cpp
clean:
rm -rf $(OBJS)
rm -rf $(EXEC)
And when I try to make this simple project I get all of these Undefined symbol errors.
This is what terminal outputs after I type make:
g++ `sdl-config --cflags` -g -W -Wall -Weffc++ -Wextra -pedantic -O0 -o run main.o - framework Foundation -framework GLUT -framework OpenGL -lm
Undefined symbols for architecture x86_64:
"TiXmlString::nullrep_", referenced from:
TiXmlString::quit() in main.o
"TiXmlDocument::LoadFile(TiXmlEncoding)", referenced from:
_main in main.o
"TiXmlDocument::TiXmlDocument(char const*)", referenced from:
_main in main.o
"TiXmlNode::Clear()", referenced from:
_main in main.o
"TiXmlNode::~TiXmlNode()", referenced from:
TiXmlDocument::~TiXmlDocument() in main.o
"TiXmlElement::Attribute(char const*) const", referenced from:
_main in main.o
"TiXmlNode::FirstChildElement() const", referenced from:
TiXmlNode::FirstChildElement() in main.o
"TiXmlNode::NextSiblingElement() const", referenced from:
TiXmlNode::NextSiblingElement() in main.o
"vtable for TiXmlDocument", referenced from:
TiXmlDocument::~TiXmlDocument() in main.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [run] Error 1
I know it is a linker error that is about it. I used Homebrew to install tinyxml. It was actually giving me problems so after I got the tar-ball for tinyxml I extracted it and put the folder in /usr/local/include. g++ doesn't complain about finding the files. Just stuff with the v-table.
Any help is greatly appreciated! Thanks in advance!!!
You should modify the makefile and instruct the linker to use tinyxml (-ltinyxml) in the "Darwin" case. AFAIK, tinyxml is not bundled with OSX so you may need to find or build that. Instead, you can use expat (simpler-easier) or libxml2 (faster-detailed), which already come with OSX (you can also use (c++) wrappers, google them...)
I'd like to use boost regex library and created a very short program to test my makefile
#include <iostream>
#include <boost/regex.hpp>
using namespace std;
using namespace boost;
int main() {
regex exp("test");
cout << "Hello World" << endl;
}
Here is my makefile (I've got the boost includes from this thread Including boost libraries in make files)
EXEC = main
SOURCES = $(wildcard *.cpp)
HEADERS = $(wildcard *.h*)
OBJECTS = $(SOURCES:.cpp=.o)
all: $(EXEC)
main: $(OBJECTS)
g++ -L/usr/local/Cellar/boost/1.54.0/lib -lboost_filesystem-mt -lboost_thread-mt $(OBJECTS) -o $(EXEC)
%.o: %.cpp $(HEADERS)
g++ -I/usr/local/Cellar/boost/1.54.0/include -c $< -o $#
clean:
rm -f $(EXEC) $(OBJECTS)
When I compile my program a get the following error message:
g++ -I/usr/local/Cellar/boost/1.54.0/include -c main.cpp -o main.o
g++ -L/usr/local/Cellar/boost/1.54.0/lib -lboost_filesystem-mt -lboost_thread-mt main.o -o main
Undefined symbols for architecture x86_64:
"boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::do_assign(char const*, char const*, unsigned int)", referenced from:
boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign(char const*, char const*, unsigned int)in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [main] Error 1
What is missing?
I've installed boost with homebrew under Mac OS X 10.8.
You are missing a link to the boost_regex_mt library
-lboost_filesystem-mt -lboost_thread-mt
In your makefile...
main: $(OBJECTS)
g++ -L/usr/local/Cellar/boost/1.54.0/lib -lboost_regex-mt -lboost_filesystem-mt -lboost_thread-mt $(OBJECTS) -o $(EXEC)
I have GNU 4.7.1 as the default on my MacBook. I keep getting tons of segfaults when I run my program on my school's server. I downloaded the current state of my program from my schools server so that I could use NetBeans to help with debugging. I've run into tons of problems getting the newer GNU to replace the ancient 4.2 version that my MacBook was continuing to set as the default.
The OSX compilers are completely new to me and I can't get my makefile adjusted to compile everything like it is on my school's server.
People have told me to use gcc or g++ instead of the other, but others have told me that it shouldn't matter. From what I understand, OSX uses different libraries for the newer versions of GNU for c/c++ and now Clang is the standard? I'd like to stick with GNU/GCC just because that's what I've used in my CS classes.
Currently it appears that when my makefile tries to link "std::mt19937" it can't find the header that links it.
My question is: how can I get my makefile to compile so that std::mt19937 and the c++11 libraries both are used?
makefile
OBJECTS = Ammunition.o Armor.o Consumable.o Creature.o Entity.o Gold.o Item.o parser.o Potion.o Scroll.o Weapon.o XMLSerializable.o CreatureFactory.o DungeonLevel.o Player.o Tile.o ItemFactory.o
HEADERS = Ammunition.h Armor.h Consumable.h Creature.h Entity.h Gold.h Item.h parser.h Potion.h Scroll.h Weapon.h XMLSerializable.h CreatureFactory.h DungeonLevel.h Player.h Tile.h ItemFactory.h
all: Jhack
# I tried this and adding $(LIBS) where "-std=c++0x" is below..
# LIBS = -std=c++0x -std=c++11 -std=gnu++11
%.o: %.cpp $(HEADERS)
gcc -c $< -o $# -std=c++0x
Jhack: $(OBJECTS) main.o
gcc -o Jhack $^
clean:
rm -f *.o Jhack
run: Jhack
./Jhack
I tried swapping out "-std=c++0x" for -std=c++11 and -std=gnu++11. I also tried adding them both. I also tried swapping gcc out with g++ but everything I seem to try or change causes more errors and warnings.
Here's the first part of the current error message (It goes on and on and on):
gcc -c Ammunition.cpp -o Ammunition.o -std=c++0x
gcc -c Armor.cpp -o Armor.o -std=c++0x
gcc -c Consumable.cpp -o Consumable.o -std=c++0x
gcc -c Creature.cpp -o Creature.o -std=c++0x
gcc -c Entity.cpp -o Entity.o -std=c++0x
gcc -c Gold.cpp -o Gold.o -std=c++0x
gcc -c Item.cpp -o Item.o -std=c++0x
gcc -c parser.cpp -o parser.o -std=c++0x
gcc -c Potion.cpp -o Potion.o -std=c++0x
gcc -c Scroll.cpp -o Scroll.o -std=c++0x
gcc -c Weapon.cpp -o Weapon.o -std=c++0x
gcc -c XMLSerializable.cpp -o XMLSerializable.o -std=c++0x
gcc -c CreatureFactory.cpp -o CreatureFactory.o -std=c++0x
gcc -c DungeonLevel.cpp -o DungeonLevel.o -std=c++0x
gcc -c Player.cpp -o Player.o -std=c++0x
gcc -c Tile.cpp -o Tile.o -std=c++0x
gcc -c ItemFactory.cpp -o ItemFactory.o -std=c++0x
gcc -c main.cpp -o main.o -std=c++0x
gcc -o Jhack Ammunition.o Armor.o Consumable.o Creature.o Entity.o Gold.o Item.o parser.o Potion.o Scroll.o Weapon.o XMLSerializable.o CreatureFactory.o DungeonLevel.o Player.o Tile.o ItemFactory.o main.o
ld: warning: ignoring file Creature.o, file was built for unsupported file format ( 0x7f 0x45 0x4c 0x46 0x 2 0x 1 0x 1 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 ) which is not the architecture being linked (x86_64): Creature.o
Undefined symbols for architecture x86_64:
"Creature::removeMonster(DungeonLevel&)", referenced from:
vtable for Player in Player.o
"Creature::dumpObjectData()", referenced from:
Player::dumpObjectData() in Player.o
"Creature::setElementData(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
Player::setElementData(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >) in Player.o
"Creature::writeDataAsFragment(std::basic_ostream<char, std::char_traits<char> >&)", referenced from:
Player::writeDataAsFragment(std::basic_ostream<char, std::char_traits<char> >&) in Player.o
"Creature::move(DungeonLevel&, Creature&, std::mersenne_twister_engine<unsigned int, 32ul, 624ul, 397ul, 31ul, 2567483615u, 11ul, 4294967295u, 7ul, 2636928640u, 15ul, 4022730752u, 18ul, 1812433253u>&)", referenced from:
vtable for Player in Player.o
"Creature::getHP()", referenced from:
vtable for Player in Player.o
_main in main.o
"Creature::setHP(int)", referenced from:
Player::Player() in Player.o
Player::Player() in Player.o
vtable for Player in Player.o
"Creature::attack(Creature*, Creature&, std::mersenne_twister_engine<unsigned int, 32ul, 624ul, 397ul, 31ul, 2567483615u, 11ul, 4294967295u, 7ul, 2636928640u, 15ul, 4022730752u, 18ul, 1812433253u>&, DungeonLevel&)", referenced from:
vtable for Player in Player.o
"Creature::getXLoc()", referenced from:
vtable for Player in Player.o
Turns out I messed up the path for my compiler and MacPorts installed to the wrong location? Fresh OSX install and proper GNU undated solves it.
I keep getting error
make: *** No rule to make target `all'. Stop.
I am sure my makefile works perfectly, because I did run it on the terminal and everything fine. But when I try to import everything into eclispe by create an Empty Makefile Project, I couldn't compile the program. So did I miss something in eclipse configuration ?
Anyway, this is my makefile, please take a look, and correct me. Thanks
CC = g++
prog: legrec.o game.o board.o piece.o
$(CC) legrec.o game.o board.o piece.o -Wall -Werror -pedantic -o legrec
legrec.o: legrec.cpp game.h
$(CC) -Wall -Werror -pedantic -c legrec.cpp
game.o: game.cpp game.h board.h piece.h move.h player.h
$(CC) -Wall -Werror -pedantic -c game.cpp
board.o: board.cpp board.h piece.h move.h player.h
$(CC) -Wall -Werror -pedantic -c board.cpp
piece.o: piece.cpp piece.h board.h move.h player.h
$(CC) -Wall -Werror -pedantic -c piece.cpp
EDIT: Thanks for all replies, I did change the first line into all:legrec, and the previous error message was gone, however another errors came out
cc legrec.o -o legrec
Undefined symbols for architecture x86_64:
"game::game()", referenced from:
_main in legrec.o
"game::printMenu()", referenced from:
_main in legrec.o
"game::printBoard()", referenced from:
_main in legrec.o
"game::nextMove()", referenced from:
_main in legrec.o
"game::ended()", referenced from:
_main in legrec.o
"game::printWinner()", referenced from:
_main in legrec.o
"game::~game()", referenced from:
_main in legrec.o
"std::terminate()", referenced from:
_main in legrec.o
"std::ios_base::Init::Init()", referenced from:
__static_initialization_and_destruction_0(int, int)in legrec.o
"std::ios_base::Init::~Init()", referenced from:
___tcf_0 in legrec.o
"___gxx_personality_v0", referenced from:
Dwarf Exception Unwind Info (__eh_frame) in legrec.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [legrec] Error 1
I just don't understand why running same platform but the program performs differently. Before I was run on the terminal and edit on there that seems very well, but after porting into Eclipse, it drives me insance with the weird errors.
Your very first rule is not really good.
You could rename it to all and it would "work". But a better approach would be:
all: legrec
legrec: legrec.o game.o board.o piece.o
$(CC) legrec.o game.o board.o piece.o -Wall -Werror -pedantic -o legrec
i.e. the rule name should match the output produced.
If you type just make on the command line, the very first rule encountered is run (that's why it works for you). I'm guessing your IDE is running make all, and you haven't defined such a rule.
I am not an expert, but I'll try to help.
Rename the maketarget prog to legrec"
Try adding the following lines
.PHONY: all clean
all: legrec
Also your makefile doesn't have clean target. For that looking at your make file I suggest adding
clean:
#rm *.o legrec
You can improve the makefile in a number of ways to reduce duplication.
make knows how to turn a cpp file into an object file so you dont need to tell it. Just define the compiler and the options to use: I have added CPPFLAGS.
make will build the first target it finds in the makefile - in this case 'legrec'. The $# in the LD (link) command refers to legrec. The $^ refers to the prerequisites (ie the list of objects)
Here is my version:
CC = g++
CPPFLAGS = -Wall -Werror -pedantic
LDFLAGS =
legrec: legrec.o game.o board.o piece.o
$(LD) $(LDFLAGS) $^ -o $#
legrec.o: game.h
game.o: board.h piece.h move.h player.h game.h
board.o: board.h piece.h move.h player.h
piece.o: board.h piece.h move.h player.h
.PHONY: clean
clean:
#rm -f *.o legrec
Note that you can add -g or -O etc to the CPPFLAGS line. By the way, there are many more warnings that the compiler can give you than are produced by -Wall. For C, I normally use:
-Wall \
-Wextra \
-Wshadow \
-Wstrict-prototypes \
-Wmissing-prototypes \
-Wundef \
-Wunreachable-code \
-Wunused \
-Wcast-qual