Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,31 @@ if (WIN32)
endif()

# OpenSSL for TLS (libevent bufferevent_openssl, libmysqlclient).
#
# Linked statically on purpose: the released shared library must not carry a runtime
# dependency on a particular OpenSSL installation. With the shared libs, the macOS
# dylib gets an absolute path baked in (/opt/homebrew/opt/openssl@N/lib/libssl.N.dylib)
# and fails to load on any machine that does not have that exact Homebrew prefix; the
# Windows DLL likewise dragged in libssl-3-x64.dll / libcrypto-3-x64.dll.
option(FAKELUA_PREFER_STATIC_DEPS "Prefer static third-party libraries where possible" ON)
if (FAKELUA_PREFER_STATIC_DEPS AND NOT MINGW)
set(OPENSSL_USE_STATIC_LIBS TRUE)
if (WIN32)
# Match the static CRT choice when consuming MSVC-built OpenSSL.
set(OPENSSL_MSVC_STATIC_RT ON)
endif ()
endif ()
# MinGW keeps the *shared* OpenSSL on purpose (libcrypto-3-x64.dll / libssl-3-x64.dll).
#
# RC4 / Blowfish / DES live in OpenSSL 3's "legacy" provider, which is a loadable module
# (ossl-modules/legacy.dll), not part of libcrypto itself. A static libcrypto can only find
# that module through the MODULESDIR compiled into it, and MSYS2 builds OpenSSL with a MSYS
# path there ("/mingw64/lib/ossl-modules") that Win32 LoadLibrary cannot resolve. Statically
# linking OpenSSL on MinGW therefore makes OSSL_PROVIDER_load("legacy") fail silently and
# breaks crypto.rc4 / blowfish / des (verified: BuildWithWindows, 8 test_crypto failures).
# The shared libcrypto derives its module directory from the DLL location at runtime, so it
# finds legacy.dll. Ship those two DLLs next to libfakelua.dll in the release archive.

if (WIN32 AND NOT OPENSSL_ROOT_DIR)
get_filename_component(_fakelua_mingw_bin "${CMAKE_CXX_COMPILER}" DIRECTORY)
get_filename_component(_fakelua_mingw_root "${_fakelua_mingw_bin}" DIRECTORY)
Expand All @@ -305,6 +330,24 @@ endif()
find_package(OpenSSL REQUIRED)
find_package(Threads REQUIRED)

if (OPENSSL_USE_STATIC_LIBS)
# Guard against silently resolving to the shared libs (e.g. a Homebrew keg installed
# without the .a files), which would reintroduce the hardcoded runtime path.
# ".dll.a" covers the MinGW/MSVC import libraries of the OpenSSL DLLs.
set(_fl_openssl_shared "")
foreach (_fl_ssl_lib OpenSSL::SSL OpenSSL::Crypto)
get_target_property(_fl_lib_loc ${_fl_ssl_lib} IMPORTED_LOCATION)
if (_fl_lib_loc MATCHES "\\.(so|dylib|dll\\.a)(\\..*)?$")
list(APPEND _fl_openssl_shared "${_fl_ssl_lib}=${_fl_lib_loc}")
endif ()
endforeach ()
if (_fl_openssl_shared)
message(WARNING
"FAKELUA_PREFER_STATIC_DEPS is ON but OpenSSL resolved to non-static libs: "
"${_fl_openssl_shared}. The shipped library will depend on OpenSSL at runtime.")
endif ()
endif ()

# libevent: per-State event_base, driven by runtime.tick() via EVLOOP_NONBLOCK.
CPMAddPackage(
NAME libevent
Expand Down Expand Up @@ -499,6 +542,20 @@ endif()

target_link_libraries(fakelua PRIVATE ${TARGET_LIB})

# MinGW runtime: drop libgcc_s_seh-1.dll and libwinpthread-1.dll from the shipped DLL.
#
# libstdc++ is deliberately NOT statically linked. include/fakelua.h exposes STL types
# across the ABI boundary (std::string returned by value, std::vector<std::pair<...>>),
# and ViToString() is implemented inline in that header — so host and library must share
# one copy of libstdc++. Statically linking it would give each side its own copy and
# corrupt the heap whenever a std::string crosses the boundary.
# libgcc / winpthread are pure C-level runtimes with no such ABI surface, so they are safe.
if (FAKELUA_PREFER_STATIC_DEPS AND MINGW)
target_link_options(fakelua PRIVATE
-static-libgcc
-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
endif ()

target_include_directories(fakelua PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
Expand Down
17 changes: 12 additions & 5 deletions src/native/crypto/native_crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,13 +532,20 @@ void RegisterCryptoLibraryApi(State *s) {

// On OpenSSL 3.x, RC4 / Blowfish / DES are in the "legacy" provider which
// is not loaded by default. Load it once here so callers don't have to
// configure openssl.cnf manually. Failure is silently ignored: if the
// legacy provider is already loaded (via config), or if this OpenSSL build
// doesn't have it, the rest of the API still works.
// configure openssl.cnf manually. Failure only degrades the legacy ciphers:
// the rest of the API still works, so warn instead of throwing.
static std::once_flag legacy_provider_init;
std::call_once(legacy_provider_init, []() {
std::call_once(legacy_provider_init, [s]() {
#if OPENSSL_VERSION_MAJOR >= 3
OSSL_PROVIDER_load(nullptr, "legacy");
if (OSSL_PROVIDER_load(nullptr, "legacy") == nullptr) {
// Most common cause: libcrypto cannot find its provider modules
// (ossl-modules/legacy), e.g. a static OpenSSL whose MODULESDIR is wrong.
LOG_WARN(s,
"crypto",
"failed to load the OpenSSL \"legacy\" provider: crypto.rc4 / blowfish / des "
"and the matching crypto.encrypt/decrypt algorithms will fail. "
"check OPENSSL_MODULES or the OpenSSL modules directory");
}
OSSL_PROVIDER_load(nullptr, "default");
#endif
});
Expand Down
Loading