ValveSoftware / GameNetworkingSockets

Reliable & unreliable messages over UDP. Robust message fragmentation & reassembly. P2P networking / NAT traversal. Encryption.
BSD 3-Clause "New" or "Revised" License
8.13k stars 606 forks source link

Windows CMAKE error: Cannot find EVP_MD_CTX_free in OpenSSL headers/libs #118

Closed kingoftheconnors closed 4 years ago

kingoftheconnors commented 4 years ago

I'm trying to build the library for use in a personal game project (pure C++ using SDL. It's a thing). Using the instructions, the CMake ran into an error:

-- OPENSSL_INCLUDE_DIR = C:/Program Files/OpenSSL-Win64/include/openssl
CMake Error at CMakeLists.txt:100 (message):
  Cannot find EVP_MD_CTX_free in OpenSSL headers/libs for the target
  architecture.  Check that you're using OpenSSL 1.1.0 or later.

I am using the 64-bit version of OpenSSL 1.1.1g and the Command Prompt for Visual Studio 2019.

CMakerError.log:

Determining if the EVP_MD_CTX_free exist failed with the following output:
Change Dir: C:/dev/GameNetworkingSockets/build/CMakeFiles/CMakeTmp

Run Build Command(s):C:/PROGRA~2/MICROS~2/2019/COMMUN~1/Common7/IDE/COMMON~1/MICROS~1/CMake/Ninja/ninja.exe cmTC_8f91b && [1/2] Building C object CMakeFiles/cmTC_8f91b.dir/CheckSymbolExists.c.obj

[2/2] Linking C executable cmTC_8f91b.exe

FAILED: cmTC_8f91b.exe 

cmd.exe /C "cd . && C:\MinGW\bin\gcc.exe    CMakeFiles/cmTC_8f91b.dir/CheckSymbolExists.c.obj  -o cmTC_8f91b.exe -Wl,--out-implib,libcmTC_8f91b.dll.a -Wl,--major-image-version,0,--minor-image-version,0  "C:/Program Files/OpenSSL-Win64/lib/libcrypto.lib"  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."

c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: CMakeFiles/cmTC_8f91b.dir/CheckSymbolExists.c.obj:CheckSymbolExists.c:(.text+0x12): undefined reference to `EVP_MD_CTX_free'

File C:/dev/GameNetworkingSockets/build/CMakeFiles/CMakeTmp/CheckSymbolExists.c:
/* */
#include <openssl/evp.h>

int main(int argc, char** argv)
{
  (void)argv;
#ifndef EVP_MD_CTX_free
  return ((int*)(&EVP_MD_CTX_free))[argc];
#else
  (void)argc;
  return 0;
#endif
}

C:/dev/GameNetworkingSockets/build/CMakeFiles/CMakeTmp is empty. I checked C:\Program Files\OpenSSL-Win64\include\openssl and evp.h DOES exist, but with the following setup:

void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
# define EVP_MD_CTX_destroy(ctx) EVP_MD_CTX_free((ctx))

EVP_MD_CTX_FREE is a function, not a macro. Is this expected? Should I be worried about my OpenSSL version? hmm.

rafal-zelek commented 4 years ago

I have the same problem on Mac, did u find the workaround?

asyncrun commented 4 years ago

same problem on Windows

aiusepsi commented 4 years ago

EVP_MD_CTX_FREE is a function, not a macro. Is this expected? Should I be worried about my OpenSSL version? hmm.

If EVP_MD_CTX_free was a macro, then #ifndef EVP_MD_CTX_free would be false, and it would have compiled and linked successfully, because the program it would have compiled would have been essentially this after preprocessing:

int main(int argc, char** argv)
{
  (void)argv; 
  (void)argc;
  return 0;
}

and if that doesn't compile, you have bigger issues!

It's falling over with the linker error undefined reference to EVP_MD_CTX_free which implies that yes, it is correctly declared as a function in evp.h, but the linker can't find the implementation of EVP_MD_CTX_free, even though "C:/Program Files/OpenSSL-Win64/lib/libcrypto.lib" is in the linker arguments. So in the first instance I would check to see that libcrypto.lib contains the EVP_MD_CTX_free symbol. On Linux/macOS you'd use nm for this, might be the same for MinGW.

aiusepsi commented 4 years ago

I have the same problem on Mac, did u find the workaround?

I'm noticing a failure on Mac, although it's subtly different. In CMakeError.log there's this: ld: cannot link directly with dylib/framework, your binary is not an allowed client of /usr/lib/libcrypto.dylib for architecture x86_64

Looks like CMake is managing to find the system version of OpenSSL, which you're apparently not allowed to link with.

One workaround is to not use OpenSSL at all. If you install libsodium (brew install libsodium) then invoke cmake with these arguments: -DUSE_CRYPTO="libsodium" -DUSE_CRYPTO25519="libsodium" then it'll use libsodium for all the crypto, and so won't hit any OpenSSL issues.

asyncrun commented 4 years ago
** Visual Studio 2019 Developer Command Prompt v16.6.0
** Copyright (c) 2020 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
PS E:\GameNetworkingSockets\build> cmake -G Ninja ..                                                             
-- The C compiler identification is MSVC 19.26.28805.0
-- The CXX compiler identification is MSVC 19.26.28805.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.26.28801/bin/Hostx86/x86/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.26.28801/bin/Hostx86/x86/cl.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.26.28801/bin/Hostx86/x86/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.26.28801/bin/Hostx86/x86/cl.exe - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- MSVC -> forcing use of dynamically-linked runtime.
-- Initial build flags:
--   'CMAKE_C_FLAGS_DEBUG': /MDd /Zi /Ob0 /Od /RTC1
--   'CMAKE_C_FLAGS_MINSIZEREL': /MD /O1 /Ob1 /DNDEBUG
--   'CMAKE_C_FLAGS_RELEASE': /MD /O2 /Ob2 /DNDEBUG
--   'CMAKE_C_FLAGS_RELWITHDEBINFO': /MD /Zi /O2 /Ob1 /DNDEBUG
--   'CMAKE_CXX_FLAGS_DEBUG': /MDd /Zi /Ob0 /Od /RTC1
--   'CMAKE_CXX_FLAGS_MINSIZEREL': /MD /O1 /Ob1 /DNDEBUG
--   'CMAKE_CXX_FLAGS_RELEASE': /MD /O2 /Ob2 /DNDEBUG
--   'CMAKE_CXX_FLAGS_RELWITHDEBINFO': /MD /Zi /O2 /Ob1 /DNDEBUG
--
-- Looking for BCryptEncrypt
-- Looking for BCryptEncrypt - found
-- Found OpenSSL: C:/Program Files/OpenSSL-Win64/lib/libcrypto.lib (found version "1.1.1g")
-- OPENSSL_INCLUDE_DIR = C:/Program Files/OpenSSL-Win64/include
-- Looking for EVP_MD_CTX_free
-- Looking for EVP_MD_CTX_free - not found
CMake Error at CMakeLists.txt:100 (message):
  Cannot find EVP_MD_CTX_free in OpenSSL headers/libs for the target
  architecture.  Check that you're using OpenSSL 1.1.0 or later.

-- Configuring incomplete, errors occurred!
See also "E:/GameNetworkingSockets/build/CMakeFiles/CMakeOutput.log".
See also "E:/GameNetworkingSockets/build/CMakeFiles/CMakeError.log".
kingoftheconnors commented 4 years ago

the linker can't find the implementation of EVP_MD_CTX_free, even though "C:/Program Files/OpenSSL-Win64/lib/libcrypto.lib" is in the linker arguments. So in the first instance I would check to see that libcrypto.lib contains the EVP_MD_CTX_free symbol

Using visual studio's command line command: dumpbin, I found that yes, EVP_MD_CTX_free is included in the linker options:

dumpbin /linkermember libcrypto.lib
      732F4 __IMPORT_DESCRIPTOR_libcrypto-1_1-x64
      ...
      65B EVP_EncryptInit_ex
      65C EVP_EncryptUpdate
      65D EVP_MD_CTX_clear_flags
      65E EVP_MD_CTX_copy
      65F EVP_MD_CTX_copy_ex
      660 EVP_MD_CTX_ctrl
      661 EVP_MD_CTX_free
      662 EVP_MD_CTX_md
      663 EVP_MD_CTX_md_data
      664 EVP_MD_CTX_new
      665 EVP_MD_CTX_pkey_ctx
      666 EVP_MD_CTX_reset
      667 EVP_MD_CTX_set_flags
      668 EVP_MD_CTX_set_pkey_ctx
      669 EVP_MD_CTX_set_update_fn
      66A EVP_MD_CTX_test_flags
      66B EVP_MD_CTX_update_fn
      66C EVP_MD_block_size
      66D EVP_MD_do_all
      66E EVP_MD_do_all_sorted
      66F EVP_MD_flags
      ...

It's also in the libcrypto.def file, and the libcrypto_static.lib file

kingoftheconnors commented 4 years ago

I managed to get around the problem by switching to a x32 version of ssl and compiling using visual studio command prompt on 32-bit. This version has its own problems, which I'm looking at. In the end, I might not even call this a solution...

Yeah. Hope this helps!

zpostfacto commented 4 years ago

Are you using windows or MinGW? Your bug title says "windows" but your command output contains references to mingw.

kingoftheconnors commented 4 years ago

Yes. I have MinGW installed, but I'm following the build instructions included in the repo. CMake seems to be using it by default. Should I flag it not to use mingw?

ZCube commented 4 years ago

@kingoftheconnors OpenSSL need ws2_32.lib and crypt32.lib but there are no these libraries in build command.

-lkernel32
-luser32
-lgdi32
-lwinspool
-lshell32
-lole32
-loleaut32
-luuid
-lcomdlg32
-ladvapi32

set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto) -> set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto ws2_32 crypt32)

will works.

kingoftheconnors commented 4 years ago

set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto) -> set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto ws2_32 crypt32)

will works.

Thanks that cut my problems AT LEAST to a third, which is huge! Who knew it was two lines in the CMake list?

But I've still been struggling with MinGW. Beginning the build, it has this warning:

"Direct definition of __USE_MINGW_ANSI_STDIO is deprecated."

After which I get a hundred copies of the same error:

In file included from ../src/public/tier0/platform.h:29,
                 from ../src/public/tier0/basetypes.h:15,
                 from ../src/public/tier0/dbg.h:16,
                 from ../src/common/steamid.cpp:11:
../src/../include/minbase/minbase_decls.h:169:28: error: '__forceinline' does not name a type
  169 |  #define FORCEINLINE       __forceinline

Not sure if this is a minGW problem, but if it is, I'd be willing to change to a different compiler if that's more standard. What's the main compiler other people use?

ZCube commented 4 years ago

Maybe you need

include/minbase/minbase_decls.h

#if defined(_WIN32)
    #define NOINLINE                __declspec(noinline)
    #define NORETURN                __declspec(noreturn)
    #define FORCEINLINE             __forceinline

->

#if defined(__MINGW32__)
    #define NOINLINE                __attribute__ ((noinline))
    #define NORETURN                __attribute__ ((noreturn))
    #define FORCEINLINE             inline
#elif defined(_WIN32)
    #define NOINLINE                __declspec(noinline)
    #define NORETURN                __declspec(noreturn)
    #define FORCEINLINE             __forceinline
kingoftheconnors commented 4 years ago

Alright. It seems the issue was with mingw. I had no idea MinGW meant so many different things.

I noticed that I had some thread errors. After some research, I found I was using mingw32, which (at least a couple years ago) didn't come with threads. This is reflected in my CMake build where it says that pthead can't be found; it isn't there to find! You can see your MinGW type using GCC -v. I changed my installation to use MinGW-w64 (installed through MSYS2), and the build script worked as desired.

As an example: OLD INSTALLATION: MinGW-32:

gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/9.2.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-9.2.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-static --enable-shared --enable-threads --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libgomp --disable-libvtv --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --disable-build-format-warnings --prefix=/mingw --with-gmp=/mingw --with-mpfr=/mingw --with-mpc=/mingw --with-isl=/mingw --enable-nls --with-pkgversion='MinGW.org GCC Build-20200227-1'
Thread model: win32                     <- important!
gcc version 9.2.0 (MinGW.org GCC Build-20200227-1)

NEW, MinGW-w64:

gcc -v
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/10.1.0/lto-wrapper.exe
Target: i686-w64-mingw32
Configured with: ../gcc-10.1.0/configure --prefix=/mingw32 --with-local-prefix=/mingw32/local --build=i686-w64-mingw32 --host=i686-w64-mingw32 --target=i686-w64-mingw32 --with-native-system-header-dir=/mingw32/i686-w64-mingw32/include --libexecdir=/mingw32/lib --enable-bootstrap --with-arch=i686 --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++ --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --disable-plugin --with-libiconv --with-system-zlib --with-gmp=/mingw32 --with-mpfr=/mingw32 --with-mpc=/mingw32 --with-isl=/mingw32 --with-pkgversion='Rev3, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld --disable-sjlj-exceptions --with-dwarf2
Thread model: **posix**                     <- this is what you want!
Supported LTO compression algorithms: zlib zstd
gcc version 10.1.0 (Rev3, Built by MSYS2 project)

If you can't change to MinGW-w64, ZCube's advice is indispensible, but it's not necessary (and for some reason adds some warnings?) when you use MinGW-w64. I'm pretty sure this difference in installation is what made the difference, but I've only observed this on my own machine, so treat it as such!