Missing dependency when staticly linking mongoc driver ubuntu

When building my project, I am statically linking to libbson-static-1.0 and libmongoc-static-1.0, but am receiving the following errors from my build. I know this is a missing dependency on my end because of the static linking but I was wondering if anyone knew what library I am missing?

linux64_gcc5/libmongoc-static-1.0.a(mongoc-scram.c.o): In function `_mongoc_sasl_prep_impl':
mongoc-scram.c:(.text+0x6eb): undefined reference to `u_strFromUTF8_60'
mongoc-scram.c:(.text+0x737): undefined reference to `u_strFromUTF8_60'
mongoc-scram.c:(.text+0x752): undefined reference to `usprep_openByType_60'
mongoc-scram.c:(.text+0x77d): undefined reference to `usprep_prepare_60'
mongoc-scram.c:(.text+0x7ca): undefined reference to `usprep_prepare_60'
mongoc-scram.c:(.text+0x7e8): undefined reference to `usprep_close_60'
mongoc-scram.c:(.text+0x7ff): undefined reference to `u_strToUTF8_60'
mongoc-scram.c:(.text+0x83e): undefined reference to `u_strToUTF8_60'
mongoc-scram.c:(.text+0x8c4): undefined reference to `usprep_close_60'
mongoc-scram.c:(.text+0x921): undefined reference to `usprep_close_60'

@Thomas_Morten That is quite peculiar. Our CI tests statically linking to both libbson and libmongoc, though I am not sure what particular library might be missing here. Can you provide the complete build output leading up to this error?

I also ran into this error, but I fixed it by reinstalling the mongoc driver. I used a script to reinstall, you can find it here.

I just ran into the same issue. I was compiling the libraries myself from source. CMake project build right away and all tests and example where running fine. However I wasn’t able to use the static library in my own project.

@Evan_Ugarte if you read this, could you check the link you’ve posted? I get a 404

I was able to fix it with linking libicuuc.a

This build command works for me (simplified pathes!):

gcc hello_mongoc.c -I./include/ -lmongoc-static-1.0 -lbson-static-1.0 -pthread -lrt -lresolv -lcrypto -lssl -lz -licuuc -L. -o hello_mongo

@bugblatterbeast are you certain that the libmongoc build was able to find the ICU libraries? I have confirmed that the static build for libmongoc correctly links with -licuuc. Another possibility is that you disabled ICU with -DENABLE_ICU=OFF on the CMake command line.

1 Like

@Roberto_Sanchez yes I am very certain about that. In the example build command line for hello_mongo as well as in my project, the linker option -licuuc is making the difference. Without it I get the exact errors mentioned by Thomas_Morten.

I am using Ubuntu 18.04 and already had the library in the std path. Nevertheless, it seems to me that the preprocessor switch you suggested is an even better solution for this problem. I’m going to try that as well.

edit: I am starting to think that I maybe mistunderstood you. Did you mean that the static library build should have found the icu libraries and that it shouldn’t have been necessary to link the application to it? I will look into that too.

@bugblatterbeast, that is strange. If you could provide the commands you used to build the C driver and sample code with a build command that triggers the failure, I can look into why our CI builds are not catching the error.

That was precisely my meaning. Any additional information you can provide will be helpful in identifying the potential build issue.

1 Like

@Roberto_Sanchez OS is Ubuntu 18.04 I’ve configured the C driver build with this command:

 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DCMAKE_BUILD_TYPE=Release ..

getting this result:

-- The C compiler identification is GNU 7.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
file VERSION_CURRENT contained BUILD_VERSION 1.17.3
-- Build and install static libraries
  -- Using bundled libbson
libbson version (from VERSION_CURRENT file): 1.17.3
-- Check if the system is big endian
-- Searching 16 bit integer
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Check size of unsigned short
-- Check size of unsigned short - done
-- Searching 16 bit integer - Using unsigned short
-- Check if the system is big endian - little endian
-- Looking for snprintf
-- Looking for snprintf - found
-- Looking for reallocf
-- Looking for reallocf - not found
-- Performing Test BSON_HAVE_TIMESPEC
-- Performing Test BSON_HAVE_TIMESPEC - Success
--     struct timespec found
-- Looking for gmtime_r
-- Looking for gmtime_r - found
-- Looking for rand_r
-- Looking for rand_r - found
-- Looking for strings.h
CMake Warning (dev) at /snap/cmake/769/share/cmake-3.19/Modules/CheckIncludeFile.cmake:80 (message):
  Policy CMP0075 is not set: Include file check macros honor
  CMAKE_REQUIRED_LIBRARIES.  Run "cmake --help-policy CMP0075" for policy
  details.  Use the cmake_policy command to set the policy and suppress this
  warning.

  CMAKE_REQUIRED_LIBRARIES is set to:

    /usr/lib/x86_64-linux-gnu/librt.so

  For compatibility with CMake 3.11 and below this check is ignoring it.
Call Stack (most recent call first):
  src/libbson/CMakeLists.txt:91 (CHECK_INCLUDE_FILE)
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Looking for strings.h - found
-- Looking for strlcpy
-- Looking for strlcpy - not found
-- Looking for clock_gettime
-- Looking for clock_gettime - found
-- Looking for strnlen
-- Looking for strnlen - found
-- Looking for stdbool.h
-- Looking for stdbool.h - found
-- Looking for SYS_gettid
-- Looking for SYS_gettid - found
-- Looking for syscall
-- Looking for syscall - found
-- Performing Test HAVE_ATOMIC_32_ADD_AND_FETCH
-- Performing Test HAVE_ATOMIC_32_ADD_AND_FETCH - Success
-- Performing Test HAVE_ATOMIC_64_ADD_AND_FETCH
-- Performing Test HAVE_ATOMIC_64_ADD_AND_FETCH - Success
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Found Threads: TRUE 
Adding -fPIC to compilation of bson_static components
libmongoc version (from VERSION_CURRENT file): 1.17.3
-- Searching for zlib CMake packages
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.2.11")
--   zlib found version "1.2.11"
--   zlib include path "/usr/include"
--   zlib libraries "/usr/lib/x86_64-linux-gnu/libz.so"
-- Looking for include file unistd.h
-- Looking for include file unistd.h - found
-- Looking for include file stdarg.h
-- Looking for include file stdarg.h - found
-- Searching for compression library zstd
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1")
-- Checking for module 'libzstd'
--   Found libzstd, version 1.3.3
--   Found zstd version 1.3.3 in
-- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so (found version "1.1.1") 
-- Looking for ASN1_STRING_get0_data in /usr/lib/x86_64-linux-gnu/libcrypto.so
-- Looking for ASN1_STRING_get0_data in /usr/lib/x86_64-linux-gnu/libcrypto.so - found
-- Searching for sasl/sasl.h
--   Found in /usr/include
-- Searching for libsasl2
--   Found /usr/lib/x86_64-linux-gnu/libsasl2.so
-- Check size of socklen_t
-- Check size of socklen_t - done
-- Looking for res_nsearch
-- Looking for res_nsearch - found
-- Looking for res_ndestroy
-- Looking for res_ndestroy - not found
-- Looking for res_nclose
-- Looking for res_nclose - found
-- Looking for sched_getcpu
-- Looking for sched_getcpu - not found
-- Detected parameters: accept (int, struct sockaddr *, socklen_t *)
-- Searching for compression library header snappy-c.h
--   Not found (specify -DCMAKE_INCLUDE_PATH=/path/to/snappy/include for Snappy compression)
Searching for libmongocrypt
-- libmongocrypt not found. Configuring without Client-Side Field Level Encryption support.
-- Performing Test MONGOC_HAVE_SS_FAMILY
-- Performing Test MONGOC_HAVE_SS_FAMILY - Success
-- Compiling against OpenSSL
-- Compiling against Cyrus SASL
Adding -fPIC to compilation of mongoc_static components
-- Building with MONGODB-AWS auth support
-- Build files generated for:
--     build system: Unix Makefiles
-- Configuring done
-- Generating done
-- Build files have been written to: SRC_PATH/mongo-c-driver-1.17.3/cmake-build

I was building with this command:

$ cmake --build .

Everything works perfectly fine. So far, I haven’t found a test or example that’s not working.

When I try this it also works fine (adjusted paths):

$ gcc -o hello_mongoc hello_mongoc.c -I./include -L. -lmongoc-1.0 -lbson-1.0 -Wl,-rpath .

This command however gives the errors mentioned above:

$ gcc -o hello_mongo hello_mongoc.c -I./include -L. -lmongoc-static-1.0 -lbson-static-1.0 -pthread -lrt -lresolv -lcrypto -lssl -lz -lsasl2 -lzstd
./libmongoc-static-1.0.a(mongoc-scram.c.o): In function `_mongoc_sasl_prep_impl':
mongoc-scram.c:(.text+0x61b): undefined reference to `u_strFromUTF8_60'
mongoc-scram.c:(.text+0x667): undefined reference to `u_strFromUTF8_60'
mongoc-scram.c:(.text+0x682): undefined reference to `usprep_openByType_60'
mongoc-scram.c:(.text+0x6ad): undefined reference to `usprep_prepare_60'
mongoc-scram.c:(.text+0x6fa): undefined reference to `usprep_prepare_60'
mongoc-scram.c:(.text+0x718): undefined reference to `usprep_close_60'
mongoc-scram.c:(.text+0x72f): undefined reference to `u_strToUTF8_60'
mongoc-scram.c:(.text+0x76e): undefined reference to `u_strToUTF8_60'
mongoc-scram.c:(.text+0x80c): undefined reference to `usprep_close_60'
mongoc-scram.c:(.text+0x871): undefined reference to `usprep_close_60'
collect2: error: ld returned 1 exit status

For a moment I thought I was wrong to assume that gcc will automatically recognize that I try to link against static libraries. So I’ve tried to add the linker option “-Wl,-Bstatic” (I thought this is only required when static and shared libraries are available with the same basename and -l option would be ambiguous) but that always results in another linker error I can not explain.

$ g++ -o hello_mongoc hello_mongoc.c -I./include -L. -Wl,-Bstatic -lmongoc-static-1.0 -lbson-static-1.0
/usr/bin/ld: cannot find -lgcc_s
./libmongoc-static-1.0.a(mongoc-client.c.o): In function `mongoc_client_connect_tcp':
mongoc-client.c:(.text+0x1145): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status

I’m not sure if this is even the right approach. Anyway, I’ve tried this:

$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ln -s /usr/lib/gcc/x86_64-linux-gnu/7.5.0/libgcc_s.so libgcc_s.so
$ gcc -o hello_mongoc hello_mongoc.c -I./include -L. -l:./libgcc_s.so -Wl,-Bstatic -lmongoc-static-1.0 -lbson-static-1.0
/usr/bin/ld: cannot find -lgcc_s
./libmongoc-static-1.0.a(mongoc-client.c.o): In function `mongoc_client_connect_tcp':
mongoc-client.c:(.text+0x1145): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status

However, the following command is working (it slightly differs from the call I posted previously because I was doing a clean start to prepare this info and installed some additional packages):

$ gcc -o hello_mongo hello_mongoc.c -I./include -L. -lmongoc-static-1.0 -lbson-static-1.0 -pthread -lrt -lresolv -lcrypto -lssl -lz -lsasl2 -lzstd -licuuc

Contact me if you need more specific details. I also want to let you know that I’m OK with it. I totally understand if you want to look into this and I’ll try to provide you with any further information you need. Just please don’t do it for my sake.

edit: FYI I just build the C driver but I don’t install it

@bugblatterbeast, so it looks like there are a few things going on here. The C driver is not meant to be built and then used from the build tree without first being installed. You might want to review the instructions for using the C driver in another project. Essentially, you should include it as a CMake module or let pkg-config provide the flags. If you are trying to avoid the need to install the C driver, then you can clone it into your project source tree and include it with something like add_subdirectory(mongo-c-driver) in your CMakeLists.txt file or you can use CMake’s external project feature. This will give you access to the same CMake targets described in the instructions I linked above, all while letting your top-level CMake project manage the build of the components you need. If you stick to the static targets, you should also not end up with any additional components installed from your project.

All that said, I ran the build on an Ubuntu 18.04 machine with the same options you gave. Then I installed the C driver. The pkg-config commands provided the following output:

ubuntu@ip-10-122-6-162:~/mongo-c-driver/cmake-build$ pkg-config --cflags libmongoc-static-1.0
-DMONGOC_STATIC -DBSON_STATIC -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0
ubuntu@ip-10-122-6-162:~/mongo-c-driver/cmake-build$ pkg-config --libs libmongoc-static-1.0
-L/usr/local/lib -lmongoc-static-1.0 -lsasl2 -lssl -lcrypto -lrt -lresolv -pthread -lz -lzstd -licuuc -lbson-static-1.0 /usr/lib/x86_64-linux-gnu/librt.so /usr/lib/x86_64-linux-gnu/libm.so -pthread

So, It looks like you should depend on the CMake or pkg-config targets to make sure you get the proper pre-processor macro definitions. Additionally, the linker options from pkg-config look to match those from your working example. Static linking always requires explicitly linking any additional libraries which were used by the static components, since static libraries cannot record linkage information in the same way as dynamic libraries. We let CMake generate these configurations since it already knows what has been linked and what would be required to link the targets we are generating. It is conceivable that some second-order linkages can be omitted, depending on which components from the static libmongoc and libbson are used and which are not used in your project, but that approach is likely to lead to difficult to diagnose issues which can be avoided by using the generated configurations.

Thanks for providing the additional information and let us know if you have any further questions.

1 Like

Thank you very much for this valuable information. The option to add the directory to our CMake configuration sounds promising. I’m gonna test it one of the next days and I’ve also forwarded your reply to our integrator.

You’re quite welcome.

Our integrator has now included a reference to the mongo-c-driver project in our CMake configuration as you suggested. I am very happy with that solution.