jtv / libpqxx

The official C++ client API for PostgreSQL.
http://pqxx.org/pqxx/
BSD 3-Clause "New" or "Revised" License
962 stars 228 forks source link

Undefined references while compiling project #820

Closed ZhengLinLei closed 1 month ago

ZhengLinLei commented 2 months ago

I'm having troubles compiling my project. It shows undefined references error.

Information:

Problem

When I try to compile the project with:

g++ -Ih -I/usr/pgsql-14/include/ -I/usr/local/include/ -L/usr/pgsql-14/lib/ -lpthread -lpqxx -lpq ../build/base_DB.o ../build/base_ServerComm.o ../build/main_RouteServer.o -o ../dist/server

I have this error:

#0 2.411 g++ -Ih -I/usr/pgsql-14/include/ -I/usr/local/include/ -L/usr/pgsql-14/lib/ -lpthread -lpqxx -lpq ../build/base_DB.o ../build/base_ServerComm.o ../build/main_RouteServer.o -o ../dist/OronetaCoreServer
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)':
#0 2.477 base_DB.cpp:(.text+0x198): undefined reference to `pqxx::argument_error::argument_error(std::string const&)'
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `DB_connection(char const*, int, char const*, char const*)':
#0 2.477 base_DB.cpp:(.text+0x270): undefined reference to `pqxx::connection::operator=(pqxx::connection&&)'
#0 2.477 /usr/bin/ld: base_DB.cpp:(.text+0x280): undefined reference to `pqxx::connection::is_open() const'
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `__static_initialization_and_destruction_0(int, int)':
#0 2.477 base_DB.cpp:(.text+0x4cc): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
#0 2.477 /usr/bin/ld: base_DB.cpp:(.text+0x50c): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
#0 2.477 /usr/bin/ld: base_DB.cpp:(.text+0x54c): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
#0 2.477 /usr/bin/ld: base_DB.cpp:(.text+0x58c): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `pqxx::check_version()':
#0 2.477 base_DB.cpp:(.text._ZN4pqxx13check_versionEv[_ZN4pqxx13check_versionEv]+0x4c): undefined reference to `pqxx::internal::check_pqxx_version_7_9()'
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `pqxx::connection::connection(char const*)':
#0 2.477 base_DB.cpp:(.text._ZN4pqxx10connectionC2EPKc[_ZN4pqxx10connectionC5EPKc]+0x50): undefined reference to `pqxx::connection::init(char const*)'
#0 2.477 /usr/bin/ld: ../build/base_DB.o: in function `pqxx::connection::~connection()':
#0 2.477 base_DB.cpp:(.text._ZN4pqxx10connectionD2Ev[_ZN4pqxx10connectionD5Ev]+0x10): undefined reference to `pqxx::connection::close()'
#0 2.478 /usr/bin/ld: ../build/main_RouteServer.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)':
#0 2.478 main_RouteServer.cpp:(.text+0x198): undefined reference to `pqxx::argument_error::argument_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
#0 2.478 /usr/bin/ld: ../build/main_RouteServer.o: in function `__static_initialization_and_destruction_0(int, int)':
#0 2.478 main_RouteServer.cpp:(.text+0x12fc): undefined reference to `pqxx::internal::demangle_type_name[abi:cxx11](char const*)'
#0 2.478 /usr/bin/ld: main_RouteServer.cpp:(.text+0x133c): undefined reference to `pqxx::internal::demangle_type_name[abi:cxx11](char const*)'
#0 2.478 /usr/bin/ld: main_RouteServer.cpp:(.text+0x14bc): undefined reference to `pqxx::internal::demangle_type_name[abi:cxx11](char const*)'
#0 2.478 /usr/bin/ld: main_RouteServer.cpp:(.text+0x1630): undefined reference to `pqxx::internal::demangle_type_name[abi:cxx11](char const*)'
#0 2.486 collect2: error: ld returned 1 exit status
tt4g commented 2 months ago

Similar issue #732

This may be due to different compile-time options, especially the -std=<CXX_VERSION> flag. Do you know what the options are when you run the make command?

ZhengLinLei commented 2 months ago

It use by default C++17 for the compilation. Also I tried changing it to C++20 but doesn't work.

tt4g commented 2 months ago

If the compile options match, then there may be another version libpqxx installed on the machine and the linker links to it.

ZhengLinLei commented 2 months ago

Nope. I'm using a docker container with empty RHEL9 image, and this is all the portion of dockerfile code relationated with libpqxx:


# Install postgresql library libpqxx
RUN yum install --nogpgcheck -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm && \
    yum install --nogpgcheck --skip-broken -y postgresql14-14.7 postgresql14-devel-14.7 postgresql14-libs-14.7

WORKDIR /opt

# Download libpqxx
RUN wget https://github.com/jtv/libpqxx/archive/refs/tags/7.9.0.tar.gz -O Libpqxx.tar.gz
# Create directory for pqxx
RUN mkdir -p libpqxx
# Extract libpqxx
RUN tar xvfz Libpqxx.tar.gz -C libpqxx --strip-components=1

WORKDIR /opt/libpqxx
RUN ./configure --with-postgres-lib=/usr/pgsql-14/lib --with-postgres-include=/usr/pgsql-14/include --build=aarch64-unknown-linux-gnu
RUN make && make install
tt4g commented 2 months ago

Is the default compiler for that Docker image g++? If not, libpqxx may be built with a different compiler unless you specify the compiler by CXX environment variable.

ZhengLinLei commented 2 months ago

Yes, the default compiler is g++. By the way I tried compiling with prebuilt libpqxx with yum, and I got fewer errors.

6.625 g++ -std=c++17 -Ih -I/usr/pgsql-14/include/ -I/usr/include/ -L/usr/pgsql-14/lib/ -L/usr/lib64/ -lpthread -lpqxx -lpq ../build/base_DB.o ../build/base_ServerComm.o ../build/main_RouteServer.o -o ../dist/OronetaCoreServer
6.821 /usr/bin/ld: ../build/base_DB.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)':
6.822 base_DB.cpp:(.text+0x1ab): undefined reference to `pqxx::argument_error::argument_error(std::string const&)'
6.822 /usr/bin/ld: ../build/base_DB.o: in function `__static_initialization_and_destruction_0(int, int)':
6.822 base_DB.cpp:(.text+0x4d1): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
6.822 /usr/bin/ld: base_DB.cpp:(.text+0x4ff): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
6.822 /usr/bin/ld: base_DB.cpp:(.text+0x52d): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
6.822 /usr/bin/ld: base_DB.cpp:(.text+0x55b): undefined reference to `pqxx::internal::demangle_type_name(char const*)'
tt4g commented 2 months ago

Are object files ( base_DB.o, base_ServerComm.o ...) built with the same image? And what happens by adding RUN dnf group install -y "Development Tools" to the Dockerfile?

ZhengLinLei commented 1 month ago

Are object files ( base_DB.o, base_ServerComm.o ...) built with the same image?

Yes.

And what happens by adding RUN dnf group install -y "Development Tools" to the Dockerfile?

Cannot find it because I don't have any official package suscription. I'm installing all the packages individually

RUN yum update -y
RUN yum install -y  \
        wget        \ 
        tar         \
        vim         \
        gcc-c++     \
        make        \
        cmake       \
        openssl-devel
tt4g commented 1 month ago

If you have built base_DB.o and others with the same compile options as libpqxx, there should be no logical reason for a link error due to undefined reference. The missing symbols must either be due to different mangle rules or different compilation options, but I can't think of a better cause.

ZhengLinLei commented 1 month ago

A will try to find any other solution to fix this using other OS image or using libpq++. Thanks for helping me. 😄

jtv commented 1 month ago

@ZhengLinLei to set an explicit C++ version, add this option to the configure command line: CXXFLAGS=-std=c++17 (for C++17), or CXXFLAGS=-std=c++20 (for C++20), etc.

jtv commented 1 month ago

@ZhengLinLei it looks like a very strange problem... I see some of the errors that you'd normally get when libpqxx and your application are compiled differently, or you're getting a different libpqxx version at link time than at compile time. But I also see much more basic link errors.

Could the libpqxx binary you built be damaged somehow, or even missing from the install location?

AFAIK it shouldn't matter but... What if you put the -lpqxx -lpq -lpthread on the command line after your own object files?

ZhengLinLei commented 1 month ago

@ZhengLinLei it looks like a very strange problem... I see some of the errors that you'd normally get when libpqxx and your application are compiled differently, or you're getting a different libpqxx version at link time than at compile time. But I also see much more basic link errors.

Using the avaliable package with yum (libpqxx v7.9.0) , the lib is installed in /usr/lib64 and the headers in /usr/include

g++ -std=c++17 -Ih -I/usr/pgsql-14/include/ -I/usr/include/ -L/usr/pgsql-14/lib/ -L/usr/lib64/ -lpthread -lpqxx -lpq ../build/base_DB.o ../build/base_ServerComm.o ../build/main_RouteServer.o -o ../dist/OronetaCoreServer

Lib imagen

Include imagen imagen

Could the libpqxx binary you built be damaged somehow, or even missing from the install location?

As you see, I tried using the prebuilt package and same errors.

It is very strange, I tried everything from internet and similar issues solutions, and nothing worked.

Additional information

Makefile

# Makefile  C

# Directories
SRC_DIR = c
INC_DIR = -Ih -I/usr/pgsql-14/include/ -I/usr/include/
LINK_DIR = -L/usr/pgsql-14/lib/ -L/usr/lib64/
LIB_DIR = -lpqxx -lpq -lpthread 
BUILD_DIR = ../build
DIST_DIR = ../dist
PROJECT_NAME = OronetaCoreServer

# Source code and object
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))

# Name of project
TARGET = $(DIST_DIR)/$(PROJECT_NAME)

# Compiler and options flag "no warning"
CC = g++
CFLAGS = -std=c++17 $(INC_DIR) $(LINK_DIR) $(LIB_DIR)

# Main executable program
all: $(TARGET)

# g++ --all
$(TARGET): $(OBJS)
    @mkdir -p $(DIST_DIR)
    $(CC) $(CFLAGS) $(OBJS) -o $(TARGET)

# g++ --code
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
    @mkdir -p $(BUILD_DIR)
    $(CC) $(CFLAGS) -c $< -o $@

# Regla para limpiar
clean:
    rm -rf $(BUILD_DIR)/*.o $(TARGET) ../dist/*.tgz ../dist/*.tar
tt4g commented 1 month ago

@ZhengLinLei If you specify CFLAGS = -std=c++17 in your project, you must specify -std=c++17 when building libpqxx.

-./configure --with-postgres-lib=/usr/pgsql-14/lib --with-postgres-include=/usr/pgsql-14/include
+./configure --with-postgres-lib=/usr/pgsql-14/lib --with-postgres-include=/usr/pgsql-14/include CXXFLAGS="-std=c++17"
 make && make install

And CC and CFLAGS are variables used for the C compiler. When compiling C++, you should use CXX and CXXFLAGS. Otherwise you will encounter strange errors. See also: https://stackoverflow.com/questions/5541946/cflags-ccflags-cxxflags-what-exactly-do-these-variables-control

jtv commented 1 month ago

We've had a lot of trouble with prepackaged libraries in part because no packaging system out there seems to take differences in compiler, compiler version, and C++ version into account. So it's easy to end up with incompatible binaries.

The other part is that the libpqxx exception class hierarchy had different ABIs depending on whether you compiled as C++17 or a newer version. And so you'd get link errors if you compiled the application and libpqxx as different C++ versions. But we changed that in 7.9.0.

jtv commented 1 month ago

@ZhengLinLei any chance you could run grep -rI DEMANGLE in the directory where the libpqxx headers got installed?

I'd expect to see it defined. It's almost as if the libpqxx build itself isn't seeing the config header...

jtv commented 1 month ago

In #828 we found that the real problem was a bad command line: in that case the compilation was done with g++ -lpqxx -lpq app.cxx. Changing it to g++ app.cxx -lpqxx -lpq solved the problem.