I have a CMake project in Linux where I build several shared libraries and some of them need OpenSSL latest version. I use Microsoft vcpkg
for my toolchain and I had to install OpenSSL 3.2.0 23 Nov 2023
using ./vcpkg install openssl:x64-linux
.
One of the libraries, myrrlib
, uses a proprietary library for which libssl.a
and libcrypto.a
are provided by the vendor in the library source folder. Their version appears to be OpenSSL 1.1.1m 14 Dec 2021
when I run strings libcrypto.a | grep "OpenSSL"
.
In the root folder, my CMakeLists.txt
has find_package(OpenSSL REQUIRED)
, which will result in vcpkg
finding the following file for libcrypto.a
:
/root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a
My question is how can I force using a OpenSSL 1.1.1 for myrrlib
?
cmake_minimum_required(VERSION 3.26)
set(RR_LIB_DIR "external/pakages/rr/lib")
set(RR_LIB_FILES
vendorlib1
vendorlib2
vendorlib3
ssl # libssl.a is provided by the RR library (it is not installed by vcpkg)
crypto # libcrypto.a is provided by the RR library (it is not installed by vcpkg)
)
add_library(myrrlib SHARED)
set_property(TARGET myrrlib PROPERTY CXX_STANDARD 17)
target_sources(myrrlib PRIVATE "src/myrrlib.cpp" "src/myrrlib.h")
target_include_directories(myrrlib PUBLIC ${RR_INCLUDE_DIR})
target_link_directories(myrrlib PUBLIC ${RR_LIB_DIR})
target_link_libraries(myrrlib PUBLIC ${RR_LIB_FILES})
When I build the shard library myrrlib
I get the following link errors:
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: warning: alignment 8 of symbol `bio_lookup_lock' in /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-bio_addr.o) is smaller than 32 in /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(b_addr.o)
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-bio_addr.o): in function `BIO_ADDR_new':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/bio/bio_addr.c:53: multiple definition of `BIO_ADDR_new'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(b_addr.o):b_addr.c:(.text+0x0): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-bio_addr.o): in function `BIO_ADDR_free':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/bio/bio_addr.c:64: multiple definition of `BIO_ADDR_free'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(b_addr.o):b_addr.c:(.text+0x50): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-bio_addr.o): in function `BIO_ADDR_clear':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/bio/bio_addr.c:96: multiple definition of `BIO_ADDR_clear'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(b_addr.o):b_addr.c:(.text+0x70): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-bio_addr.o): in function `BIO_ADDR_make':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/bio/bio_addr.c:106: multiple definition of `BIO_ADDR_make'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(b_addr.o):b_addr.c:(.text+0x110): first defined here
...
many more
...
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/engine/eng_lib.c:280: multiple definition of `ENGINE_get_finish_function'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(eng_lib.o):eng_lib.c:(.text+0x530): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-eng_lib.o): in function `ENGINE_get_ctrl_function':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/engine/eng_lib.c:285: multiple definition of `ENGINE_get_ctrl_function'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(eng_lib.o):eng_lib.c:(.text+0x540): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-eng_lib.o): in function `ENGINE_get_flags':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/engine/eng_lib.c:290: multiple definition of `ENGINE_get_flags'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(eng_lib.o):eng_lib.c:(.text+0x550): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-eng_lib.o): in function `ENGINE_get_cmd_defns':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/engine/eng_lib.c:295: multiple definition of `ENGINE_get_cmd_defns'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(eng_lib.o):eng_lib.c:(.text+0x560): first defined here
/opt/rh/devtoolset-11/root/usr/libexec/gcc/x86_64-redhat-linux/11/ld: /root/programs/vcpkg/installed/x64-linux/debug/lib/libcrypto.a(libcrypto-lib-eng_lib.o): in function `ENGINE_get_static_state':
/root/programs/vcpkg/buildtrees/openssl/x64-linux-dbg/../src/nssl-3.2.0-5a1db6e780.clean/crypto/engine/eng_lib.c:307: multiple definition of `ENGINE_get_static_state'; /mnt/c/Dev/myproject/external/packages/rr/lib/libcrypto.a(eng_lib.o):eng_lib.c:(.text+0x570): first defined here
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/myrrlib.dir/build.make:119: lib/libmyrrlib.so] Error 1
make[2]: *** [CMakeFiles/Makefile2:520: CMakeFiles/myrrlib.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:527: CMakeFiles/myrrlib.dir/rule] Error 2
make: *** [Makefile:283: myrrlib] Error 2
If I build it as static, add_library(myrrlib STATIC)
, I can successfully build the library with no issues. I don't know where the problem is when I build it as a shared library.
Could someone kindly let me know how this can be solved?
TL/DR:
First of all changing to STATIC
didn't solve the problem, but it just delayed it in time to the final linkage.
Solution is to use only one version of OpenSSL and in your case it looks like 1.1.1m provided by the vendor would be easier(I think), so use cmake -DOPENSSL_ROOT_DIR=/path/to/vendor/openssl
or try using find_package (<package> PATHS paths... NO_DEFAULT_PATH)
To understand it lets get back to the basic how compile process looks like in this case I will explain in GCC.
When we have some C++ file a.cpp
first is to generate object file a.o
it's just an output of each Translation Unit(simply saying one *.o
file per .cpp
file).
Next step depends on what we want to create:
add_library(X STATIC)
)add_library(X SHARED)
)add_executable(X)
)Shared Library and Executable are almost the same (Executable needs to have main()
) but Static Library is much different because especially in this case it's not linking everything and not verifying all the connections between function. So this in your case using Static Library not showing that some functions are linked two because there is not linking at all. Why I said it just delayed it in time to the final linkage
? At the end you will need to create Executable or Shared Library and errors of duplicates will reappear.
The demonstrate the issue we need 2 static libs(let say a
and b
) that will simulate two difference version of OpenSSL, next library that will be our myrrlib
from the question and to show that it's only delayed in time some executable (or dynamic lib as in this case they behave the same).
Let create a.hpp
#pragma once
int add(int, int);
int mul(int, int);
a.cpp
#include "a.hpp"
int add(int a, int b)
{
return a + b;
}
int mul(int a, int b)
{
return a * b;
}
b.hpp
#pragma once
int add(int, int);
int sub(int, int);
b.cpp
#include "a.hpp"
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
also myrrlib.cpp
#include <cstdio>
#include "a.hpp"
#include "b.hpp"
void func()
{
// some usage of all functions
printf("add %i!\n", add(2, 5));
printf("sub %i!\n", sub(2, 5));
printf("mul %i!\n", mul(2, 5));
}
and main.cpp
extern void func();
int main()
{
func();
}
and CMakeLists.txt
cmake_minimum_required(VERSION 3.27)
project(issue)
add_library(a STATIC a.cpp)
add_library(b STATIC b.cpp)
add_library(myrrlib STATIC myrrlib.cpp)
target_link_libraries(myrrlib b a)
To me able to reproduce this error we need library a
and b
to have at least one function in common and also one unique per library, so add
is duplicated but mul
and sub
unique per lib(same happen in the example some function are the same in both versions of OpenSSL and some have to differ).
Let build it with
cmake -S . -B build
cmake --build build --clean-first
You should see no issues and [100%] Built target myrrlib
but when we change myrrlib
to SHARED
we will get exactly the same error for add
function.
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: liba.a(a.cpp.o): in function `add(int, int)':
a.cpp:(.text+0x0): multiple definition of `add(int, int)'; libb.a(b.cpp.o):b.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/myrrlib.dir/build.make:99: libmyrrlib.so] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:140: CMakeFiles/myrrlib.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
To show that error it is only delayed in time, let change it back to STATIC
and add executable
cmake_minimum_required(VERSION 3.27)
project(issue)
add_library(a STATIC a.cpp)
add_library(b STATIC b.cpp)
add_library(myrrlib STATIC myrrlib.cpp)
target_link_libraries(myrrlib b a)
add_executable(final main.cpp)
target_link_libraries(final myrrlib)
When we compile it we will get
[ 75%] Built target myrrlib
[ 87%] Building CXX object CMakeFiles/final.dir/main.cpp.o
[100%] Linking CXX executable final
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: liba.a(a.cpp.o): in function `add(int, int)':
a.cpp:(.text+0x0): multiple definition of `add(int, int)'; libb.a(b.cpp.o):b.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/final.dir/build.make:100: final] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:170: CMakeFiles/final.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
myrrlib
compiled without errors but everything failed when creating final
executable.
Finally to answer you questions
My question is how can I force using a OpenSSL 1.1.1 for myrrlib?
You have to use only one version of OpenSSL and probably provided by the vendor would be the best for you, so instead of using vcpkg to install it use cmake -DOPENSSL_ROOT_DIR=/path/to/vendor/openssl
or try using find_package (<package> PATHS paths... NO_DEFAULT_PATH)
If I build it as static, add_library(myrrlib STATIC),
I can successfully build the library with no issues.
I don't know where the problem is when I build it as a shared library.
As describe issue is not resolved but just delayed in time