Thread: Using C in C++

  1. #1
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50

    Using C in C++

    Hello all,

    I'm using some libraries made in C, in my C++ program. I must design a library that will basically encapsulate this C library. There is a test1.c example of the use of the library. I worked so far 2 classes:

    Code:
    class base_lvl1;
    class base_lvl2;
    each in it's own .h,.cpp pair, denoted here by base_lvl1.h(.cpp) and base_lvl2.h(.cpp). The only include test1.c have is original.h.

    I made a base_inc.h file to include the needed include files. The files include list are below:

    Code:
    //base_inc.h
    #include "base_lvl2.h"
    
    ...
    
    //base_lvl2.h
    #include "base_lvl1.h"
    
    ..
    
    //base_lvl1.h
    #include "original.h"
    I've searched around and found I need the extern C directive, and original.h already does that.

    My first test (test1.cpp) was a copy of test1.c, and it compiled. test1.cpp #include original.h

    My second test (test2.cpp) was the creation of class base_lvl1 and the substitution of it's associated not encapsulated data by it, and it compiles. test2.cpp #include base_lvl1.h.

    My third test (test3.cpp) was the creation of class base_lvl2 and the substitution of it's associated not encapsulated data by it, and it does not compile. test3.cpp #include base_lvl2.h

    To explain exactly where the error goes:
    - I can generate base_lvlx.o
    - I can't compile test3.cpp with the line
    Code:
    $(CXX)  -o $@ $< $(I) $(LIB) $(LIB2) $(CXXFLAGS)
    but test1.cpp and test2.cpp works
    - If I try to generate test3.o first, and then use the line above, only test3.o is generated, and the error is the same.
    - The error is in base_lvl2.o:
    Code:
    In function 'xxx::xxx::xxx':
    base_lvl2.cpp:(.text+0x2f): undefined reference to 'orig_func'
    where orig_func is a function that was is test1.c, test1.cpp and test2.cpp directly, but was moved to base_lvl2.cpp.

    Does anyone have any idea of why is that happening?

  2. #2
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    At what point do you tell the compiler to link to the C library? When producing base_lvlx.o or the final executable?
    Consider this post signed

  3. #3
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    The final executable. If I try to include the libraries before, the compiler says they where not used.

  4. #4
    30 Helens Agree neandrake's Avatar
    Join Date
    Jan 2002
    Posts
    640
    I'm confused how the files are setup. Can you post function declarations and #include statements are in which .h/cpp files?
    Environment: OS X, GCC / G++
    Codes: Java, C#, C/C++
    AOL IM: neandrake, Email: neandrake (at) gmail (dot) com

  5. #5
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Okay.

    First of all, sorry for the big post.

    I'm trying to work with CHOLMOD. There is a huge number of functions and definitions here, but all I need to include is cholmod.h, which have extern "C".

    All functions that start with cholmod_ are in the library CHOLMOD.

    To make it clearer, I have renamed the files to short1.c, short1.cpp, short2.cpp and short3.cpp. They are:

    Code:
    //short1.c
    #include "cholmod.h"
    
    int main (void) {
        cholmod_sparse *A ;
        cholmod_common c ;
        cholmod_start (&c) ;			    /* start CHOLMOD */
        A = cholmod_read_sparse (stdin, &c) ;	    /* read in a matrix */
        cholmod_print_sparse (A, "A", &c) ;		    /* print the matrix */
        cholmod_free_sparse (&A, &c) ;
        cholmod_finish (&c) ;			    /* finish CHOLMOD */
        return (0) ;
    }
    Code:
    //short1.cpp
    #include "base_matrices.h"
    
    int main (void) {
        cholmod_sparse *A ;
        cholmod_common c ;
        cholmod_start (&c) ;			    /* start CHOLMOD */
        A = cholmod_read_sparse (stdin, &c) ;	    /* read in a matrix */
        cholmod_print_sparse (A, "A", &c) ;		    /* print the matrix */
        cholmod_free_sparse (&A, &c) ;
        cholmod_finish (&c) ;			    /* finish CHOLMOD */
        return (0) ;
    }
    Code:
    //short2.cpp
    #include "base_matrices.h"
    
    using namespace base_matrices;
    
    int main (void) {
        cholmod_sparse *A ;
        base_common Common;
        A = cholmod_read_sparse (stdin, Common.get_pcm()) ;
        cholmod_print_sparse (A, "A", Common.get_pcm()) ;
        cholmod_free_sparse (&A, Common.get_pcm()) ;
        return (0) ;
    }
    Code:
    //short3.cpp
    #include "base_matrices.h"
    
    using namespace base_matrices;
    
    int main (void) {
      base_common c;
      base_sym_matrix A(c);
      A.read_sparse(stdin);
      A.print_sparse(string("A"));
      return (0) ;
    }
    Now base_matrices.h, and other needed ones:

    Code:
    #ifndef base_matrices_h
    #define base_matrices_h
    
    #include "base_sym_matrix.h"
    
    #endif
    Code:
    #ifndef base_sym_matrix_h
    #define base_sym_matrix_h
    
    #include "base_common.h"
    #include <string>
    
    using std::string;
    
    namespace base_matrices {
      class base_sym_matrix {
        public:
          base_sym_matrix (); //Not defined, because not allowed!
          base_sym_matrix (base_common &);
          ~base_sym_matrix ();
          //Needed function
          void read_sparse (FILE *);
          void print_sparse (string);
          cholmod_sparse * get_matrix () { return matrix; };
        private:
          cholmod_sparse *matrix;
          base_common *common;
      };
    }
    
    #endif
    Code:
    #ifndef base_common_h
    #define base_common_h
    
    #include "cholmod.h"
    
    /* ==============================================
     * Class base_common
     *
     * This class in a wraper for cholmod_common.
     * Since cholmod_start(&c) must be the first call to solve
     * cholesky by CHOLMOD, then it is in the constructor.
     * Also, since cholmod_finish(&c) must be the last call, 
     * then it is in the destructor.
     * Note that base_common will be the first variable created
     * because the others will have to point to it.
     * ==============================================
     */
    
    namespace base_matrices {
      class base_common {
        public:
          base_common ();
          ~base_common ();
          //Verify which options will need to be set, so that they
          //are included here.
          cholmod_common *get_pcm () { return common; };
        private:
          cholmod_common *common;
      };
    }
    
    #endif
    Now, the cpp's:

    Code:
    #include "base_sym_matrix.h"
    
    namespace base_matrices {
    
      base_sym_matrix::base_sym_matrix (base_common & cm) {
        common = &cm;
        matrix = 0;
      }
    
      base_sym_matrix::~base_sym_matrix () {
        cholmod_free_sparse(&matrix, common->get_pcm());
      }
    
      void base_sym_matrix::read_sparse (FILE *f) {
        matrix = cholmod_read_sparse(f, common->get_pcm());
      }
    
      void base_sym_matrix::print_sparse(string name) {
        cholmod_print_sparse(matrix, name.c_str(), common->get_pcm());
      }
    }
    Code:
    #include "base_common.h"
    
    namespace base_matrices {
    
      base_common::base_common () {
        common = new cholmod_common;
        cholmod_start(common);
      }
    
      base_common::~base_common () {
        cholmod_finish(common);
        delete common;
      }
    
    }
    These shortx.c* are short versions of the old files. Now the error is the same ('undefined reference'), but for any cholmod_* function.

    Note that the error only happens for short3.cpp, but I compile all 3 cpp files with the same arguments.

    Code:
    gcc -o shortc -I../Cholesky/CHOLMOD/Include -I../Cholesky/UFconfig -I../Include short1.c ../Cholesky/CHOLMOD/Lib/libcholmod.a ../Cholesky/AMD/Lib/libamd.a ../Cholesky/COLAMD/Lib/libcolamd.a ../Cholesky/CAMD/Lib/libcamd.a ../Cholesky/CCOLAMD/Lib/libccolamd.a ../Cholesky/GotoBLAS2/libgoto2.so -lgfortran -lgfortranbegin ../Cholesky/metis-4.0/libmetis.a -lm -O3 -fexceptions
    g++ -o short1 short1.cpp ../Cholesky/CHOLMOD/Lib/libcholmod.a ../Cholesky/AMD/Lib/libamd.a ../Cholesky/COLAMD/Lib/libcolamd.a ../Cholesky/CAMD/Lib/libcamd.a ../Cholesky/CCOLAMD/Lib/libccolamd.a ../Cholesky/GotoBLAS2/libgoto2.so -lgfortran -lgfortranbegin ../Cholesky/metis-4.0/libmetis.a -lm ../Lib/libbasematrices.a -I../Cholesky/CHOLMOD/Include -I../Cholesky/UFconfig -I../Include -O3 -fexceptions -Wall -Werror -Wextra
    g++ -o short2 short2.cpp ../Cholesky/CHOLMOD/Lib/libcholmod.a ../Cholesky/AMD/Lib/libamd.a ../Cholesky/COLAMD/Lib/libcolamd.a ../Cholesky/CAMD/Lib/libcamd.a ../Cholesky/CCOLAMD/Lib/libccolamd.a ../Cholesky/GotoBLAS2/libgoto2.so -lgfortran -lgfortranbegin ../Cholesky/metis-4.0/libmetis.a -lm ../Lib/libbasematrices.a -I../Cholesky/CHOLMOD/Include -I../Cholesky/UFconfig -I../Include -O3 -fexceptions -Wall -Werror -Wextra
    g++ -o short3 short3.cpp ../Cholesky/CHOLMOD/Lib/libcholmod.a ../Cholesky/AMD/Lib/libamd.a ../Cholesky/COLAMD/Lib/libcolamd.a ../Cholesky/CAMD/Lib/libcamd.a ../Cholesky/CCOLAMD/Lib/libccolamd.a ../Cholesky/GotoBLAS2/libgoto2.so -lgfortran -lgfortranbegin ../Cholesky/metis-4.0/libmetis.a -lm ../Lib/libbasematrices.a -I../Cholesky/CHOLMOD/Include -I../Cholesky/UFconfig -I../Include -O3 -fexceptions -Wall -Werror -Wextra
    ../Lib/libbasematrices.a(base_common.o): In function `base_matrices::base_common::~base_common()':
    base_common.cpp:(.text+0x28): undefined reference to `cholmod_finish'
    ../Lib/libbasematrices.a(base_common.o): In function `base_matrices::base_common::base_common()':
    base_common.cpp:(.text+0x16): undefined reference to `cholmod_start'
    ../Lib/libbasematrices.a(base_sym_matrix.o): In function `base_matrices::base_sym_matrix::read_sparse(_IO_FILE*)':
    base_sym_matrix.cpp:(.text+0x2f): undefined reference to `cholmod_read_sparse'
    ../Lib/libbasematrices.a(base_sym_matrix.o): In function `base_matrices::base_sym_matrix::~base_sym_matrix()':
    base_sym_matrix.cpp:(.text+0x18): undefined reference to `cholmod_free_sparse'
    ../Lib/libbasematrices.a(base_sym_matrix.o): In function `base_matrices::base_sym_matrix::print_sparse(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
    base_sym_matrix.cpp:(.text+0x4e): undefined reference to `cholmod_print_sparse'

  6. #6
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    I've just made the following modification to short3.cpp:

    Code:
    //short3.cpp modified
    #include "base_matrices.h"
    
    using namespace base_matrices;
    
    int main (void) {
      cholmod_sparse *B; //Here
      base_common Common;
      base_sym_matrix A(Common);
      B = cholmod_read_sparse(stdin, Common.get_pcm()); //Here
      A.read_sparse(stdin);
      cholmod_print_sparse(B, "B", Common.get_pcm()); //Here
      A.print_sparse(string("A"));
      cholmod_free_sparse(&B, Common.get_pcm()); //Here
      return (0) ;
    }
    Which is basically a merge of short2 and short3. It compiled and ran normally. I still don't know why it works. Can anyone help me?

  7. #7
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Still no solution found, nobody can help with this?

  8. #8
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Hello all,

    I found the problem. My linking was done wrong, because of inverted order of inclusion of libraries. I didn't know that the compiler (g++) reads it from the right to the left.

    Thank you

Popular pages Recent additions subscribe to a feed