Linking cabalized Haskell package to C program (undefined reference linker error) - haskell

My link command is:
gcc -O2 -m32 -o ParseInt.exe ParseInt.o hsbracket.o \
-L../../dist/ia32/build -lffi -lHSarray-0.5.0.0-ghc7.8.3 \
-lHSbin-package-db-0.0.0.0-ghc7.8.3 -lHSbinary-0.7.1.0-ghc7.8.3 \
-lHSbytestring-0.10.4.0-ghc7.8.3 -lHSCabal-1.18.1.3-ghc7.8.3 \
-lHScontainers-0.5.5.1-ghc7.8.3 -lHSdeepseq-1.3.0.2-ghc7.8.3 \
-lHSdirectory-1.2.1.0-ghc7.8.3 -lHSfilepath-1.3.0.2-ghc7.8.3 \
-lHSghc-7.8.3-ghc7.8.3 -lHSghc-prim-0.3.1.0-ghc7.8.3 \
-lHShaskeline-0.7.1.2-ghc7.8.3 -lHShaskell2010-1.1.2.0-ghc7.8.3 \
-lHShaskell98-2.0.0.3-ghc7.8.3 -lHShoopl-3.10.0.1-ghc7.8.3 \
-lHShpc-0.6.0.1-ghc7.8.3 -lHSinteger-gmp-0.5.1.0-ghc7.8.3 \
-lHSold-locale-1.0.0.6-ghc7.8.3 -lHSold-time-1.1.0.2-ghc7.8.3 \
-lHSpads-haskell-1.1-ghc7.8.3 -lHSpretty-1.1.1.1-ghc7.8.3 \
-lHSprocess-1.2.0.0-ghc7.8.3 -lHSrts-ghc7.8.3 \
-lHSrts_debug-ghc7.8.3 -lHSrts_l-ghc7.8.3 -lHSrts_thr-ghc7.8.3 \
-lHSrts_thr_debug-ghc7.8.3 -lHSrts_thr_l-ghc7.8.3 \
-lHStemplate-haskell-2.9.0.0-ghc7.8.3 -lHSterminfo-0.4.0.0-ghc7.8.3 \
-lHStime-1.4.2-ghc7.8.3 -lHStransformers-0.3.0.0-ghc7.8.3 \
-lHSunix-2.7.0.1-ghc7.8.3 -lHSxhtml-3000.2.1-ghc7.8.3 \
-lHSbase-4.7.0.1-ghc7.8.3 -Wl,-melf_i386
and I'm getting a bunch of errors like:
ParseInt.o: In function `main':
ParseInt.c:(.text.startup+0x16): undefined reference to `test'
../../dist/ia32/build/libHSrts-ghc7.8.3.so: undefined reference to `base_GHCziWord_W16zh_con_info'
../../dist/ia32/build/libHSrts-ghc7.8.3.so: undefined reference to `base_GHCziConcziSync_runSparks_closure'
../../dist/ia32/build/libHSrts-ghc7.8.3.so: undefined reference to `base_ControlziExceptionziBase_nonTermination_closure'
but the undefined references are defined in the base .so I linked against:
$ nm ../../dist/ia32/build/libHSbase-4.7.0.1-ghc7.8.3.so | grep base_GHCziWord_W16zh_con_info
26690:00550884 T base_GHCziWord_W16zh_con_info
$ nm ../../dist/ia32/build/libHSrts-ghc7.8.3.so | grep base_GHCziWord_W16zh_con_info
104: U base_GHCziWord_W16zh_con_info
So why doesn't libHSrts see things defined in libHSbase? I was following the directions here: http://www.vex.net/~trebla/haskell/so.xhtml, and had ParseInt.exe correctly linking at one point but then I added some libraries to the cabal package / wrote a bunch more Haskell code (ParseInt.c and hsbracket.c did not change).
I've read about linking order (https://stackoverflow.com/a/409470/1542000), and rts is earlier in the link command than the base library it depends on, so I'm not sure why I'm getting undefined references.

I was dumb and missed the obvious: try to fix the first error gcc printed.
I managed to get the test function removed from the exported modules in my cabal package. Upon re-building the cabal package with test added to the .so, all the linking errors went away.

Related

Build configuration for llvm-config to include correct .inc files

I am currently working on a project that requires llvm-hs package. Since this package only supports up to llvm-9, while I do have llvm-13 installed on my machine for other projects, I built llvm-9 from source on my machine, and added its bin to PATH. However, it seems that when the C compiler was resolving the .inc files included in llvm-9's header files (e.g. #include "llvm/IR/Attributes.inc" in llvm/IR/Attributes.h), it incorrectly used those from /usr/include rather than those from the built llvm-9.
My observation is that GHC uses llvm-config to determine the relevant compiler arguments. On this machine, llvm-config-9 --includedir gives me {llvm-9-src-dir}/llvm/include, which is missing {llvm-9-src-dir}/build/include/ (where the correct .inc files are located). How should I build my llvm-9 such that llvm-config gives the correct includedir? The cmake configurations I used for building my llvm-9 was:
cmake ../llvm \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/llvm90 \
-DLLVM_BUILD_LLVM_DYLIB=ON \
-DLLVM_LINK_LLVM_DYLIB=ON \
-DLLVM_INSTALL_UTILS=ON \
-DLLVM_ENABLE_RTTI=ON \
-DLLVM_ENABLE_FFI=ON \
-DLLVM_BUILD_TESTS=OFF \
-DLLVM_ENABLE_DOXYGEN=OFF \
-DLLVM_ENABLE_PROJECTS=clang

Cmake vcpkg and Bullet

I am very much lost here and could really use some help.
I'm working on an Honours project for next year that involves a physics simulation using Bullet and Vulkan for rendering. After a few months of work I have most of the project functioning. It needs a lot of refactoring and cleaning which will be the next stage.
I have been using a makefile but wish to migrate to CMake for a few reasons. Mainly because it seems to be the standard and because I want to compile for different OS's in the future (I'm running Linux but may need to deploy on Windows or Mac). Finally, I was recompiling the whole project for even a small change, which was beginning to become a problem as I started Unit Testing more.
The old makefile is as follows :
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
OWN_INCLUDES = \
-I$(ROOT_DIR)/src/Domain \
-I$(ROOT_DIR)/src/Vk \
-I$(ROOT_DIR)/src/Ui \
-I$(ROOT_DIR)/src/Service
ADD_INCLUDES = \
-I/opt/bullet3-master/src \
-I/opt/vk_mem_alloc \
-I/opt/stb_image \
-I/opt/tiny_obj_loader/ \
-I/opt/imgui-vulkan/
BULLET_INCLUDE_PATHS_LIBS = -L/opt/bullet3-master/src/BulletCollision/ \
-L/opt/bullet3-master/src/BulletDynamics/ \
-L/opt/bullet3-master/src/LinearMath/ \
-lBulletDynamics -lBulletCollision -lLinearMath
VULKAN_SDK_PATH = /opt/Vulkan_SDK/1.2.162.1/x86_64
CFLAGS = -std=c++17 -I$(VULKAN_SDK_PATH)/include $(OWN_INCLUDES) $(ADD_INCLUDES)
LDFLAGS = -L$(VULKAN_SDK_PATH)/lib `pkg-config --static --libs glfw3` -lvulkan $(BULLET_INCLUDE_PATHS_LIBS)
IMGUI_CPP_PATHS = /opt/imgui-vulkan/*.cpp
OWN_CPP_PATHS = src/*.cpp src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp
###### Unit Testing Paths
UNIT_TEST_INCLUDE = -I/opt/catch-header/
UNIT_TESTS_PATH = $(ROOT_DIR)/unit_tests/*.cpp
VulkanRun: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
g++ $(CFLAGS) -o VulkanRun $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)
Unit_Test: $(UNIT_TESTS_PATH) src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp $(IMGUI_CPP_PATHS)
g++ $(UNIT_TEST_INCLUDE) $(CFLAGS) -o Unit_Test $(UNIT_TESTS_PATH) src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp $(IMGUI_CPP_PATHS) $(LDFLAGS)
VulkanDebug: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
g++ $(CFLAGS) -g -o VulkanDebug $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)
VulkanOpt: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
g++ $(CFLAGS) -O3 -o VulkanOpt $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)
.PHONY: test clean
run: VulkanRun
LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d
./VulkanRun
test: Unit_Test
LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d
./Unit_Test
debug: VulkanDebug
LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d
optimise: VulkanOpt
LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d
./VulkanOpt
7 clean:
rm -f VulkanRun
rm -f Unit_Test
rm -f VulkanDebug
rm -f VulkanOpt
I installed cmake using the latest install script for 3.21.0.
I created a CMakeLists.txt in the root of the project as follows :
cmake_minimum_required(VERSION 3.21.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
project(LanderSim)
file(GLOB_RECURSE SOURCES "src/**.cpp")
add_executable(main ${SOURCES})
find_package(Bullet CONFIG REQUIRED)
if (BULLET_FOUND)
include_directories(${BULLET_INCLUDE_DIRS})
target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)
endif (BULLET_FOUND)
After many hours of trying I decided to try vcpkg. Following the install instructions from bullet :
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install bullet3
This resulted in errors of
CMake Error at CMakeLists.txt:11 (find_package):
Could not find a package configuration file provided by "Bullet" with any
of the following names: BulletConfig.cmake bullet-config.cmake
Looking in CMakeCache.txt i see "Bullet_DIR:PATH=Bullet_DIR-NOTFOUND"
I found the BulletConfig.make file in "/home/ash/vcpkg/installed/x64-linux/share/bullet3" and in "/home/ash/vcpkg/packages/bullet3_x64-linux/share/bullet3" and set the MakeCache.txt var Bullet_DIR:PATH to these variables (tested one at a time).
Running again I get CMake set_and_check() function not recognised. Or something to that effect. Looking in the BulletConfig.make file I see these set_and_check() functions aren't recognised by the linter. I cant find any information about them being deprecated online but I assume this is the case. So I change to set() and CMake then succeeds and builds its files.
Running make I then get an error.
fatal error: btBulletDynamicsCommon.h: No such file or directory,
#include <btBulletDynamicsCommon.h>
I tried prepending bullet/ to the include path as others had this issue but it causes the same error.
So I must be doing something wrong and I'm obviously not understanding the process that CMake uses to add includes and link libraries. I'm sure, given the popularity of CMake, that there must be something obvious. But I've spent about 10 hours over a few days searching and trying different variations and I'm starting to get very frustrated.
I've bounced off CMake before (hence why I was working with a makefile for months), but I'm determined to do this properly. I just could really use some help if anyone knows how to get CMake to generate a makefile that can see a package installed with vcpkg.
Or indeed if the vcpkg of Bullet is out of date, then a way to link and include it with CMake alone would be great. I just thought vcpkg would be easier as it provides a cleaner file structure by default as well as a CMake config file.
Thanks.
EDIT1
I've used 'cmake .' and 'cmake . -DCMAKE_TOOLCHAIN_FILE=/home/ash/vcpkg/scripts/buildsystems/vcpkg.cmake' to build the makefile. Both result in the same missing headers errors when calling make.
EDIT2
All CMake files were removed from the project (except CMakeLists.txt) before each call to cmake to ensure no values were stored there.
EDIT3
Poked around a bit more. Here is the BulletConfig.cmake file :
#
# BulletConfig.cmake(.in)
#
# Use the following variables to compile and link against Bullet:
# BULLET_FOUND - True if Bullet was found on your system
# BULLET_USE_FILE - The file making Bullet usable
# BULLET_DEFINITIONS - Definitions needed to build with Bullet
# BULLET_INCLUDE_DIR - Directory where Bullet-C-Api.h can be found
# BULLET_INCLUDE_DIRS - List of directories of Bullet and it's dependencies
# BULLET_LIBRARIES - List of libraries to link against Bullet library
# BULLET_LIBRARY_DIRS - List of directories containing Bullet' libraries
# BULLET_ROOT_DIR - The base directory of Bullet
# BULLET_VERSION_STRING - A human-readable string containing the version
set(PACKAGE_PREFIX_DIR /home/ash/installed/x64-linux)
set ( BULLET_FOUND 1 )
set ( BULLET_USE_FILE "${PACKAGE_PREFIX_DIR}/share/bullet3/UseBullet.cmake" )
set ( BULLET_DEFINITIONS "" )
set ( BULLET_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include/bullet" )
set ( BULLET_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/bullet" )
set ( BULLET_LIBRARIES "LinearMath;Bullet3Common;BulletInverseDynamics;BulletCollision;BulletDynamics;BulletSoftBody" )
set ( BULLET_LIBRARY_DIRS "${PACKAGE_PREFIX_DIR}/lib" )
set ( BULLET_ROOT_DIR "${PACKAGE_PREFIX_DIR}" )
set ( BULLET_VERSION_STRING "3.17" )
# Load targets
if(NOT TARGET Bullet3Common)
file(GLOB CONFIG_FILES "${PACKAGE_PREFIX_DIR}/share/bullet3/*Targets.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
set(_DIR)
endif()
As stated before a few of the set functions were set_and_check(). So I changed to set() as apparently cmake 3.21 has no set_and_check() function. After a little testing by printing message(), i found that PACKAGE_PREFIX_DIR was not being set anywhere. So that is why I've set it explicitly in this file. The variables are now set correctly as reported by message() in the CMakeLists.txt file. But still it make cannot find the header files.
EDIT4
I created an empty project and ran through each library I wanted to include. Everything works except for Bullet3. However it does now see the header files. What changed between the two CMakeFiles? Nothing as far as I can tell. I'll need to find out because I have to port this project over but in the meantime this is another issue with the package.
from /home/ash/projects/C++/CMakeImportTests/src/main.cpp:22:
/home/ash/vcpkg/installed/x64-linux/include/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h:77:10:
fatal error: LinearMath/btVector3.h: No such file or directory
77 | #include "LinearMath/btVector3.h"
I think this is the same issue as described #7877
If i remove all includes of Bullet but leave the CMakeList.txt untouched, we get this error:
[ 50%] Building CXX object CMakeFiles/main.dir/src/main.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: cannot find -lLinearMath
/usr/bin/ld: cannot find -lBullet3Common
/usr/bin/ld: cannot find -lBulletDynamics
/usr/bin/ld: cannot find -lBulletSoftBody
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:104: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
Is this a clue that some environment variable is not set?
EDIT5
There seems to be an ordering dependency for the target_link_library call. The suggested usage is:
target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)
Checking bullet.pc in the libs/ directory i found
Libs: -L${libdir} -lBulletSoftBody -lBulletDynamics -lBulletCollision -lLinearMath
So I tried rearranging and following the pattern:
target_link_libraries(main PRIVATE BulletSoftBody BulletDynamics BulletCollision Bullet3Common LinearMath)
Additionally there was also a need to manually link directories.
target_link_directories(main PRIVATE ${BULLET_LIBRARY_DIRS})
This now compiles without error in my test project. It seems LinearMath must be after most of the other libraries (although it can be before Bullet3Common it seems).
For some reason it's still not finding the header files when I copy the exact same CMake commands over to my main project. So I'm not free of this yet.
I should say that I was able to remove the change I made to BulletConfig.cmake of setting PACKAGE_PREFIX_DIR statically.
So just to recap my issue. A small test project works and I can use bullet and number of other libraries that I use in my main project. But if i copy this working CMakeLists.txt to my main project it can no longer find the headers and throws this error :
btBulletDynamicsCommon.h: No such file or directory
8 | #include <btBulletDynamicsCommon.h>
Bullet_DIR:PATH=/home/ash/vcpkg/installed/x64-linux/share/bullet3 is the same in both cases.
After all that.
The set_and_include() error is a known issue and mathisloge over at vcpkg git said the Bullet package needs to be updated. The workaround is to change the calls to set().
The ordering of the target libraries is important. The suggested way in the Bullet vcpkg package is :
target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)
But this fails to compile. It should be:
target_link_libraries(main PRIVATE BulletSoftBody BulletDynamics BulletCollision Bullet3Common LinearMath)
Also had to tell cmake the link directories using :
target_link_directories(main PRIVATE ${BULLET_LIBRARY_DIRS})
Then I still had header missing errors. But after a restart things just started working again. Hopefully there is enough here to help someone if they hit similar problems.

Linking issue using the Yocto SDK (undefined reference to `_rtld_global_ro')

I'm trying to build an application using the Yocto SDK. The compilation worked well, but when it comes to linking, following linker errors occurs:
...
/opt/mydistro/1.0.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/8.3.0/real-ld: /opt/mydistro/1.0.0/sysroots/cortexa9t2hf-neon-poky-linux-gnueabi/usr/lib/libc.a(getcontext.o): in function `getcontext':
/usr/src/debug/glibc/2.29-r0/git/stdlib/../sysdeps/unix/sysv/linux/arm/getcontext.S:101: undefined reference to `_rtld_global_ro'
/opt/mydistro/1.0.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/8.3.0/real-ld: /opt/mydistro/1.0.0/sysroots/cortexa9t2hf-neon-poky-linux-gnueabi/usr/lib/libc.a(setcontext.o): in function `__startcontext':
/usr/src/debug/glibc/2.29-r0/git/stdlib/../sysdeps/unix/sysv/linux/arm/setcontext.S:100: undefined reference to `_rtld_global_ro'
collect2: error: ld returned 1 exit status
makefile:116: recipe for target 'ortable' failed
make: *** [ortable] Error 1
I have really no clue, why the object '_rtld_global_ro' cannot be found. Could someone tell me what is going wrong and what I can do to link the application, please? Maybe, there is a workaround for this?
Other applications could be build with same setup without this issue (sourcing the SDK using following command):
source /opt/mydistro/1.0.0/environment-setup-cortexa9t2hf-neon-poky-linux-gnueabi
Here is the image bb file (which I have used for building the SDK using the command bitbake my-image -c populate_sdk).
require recipes-extended/images/core-image-full-cmdline.bb
IMAGE_INSTALL_append = " \
emmy-w1-driver-sdiosdio \
emmy-w1-systemd \
eth-systemd \
can-systemd \
can-utils \
lighttpd \
dnsmasq \
parted \
swupdate \
swupdate-www \
u-boot-fw-utils \
linux-firmware-imx-sdma-imx6q \
"
TOOLCHAIN_HOST_TASK_append = " nativesdk-perl-modules"
SDKIMAGE_FEATURES_append = " staticdev-pkgs"
This is an issue in the upstream glibc sources: The ARM assembler version of setcontext assumes that all PIC code is dynamic linked, which means that static linking fails if glibc was built in static PIE mode (because that actives PIC without providing the dynamic linker code).
You either need to build glibc without static PIE support (I did not even know this was a supported configuration for 32-bit ARM), or replace the PIC macro with SHARED in sysdeps/unix/sysv/linux/arm/setcontext.S.

PETSC 3.3 - How to compile and have all libpetscSOMETHING.so files?

I tried to compile PESTC using this configuration:
./configure --with-cc=gcc --with-cxx=g++ --with-fc=gfortran --download-f-blas-lapack=1 --download-openmpi --with-shared-libraries
make PETSC_DIR=/tmp/petsc-3.3-p7 PETSC_ARCH=arch-linux2-c-debug all
But when compiling my lib that uses petsc, even though I linked all petsc libs it's complain at runtime of: undefined symbol: _Z10VecGetSizeP6_p_VecPi, and after some search in the interne I came across some .so that my petsc didn't build, libs like libpetscvec.so or libpetscsnes.so.
I also found that it will generate some .mod with the same name of these non-generated libs (ex: /tmp/petsc-3.3-p7/arch-linux2-c-debug/include/petscsnes.mod).
so I'm not sure if I'm missing a flag that should tell the compiler to give me libs no modules, or maybe if they are in some external packages, and that I should install with --download-SOMEPACKAGE.
Here is the .so libs that are generated in the $PETSC_DIR/$PETSC_ARCH/lib:
libmca_common_sm.so
libmca_common_sm.so.1
libmca_common_sm.so.1.0.2
libmpi.so
libmpi.so.0
libmpi.so.0.0.4
libmpi_cxx.so
libmpi_cxx.so.0
libmpi_cxx.so.0.0.1
libmpi_f77.so
libmpi_f77.so.0
libmpi_f77.so.0.0.3
libmpi_f90.so
libmpi_f90.so.0
libmpi_f90.so.0.1.0
libopen-pal.so
libopen-pal.so.0
libopen-pal.so.0.0.0
libopen-rte.so
libopen-rte.so.0
libopen-rte.so.0.0.0
libopenmpi_malloc.so
libopenmpi_malloc.so.0
libopenmpi_malloc.so.0.0.0
libpetsc.so
This one was quite trick here is how I solved it:
./configure --with-pic=1 \
--with-x11=0 --download-openmpi=yes \
--doCleanup=1 --useThreads=0 \
--with-shared-libraries=1 --with-clanguage=Cxx \
--with-c++-support --with-fc=0 --ignore-cygwin-link \
--with-blas-lib="[$VENDOR_LIBS/intel/mkl/lib/intel64/libmkl_blas95_lp64.a,$VENDOR_LIBS/intel/mkl/lib/intel64/libmkl_intel_lp64.so,$VENDOR_LIBS/intel/mkl/lib/intel64/libmkl_core.so,$VENDOR_LIBS/intel/mkl/lib/intel64/libmkl_intel_thread.so,$VENDOR_LIBS/intel/lib/intel64/libiomp5.so]" \
--with-lapack-lib="[$VENDOR_LIBS/intel/mkl/lib/intel64/libmkl_lapack95_lp64.a]"
So, yes, I saw that I was missing the Intel MKL libraries (that was a big part of the error, but also was the rest of the arguments passed in the configure).
I'm not sure if this is something that will be useful for others, since this lib has tons of different configurations for many cases. But, hey, who knows...

Undefined Symbols even with explicit links

Been dealing in linker hell for the past day and figured I'd throw this out there and see if anyone could help me out.
I have two shared libraries that I'm building: one called "libhttp" that has some helper functions for the http protocol which seems to be building for better or worse OK. The second is called "libvpcutil" which is causing the issues. It depends on symbols that are in libhttp so I link it against libhttp. Here's the compilation directive (exploded from the make file) with minor things like my personal path to openssl generified:
g++ -shared -Wl,-soname,libvpcutil.so.1 -o libvpcutil.so.1.0 vpcreg/registry.o \
vpcreg/vpcreg2.o dbase/dbase.o dbase/sqlutils.o diaglog/diaglog.o errmsg/errmsg.o \
faillib/faillib.o failover/failover.o initerr/init_err.o kmq/kmq.o kmq/publish.o \
kthread/kcom.o kthread/kthread.o libobdi/odi_serv.o mutex/mutex.o netserv/netserv.o \
newmem/newmem.o rmtstore/avlmem.o rmtstore/rmtstore.o rmtstore/shm_aloc.o \
servhand/servhand.o timers/timers.o vpcstamp/vpcstamp.o websql/websql.o types/blob.o \
types/hitime.o types/ticks.o types/timestamp.o odasm/odasm.o webvibapi/webvibapi.o \
vibusfeed/vibusfeed.o propstore/propstore2.o cardlib/cardlib.o cardlib/sortlist.o \
gapi/genapi.o -L/usr/lib/i386-linux-gnu -lm -lrt -lxml2 -lodbc -L/usr/lib/i386-linux-gnu -\
lcurl -Wl,-Bsymbolic-functions -Wl,-z,relro \
-L/pathtoopenssl/openssl -lssl -lcrypto -lxml2 -lreadline -\
lcurses -Wl,-rpath=.:/pathtobin/bin http/libhttp.so.1.0 ../ddldata/ddldata.o
../cardddl/cardddl.o ../gendata/generic.o
The compilation and linking completes successfully. Hopefully you noted the link step to http/libhttp.so.1.0.
Now, if I do a nm on libhttp.so.1.0, I get the following output (amongst others):
00015d5a T _ZN12http_cookiesC1Ev
00015d5a T _ZN12http_cookiesC2Ev
00015d7e T _ZN12http_cookiesD1Ev
00015d7e T _ZN12http_cookiesD2Ev
00011574 T _ZN12http_headers11url_expressERSo
00011466 T _ZN12http_headers12http_expressERSo
But when I do a nm on libvpcutil.so.1.0 I get essentially:
U _ZN12http_cookiesC1Ev
U _ZN12http_cookiesD1Ev
U _ZN12http_headers11url_expressERSo
U _ZN12http_headers3setEPKcRKSs
U _ZN12http_headers3setEPKcS1_
U _ZN12http_headersC1Ev
U _ZN12http_headersD1Ev
I'm obviously snipping here, but where I'm stuck here is the symbols are clearly defined in libhttp, I link against it for libvpcutil, but then the symbols are undefined in libvpcutil. This creates runtime errors.
Anyone see the issue?
That looks like the expected behaviour.
Linking to a shared library is not like linking to a static library, the required symbols do not get copied into the output file, you just get a reference to the symbol which must still be resolved at run-time. So it's normal that the symbols are shown as U by nm.
What are the run-time errors? It probably means the libhttp.so.1.0 library isn't found at run-time. You should be able to run ldd on libvpcutil.so and on the executable to see if they depend on libhttp.so.1.0 and if they're finding the right one.
Does libhttp.so.1.0 have a soname set? If it's not the same as the filename, do you have a symlink with the same name as the soname? (e.g. if the soname is libhttp.so.1 you'll need a symlink libhttp.so.1 -> libhttp.so.1.0). I also see your libhttp.so.1.0 is in a directory called http but that's not in your RPATH, so won't be found at runtime.

Resources