Recent

Author Topic: Link C++ library statically  (Read 6354 times)

alex1

  • Newbie
  • Posts: 3
Link C++ library statically
« on: December 11, 2014, 12:30:36 pm »
Hi,
I have a following requirements for the windows app and want to use Lazarus for it:

1) must compile to single exe file, this exe file must run on Windows XP without redistributable packages
2) must use C++ library (with a C wrapper) compiled with MinGW

The first point works out of the box, but I gave up on second one after some time. I can link statically simple C lib (with {$linklib libmsvcrt.a} from mingw) into lazarus app. And I can link a C++ lib that doesn't use C++ stdlib and declares public functions with extern "C". But if I cannot link C++ lib which uses stdlib internally (string, vector etc).

If I link with {$linklib libstdc++.a} I got a bunch of "Duplicated symbols error". Link with {$linklib libstdc++.dll.a} succeed, but the application won't run asking for libstdc++-6.dll (no such lib exists in mingw).

I read "CInFreePascal.pdf" but unfortunately it is linux-specific.

Any help would be appreciated.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8112
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Link C++ library statically
« Reply #1 on: December 12, 2014, 07:02:54 am »
If I link with {$linklib libstdc++.a} I got a bunch of "Duplicated symbols error".
Try compiling with mingw g++ statically and try to get the linker script (I forgot the option, please search yourself). Open it and find the list of required libraries to link.
Link with {$linklib libstdc++.dll.a} succeed, but the application won't run asking for libstdc++-6.dll (no such lib exists in mingw).
libstdc++-6.dll does exist in mingw, if you install gcc-c++-<mingw gcc version here>-mingw32-dll package, it's should be there because it's required by g++ compiled programs, which are linked dynamically by default.

alex1

  • Newbie
  • Posts: 3
Re: Link C++ library statically
« Reply #2 on: December 13, 2014, 03:25:43 am »
Thanks for the response.

Experimented for some time with different variants and was unable to make it work. libstdc++.a cannot be linked statically (a lot of "Multiple defined symbol" errors). And it doesn't matter much, as If I try to use exceptions inside C++ sample lib (in internal functions, without crossing the border) I cannot link this lib statically even with libstdc++.dll.a.

And of course you were right about libstdc++-6.dll it is shipped with mingw and it and libgcc_s_dw2-1.dll is required in runtime when I link my lib dynamically. With dynamic linking C++ exceptions work fine.

Going to use a dynamic library and ship the app with minimal installer instead of standalone exe.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8112
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Link C++ library statically
« Reply #3 on: December 13, 2014, 08:39:07 am »
Going to use a dynamic library and ship the app with minimal installer instead of standalone exe.
Yes, that's a better way for multi language project. Static linking suffers too much problems.

alex1

  • Newbie
  • Posts: 3
Re: Link C++ library statically
« Reply #4 on: December 13, 2014, 01:41:11 pm »
It turned out to be easier than expected. I tried static linking (and MinGW) because I wanted single EXE. But I realized, that I can bundle C++ DLL and Lazarus EXE into "fat" EXE with NSIS. And I do not need to use MinGW for Lazarus integration - MSVC DLL works fine without any wrappers. So with Lazarus I can actually build snappy UI on top of my C++11 lib without resorting to MFC/WTL.

If someone will be interested, here is the full example for a single EXE app with Lazarus, MSVC2013 Express, CMake and NSIS. I haven't used it myself yet (maybe some hidden problems), but simple examples work for me so far.

lazarus_lib1.cpp (with exceptions and stdlib to check these features):
Code: [Select]
#include <string>
#include <exception>

std::string myfun(int num) /* noexcept(false) */ {
    return num > 0 ? std::to_string(num) : throw std::exception();
}

extern "C" __declspec(dllexport) int libfun1(int num) /* noexcept */ {
    try {
        return myfun(num).length();
    } catch(...) {
        return -1;
    }
}

CMakeLists.txt:
Code: [Select]
project ( lazarus_lib1 )
add_library ( lazarus_lib1 SHARED "lazarus_lib1.cpp" )

Unit1.pas (snippet):
Code: [Select]
interface
uses
  CTypes;

function libfun1(v: CTypes.cint32): CTypes.cint32; cdecl; external 'lazarus_lib1.dll' name 'libfun1';

lazarusapp.nsi:
Code: [Select]
!define exe 'lazarusapp.exe'
OutFile ${exe}
SilentInstall silent
RequestExecutionLevel user ; prevent UAC window
Section
    InitPluginsDir
    SetOutPath '$PLUGINSDIR'
    File lazarus_lib1.dll
    File project1.exe
    ExecWait '"$PLUGINSDIR\project1.exe"'
    SetOutPath $TEMP ; allows NSIS to delete PLUGINSDIR
SectionEnd