Static linking of occt libraries into executable.

Forums: 

Hi all.
I have built opencascade statically, and I'm trying to link opencascade static libraries into executable using cmake.
I develop library (let's name it mylib.a) that use opencascade functionality. And I want link mylib.a and opencascade libraries into executable (test app for example). When I try build my project I have many errors from opencascade libraries (compile output attached to this topic).
Here is a CMakeLists.txt from my executable:

project(test)

aux_source_directory(. SRC_LIST)
link_directories(/usr/lib /usr/lib/x86_64-linux-gnu /usr/local/lib)
include_directories(/usr/include /usr/local/include /usr/local/include/opencascade)

set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")

if(POLICY CMP0037)
cmake_policy(PUSH)
cmake_policy(SET CMP0037 OLD)
endif()

if(POLICY CMP0037)
cmake_policy(POP)
endif()

add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} mylib.a TKernel.a TKMath.a TKG2d.a TKG3d.a TKGeomBase.a
TKBRep.a TKGeomAlgo.a TKTopAlgo.a TKPrim.a TKShHealing.a TKBO.a TKBool.a TKHLR.a
TKFillet.a TKFeat.a TKOffset.a TKMesh.a TKXMesh.a TKService.a TKV3d.a TKOpenGl.a
TKMeshVS.a TKCDF.a TKLCAF.a TKCAF.a TKBinL.a TKXmlL.a TKBin.a TKXml.a TKStdL.a
TKStd.a TKXSBase.a TKSTEPBase.a TKSTEPAttr.a TKSTEP209.a TKSTEP.a TKIGES.a TKXCAF.a
TKXDEIGES.a TKXmlXCAF.a TKBinXCAF.a TKXDESTEP.a TKDraw.a TKTopTest.a TKViewerTest.a
TKXSDRAW.a TKDCAF.a TKXDEDRAW.a TKQADraw.a TKTObjDRAW.a FWOSPlugin.a)

I don't have any errors when I try link my static library (mylib.a) with shared opencascade libraries and my test application successfully link mylib.a and use dynamic opencascade libraries. But I want use my test application on machines without installed opencascade.
I think the problem is in the opencascade libraries dependencies, I guess I didn't specify all needed libraries which opencascade libraries use, and that's why I have so many errors. Could some body specify opencascade dependencies? Also I think it's a good idea to add this info into documentation. I think I didn't first who have the same problem with static linkage of opencascade libraries.

Regards, Volodymyr.

EDIT:
https://anotepad.com/notes/i57rfb -- free notes with compile output

Kirill Gavrilov's picture

Hello Volodymyr,

this forum is intended for questions related to development of OCCT itself, not for application-specific problems. The users forum is better place for your question (https://www.opencascade.com/forums).

target_link_libraries(${PROJECT_NAME} mylib.a TKernel.a TKMath.a TKG2d.a TKG3d.a TKGeomBase.a

The dependency libraries are placed in wrong order - TKernel.a should be a last library in the list of OCCT libraries (since all other libraries depend on it) and other libraries should be reordered as well. This issue is unrelated to OCCT itself - you should look for information about static linking.

You can refer to the graphs in the documentation:
https://dev.opencascade.org/doc/refman/html/index.html

Volodymyr vvv's picture

Hi.
Thanks for your reply. You right, when I changed order of libraries i had less errors then before.
But I think this is not inconveniently to make list of libraries in right order by diagrams (graphs).

UPD:

target_link_libraries(${PROJECT_NAME} mylib.a FWOSPlugin.a TKTObjDRAW.a TKQADraw.a TKXDEDRAW.a TKDCAF.a TKDCAF.a TKXSDRAW.a
TKViewerTest.a TKTopTest.a TKDraw.a TKXDESTEP.a TKBinXCAF.a TKXmlXCAF.a TKXDEIGES.a TKXCAF.a TKIGES.a TKSTEP.a TKSTEP209.a TKSTEPAttr.a
TKSTEPBase.a TKXSBase.a TKStd.a TKStdL.a TKXml.a TKBin.a TKXmlL.a TKBinL.a TKCAF.a TKXCAF.a TKLCAF.a TKCDF.a TKMeshVS.a TKOpenGl.a TKV3d.a TKService.a
TKXMesh.a TKMesh.a TKOffset.a TKFeat.a TKFillet.a TKHLR.a TKBool.a TKBO.a TKShHealing.a TKPrim.a TKTopAlgo.a TKGeomAlgo.a TKBRep.a
TKGeomBase.a TKG3d.a TKG2d.a TKMath.a TKernel.a)

the error list is:
/usr/local/lib/libTKXCAF.a(XCAFApp_Application.cxx.o): In function `XCAFApp_Application::XCAFApp_Application()':
XCAFApp_Application.cxx:(.text+0x1d3): undefined reference to `TPrsStd_DriverTable::Get()'
XCAFApp_Application.cxx:(.text+0x1e8): undefined reference to `TPrsStd_Driver::TPrsStd_Driver()'
XCAFApp_Application.cxx:(.text+0x219): undefined reference to `TPrsStd_DriverTable::AddDriver(Standard_GUID const&, opencascade::handle const&)'
/usr/local/lib/libTKXCAF.a(XCAFPrs_Driver.cxx.o): In function `XCAFPrs_Driver::get_type_descriptor()':
XCAFPrs_Driver.cxx:(.text+0x3c4): undefined reference to `typeinfo for TPrsStd_Driver'
/usr/local/lib/libTKXCAF.a(XCAFPrs_Driver.cxx.o):(.data.rel.ro._ZTI14XCAFPrs_Driver[_ZTI14XCAFPrs_Driver]+0x10): undefined reference to `typeinfo for TPrsStd_Driver'
/usr/local/lib/libTKernel.a(OSD_SharedLibrary.cxx.o): In function `OSD_SharedLibrary::DlOpen(OSD_LoadMode)':
OSD_SharedLibrary.cxx:(.text+0xe8): undefined reference to `dlopen'
OSD_SharedLibrary.cxx:(.text+0x10a): undefined reference to `dlopen'
/usr/local/lib/libTKernel.a(OSD_SharedLibrary.cxx.o): In function `OSD_SharedLibrary::DlSymb(char const*) const':
OSD_SharedLibrary.cxx:(.text+0x124): undefined reference to `dlsym'
/usr/local/lib/libTKernel.a(OSD_SharedLibrary.cxx.o): In function `OSD_SharedLibrary::DlClose() const':
OSD_SharedLibrary.cxx:(.text+0x134): undefined reference to `dlclose'
/usr/local/lib/libTKernel.a(OSD_SharedLibrary.cxx.o): In function `OSD_SharedLibrary::DlError() const':
OSD_SharedLibrary.cxx:(.text+0x141): undefined reference to `dlerror'
/usr/local/lib/libTKernel.a(OSD_Thread.cxx.o): In function `OSD_Thread::Run(void*, int)':
OSD_Thread.cxx:(.text+0xf5): undefined reference to `pthread_create'
/usr/local/lib/libTKernel.a(OSD_Thread.cxx.o): In function `OSD_Thread::Detach()':
OSD_Thread.cxx:(.text+0x13e): undefined reference to `pthread_detach'
/usr/local/lib/libTKernel.a(OSD_Thread.cxx.o): In function `OSD_Thread::Wait(void*&) const':
OSD_Thread.cxx:(.text+0x17d): undefined reference to `pthread_join'
/usr/local/lib/libTKernel.a(OSD_Thread.cxx.o): In function `OSD_Thread::Wait(int, void*&) const':
OSD_Thread.cxx:(.text+0x22c): undefined reference to `pthread_timedjoin_np'
/usr/local/lib/libTKernel.a(Standard_Mutex.cxx.o): In function `Standard_Mutex::Standard_Mutex()':
Standard_Mutex.cxx:(.text+0xa1): undefined reference to `pthread_mutexattr_init'
Standard_Mutex.cxx:(.text+0xae): undefined reference to `pthread_mutexattr_settype'
Standard_Mutex.cxx:(.text+0xc2): undefined reference to `pthread_mutexattr_destroy'
/usr/local/lib/libTKernel.a(Standard_Mutex.cxx.o): In function `Standard_Mutex::TryLock()':
Standard_Mutex.cxx:(.text+0x109): undefined reference to `pthread_mutex_trylock'
collect2: error: ld returned 1 exit status

Kirill Gavrilov's picture

OSD_SharedLibrary.cxx:(.text+0xe8): undefined reference to `dlopen'
OSD_Thread.cxx:(.text+0x17d): undefined reference to `pthread_join'

While using statically built OCCT, your application should be linked not only with OCCT itself, but also with all its dependencies (including standard threading / library loading libraries). You can find a hundreds of posts across internet how to fix these unresolved symbols.

Henning V's picture

I have come across this post years later since it's listed very high in google search results when searching for "Occt static compilation" and since there is no definitive answer I thought I add this.

In the end what did it for me was using a different linker, in my case lld instead of ld. lld is capable of figuring out the dependency order by itself, it seems. Here here is some further reading [1,2].

without CMake
Compile main.cpp into object.

$ g++ -std=c++11 -c -I<path>/OCCT-7_8_0/install-gnu-static-release/include/opencascade/ main.cpp

Link executable.

$ g++ -static -fuse-ld=lld -L<path>/OCCT-7_8_0/install-gnu-static-release/lib/ -lTKBool -lTKDECascade -lTKDESTEP -lTKFillet -lTKHLR -lTKOffset -lTKShHealing -lTKV3d -lTKXmlL -lTKBinL -lTKBRep -lTKDEGLTF -lTKDESTL -lTKG2d -lTKLCAF -lTKOpenGl -lTKStd -lTKVCAF -lTKXmlTObj -lTKBinTObj -lTKCAF -lTKDEIGES -lTKDEVRML -lTKG3d -lTKMath -lTKPrim -lTKStdL -lTKXCAF -lTKXmlXCAF -lTKBinXCAF -lTKCDF -lTKDEOBJ -lTKernel -lTKGeomAlgo -lTKMesh -lTKRWMesh -lTKTObj -lTKXMesh -lTKXSBase -lTKBO -lTKDE -lTKDEPLY -lTKFeat -lTKGeomBase -lTKMeshVS -lTKService -lTKTopAlgo -lTKXml -std=c++11  -o main.out main.o

-static makes sure you get the standard libraries such as libm statically as well. -fuse-ld=lld sets the new linker. In my case I had to install it first.

$ sudo apt install lld

with cmake
The same can be done though CMake.

This is the CMakeLists.txt.

cmake_minimum_required(VERSION 3.13.0)
include(CMakePrintHelpers)

project(STEP_IGES_to_STL)
add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC "${OCCT_DIR}/include/opencascade/")
target_link_directories(${PROJECT_NAME} PUBLIC "${OCCT_DIR}/lib")

target_link_libraries(${PROJECT_NAME} PUBLIC
   "TKBin"     "TKCAF"       "TKDEPLY"  "TKG2d"      "TKMesh"    "TKShHealing" "TKXCAF"
   "TKBinL"    "TKCDF"       "TKDESTEP" "TKG3d"      "TKMeshVS"  "TKStd"       "TKXMesh"
   "TKBinTObj" "TKDE"        "TKDESTL"  "TKGeomAlgo" "TKOffset"  "TKStdL"      "TKXml"
   "TKBinXCAF" "TKDECascade" "TKDEVRML" "TKGeomBase" "TKOpenGl"  "TKTObj"      "TKXmlL"
   "TKBO"      "TKDEGLTF"    "TKernel"  "TKHLR"      "TKPrim"    "TKTopAlgo"   "TKXmlTObj"
   "TKBool"    "TKDEIGES"    "TKFeat"   "TKLCAF"     "TKRWMesh"  "TKV3d"       "TKXmlXCAF"
   "TKBRep"    "TKDEOBJ"     "TKFillet" "TKMath"     "TKService" "TKVCAF"      "TKXSBase"
)

install(TARGETS ${PROJECT_NAME})

And this is the command invoked from inside the build dir.

$ cmake -DCMAKE_CXX_FLAGS="-std=c++11 -fuse-ld=lld" -DCMAKE_INSTALL_PREFIX=<install-dir> -DOCCT_DIR=<path>/OCCT-7_8_0/install-gnu-static-release/ -S .. -B .

Note: we are not setting the actual linker in CMake since the linker is usually called through the compiler. Instead we tell the compiler what linker to use. See [3]

[1] https://stackoverflow.com/questions/45135
[2] https://stackoverflow.com/questions/34164594
[3] https://stackoverflow.com/a/64174822