Reputation: 1141
I've already wasted time trying to figure this out but no luck so far...I've tried looking through StackOverflow for the same problem but mostly it's related to the IDE people are using, such as VS or Eclipse.
I was doing some examples from the Stanford Reader for their C++ course but the code won't work right. I'm trying to figure out how to use external libraries but something keeps going wrong. I'm probably not using the right command but then I don't know which command to use.
I'm using Cygwin and it's terminal to do the c++ exercises. I have all the files in the same folder. I am using windows 7 but that shouldn't be the biggest problem though.
As an example this error shows well what I get when writing g++ Craps.cpp:
$ g++ Craps.cpp
/tmp/ccdTdi0t.o:Craps.cpp:(.text+0x1cf): undefined reference to `randomInteger(int, int)'
/tmp/ccdTdi0t.o:Craps.cpp:(.text+0x1e6): undefined reference to `randomInteger(int, int)'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/bin/ld: /tmp/ccdTdi0t.o: bad
reloc address 0x0 in section `.ctors'
collect2: ld returned 1 exit status
The example I was running this time is just one of the ones with external libraries which gives me the same kind of error if I wrong the other. It won't find the library.
This is my main also called Craps.cpp:
#include <iostream>
#include "random.h"
using namespace std;
bool tryToMakePoint(int point);
int rollTwoDice();
int main() {
cout << "This program plays a game of craps." << endl;
int point = rollTwoDice();
switch (point) {
case 7: case 11:
cout << "That's a natural. You win." << endl;
break;
case 2: case 3: case 12:
cout << "That's craps. You lose" << endl;
break;
default:
cout << "Your point is " << point << "." << endl;
if (tryToMakePoint(point)) {
cout << "You made your point. You win." << endl;
} else {
cout << "You rolled a seven. You lose." << endl;
}
}
return 0;
}
bool tryToMakePoint(int point) {
while (true) {
int total = rollTwoDice();
if (total == point) return true;
if (total == 7) return false;
}
}
int rollTwoDice() {
cout << "Rolling the dice . . . " << endl;
int d1 = randomInteger(1, 6);
int d2 = randomInteger(1, 6);
int total = d1 + d2;
cout << "You rolled " << d1 << " and " << d2
<< " - that's " << total << endl;
return total;
}
My random.cpp:
#include <cstdlib>
#include <cmath>
#include <ctime>
#include "random.h"
using namespace std;
void initRandomSeed();
int randomInteger(int low, int high) {
initRandomSeed();
double d = rand() / (double(RAND_MAX) + 1);
double s = d * (double(high) - low + 1);
return int(floor(low + s ));
}
double randomReal(double low, double high) {
initRandomSeed();
double d = rand() / (double(RAND_MAX) + 1);
double s = d * (high - low);
return low + s;
}
bool randomChance(double p) {
initRandomSeed();
return randomReal(0, 1) < p;
}
void setRandomSeed(int seed) {
initRandomSeed();
srand(seed);
}
void initRandomSeed() {
static bool initialized = false;
if (!initialized) {
srand(int(time(NULL)));
initialized = true;
}
}
and lastly my random.h:
#ifndef _random_h
#define _random_h
int randomInteger(int low, int high);
double randomReal(double low, double high);
bool randomChance(double p);
void setRandomSeed(int seed);
#endif
I hope someone can help me. If it's the Cygwin command that's wrong it would be great if I could see what I should write.
Edit: Just found out that I couldn't even write down the examples in the book right. Fixed now and should be without mistakes...I dearly hope so. Sorry about that.
Upvotes: 2
Views: 6651
Reputation: 62787
Other answer has the simple command to compile this, but here's a very rough and simple Makefile example, to get you started down that road. Create a file named Makefile
with these contents, where <tab>
must be an actual tab character, not some number of spaces:
Craps.exe : Craps.o random.o
<tab>g++ -o $@ $^
Craps.o random.o : random.h
Then just run
make Craps.exe
(possibly gmake
or mingw32-make
instead of plain make
).
Now Make has some magic built in about file types, so when it sees Craps.exe
needs those two .o
files, it'll start looking for files it could make them from, and it finds .cpp files, and knows how to compile them into .o files. Now it doesn't implicitly know how make .exe
out of .o
files, so that's why we have the 2nd line. There $@
means the target of the rule (Craps.exe
here), while $^
means all the files listed after the :
.
The Craps.o random.o:random.h
rule means, that if random.h is changed, Craps.o and random.o needs to be re-created again (these .h file dependencies can be generated automatically, but as long as you have just a few files, writing them by hand is ok).
If you need to add more source files, just add them with the .o suffix to the first line, and make will include them in the compilation. Also note how make will only compile changed files... Then you will need to add .h file dependencies when you get more .h files.
Upvotes: 1
Reputation: 12784
Shortly, you should add random.cpp
(or, if you already compiled it, an object file or a library where its compiled code resides) into your command line:
g++ Craps.cpp random.cpp
The problem you face is that the command line says the code in Craps.cpp should be compiled and then linked into an executable. While it's sufficient to have forward declarations of external functions to compile the file, you should provide the code of these functions to the linker for it to be able to create an executable.
As for libraries, you usually specify ones that you need to use with -l
option to GCC. And you might need to specify (with -L
) the path where to take libraries from, even if they all are in the current directory. E.g. provided that you have a library called librandom.a
or librandom.so
in the current directory:
g++ Craps.cpp -L. -l random
For external libraries, other directories may need to be specified so that the linker knows where to find the libraries it needs.
Upvotes: 3