Re: Linking a C program to a C++ library which uses STL

Discussion in 'C++' started by Default User, Feb 12, 2008.

  1. Default User

    Default User Guest

    wrote:

    > Hi,
    >
    > I tried to link a C program to a library which is written by me in C+
    > +.
    > I read some posts about linking a C program to C++ libraries. It seems
    > doable by adding extern "C" to the C++ head file and to the function
    > body modifier. However, in my test, it still doesn't work. The linking
    > error messages are like undefined reference for new operator, and
    > undefined reference from dequeue.tcc. ( sorry I don't know how to copy
    > lines from terminals under solaris.)


    extern "C" doesn't magically allow you to compile C++ code as C. You
    need to have the library compiled with a C++ compiler, with a C-style
    API, and link with the C code.

    The newsgroup comp.lang.c++ is the correct one for this question. I
    have crossposted this reply and set follow-ups.




    Brian
     
    Default User, Feb 12, 2008
    #1
    1. Advertising

  2. Default User

    Guest

    I looked at the C++ faq at http://www.parashift.com/c -faq-lite/mixing-c-and-cpp.html,
    and wrote some simple code to experiment.
    But in the end, the compiler complains about not recognize "extern".

    Here is what I did.

    First, I compiled a lib.a, which is made of lib.h, lib.cpp, and
    Makefile.
    Here is the code.

    lib.h
    =====
    #ifndef _LIB_H_
    #define _LIB_H_

    typedef int integer;

    extern "C" void push_into( integer i );
    extern "C" void show();

    #endif


    lib.cpp
    =======

    #include "lib.h"
    #include <iostream>
    #include <vector>

    using namespace std;

    vector< int > vec;

    void push_into( integer i )
    {
    vec.push_back( i );
    }

    void show()
    {
    for( integer i = 0; i < vec.size() ; i++ )
    cout<< vec << " ";
    cout<< endl;
    }


    Makefile
    ========
    G=g++
    OBJ=lib.o

    lib.a: $(OBJ)
    ar rcs $@ $(OBJ)

    lib.o: lib.cpp lib.h
    $(GG) -g -c lib.cpp

    clean:
    \rm $(OBJ) lib.a



    The Makefile uses g++, and generates lib.a. The command "ar" archived
    lib.o into lib.a.
    Then I have another two files, main.c and Makfile.1. main.c must
    include "lib.h" since "lib.h" is the interface to my library.

    main.c
    ======
    #include <stdio.h>
    #include "lib.h"

    main(int argv, char** args)
    {
    integer a = 3;
    push_into( a );
    show();
    }


    Makefile.1
    ==========
    GG=gcc
    OBJ=main.o

    main: $(OBJ)
    $(GG) -g -o $@ $(OBJ) lib.a

    main.o: main.c
    $(GG) -g -c main.c

    clean:
    \rm $(OBJ) main


    Makefile.1 uses gcc since main.c is written in C. (If I use g++ here,
    there is no errors. But I do want to test my library under C
    environment.)

    Finally, here is the compiler error.

    gcc -g -c main.c
    In file included from main.c:2:
    lib.h:7: error: expected identifier or '(' before string constant
    lib.h:8: error: expected identifier or '(' before string constant
    make: *** [main.o] Error 1


    What should I do to make it work?
     
    , Feb 13, 2008
    #2
    1. Advertising

  3. Default User

    Guest

    It can be compiled if I got rid of extern "C" in lib.h to

    lib.h
    =====
    #ifndef _LIB_H_
    #define _LIB_H_

    typedef int integer;

    void push_into( integer i );
    void show();

    #endif


    This new lib.h is ONLY used to compile with main.c. lib.a is still
    compiled from the old lib.h which has extern "C" in front of each
    function.
    But now the errors are:

    gcc -g -c main.c
    gcc -g -o main main.o lib.a
    lib.a(lib.o): In function `__static_initialization_and_destruction_0':
    /usr/include/c++/4.1.3/iostream:76: undefined reference to
    `std::ios_base::Init::Init()'
    lib.a(lib.o): In function `__tcf_0':
    /usr/include/c++/4.1.3/iostream:76: undefined reference to
    `std::ios_base::Init::~Init()'
    lib.a(lib.o): In function `show':
    /home/joe/Desktop/bg/lib.cpp:18: undefined reference to `std::cout'
    /home/joe/Desktop/bg/lib.cpp:18: undefined reference to
    `std::basic_ostream<char, std::char_traits<char> >::eek:perator<<(int)'
    /home/joe/Desktop/bg/lib.cpp:18: undefined reference to
    `std::basic_ostream<char, std::char_traits<char> >& std::eek:perator<<
    <std::char_traits<char> >(std::basic_ostream<char,
    std::char_traits<char> >&, char const*)'
    /home/joe/Desktop/bg/lib.cpp:19: undefined reference to
    `std::basic_ostream<char, std::char_traits<char> >& std::endl<char,
    std::char_traits<char> >(std::basic_ostream<char,
    std::char_traits<char> >&)'
    /home/joe/Desktop/bg/lib.cpp:19: undefined reference to `std::cout'
    /home/joe/Desktop/bg/lib.cpp:19: undefined reference to
    `std::basic_ostream<char, std::char_traits<char>
    >::eek:perator<<(std::basic_ostream<char, std::char_traits<char> >& (*)

    (std::basic_ostream<char, std::char_traits<char> >&))'
    lib.a(lib.o): In function
    `__gnu_cxx::new_allocator<int>::deallocate(int*, unsigned int)':
    /usr/include/c++/4.1.3/ext/new_allocator.h:94: undefined reference to
    `operator delete(void*)'
    lib.a(lib.o): In function
    `__gnu_cxx::new_allocator<int>::allocate(unsigned int, void const*)':
    /usr/include/c++/4.1.3/ext/new_allocator.h:86: undefined reference to
    `std::__throw_bad_alloc()'
    /usr/include/c++/4.1.3/ext/new_allocator.h:88: undefined reference to
    `operator new(unsigned int)'
    lib.a(lib.o): In function `std::vector<int, std::allocator<int>
    >::_M_insert_aux(__gnu_cxx::__normal_iterator<int*, std::vector<int,

    std::allocator<int> > >, int const&)':
    /usr/include/c++/4.1.3/bits/vector.tcc:266: undefined reference to
    `std::__throw_length_error(char const*)'
    lib.a(lib.o):(.eh_frame+0x11): undefined reference to
    `__gxx_personality_v0'
    collect2: ld returned 1 exit status
    make: *** [main] Error 1
     
    , Feb 13, 2008
    #3
  4. Default User

    Ian Collins Guest

    wrote:
    > It can be compiled if I got rid of extern "C" in lib.h to
    >
    > lib.h
    > =====
    > #ifndef _LIB_H_
    > #define _LIB_H_
    >
    > typedef int integer;
    >
    > void push_into( integer i );
    > void show();
    >
    > #endif
    >
    >
    > This new lib.h is ONLY used to compile with main.c. lib.a is still
    > compiled from the old lib.h which has extern "C" in front of each
    > function.
    > But now the errors are:
    >
    > gcc -g -c main.c
    > gcc -g -o main main.o lib.a


    Try g++.

    --
    Ian Collins.
     
    Ian Collins, Feb 13, 2008
    #4
  5. * :
    > I looked at the C++ faq at http://www.parashift.com/c -faq-lite/mixing-c-and-cpp.html,
    > and wrote some simple code to experiment.
    > But in the end, the compiler complains about not recognize "extern".
    >

    [snip code]
    >
    >
    > What should I do to make it work?


    As Ian Collins remarked else-thread, in order to make 'extern "C"'
    compile you need to compile that as C++, because it's a C++ feature.
    C++ supports C. C does not support C++.

    And a special consequence of that is the very first thing mentioned in
    the FAQ page you refer to above:

    * You must use your C++ compiler when compiling main() (e.g., for
    static initialization)

    This means that your attempt to have a C main program that calls a C++
    library is ill-fated from the beginning.

    If you absolutely must keep the 'main' etc. in C then transform the C
    'main' into an ordinary C function,

    int cLanguageMain( int argc, char* argv[] ) { ... }

    then make a C++ main program that calls that,

    extern "C" int cLanguageMain( int argc, char* argv[] );

    int main( int argc, char* argv[] )
    {
    return cLanguageMain( argc, argv );
    }

    and of course compile this C++ main with your C++ compiler.

    That said, back to 'extern "C"'.

    When used in a header file, the usual intent is that that header file is
    to be used by both a C++ and a C compiler. Typically by a C compiler
    when building the library or object file, and a C++ compiler when using
    it. You have it opposite, but that doesn't matter: the point is that
    you need to support both C and C++ compilers in the same file.

    And that's discussed in FAQ item 32.4 on the same page you referred to
    above.


    Cheers, & hth.,

    - Alf


    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Feb 13, 2008
    #5
  6. On Feb 13, 3:05 am, wrote:
    > I looked at the C++ faq athttp://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html,
    > and wrote some simple code to experiment.
    > But in the end, the compiler complains about not recognize "extern".
    >
    > Here is what I did.
    >
    > First, I compiled a lib.a, which is made of lib.h, lib.cpp, and
    > Makefile.
    > Here is the code.
    >
    > lib.h
    > =====
    > #ifndef _LIB_H_
    > #define _LIB_H_
    >
    > typedef int integer;
    >
    > extern "C" void push_into( integer i );
    > extern "C" void show();
    >
    > #endif
    >
    > What should I do to make it work?


    #ifdef __cplusplus
    extern "C" {
    #endif
    void push_into( integer i );
    void show();
    #ifdef __cplusplus
    }
    #endif
     
    tragomaskhalos, Feb 13, 2008
    #6
  7. Default User

    Guest

    Hi,

    I finally understand the whole thing.
    I was having a wrong impression that I could make a C program call a C+
    + library if g++ is used in the command, even without extern "C" in
    the library header.
    So I thought extern "C" is used for situations where gcc is used in
    the compile command.

    But I was wrong.
    If there's no extern "C" in the library head file, trying to compile a
    C main program (use g++) would give you undefined reference errors.
    To get rid of those errors, include extern "C" in the head file.

    Like tragomaskhalos said, use #ifdef __cplusplus in the head file, so
    the same head file could be used for building the library and for
    building the main program.
    And the last step is to use g++ to compile the main program. gcc won't
    work.
     
    , Feb 13, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    556
    klaus hoffmann
    Feb 22, 2006
  2. kris
    Replies:
    5
    Views:
    399
    Joachim Schmitz
    Jun 22, 2007
  3. grbgooglefan
    Replies:
    6
    Views:
    434
    Christian Heimes
    Dec 7, 2007
  4. Replies:
    6
    Views:
    408
    Ian Collins
    Feb 13, 2008
  5. Sammy
    Replies:
    1
    Views:
    316
    NET_NET_2003
    Aug 18, 2003
Loading...

Share This Page