How do you properly link to a static library using g++

30,281

Solution 1

Solution: Thanks to everyone who commented on this issue, but I resolved it on another forum, and figured out I would post the answer here for anybody having the same issue.

So, I guess only dynamic libraries make use of __declspec(dllexport), so when you try to create a static library, the methods are exported (an the names need to be mangled to be C++ compatible), so when declaring extern "C" __declspec.... you end up with method names that aren't recognized when trying to link statically.

So, simple fix: remove the __declspec

Solution 2

-L/path/to/library/ and -lName as g++ options worked for me. Do not specify the library name in the path/to/library .

Solution 3

Try putting -L and -l before main.o in the linking command line.

Share:
30,281
DivXZero
Author by

DivXZero

Updated on April 06, 2020

Comments

  • DivXZero
    DivXZero about 4 years

    Solution: Thanks to everyone who commented on this issue, but I resolved it on another forum, and figured I would post the answer here for anybody having the same issue.

    So, I guess only dynamic libraries make use of __declspec(dllexport), so when you try to create a static library, the methods are exported (an the names need to be mangled to be c++ compatible), so when declaring extern "C" __declspec.... you end up with method names that aren't recognized when trying to link statically.

    So, simple fix.....remove the __declspec

    I have 2 projects, one is a static library, the other is just a win32 application.

    I simply want to include the library I've created into my win32 application, however g++ keeps giving me this error:

    ../MyLib/TestClass.h:16: undefined reference to `imp__ZTV9TestClass'

    That is the error I get when trying to compile the application, even though that file is part of the library.

    I have attempted to create the most simplified version of this project as possible in an attempt to find the error.

    Here are the source files for both projects:

    MyLib.h - This is the main include file for clients to reference functions in the library

    #ifndef MYLIB_H
    #define MYLIB_H
    
    #include "libexport.h"
    #include "TestClass.h"
    
    #endif  /* MYLIB_H */
    

    libexport.h - Pretty generic file to define import/export keywords

    #ifndef LIBEXPORT_H
    #define LIBEXPORT_H
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifdef LIB
    #define DLL_EXPORT __declspec(dllexport)
    #else
    #define DLL_EXPORT __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif  /* LIBEXPORT_H */
    

    TestClass.h

    #ifndef TESTCLASS_H
    #define TESTCLASS_H
    
    #include "libexport.h"
    
    class DLL_EXPORT TestClass
    {
    public:
        TestClass() {};
        virtual ~TestClass() {};
    
        void TestFunc();
    };
    
    #endif  /* TESTCLASS_H */
    

    TestClass.cpp

    #define LIB
    
    #include <stdio.h>
    #include "TestClass.h"
    
    void TestClass::TestFunc()
    {
        printf("This function was called from within the library.\n");
    }
    

    And lastly, the win32 application that implements the library:

    Main.cpp

    #include <windows.h>
    #include "../MyLib/MyLib.h"
    
    #pragma comment(lib, "libmylib.a")
    
    int __stdcall WinMain(HINSTANCE hInstance,
                          HINSTANCE hPrevInstance,
                          LPSTR lpCmdLine,
                          int nCmdShow)
    {
    
        TestClass *myClass = new TestClass();
    
        delete myClass;
        myClass = 0;
    
        return 0;
    }
    

    The library compiles with no errors, however, here is the output when compiling the main application:

    g++.exe    -c -g -MMD -MP -MF build/Debug/MinGW-Windows/main.o.d -o build/Debug/MinGW-Windows/main.o main.cpp
    mkdir -p dist/Debug/MinGW-Windows
    g++.exe     -mwindows -o dist/Debug/MinGW-Windows/testclient build/Debug/MinGW-Windows/main.o -L../MyLib/dist/Debug/MinGW-Windows -lmylib 
    build/Debug/MinGW-Windows/main.o: In function `TestClass':
    C:\Users\Nick\Documents\NetBeansProjects\TestClient/../MyLib/TestClass.h:16: undefined reference to `_imp___ZTV9TestClass'
    make[2]: Leaving directory `/c/Users/Nick/Documents/NetBeansProjects/TestClient'
    build/Debug/MinGW-Windows/main.o: In function `~TestClass':
    make[1]: Leaving directory `/c/Users/Nick/Documents/NetBeansProjects/TestClient'
    C:\Users\Nick\Documents\NetBeansProjects\TestClient/../MyLib/TestClass.h:17: undefined reference to `_imp___ZTV9TestClass'
    collect2: ld returned 1 exit status
    make[2]: *** [dist/Debug/MinGW-Windows/testclient.exe] Error 1
    make[1]: *** [.build-conf] Error 2
    make: *** [.build-impl] Error 2
    
    
    BUILD FAILED (exit value 2, total time: 1s)
    

    Most of the other posts I've seen regarding this topic say that the problem lies in the linking order, but even after adding -lmylib to the beginning of the compiler build line, the same errors persist:

    g++.exe -lmylib -mwindows -o dist/Debug/MinGW-Windows/testclient build/Debug/MinGW-Windows/main.o -L../MyLib/dist/Debug/MinGW-Windows -lmylib 
    build/Debug/MinGW-Windows/main.o: In function `TestClass':
    C:\Users\Nick\Documents\NetBeansProjects\TestClient/../MyLib/TestClass.h:16: undefined reference to `_imp___ZTV9TestClass'
    

    I really need help on this, I've built many dynamic libraries before using the above code, and it works with no problems, I can't understand why I'm having so much trouble building a simple static library. Any help is greatly appreciated.

  • DivXZero
    DivXZero over 12 years
    That's exactly how I specified it in the given example... "-L../MyLib/dist/Debug/MinGW-Windows -lmylib" but it still gives the undefined reference error, that's why i'm confused
  • DivXZero
    DivXZero over 12 years
    Didn't make a difference, still getting the same undefined reference error
  • TeaOverflow
    TeaOverflow over 12 years
    Oh, sorry, must have missed it. Is mylib named libmylib.a ? Because thats what the -l option assumes it to be.