Skip to content

Commit

Permalink
Add support for musl c
Browse files Browse the repository at this point in the history
  • Loading branch information
fealebenpae committed Oct 18, 2023
1 parent 3618b2e commit 210aff0
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 16 deletions.
35 changes: 34 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ endif()
include(GNUInstallDirs)
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CMakePushCheckState)
include(Utilities)
include(SpecialtyBuilds)
include(GetVersion)
Expand Down Expand Up @@ -237,11 +238,19 @@ if(MSVC)
endif()

if(UNIX)
cmake_push_check_state(RESET)
# Enable access to large file APIs, but don't make them the default.
add_compile_definitions("_LARGEFILE_SOURCE" "_LARGEFILE64_SOURCE")
set(CMAKE_REQUIRED_DEFINITIONS "-D_LARGEFILE_SOURCE" "-D_LARGEFILE64_SOURCE")
# Use readdir64 if available.
check_symbol_exists(readdir64 "dirent.h" REALM_HAVE_READDIR64)
cmake_reset_check_state()
set(CMAKE_REQUIRED_DEFINITIONS "-D_POSIX_C_SOURCE=200809L")
check_symbol_exists(posix_fallocate "fcntl.h" REALM_HAVE_POSIX_FALLOCATE)
if(REALM_HAVE_POSIX_FALLOCATE)
add_compile_definitions("_POSIX_C_SOURCE=200809L")
endif()
cmake_pop_check_state()
endif()

# Options (passed to CMake)
Expand All @@ -262,6 +271,28 @@ option(REALM_ENABLE_GEOSPATIAL "Enable geospatial types and queries." ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

# Threads library is pthread-compatible
# Check for these explicitly because older versions of musl define only one or the other
if(CMAKE_USE_PTHREADS_INIT)
check_symbol_exists(pthread_getname_np "pthread.h" REALM_HAVE_PTHREAD_GETNAME)
check_symbol_exists(pthread_setname_np "pthread.h" REALM_HAVE_PTHREAD_SETNAME)
endif()

find_package(Backtrace)
if(Backtrace_FOUND)
add_library(Backtrace::Backtrace INTERFACE IMPORTED)
if(Backtrace_LIBRARIES AND NOT CMAKE_GENERATOR STREQUAL Xcode)
# Apple platforms always have backtrace. We disregard the `Backtrace_*` variables
# because their paths are hardcoded to one SDK within Xcode (e.g. macosx),
# whereas we build for several different SDKs and thus we can't use the include path from one in the other.
# Otherwise if CMake found that the backtrace facility is provided by an external library and not built-in
# we need to configure the interface target with the library include and link path.
target_include_directories(Backtrace::Backtrace INTERFACE ${Backtrace_INCLUDE_DIRS})
target_link_libraries(Backtrace::Backtrace INTERFACE ${Backtrace_LIBRARIES})
endif()
set(REALM_HAVE_BACKTRACE ON)
endif()

if(REALM_ENABLE_SYNC)
option(REALM_FORCE_OPENSSL "Always use OpenSSL for SSL needs, regardless of target platform." OFF)
if(CMAKE_SYSTEM_NAME MATCHES "^Windows|Linux|Android")
Expand All @@ -282,7 +313,9 @@ if(REALM_NEEDS_OPENSSL OR REALM_FORCE_OPENSSL)
include(${OPENSSL_CMAKE_INCLUDE_FILE})
endif()

set(OPENSSL_USE_STATIC_LIBS ON)
if(NOT DEFINED OPENSSL_USE_STATIC_LIBS)
set(OPENSSL_USE_STATIC_LIBS ON)
endif()
find_package(OpenSSL REQUIRED)
set(REALM_HAVE_OPENSSL ON)
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" OPENSSL_VERSION_MAJOR_MINOR "${OPENSSL_VERSION}")
Expand Down
54 changes: 54 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ branch = tokens[tokens.size()-1]
ctest_cmd = "ctest -VV"
warningFilters = [
excludeFile('/external/*'), // submodules and external libraries
excludeFile('/src/external/*'), // submodules and external libraries
excludeFile('/libuv-src/*'), // libuv, where it was downloaded and built inside cmake
excludeFile('/src/realm/parser/generated/*'), // the auto generated parser code we didn't write
]
Expand Down Expand Up @@ -180,6 +181,7 @@ jobWrapper {

parallelExecutors = [
buildLinuxRelease : doBuildLinux('Release'),
checkAlpine : doCheckAlpine(buildOptions + [enableSync: true]),
checkLinuxDebug : doCheckInDocker(buildOptions + [useToolchain : true]),
checkLinuxDebugEncrypt : doCheckInDocker(buildOptions + [useEncryption : true]),
checkLinuxRelease_4 : doCheckInDocker(buildOptions + [maxBpNodeSize: 4, buildType : 'Release', useToolchain : true]),
Expand Down Expand Up @@ -312,6 +314,58 @@ def doCheckInDocker(Map options = [:]) {
}
}

def doCheckAlpine(Map options = [:]) {
def cmakeOptions = [
CMAKE_BUILD_TYPE: options.buildType,
REALM_MAX_BPNODE_SIZE: options.maxBpNodeSize,
REALM_ENABLE_ENCRYPTION: options.enableEncryption ? 'ON' : 'OFF',
REALM_ENABLE_SYNC: options.enableSync ? 'ON' : 'OFF',
REALM_USE_SYSTEM_OPENSSL: 'ON',
OPENSSL_USE_STATIC_LIBS: 'OFF',
]

def cmakeDefinitions = cmakeOptions.collect { k,v -> "-D$k=$v" }.join(' ')

return {
rlmNode('docker') {
getArchive()

def buildEnv = buildDockerEnv('alpine.Dockerfile')

def environment = environment()
environment << 'UNITTEST_XML=unit-test-report.xml'
environment << "UNITTEST_SUITE_NAME=Alpine-${options.buildType}"
if (options.useEncryption) {
environment << 'UNITTEST_ENCRYPT_ALL=1'
}

// We don't enable this by default, because using a toolchain with its own sysroot
// prevents CMake from finding system libraries like curl which we use in sync tests.
if (options.useToolchain) {
cmakeDefinitions += " -DCMAKE_TOOLCHAIN_FILE=\"${env.WORKSPACE}/tools/cmake/x86_64-linux-musl.toolchain.cmake\""
}

buildEnv.inside {
withEnv(environment) {
try {
dir('build-dir') {
sh "cmake ${cmakeDefinitions} -G Ninja .."
runAndCollectWarnings(
script: 'ninja',
name: "alpine-${options.buildType}-encrypt${options.enableEncryption}-BPNODESIZE_${options.maxBpNodeSize}",
filters: warningFilters,
)
sh "${ctest_cmd}"
}
} finally {
junit testResults: 'build-dir/test/unit-test-report.xml'
}
}
}
}
}
}

def doCheckSanity(Map options = [:]) {
def privileged = '';

Expand Down
11 changes: 11 additions & 0 deletions alpine.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM alpine:3.11

RUN apk add --no-cache --update \
build-base \
cmake \
curl-dev \
git \
libuv-dev \
ninja \
openssl-dev \
zlib-dev
4 changes: 4 additions & 0 deletions src/realm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ endif()

target_link_libraries(Storage INTERFACE Threads::Threads)

if(TARGET Backtrace::Backtrace)
target_link_libraries(Storage PUBLIC Backtrace::Backtrace)
endif()

if(REALM_ENABLE_ENCRYPTION AND UNIX AND NOT APPLE AND REALM_HAVE_OPENSSL)
target_link_libraries(Storage PUBLIC OpenSSL::Crypto)
endif()
Expand Down
14 changes: 12 additions & 2 deletions src/realm/util/backtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,19 @@
#include <cstdlib>
#include <cstring>

#if REALM_PLATFORM_APPLE || (defined(__linux__) && !REALM_ANDROID)
#ifndef REALM_HAVE_BACKTRACE
// we detect the backtrace facility in CMake, but if building outside it we assume
// it's available on Apple or Linux/glibc
#define REALM_HAVE_BACKTRACE REALM_PLATFORM_APPLE || (REALM_LINUX && defined(__GNUC__))
#endif

#if REALM_HAVE_BACKTRACE
#if defined(REALM_BACKTRACE_HEADER)
#include REALM_BACKTRACE_HEADER
#else
#include <execinfo.h>
#endif
#endif

using namespace realm::util;

Expand Down Expand Up @@ -105,7 +115,7 @@ Backtrace& Backtrace::operator=(const Backtrace& other) noexcept

Backtrace Backtrace::capture() noexcept
{
#if REALM_PLATFORM_APPLE || (defined(__linux__) && !REALM_ANDROID)
#if REALM_HAVE_BACKTRACE
static_cast<void>(g_backtrace_unsupported_error);
void* callstack[g_backtrace_depth];
int frames = ::backtrace(callstack, g_backtrace_depth);
Expand Down
2 changes: 1 addition & 1 deletion src/realm/util/basic_system_errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
**************************************************************************/

// opt into the POSIX version of strerror_r
#define _POSIX_C_SOURCE 200112L
#define _POSIX_C_SOURCE 200809L

#include <cstdlib>
#include <cstring>
Expand Down
9 changes: 7 additions & 2 deletions src/realm/util/config.h.in
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
// Version information
#cmakedefine REALM_VERSION "@VERSION@"

// Realm-specific configuration
// Feature detection
#cmakedefine01 REALM_HAVE_READDIR64
#cmakedefine01 REALM_HAVE_POSIX_FALLOCATE
#cmakedefine01 REALM_HAVE_OPENSSL
#cmakedefine01 REALM_HAVE_SECURE_TRANSPORT
#cmakedefine01 REALM_HAVE_PTHREAD_GETNAME
#cmakedefine01 REALM_HAVE_PTHREAD_SETNAME
#cmakedefine01 REALM_HAVE_BACKTRACE
#cmakedefine01 REALM_INCLUDE_CERTS
#cmakedefine REALM_MAX_BPNODE_SIZE @REALM_MAX_BPNODE_SIZE@
#define REALM_MAX_BPNODE_SIZE @REALM_MAX_BPNODE_SIZE@
#define REALM_BACKTRACE_HEADER <@Backtrace_HEADER@>
#cmakedefine01 REALM_ENABLE_ASSERTIONS
#cmakedefine01 REALM_ENABLE_ALLOC_SET_ZERO
#cmakedefine01 REALM_ENABLE_ENCRYPTION
Expand Down
8 changes: 4 additions & 4 deletions src/realm/util/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ void File::prealloc(size_t size)
#endif
};

#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version
#if REALM_HAVE_POSIX_FALLOCATE
// Mostly Linux only
if (!prealloc_if_supported(0, new_size)) {
consume_space_interlocked();
Expand Down Expand Up @@ -954,15 +954,15 @@ void File::prealloc(size_t size)
#error Please check if/how your OS supports file preallocation
#endif

#endif // !(_POSIX_C_SOURCE >= 200112L)
#endif // REALM_HAVE_POSIX_FALLOCATE
}


bool File::prealloc_if_supported(SizeType offset, size_t size)
{
REALM_ASSERT_RELEASE(is_attached());

#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version
#if REALM_HAVE_POSIX_FALLOCATE

REALM_ASSERT_RELEASE(is_prealloc_supported());

Expand Down Expand Up @@ -1015,7 +1015,7 @@ bool File::prealloc_if_supported(SizeType offset, size_t size)

bool File::is_prealloc_supported()
{
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version
#if REALM_HAVE_POSIX_FALLOCATE
return true;
#else
return false;
Expand Down
22 changes: 16 additions & 6 deletions src/realm/util/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,29 @@ void Thread::join()

void Thread::set_name(const std::string& name)
{
#if defined _GNU_SOURCE && !REALM_ANDROID && !REALM_PLATFORM_APPLE && !defined(__EMSCRIPTEN__)
#if REALM_PLATFORM_APPLE
int r = pthread_setname_np(name.data());
if (REALM_UNLIKELY(r != 0))
throw std::system_error(r, std::system_category(), "pthread_setname_np() failed");
#elif REALM_HAVE_PTHREAD_SETNAME || (!defined(REALM_HAVE_PTHREAD_SETNAME) && defined(_GNU_SOURCE))
// Look for the HAVE_ macro defined by CMake. If building outside CMake and the macro wasn't explicitly defined, fall
// back to assuming this is available on Unix-y systems.
#if defined(__linux__)
// Thread names on Linux can only be 16 characters long, including the null terminator
const size_t max = 16;
size_t n = name.size();
if (n > max - 1)
n = max - 1;
char name_2[max];
std::copy(name.data(), name.data() + n, name_2);
name_2[n] = '\0';
#else
const char* name_2 = name.c_str();
#endif
pthread_t id = pthread_self();
int r = pthread_setname_np(id, name_2);
if (REALM_UNLIKELY(r != 0))
throw std::system_error(r, std::system_category(), "pthread_setname_np() failed");
#elif REALM_PLATFORM_APPLE
int r = pthread_setname_np(name.data());
if (REALM_UNLIKELY(r != 0))
throw std::system_error(r, std::system_category(), "pthread_setname_np() failed");
#else
static_cast<void>(name);
#endif
Expand All @@ -103,7 +110,10 @@ void Thread::set_name(const std::string& name)

bool Thread::get_name(std::string& name) noexcept
{
#if (defined _GNU_SOURCE && !REALM_ANDROID && !defined(__EMSCRIPTEN__)) || REALM_PLATFORM_APPLE
// Look for the HAVE_ macro defined by CMake. If building outside CMake and the macro wasn't explicitly defined, fall
// back to assuming this is available on Unix-y systems.
#if REALM_HAVE_PTHREAD_GETNAME || \
(!defined(REALM_HAVE_PTHREAD_GETNAME) && (defined(_GNU_SOURCE) || REALM_PLATFORM_APPLE))
const size_t max = 64;
char name_2[max];
pthread_t id = pthread_self();
Expand Down
5 changes: 5 additions & 0 deletions test/test_util_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ TEST(BasicSystemErrors_Category)

TEST(BasicSystemErrors_Messages)
{
#if defined(__linux__) && !defined(__GLIBC__)
// Linux and not glibc implies Musl, which has its own message
const std::string error_message("No error information");
#else
const std::string error_message("Unknown error");
#endif

{
std::error_code err = make_error_code(error::address_family_not_supported);
Expand Down
3 changes: 3 additions & 0 deletions test/test_util_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ TEST(Utils_File_SystemErrorMessage)
std::string_view message = "my message";
#ifdef _WIN32
const char* expected = "my message: too many files open (%1)";
#elif defined(__linux__) && !defined(__GLIBC__)
// Linux and not glibc implies Musl, which has its own message
const char* expected = "my message: No file descriptors available (%1)";
#else
const char* expected = "my message: Too many open files (%1)";
#endif
Expand Down

0 comments on commit 210aff0

Please sign in to comment.