So, in the course of a bigger project, I need to generate normally distributed random numbers. I've decided to try to use the GSL rng library.

From the gsl webpage I got an example code, just to get an idea of how the interface works.

The program looks like:

#include <iostream>
#include <gsl_rng.h>

int main(){
  const gsl_rng_type * T;
  gsl_rng * r;
  int i, n = 10;
  T = gsl_rng_default;
  r = gsl_rng_alloc (T);
  for (i = 0; i < n; i++) 
    double u = gsl_rng_uniform(r);
    printf ("%.5f\n", u);
  gsl_rng_free (r);
  return 0;

and the output when compiling is:

g++ -Wall -I /usr/include/gsl -o main.exe main.cpp
/tmp/ccId4VRU.o: In function `main':
main.cpp:(.text+0x10): undefined reference to `gsl_rng_env_setup'
main.cpp:(.text+0x17): undefined reference to `gsl_rng_default'
main.cpp:(.text+0x27): undefined reference to `gsl_rng_alloc'
main.cpp:(.text+0x40): undefined reference to `gsl_rng_uniform'
main.cpp:(.text+0x76): undefined reference to `gsl_rng_free'
collect2: ld returned 1 exit status
make: *** [main.exe] Error 1

Now clearly the compiler did find some things that it needed, otherwise I would have gotten errors from declaring r and T, for instance. Indeed, this also happens if I remove the ".h" from the #include-command.
So, why doesn't it have all the commands?

Should I be considering using a library written specifically for c++ rather than c (have boost in mind)? Should I be thinking of updating my gsl installation? I only got Linux within the last few months, so I wouldn't think GSL had changed much since I installed it.

Helpful comments will be much appreciated =)

Libraries have two parts. You have the header and included it in your code, but did you link with the built object file paired with the header? The object files for libraries on Linux are usually .so for static libraries. Your build command should look something like this for gsl.

g++ -lgsl prog.cpp

If that does not work, you might need to use the -L switch to specify which directory the .so files are in.

You have forgotten to add a -lgsl .

That assumes that you want to make a shared library version of your code,
and that you have a path to the file [defined in:].

IF that doesn't work but you have then you can set the path explicitly e.g.
if the file is in /home/userName/lib g++ -Wall -I /usr/include/gsl -L/home/userName/lib -lgsl -o main.exe main.cpp Finally: Can I say (a) it is "non-unix-like" to use main.exe, normally, just a name, e.g main. Almost all the programs on your linux box are without the .exe. e.g. emacs, vim, ls etc. (b) I assume that you know how to compile the program to object code, and link separately:

g++ -c -I/usr/include/gsl main.cpp
g++ -c -I/usr/include/gsl extraFunc.cpp
// Then the link:
g++ -o testProg main.o extraFunc.o -lgsl

This way your code can be split up etc, and you can reduce compile time dramatically, especially when making small adjustments to a big code.
Hope that helps.

Thanks for the (very) speedy feedback! =)

when I added -lgsl I got A LOT of new undefined references. However (from googling lgsl) I tried also adding -lgslcblas, and now it just works.

Can anyone explain to me what I just did?

Ok well here goes 101 of code compilation on Linux with g++/gcc.

This is simplified from the actual process so after you understand this, there is another level of detail to see.

Basically you can think of code compilation in two stages:

(a) Producing an object file, that is taking your c++ code and turning each of your statements into machine code.

Before I go on, let me discuss that a bit. In your code if you write double a(1.5); a+=1.3; , the compiler (g++) can do this it reserves
a memory location for a, puts 1.5 in it, and the adds 1.3 to it. It writes this in the form of machine code. You can see the direct assembler that it corresponds to by
compiling your program with -S, but this will have a lot of other instructions in the code, but you can find your code.

However, what happens if you write this

#include <cmath>

double func(const double A)
 return 2*sin(A);

Now the sin function is only declared in <cmath>. You do not have its definition, so the compiler has to put a function call into the assembler, but it doesn't yet know what the definition of that call is.

(b) Now after the source code has been converted to objects, the compiler <em>links</em>
the code together. This is done by ordering the source code AND by ensuring that the links to functions declared in other files have the correct call addresses.

However, there are two ways to do this, the first "static" linkings. Consider the example above, make an executable with all the machine code for the program AND the machine code for sin.

That is perfectly fine since in the case that you run the program, that machine code needs to be in memory. However, if you have lots of executables, and linux is a whole host of executables [e.g. do an ls /usr/bin, and count the files.] Common code like printf etc is repeated lots and lots, which is wasteful.

So we have shared libraries. These are libraries for common functions, e.g. the gsl, that all programs that need to use the functions commonly point at. That has the advantage that you save disk space. It has the advantage/disadvantage that if you update the library [and are not careful] all your programs now point to the new library, which is often not what you want.

The line you typed adding -lgsl and -lgslcblas did the following. You needed to resolve some functions in your code that are in the library and the functions that are in the that you are using [the others don't mattter] require some functions from the library In addition the g++ compiler add the linkage to standard libraries, [e.g. STL etc]

commented: Always solid answers +4
commented: very helpful (and friendly!) +1

*bows deeply*

thanks =)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.