Find the answer to your Linux question:
Results 1 to 4 of 4
Hey all, I'm new to Linux and fairly new to C++. I've run into a problem that I haven't been able to get around even after considerable amount search on ...
  1. #1
    Just Joined!
    Join Date
    Apr 2010
    Posts
    2

    Linking files in C++

    Hey all,

    I'm new to Linux and fairly new to C++. I've run into a problem that I haven't been able to get around even after considerable amount search on this forum and other similar ones on the web.

    I have attached my code below.
    Code:
    #include <stdio.h>
    #include <ncurses.h>
    #include <fstream>
    #include <iostream>
    #include <iomanip>
    #include </filespace/people/v/vvats/ece556/Trials/lpsolve55/lp_lib.h>	/*lp_solve library*/
    
    //#include "lp_lib.h"
    //#include <stdlib.h>
    //#include <string.h>
    //#include <math.h>
    //#include <time.h>
    
    
    # if defined ERROR
    #  undef ERROR
    # endif
    # define ERROR() { fprintf(stderr, "Error\n"); exit(1); }
    
    int grid[2]= {0,0};
    int *constr_ID;                     // modify to allocate dynamically (num_edges + 1)
    int e_count;
    int num_edge_constr = 0;  
    
    struct edge
        {
               int id;
               int term1[2];
               int term2[2];
               int cap;
        };
        struct edge *e = NULL;
    
    struct nets
        {
               char name[12];
               int  id;
               int  num_term;
               int  term1[2];
               int  term2[2];
               int  num_edges_used;
               int  *edges_used_1;
               int  *edges_used_2;
        };
                               
    using namespace std;
    using std::setw;
    
    /************************************************************************************************************************/
    void create_grid (int hor_cap, int ver_cap)
    {
        int num_edges = 0;                      // Number of edges in grid
        int i=0, j=0;
        
        e_count = (grid[0]*(grid[1]+1)) + (grid[1]*(grid[0]+1));
        
        e = new struct edge[e_count];    // Total # of edges = 40*41*2
                                                
                                                
        for (j=0; j<=grid[1]; j++)                    
        {
            for (i=0; i<grid[0]; i++)                
            {     
                    num_edges = num_edges + 1;
                    e[num_edges-1].id = num_edges;
                    e[num_edges-1].term1[0]= i;
                    e[num_edges-1].term1[1]= j;
                    e[num_edges-1].term2[0]= i+1;
                    e[num_edges-1].term2[1]= j;
                    e[num_edges-1].cap     = hor_cap;     
            }
        }
        for (j=0; j<=grid[0]; j++)                    
        {
            for (i=0; i<grid[1]; i++)                
            {
                
                    num_edges = num_edges + 1;
                    e[num_edges-1].id = num_edges;
                    e[num_edges-1].term1[0]= j;
                    e[num_edges-1].term1[1]= i;
                    e[num_edges-1].term2[0]= j;
                    e[num_edges-1].term2[1]= i+1;
                    e[num_edges-1].cap     = ver_cap;     
            }
        }
    
    //    for (j=0; j<num_edges; j++)                     // Remove this block later
    //    {
    //        printf ("\n\%5d  (%2d,%2d) - (%2d,%2d)  cap:%d",e[j].id, e[j].term1[0], e[j].term1[1], e[j].term2[0], e[j].term2[1], e[j].cap);
    //        getch();
    //    }
    //    printf ("\nTotal number of edges is %d", num_edges);   // Remove this later
        //getch();
    
    }
    
    /************************************************************************************************************************/
    
        
    /************************************************************************************************************************/
    void vertical (int& num_edges_used, int*& e_u_1, int*& e_u_2, int x1, int y1, int x2, int y2)
    {        
             int i, j;
             num_edges_used = y2 - y1;
             e_u_1 = new int [num_edges_used];
             e_u_2 = NULL;
             i = 0;
             for (j = y1+1; j <= y2; j++)
             {
                 e_u_1[i] = grid[0]*(grid[1]+1) + x2*grid[1] + j;
                 if (constr_ID[e_u_1[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_1[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
    }
    /*********************************************End of function vertical*************************************************/
    
    
    /************************************************************************************************************************/                      
    void horizontal (int& num_edges_used, int*& e_u_1, int*& e_u_2, int x1, int y1, int x2, int y2)
    {
             int i, j;
             num_edges_used = x2 - x1;
             e_u_1 = new int [num_edges_used];
             e_u_2 = NULL;
             i = 0;
             for (j = x1+1; j <= x2; j++)
             {
                 e_u_1[i] = y1*grid[0] + j;
                 if (constr_ID[e_u_1[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_1[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
    } 
    /*********************************************End of function horizontal*************************************************/
    
    
    /************************************************************************************************************************/
    void bend (int& num_edges_used, int*& e_u_1, int*& e_u_2, int x1, int y1, int x2, int y2)
    {
             int i, j;
             num_edges_used = (y2 - y1) + (x2 - x1);
             e_u_1 = new int [num_edges_used];
             e_u_2 = new int [num_edges_used];
             
             /*********Edges used by x1i*********/
             i = 0;                                
             for (j = x1+1; j <= x2; j++)
             {
                 e_u_1[i] = y1*grid[0] + j;
                 if (constr_ID[e_u_1[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_1[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
             for (j = y1+1; j <= y2; j++)
             {
                 e_u_1[i] = grid[0]*(grid[1]+1) + x2*grid[1] + j;
                 if (constr_ID[e_u_1[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_1[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
             
             /*********Edges used by x2i*********/
             i=0;
             for (j = y1+1; j <= y2; j++)
             {
                 e_u_2[i] = grid[0]*(grid[1]+1) + x1*grid[1] + j;
                 if (constr_ID[e_u_2[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_2[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
             for (j = x1+1; j <= x2; j++)
             {
                 e_u_2[i] = y2*grid[0] + j;
                 if (constr_ID[e_u_2[i]] == 0)
                 {
                                         num_edge_constr = num_edge_constr + 1;
                                         constr_ID[e_u_2[i]] = num_edge_constr;
                 }
                 i = i+1;
             }
    }
    /*********************************************End of function bend*******************************************************/
    
    
    /************************************************************************************************************************/
     
     void lp_feeder (int num_var, int num_net, struct nets* net_1)
     {
          int i, j, k;
          int a=0;
          int *rowno = NULL;                    // contains the row numbers which have a non-zero value
          double *sp_col = NULL;                // contains values of the non-zero elements in the column
          double *rhs = NULL;                      // contains the rhs of constraint equations
          int num_rows_lp = num_edge_constr + num_net;
          int num_var_verify =0;                // used for set_binary for variables. Also serves to verify the variable count
          int num_edge_constr_verify = 0;
          double *variables ;
          
          rhs = new double[1 + num_rows_lp];       // +1 because the first value (rhs[0]) is reserved for the objective function
     
          lprec *lp;
          
          lp = make_lp(num_rows_lp , 0);
          if (lp == NULL)
          {
                 cout <<"\nCould not create new LP model.";
                 ERROR();
          }
        
          for (i=0; i<num_net; i++)
          {
              a = (net_1[i].num_edges_used+1+1);  // +1 for the net constraint in the column, +1 for objective fn.
              rowno = new int[a];  
              sp_col = new double[a]; 
              rowno[0] = 0;
              sp_col[0] = 1;
              rowno[a-1] = 1+num_edge_constr+i+1;
              sp_col[a-1] = 1;
              
              if ((net_1[i].edges_used_1 != NULL) && (net_1[i].edges_used_1 == NULL))
              {
                                         for (k=1; k<(a-1); k++)
                                         {
                                             rowno[k] = constr_ID[net_1[i].edges_used_1[k-1]];
                                             sp_col[k] = 1;
                                         }
                                         add_columnex (lp, a, sp_col, rowno);
                                         num_var_verify = num_var_verify + 1;
                                         set_binary(lp, num_var_verify, TRUE);
              }
              else if ((net_1[i].edges_used_1 != NULL) && (net_1[i].edges_used_2 != NULL))
              {
                   for (k=1; k<(a-1); k++)
                   {
                       rowno[k] = constr_ID[net_1[i].edges_used_1[k-1]];
                       sp_col[k] = 1;
                   }
                   add_columnex(lp, a, sp_col, rowno);
                   num_var_verify = num_var_verify + 1;
                   set_binary(lp, num_var_verify, TRUE);
                   
                   for (k=1; k<(a-1); k++)
                   {
                       rowno[k] = constr_ID[net_1[i].edges_used_2[k-1]];
                       sp_col[k] = 1;
                   }
                   add_columnex(lp, a, sp_col, rowno);
                   num_var_verify = num_var_verify + 1;
                   set_binary(lp, num_var_verify, TRUE);
              }
          }
          
          rhs[0] = 0;
          for (j=1; j <= e_count; j++)            
          {
              if (constr_ID[j] != 0)
              {
                                  rhs[constr_ID[j]] = e[j].cap;
                                  set_constr_type(lp, constr_ID[j], LE);                              
              }
          }
          for (j=(num_edge_constr + 1); j < (1+num_rows_lp); j++)
          {
              rhs[j] = 1;                       // specifies that at max only 1 route has to be chosen.
              set_constr_type(lp, j, LE);
          }
          
          set_rh_vec(lp, rhs);
          set_maxim(lp);
    	  print_lp(lp);
    	  solve(lp); 
          
          variables = new double[num_var];
    	  get_variables(lp, variables);
    }
    
    /************************************************************************************************************************/
                                         
    
    /************************************************************************************************************************/
    int main ()
    {
        using namespace std;
        int i=0, j=0, k=0;
        int hor_cap;
        int ver_cap;
        int num_net;                            // # of nets in design
        int num_row=0;                          // # of edge constraints (i.e. # of edges that could have a route on them)
        int num_var=0;                          // # of variables (= # of columns in constraint matrix) 
        char dump[15];                          // any unnecessary data read from file
        
        struct nets *net = NULL;
        
    /**************** Read test_bench.txt ***************/    
        ifstream tb("test_bench.txt");     // need to use std:: to avoid error with using <fstream>
        
        if (tb.is_open())
        {
                         tb >> dump;
                         tb >> grid[0];
                         tb >> grid[1];
                         
                         e_count = (grid[0]*(grid[1]+1)) + (grid[1]*(grid[0]+1));
                          
                         tb >> dump;
                         tb >> dump;
                         tb >> ver_cap;
                         tb >> dump;
                         tb >> dump;
                         tb >> hor_cap;
                         tb >> dump;
                         tb >> dump;
                         tb >> num_net;
                         
                         net = new struct nets[num_net];
                         
                         constr_ID = new int[e_count];
                         for (k=0; k<(e_count+1); k++)    // +1 because constr_ID[0] is not used
                         {
                             constr_ID[k] = 0;
                             cout << "\n" <<k <<"\t" <<constr_ID[k];
                         }
    //                     getch();
                         
                         create_grid (hor_cap, ver_cap);
                         
                         for (i=0; i<num_net; i++)             // Read data of net[i]
                         {
                             tb >> net[i].name;
                             tb >> net[i].id;
                             tb >> net[i].num_term;
                             tb >> net[i].term1[0];
                             tb >> net[i].term1[1];
                             tb >> net[i].term2[0];
                             tb >> net[i].term2[1];
                             
                             if (net[i].term1[0] == net[i].term2[0])     // x1 = x2
                             {
                                  vertical (net[i].num_edges_used, net[i].edges_used_1, net[i].edges_used_2, 
                                                                       net[i].term1[0], net[i].term1[1],
                                                                       net[i].term2[0], net[i].term2[1]);
                                  num_var = num_var+1;
                             }
                             
                             else if (net[i].term1[1] == net[i].term2[1])//y1 =1 y2
                             {
                                  horizontal (net[i].num_edges_used, net[i].edges_used_1, net[i].edges_used_2, 
                                                                         net[i].term1[0], net[i].term1[1],
                                                                         net[i].term2[0], net[i].term2[1]);
                                  num_var = num_var+1;
                             }
                              
                             else if ((net[i].term1[0] != net[i].term2[0]) && (net[i].term1[1] < net[i].term2[1])) 
                             {
                                  bend (net[i].num_edges_used, net[i].edges_used_1, net[i].edges_used_2, 
                                                                   net[i].term1[0], net[i].term1[1],
                                                                   net[i].term2[0], net[i].term2[1]);
                                  num_var = num_var+2;
                             }
                             else if ((net[i].term1[0] != net[i].term2[0]) && (net[i].term1[1] > net[i].term2[1]))
                             {
                                  bend (net[i].num_edges_used, net[i].edges_used_1, net[i].edges_used_2, 
                                                                   net[i].term1[0], net[i].term2[1],
                                                                   net[i].term2[0], net[i].term1[1]);
                                  num_var = num_var+2;
                             }        
                         }
        }
        else
        {
            cout << "Error: Could not open file.";
            exit(1);
        }
        
        lp_feeder (num_var, num_net, net);
        
        for (i=0; i<num_net; i++)
        {
    //        cout <<"\n"    <<setw(10) <<left <<net[i].name <<" " <<setw(2) <<net[i].id <<" " <<net[i].num_term; 
    //        cout <<"\n  (" <<setw(2) <<net[i].term1[0] <<"," <<net[i].term1[1] <<")";
    //        cout <<"\n  (" <<setw(2) <<net[i].term2[0] <<"," <<net[i].term2[1] <<")";
    //        cout <<"\n   " << net[i].num_edges_used << "\n  Edges used:";
            for (j=0; j<net[i].num_edges_used; j++)
            {
                if ((net[i].edges_used_1 != NULL) && (net[i].edges_used_2 == NULL))
                   cout <<"\n  " <<net[i].edges_used_1[j] <<"  ID: " <<constr_ID[net[i].edges_used_1[j]];
                else if ((net[i].edges_used_1 != NULL) && (net[i].edges_used_2 != NULL))
                {
                   cout <<"\n  " <<net[i].edges_used_1[j] <<"  ID: " <<constr_ID[net[i].edges_used_1[j]];
                   cout <<"\n  " <<net[i].edges_used_2[j] <<"  ID: " <<constr_ID[net[i].edges_used_2[j]];
                }
            }
            cout <<"\n";  
    //        getch();  
        }
    //    printf ("\nNumber of variables: %d", num_var);
    //    cout << "\nNumber of edge constraints: " << num_edge_constr;
    
    }
    /***********************************************End of function main()**************************************************/
    The Makefile:
    Code:
    #------------------------------------------------------------
    #
    # When you adapt this makefile to compile your lpsolve programs
    # please copy this makefile and set LPSOLVEDIR to
    # the directories where lpsolve is installed.
    #
    #------------------------------------------------------------
    
    LPSOLVEDIR      = ./lpsolve55
    
    # ---------------------------------------------------------------------
    # Compiler selection 
    # ---------------------------------------------------------------------
    
    CCC = g++
    CC  = gcc
    
    # ---------------------------------------------------------------------
    # Compiler options 
    # ---------------------------------------------------------------------
    
    CCOPT = -Wall -O -fPIC -fexceptions -DNDEBUG -DIL_STD
    COPT  = -Wall -fPIC 
    
    # ---------------------------------------------------------------------
    # Link options and libraries
    # ---------------------------------------------------------------------
    
    CCLNFLAGS = -lm -ldl $(LPSOLVEDIR)/liblpsolve55.a
    CLNFLAGS = -lm -ldl $(LPSOLVEDIR)/liblpsolve55.a
    
    
    all:
    	make all_c
    	make all_cpp
    
    execute: all
    	make execute_c
    	make execute_cpp
    
    CFLAGS  = $(COPT) -I$(LPSOLVEDIR) 
    CCFLAGS = $(CCOPT) -I$(LPSOLVEDIR) 
    
    
    #------------------------------------------------------------
    #  make all      : to compile the examples. 
    #  make execute  : to compile and execute the examples.
    #------------------------------------------------------------
    
    C_EX = tester 
    
    CPP_EX = 
    
    all_c: $(C_EX)
    
    all_cpp: $(CPP_EX)
    
    execute_c: $(C_EX) 
    	 ./tester
    	 
    execute_cpp: $(CPP_EX)
    	 
    
    # ------------------------------------------------------------
    
    clean :
    	/bin/rm -rf *.o *~ *.class
    	/bin/rm -rf $(C_EX) $(CPP_EX)
    	/bin/rm -rf *.mps *.ord *.sos *.lp *.sav *.net *.msg *.log
    
    # ------------------------------------------------------------
    #
    # The examples
    #
    
    tester: tester.o 
    	$(CCC) $(CFLAGS) tester.o -o tester $(CLNFLAGS)
    tester.o: ./tester.cpp
    	$(CCC) -c $(CFLAGS) ./tester.cpp -o tester.o

    The directory Trials contains:
    1. tester.cpp (my code)
    2. lpsolve55 (The directory that contains the header lp_lib.h)
    3. Makefile


    When I try to compile the program using
    Code:
    g++ -o tester.o -lncurses tester.cpp -Wall
    I get the following error:
    Code:
    tester.cpp: In function ‘void lp_feeder(int, int, nets*)’:
    tester.cpp:213: warning: unused variable ‘num_edge_constr_verify’
    tester.cpp: In function ‘int main()’:
    tester.cpp:305: warning: unused variable ‘num_row’
    /tmp/ccap4Cls.o: In function `lp_feeder(int, int, nets*)':
    tester.cpp:(.text+0x94c): undefined reference to `make_lp'
    tester.cpp:(.text+0xb7c): undefined reference to `add_columnex'
    tester.cpp:(.text+0xb91): undefined reference to `set_binary'
    tester.cpp:(.text+0xca3): undefined reference to `add_columnex'
    tester.cpp:(.text+0xcb8): undefined reference to `set_binary'
    tester.cpp:(.text+0xd73): undefined reference to `add_columnex'
    tester.cpp:(.text+0xd88): undefined reference to `set_binary'
    tester.cpp:(.text+0xe3a): undefined reference to `set_constr_type'
    tester.cpp:(.text+0xe89): undefined reference to `set_constr_type'
    tester.cpp:(.text+0xea5): undefined reference to `set_rh_vec'
    tester.cpp:(.text+0xeae): undefined reference to `set_maxim'
    tester.cpp:(.text+0xeb7): undefined reference to `print_lp'
    tester.cpp:(.text+0xec0): undefined reference to `solve'
    tester.cpp:(.text+0xee3): undefined reference to `get_variables'
    collect2: ld returned 1 exit status
    Now these functions are all defined in the header lp_lib.h. I'm not really sure why those undefined reference errors are creeping up.

    My question:
    1. Is my compile command alright? If no, what am I missing?
    2. Should I link the library lp_lib.h? If so, how?


    Any help in this direction is highly appreciated.

    Thank you.

    Cheers,
    Varun

  2. #2
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    We need to differentiate between a header and the implementation. Even if you include a header in your program, this just allows typechecking and the like. The actual machine code for the library is not in the header file: it is in a "shared object" (assuming dynamic linking). Therefore, you need to find the lp_lib.so file and link against it.
    DISTRO=Arch
    Registered Linux User #388732

  3. #3
    Just Joined!
    Join Date
    Apr 2010
    Posts
    2
    Thats some info. Now my library has a .h extension. However, you ( I've seen elsewhere too) have mentioned it with a .so extension (I assume there's a .a extension too).
    So two questions:
    1. What does a .so extension mean and can I use a .h extension instead (probably I should do some reading on this...)
    2. How do I link my lp_lib.h library? (I read something about using a -L switch but I got an impression that it requires the library name to begin with "lib" and an extension .so or .a. I'm not really sure if I understood it right )


    Thank you.

    Cheers,
    Varun

  4. #4
    Linux Newbie
    Join Date
    Mar 2010
    Posts
    121
    Quote Originally Posted by varunvats69 View Post
    1. What does a .so extension mean and can I use a .h extension instead (probably I should do some reading on this...)
    2. How do I link my lp_lib.h library? (I read something about using a -L switch but I got an impression that it requires the library name to begin with "lib" and an extension .so or .a. I'm not really sure if I understood it right )
    A .h file is a header file - a plain-text source file the compiler reads to see what symbols (i.e. the names of functions and global variables) it can assume are provided by other compilation units (both shared libraries and other object files). Putting something in the header file is like telling the compiler "look, just trust me, I promise that at some point, all these functions will be defined" so it can use them without seeing the definition (just the declaration) each time.

    a .so file is a shared object file - a shared library. It contains the actual definitions of the symbols promised in the header file. This is the file the linker looks at (i) at compile-time and (ii) at run-time and expects to see the symbols it needs are actually there.

    If there's any discrepancy between what the .h file promises and what the .so file provides, you get the sort of errors you've got. In this case you haven't provided the .so file, so you're not going to get very far

    If it's not too much like blowing my own trumpet, I can point you to my webshite, which is about this (because as far as I can tell, this sort of thing is fairly neglected in text books!):

    prognix.blogspot.com

    (Sorry, can't post full url or link because I don't have enough posts here, which is most annoying...)

    The two posts on the compilation chain and the first part of "libraries - your own and the system's" should tell you everything you need to know.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...