在 C++ 项目中链接 libpq 时未定义的引用
Undefined reference when linking libpq in C++ project
我正在尝试在 C++ 项目中使用 libpqxx
(并且隐含地 libpq
)。
我使用 vcpkg
作为 submodule
通过设置 CMAKE_TOOLCHAIN_FILE
.
来获取我的库
当我尝试构建时,出现以下错误:
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `pg_fe_sendauth':
fe-auth.c:(.text+0x4fe): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: fe-auth.c:(.text+0x51b): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `pg_fe_getauthname':
fe-auth.c:(.text+0x838): undefined reference to `pqGetpwuid'
/usr/bin/ld: fe-auth.c:(.text+0x8a4): undefined reference to `pg_strerror_r'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `PQencryptPassword':
fe-auth.c:(.text+0x936): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `PQencryptPasswordConn':
fe-auth.c:(.text+0x9ed): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth-scram.o): in function `build_client_final_message':
fe-auth-scram.c:(.text+0xdb): undefined reference to `scram_SaltedPassword'
/usr/bin/ld: fe-auth-scram.c:(.text+0xee): undefined reference to `scram_ClientKey'
/usr/bin/ld: fe-auth-scram.c:(.text+0xfe): undefined reference to `scram_H'
/usr/bin/ld: fe-auth-scram.c:(.text+0x113): undefined reference to `scram_HMAC_init'
/usr/bin/ld: fe-auth-scram.c:(.text+0x12d): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x141): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x15b): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x16f): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x185): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x195): undefined reference to `scram_HMAC_final'
/usr/bin/ld: fe-auth-scram.c:(.text+0x1e4): undefined reference to `pg_b64_enc_len'
/usr/bin/ld: fe-auth-scram.c:(.text+0x213): undefined reference to `pg_b64_encode'
/usr/bin/ld: fe-auth-scram.c:(.text+0x344): undefined reference to `pg_b64_enc_len'
/usr/bin/ld: fe-auth-scram.c:(.text+0x368): undefined reference to `pg_b64_encode'
...
我在这里分解了 linking 命令:
/usr/bin/cmake -E cmake_link_script CMakeFiles/hello-pq.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/hello-pq.dir/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp.o CMakeFiles/hello-pq.dir/main.cpp.o
-o ../bin/hello-pq
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a
-lpthread
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a -ldl
我的 CMakeLists.txt
看起来像这样:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../../third-party/vcpkg/scripts/buildsystems/vcpkg.cmake
CACHE STRING "Vcpkg toolchain file")
project(hello-pq)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
find_package(OpenSSL REQUIRED)
find_package(libpqxx CONFIG REQUIRED)
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
target_link_libraries(${PROJECT_NAME}
PRIVATE OpenSSL::SSL
PRIVATE OpenSSL::Crypto
PRIVATE libpqxx::pqxx)
我用 nm
查看了 vcpkg
installed 目录中的 libpq.a
,我可以看到 pg_md5_encrypt
显示为 undefined:
U pg_md5_encrypt
我不明白,pg_md5_encrypt
这些缺失的功能在哪里?
是否有另一个 libpq...
我需要 link 或者可能是不同的版本?
经过更多的挖掘和测试后,我发现我还需要 2 个 postgres
静态库 link:
- libpqcommon.a
- libpgport.a
此外,link 顺序也很重要,尽管我预计必须在 libs that need them
之前通过 libs that are needed
,但这里并非如此,感觉倒退了。
这是一个有效的 linker 命令:
usr/bin/c++ CMakeFiles/hello-pq.dir/src/main.cpp.o \
-o ../bin/hello-pq \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgcommon.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgport.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a \
-lpthread \
-ldl
为了 link 额外的 2 个静态库并实现上述顺序,我更新了 CMakeLists.txt
如下:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../../third-party/vcpkg/scripts/buildsystems/vcpkg.cmake
CACHE STRING "Vcpkg toolchain file")
project(hello-pq)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
find_package(OpenSSL REQUIRED)
#find_package(PostgreSQL REQUIRED) # Not needed (it will duplicate the libs)
find_package(libpqxx CONFIG REQUIRED)
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
target_link_libraries(${PROJECT_NAME}
PRIVATE libpqxx::pqxx
PRIVATE PostgreSQL::PostgreSQL
PRIVATE OpenSSL::SSL
PRIVATE OpenSSL::Crypto)
这转化为以下 linker 命令:
/usr/bin/c++ \
CMakeFiles/hello-pq.dir/src/main.cpp.o \
-o ../bin/hello-pq \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgport.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgcommon.a \
-ldl \
-lpthread
我们可以看到 libpq.a
在 link 个参数中出现了两次:
- 一次由于
libpqxx::pqxx
目标(我假设)
- 一次由于
PostgreSQL::PostgreSQL
目标
其中还包含需要 linked 的 2 个缺失的静态库(libpgport.a
和 libpgcommon.a
)。
我的结论是这是一个 libpqxx
错误,它也应该 link 在它公开的唯一目标中具有 target_link_libraries(PUBLIC...)
的 2 个静态库(libpqxx::pqxx
)
我正在尝试在 C++ 项目中使用 libpqxx
(并且隐含地 libpq
)。
我使用 vcpkg
作为 submodule
通过设置 CMAKE_TOOLCHAIN_FILE
.
当我尝试构建时,出现以下错误:
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `pg_fe_sendauth':
fe-auth.c:(.text+0x4fe): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: fe-auth.c:(.text+0x51b): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `pg_fe_getauthname':
fe-auth.c:(.text+0x838): undefined reference to `pqGetpwuid'
/usr/bin/ld: fe-auth.c:(.text+0x8a4): undefined reference to `pg_strerror_r'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `PQencryptPassword':
fe-auth.c:(.text+0x936): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth.o): in function `PQencryptPasswordConn':
fe-auth.c:(.text+0x9ed): undefined reference to `pg_md5_encrypt'
/usr/bin/ld: /home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a(fe-auth-scram.o): in function `build_client_final_message':
fe-auth-scram.c:(.text+0xdb): undefined reference to `scram_SaltedPassword'
/usr/bin/ld: fe-auth-scram.c:(.text+0xee): undefined reference to `scram_ClientKey'
/usr/bin/ld: fe-auth-scram.c:(.text+0xfe): undefined reference to `scram_H'
/usr/bin/ld: fe-auth-scram.c:(.text+0x113): undefined reference to `scram_HMAC_init'
/usr/bin/ld: fe-auth-scram.c:(.text+0x12d): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x141): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x15b): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x16f): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x185): undefined reference to `scram_HMAC_update'
/usr/bin/ld: fe-auth-scram.c:(.text+0x195): undefined reference to `scram_HMAC_final'
/usr/bin/ld: fe-auth-scram.c:(.text+0x1e4): undefined reference to `pg_b64_enc_len'
/usr/bin/ld: fe-auth-scram.c:(.text+0x213): undefined reference to `pg_b64_encode'
/usr/bin/ld: fe-auth-scram.c:(.text+0x344): undefined reference to `pg_b64_enc_len'
/usr/bin/ld: fe-auth-scram.c:(.text+0x368): undefined reference to `pg_b64_encode'
...
我在这里分解了 linking 命令:
/usr/bin/cmake -E cmake_link_script CMakeFiles/hello-pq.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/hello-pq.dir/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp.o CMakeFiles/hello-pq.dir/main.cpp.o
-o ../bin/hello-pq
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a
-lpthread
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a -ldl
我的 CMakeLists.txt
看起来像这样:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../../third-party/vcpkg/scripts/buildsystems/vcpkg.cmake
CACHE STRING "Vcpkg toolchain file")
project(hello-pq)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
find_package(OpenSSL REQUIRED)
find_package(libpqxx CONFIG REQUIRED)
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
target_link_libraries(${PROJECT_NAME}
PRIVATE OpenSSL::SSL
PRIVATE OpenSSL::Crypto
PRIVATE libpqxx::pqxx)
我用 nm
查看了 vcpkg
installed 目录中的 libpq.a
,我可以看到 pg_md5_encrypt
显示为 undefined:
U pg_md5_encrypt
我不明白,pg_md5_encrypt
这些缺失的功能在哪里?
是否有另一个 libpq...
我需要 link 或者可能是不同的版本?
经过更多的挖掘和测试后,我发现我还需要 2 个 postgres
静态库 link:
- libpqcommon.a
- libpgport.a
此外,link 顺序也很重要,尽管我预计必须在 libs that need them
之前通过 libs that are needed
,但这里并非如此,感觉倒退了。
这是一个有效的 linker 命令:
usr/bin/c++ CMakeFiles/hello-pq.dir/src/main.cpp.o \
-o ../bin/hello-pq \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgcommon.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgport.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a \
-lpthread \
-ldl
为了 link 额外的 2 个静态库并实现上述顺序,我更新了 CMakeLists.txt
如下:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../../third-party/vcpkg/scripts/buildsystems/vcpkg.cmake
CACHE STRING "Vcpkg toolchain file")
project(hello-pq)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
find_package(OpenSSL REQUIRED)
#find_package(PostgreSQL REQUIRED) # Not needed (it will duplicate the libs)
find_package(libpqxx CONFIG REQUIRED)
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
target_link_libraries(${PROJECT_NAME}
PRIVATE libpqxx::pqxx
PRIVATE PostgreSQL::PostgreSQL
PRIVATE OpenSSL::SSL
PRIVATE OpenSSL::Crypto)
这转化为以下 linker 命令:
/usr/bin/c++ \
CMakeFiles/hello-pq.dir/src/main.cpp.o \
-o ../bin/hello-pq \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpqxx-7.3.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libssl.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/debug/lib/libcrypto.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpq.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgport.a \
/home/user/work/cxx-playground/third-party/vcpkg/installed/x64-linux/lib/libpgcommon.a \
-ldl \
-lpthread
我们可以看到 libpq.a
在 link 个参数中出现了两次:
- 一次由于
libpqxx::pqxx
目标(我假设) - 一次由于
PostgreSQL::PostgreSQL
目标 其中还包含需要 linked 的 2 个缺失的静态库(libpgport.a
和libpgcommon.a
)。
我的结论是这是一个 libpqxx
错误,它也应该 link 在它公开的唯一目标中具有 target_link_libraries(PUBLIC...)
的 2 个静态库(libpqxx::pqxx
)