epics-base / p4p

Python bindings for the PVAccess network client and server.
BSD 3-Clause "New" or "Revised" License
27 stars 38 forks source link

Undefined Reference when building p4p #65

Closed princessirabor closed 3 years ago

princessirabor commented 3 years ago

I get the following error when I build p4p as an EPICS module .

Steps followed

  1. Install python dependencies conda activate p4p export EPICS_HOST_ARCH=linux-x86_64 export EPICS_BASE=/opt/develop/epics/base conda install numpy nose Cython ply

  2. Set Location of EPICS module(base-7.0.4) cat < configure/RELEASE.local EPICS_BASE=/opt/develop/epics/base EOF make

python ../bootgw.py -P "../../python3.8/linux-x86_64" pvagw Installing created executable ../../bin/linux-x86_64/pvagw mkdir ../../bin mkdir ../../bin/linux-x86_64 make[2]: Leaving directory '/opt/develop/test_p4p/p4p/src/O.linux-x86_64' make[1]: Leaving directory '/opt/develop/test_p4p/p4p/src' make -C ./testing install make[1]: Entering directory '/opt/develop/test_p4p/p4p/testing' perl -CSD /opt/develop/epics/base-7.0.4/bin/linux-x86_64/makeMakefile.pl O.linux-x86_64 ../.. mkdir -p O.Common make -C O.linux-x86_64 -f ../Makefile TOP=../.. \ T_A=linux-x86_64 install make[2]: Entering directory '/opt/develop/test_p4p/p4p/testing/O.linux-x86_64' /usr/bin/g++ -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_X8664 -DUNIX -Dlinux -O3 -Wall -mtune=generic -m64 -Werror=pointer-arith -fvisibility=hidden -std=c++98 -fvisibility-inlines-hidden -I. -I../O.Common -I. -I. -I.. -I../../include/compiler/gcc -I../../include/os/Linux -I../../include -I/opt/develop/epics/base-7.0.4//include/compiler/gcc -I/opt/develop/epics/base-7.0.4//include/os/Linux -I/opt/develop/epics/base-7.0.4//include -MM -MF odometer.d ../odometer.cpp /usr/bin/g++ -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_X8664 -DUNIX -Dlinux -O3 -Wall -mtune=generic -m64 -Werror=pointer-arith -fvisibility=hidden -std=c++98 -fvisibility-inlines-hidden -I. -I../O.Common -I. -I. -I.. -I../../include/compiler/gcc -I../../include/os/Linux -I../../include -I/opt/develop/epics/base-7.0.4//include/compiler/gcc -I/opt/develop/epics/base-7.0.4//include/os/Linux -I/opt/develop/epics/base-7.0.4//include -c ../odometer.cpp /usr/bin/g++ -o odometer -L/opt/develop/test_p4p/p4p/lib/linux-x86_64 -L/opt/develop/epics/base-7.0.4/lib/linux-x86_64 -Wl,-rpath,/opt/develop/test_p4p/p4p/lib/linux-x86_64 -Wl,-rpath,/opt/develop/epics/base-7.0.4/lib/linux-x86_64 -rdynamic -m64 odometer.o -lpvAccess -lpvData -ldbRecStd -ldbCore -lca -lCom
odometer.o: In function (anonymous namespace)::CounterProvider::channelFind(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::tr1::shared_ptr<epics::pvAccess::ChannelFindRequester> const&)': odometer.cpp:(.text+0x452): undefined reference toepics::pvAccess::ChannelFind::buildDummy(std::tr1::shared_ptr const&)' odometer.o:(.rodata+0x530): undefined reference to epics::pvAccess::ChannelProvider::channelList(std::tr1::shared_ptr<epics::pvAccess::ChannelListRequester> const&)' odometer.o:(.rodata+0x538): undefined reference toepics::pvAccess::ChannelProvider::createChannel(std::cxx11::basic_string<char, std::char_traits, std::allocator > const&, std::tr1::shared_ptr const&, short)' odometer.o:(.rodata+0x788): undefined reference to `epics::pvAccess::Channel::getField(std::tr1::shared_ptr const&, std::cxx11::basic_string<char, std::char_traits, std::allocator > const&)' odometer.o:(.rodata+0x790): undefined reference to epics::pvAccess::Channel::getAccessRights(std::tr1::shared_ptr<epics::pvData::PVField> const&)' odometer.o:(.rodata+0x798): undefined reference toepics::pvAccess::Channel::createChannelProcess(std::tr1::shared_ptr const&, std::tr1::shared_ptr const&)' odometer.o:(.rodata+0x7a8): undefined reference to epics::pvAccess::Channel::createChannelPut(std::tr1::shared_ptr<epics::pvAccess::ChannelPutRequester> const&, std::tr1::shared_ptr<epics::pvData::PVStructure> const&)' odometer.o:(.rodata+0x7b0): undefined reference toepics::pvAccess::Channel::createChannelPutGet(std::tr1::shared_ptr const&, std::tr1::shared_ptr const&)' odometer.o:(.rodata+0x7b8): undefined reference to epics::pvAccess::Channel::createChannelRPC(std::tr1::shared_ptr<epics::pvAccess::ChannelRPCRequester> const&, std::tr1::shared_ptr<epics::pvData::PVStructure> const&)' odometer.o:(.rodata+0x7c0): undefined reference toepics::pvAccess::Channel::createMonitor(std::tr1::shared_ptr const&, std::tr1::shared_ptr const&)' odometer.o:(.rodata+0x7c8): undefined reference to `epics::pvAccess::Channel::createChannelArray(std::tr1::shared_ptr const&, std::tr1::shared_ptr const&)' collect2: error: ld returned 1 exit status make[2]: [/opt/develop/epics/base-7.0.4//configure/RULES_BUILD:213: odometer] Error 1 make[2]: Leaving directory '/opt/develop/test_p4p/p4p/testing/O.linux-x86_64' make[1]: [/opt/develop/epics/base-7.0.4//configure/RULES_ARCHS:58: install.linux-x86_64] Error 2 make[1]: Leaving directory '/opt/develop/test_p4p/p4p/testing' make: *** [/opt/develop/epics/base-7.0.4//configure/RULES_DIRS:85: testing.install] Error 2

mdavidsaver commented 3 years ago
EPICS_BASE=/opt/develop/epics/base

Was Base built on the same host, with the same compiler version options? The symbols mentioned as undefined should be provided by libpvAccess.so. Code using this library must be compiled with the same C++ language options used to build the library itself.

$ nm -g -C lib/linux-x86_64/libpvAccess.so|grep createChannelProcess
00000000000642a0 T epics::pvAccess::Channel::createChannelProcess(std::shared_ptr<epics::pvAccess::ChannelProcessRequester> const&, std::shared_ptr<epics::pvData::PVStructure> const&)

As can be seen in this example from my laptop, the symbol names are slightly different when built with -std=c++11, as opposed to -std=c++98 which appears in your build of P4P.

fyi. you could also try to install my pre-built binaries from pypi.org with pip install p4p.

princessirabor commented 3 years ago

Thank you for your prompt feedback. Base was built on the same host with same version (g++ (GCC) 8.3.1 20190507 (Red Hat 8.3.1-4)). Base and p4p were built without any compiler flags. I still got the same error when I tried to build p4p with -std=c++11.

$ nm -g -C /opt/_develop/epics/base-7.0.4/lib/linux-x86_64/libpvAccess.so.7.1.1|grep createChannelProcess 000000000009c030 T epics::pvAccess::Channel::createChannelProcess(std::shared_ptr const&, std::shared_ptr const&)

How do I ensure p4p is built correctly with -std=c++11,?

Also attaching output for completeness output.txt

mdavidsaver commented 3 years ago

from you output.txt

/usr/bin/g++ ... -std=c++14   ...  -std=c++98

It looks like -std=c++98 is still sneaking in somehow, and overriding the earlier -std=c++14.

grep -R 'c++98' /opt/develop/test_p4p /opt/_develop/epics/base-7.0.4

will hopefully find this.

princessirabor commented 3 years ago

I set the cxxflags and cppflags to explicitly use c++14 (so c++98 no longer shows up) but I got the error below even when I recompiled with -fPIC. The *.o files exist under /opt/develop/test_p4p/p4p/src/O.linux-x86_64. The output is the same when I use c++11 and c++98. (Also see attached output when I attempt to run it with -no-pie flag)

/usr/bin/ld: p4p_top.o: relocation R_X86_64_32 against .rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_type.o: relocation R_X86_64_32S against.rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_value.o: relocation R_X86_64_32 against .rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_array.o: relocation R_X86_64_32 against symbol_ZN14PyClassWrapperIN5epics6pvData13shared_vectorIKvvEELb0EE4typeE' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_server.o: relocation R_X86_64_32 against .rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_server_provider.o: relocation R_X86_64_32 against.rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_server_sharedpv.o: relocation R_X86_64_32 against .rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: p4p_client.o: relocation R_X86_64_32 against.rodata' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Nonrepresentable section on output collect2: error: ld returned 1 exit status make[2]: [/opt/develop/epics/base-7.0.4//configure/RULES_BUILD:311: _p4p.so] Error 1 make[2]: Leaving directory '/opt/develop/test_p4p/p4p/src/O.linux-x86_64' make[1]: [/opt/develop/epics/base-7.0.4//configure/RULES_ARCHS:58: install.linux-x86_64] Error 2 make[1]: Leaving directory '/opt/develop/test_p4p/p4p/src' make: *** [/opt/develop

undefinedref_nopie.txt

mdavidsaver commented 3 years ago

Have you done a full clean (make distclean) and rebuild of both Base and P4P after changing build flags? (-std=* or otherwise)

princessirabor commented 3 years ago

I was able to build after doing a full clean and rebuild of Base. However, I get an undefined symbol error when I run pvvagw. I was previously getting an ImportError: libpvAccess.so.7.0.4.99.0: cannot open shared object file: No such file or directory so I added epocscorelibs/lib to my library path. Thanks for your help $ pvagw -v ~/gwconfig Traceback (most recent call last): File "/home/user1/miniconda3/envs/p4p/bin/pvagw", line 33, in sys.exit(load_entry_point('p4p==3.5.3a1', 'console_scripts', 'pvagw')()) File "/home/user1/miniconda3/envs/p4p/bin/pvagw", line 25, in importlib_load_entry_point return next(matches).load() File "/home/user1/miniconda3/envs/p4p/lib/python3.8/importlib/metadata.py", line 77, in load module = import_module(match.group('module')) File "/home/user1/miniconda3/envs/p4p/lib/python3.8/importlib/init.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1014, in _gcd_import File "", line 991, in _find_and_load File "", line 961, in _find_and_load_unlocked File "", line 219, in _call_with_frames_removed File "", line 1014, in _gcd_import File "", line 991, in _find_and_load File "", line 975, in _find_and_load_unlocked File "", line 671, in _load_unlocked File "", line 783, in exec_module File "", line 219, in _call_with_frames_removed File "/home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/p4p-3.5.3a1-py3.8-linux-x86_64.egg/p4p/init.py", line 11, in from .wrapper import Value, Type File "/home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/p4p-3.5.3a1-py3.8-linux-x86_64.egg/p4p/wrapper.py", line 5, in from ._p4p import TypeBase, ValueBase ImportError: libpvAccess.so.7.0.4.99.0: cannot open shared object file: No such file or directory (p4p) [user1@-develop p4p]$ export LD_LIBRARY_PATH=$(echo /home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/epicscorelibs/lib) (p4p) [user1@-develop p4p]$ pvagw -v ~/gwconfig Traceback (most recent call last): File "/home/user1/miniconda3/envs/p4p/bin/pvagw", line 33, in sys.exit(load_entry_point('p4p==3.5.3a1', 'console_scripts', 'pvagw')()) File "/home/user1/miniconda3/envs/p4p/bin/pvagw", line 25, in importlib_load_entry_point return next(matches).load() File "/home/user1/miniconda3/envs/p4p/lib/python3.8/importlib/metadata.py", line 77, in load module = import_module(match.group('module')) File "/home/user1/miniconda3/envs/p4p/lib/python3.8/importlib/init.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1014, in _gcd_import File "", line 991, in _find_and_load File "", line 961, in _find_and_load_unlocked File "", line 219, in _call_with_frames_removed File "", line 1014, in _gcd_import File "", line 991, in _find_and_load File "", line 975, in _find_and_load_unlocked File "", line 671, in _load_unlocked File "", line 783, in exec_module File "", line 219, in _call_with_frames_removed File "/home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/p4p-3.5.3a1-py3.8-linux-x86_64.egg/p4p/init.py", line 11, in from .wrapper import Value, Type File "/home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/p4p-3.5.3a1-py3.8-linux-x86_64.egg/p4p/wrapper.py", line 5, in from ._p4p import TypeBase, ValueBase ImportError: /home/user1/miniconda3/envs/p4p/lib/python3.8/site-packages/p4p-3.5.3a1-py3.8-linux-x86_64.egg/p4p/_p4p.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN5epics8pvAccess20ConfigurationBuilder4_addERKNSt7__cxx1112basic_stringIcSt11chartraitsIcESaIcEEES9

mdavidsaver commented 3 years ago

What changes to Base (under configure/ or otherwise) are you making?

I added epocscorelibs/lib to my library path.

The default uses -rpath to encoded this path automatically, which makes setting $LD_LIBRARY_PATH unnecessary.

As a test. Could you please unset all $EPICS_* environment variables and try to run the following:

install -d /tmp/p4pbuild
cd /tmp/p4pbuild
virtualenv -p python3 env
. env/bin/activate
git clone --depth 1 --recursive https://github.com/epics-base/epics-base
git clone --depth 1 --recursive https://github.com/mdavidsaver/p4p
cat <<EOF > p4p/configure/RELEASE.local
EPICS_BASE=\$(TOP)/../epics-base
EOF
pip install -r p4p/requirements-latest.txt
make -C epics-base
make -C p4p
./p4p/bin/linux-x86_64/pvagw p4p/loopback.conf

This being one of the variants described in https://mdavidsaver.github.io/p4p/building.html#build-as-epics-module

princessirabor commented 3 years ago

I was able to run the test successfully. No changes were made to Base. I think the issue was the path the required packages were installed to when I used conda install. It works now. Thanks for your help.

mdavidsaver commented 3 years ago

The build logs you shared don't show any sign, but maybe you've picked up a conda packaged build of epics-base as well? Having multiple versions in play is a good way to get confused.