Skip to content

Commit 7add56e

Browse files
authored
Make: Better builds for shared libraries (#136)
* Fixed build issues with the shared libraries * Fixed arm shared library march * Added missing defined check * Made the mem* exported using `#pragma` instead of from cmake * Changed non-mask AVX512 loads/stores using epi8 to `si512` * Fixed python build 64bit platform detection * Changed python MSVC build all AVX functions * Removed explicit arm arch * Fixed python build to properly detect platform when cross-compiling * Avoid including `arm_acle` & `arm_sve` for MSVC * Update clang version to 16 for cross compile builds * Added check for `cibuildwheels` in python builds * Removed cmake dependency for python builds
1 parent ddab0cc commit 7add56e

File tree

6 files changed

+226
-77
lines changed

6 files changed

+226
-77
lines changed

.github/workflows/prerelease.yml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ jobs:
202202
name: Cross Compilation
203203
runs-on: ubuntu-22.04
204204
env:
205-
CC: clang
206-
CXX: clang++
207-
AR: llvm-ar
208-
NM: llvm-nm
209-
RANLIB: llvm-ranlib
205+
CC: clang-16
206+
CXX: clang++-16
207+
AR: llvm-ar-16
208+
NM: llvm-nm-16
209+
RANLIB: llvm-ranlib-16
210210

211211
strategy:
212212
fail-fast: false
@@ -222,11 +222,15 @@ jobs:
222222

223223
# C/C++
224224
# We need to install the cross-compilation toolchain for ARM64 and ARMHF
225+
# Clang 16 isn't available from default repos on Ubuntu 22.04, so we have to install it manually
225226
- name: Install dependencies
226227
run: |
227228
sudo apt-get update
228-
sudo apt-get install -y clang lld make crossbuild-essential-arm64 crossbuild-essential-armhf
229-
229+
sudo apt-get install -y make build-essential crossbuild-essential-arm64 crossbuild-essential-armhf libjemalloc-dev
230+
wget https://apt.llvm.org/llvm.sh
231+
chmod +x llvm.sh
232+
sudo ./llvm.sh 16
233+
230234
- name: Build C/C++
231235
run: |
232236
cmake -B build_artifacts \

CMakeLists.txt

Lines changed: 82 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
3838
"MinSizeRel" "RelWithDebInfo")
3939
endif()
4040

41+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
42+
SET(SZ_PLATFORM_X86 TRUE)
43+
message(STATUS "Platform: x86")
44+
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
45+
SET(SZ_PLATFORM_ARM TRUE)
46+
message(STATUS "Platform: ARM")
47+
endif()
48+
4149
# Determine if StringZilla is built as a subproject (using `add_subdirectory`)
4250
# or if it is the main project
4351
set(STRINGZILLA_IS_MAIN_PROJECT OFF)
@@ -99,8 +107,17 @@ if(${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)
99107
enable_testing()
100108
endif()
101109

110+
if (MSVC)
111+
# Remove /RTC* from MSVC debug flags by default (it will be added back in the set_compiler_flags function)
112+
# Beacuse /RTC* cannot be used without the crt so it needs to be disabled for that specifc target
113+
string(REGEX REPLACE "/RTC[^ ]*" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
114+
string(REGEX REPLACE "/RTC[^ ]*" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
115+
endif()
116+
102117
# Function to set compiler-specific flags
103118
function(set_compiler_flags target cpp_standard target_arch)
119+
get_target_property(target_type ${target} TYPE)
120+
104121
target_include_directories(${target} PRIVATE scripts)
105122
target_link_libraries(${target} PRIVATE ${STRINGZILLA_TARGET_NAME})
106123

@@ -152,17 +169,26 @@ function(set_compiler_flags target cpp_standard target_arch)
152169
"$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>>:/Zi>"
153170
)
154171

172+
if(NOT target_type STREQUAL "SHARED_LIBRARY")
173+
if(MSVC)
174+
target_compile_options(${target} PRIVATE "$<$<CONFIG:Debug>:/RTC1>")
175+
endif()
176+
endif()
177+
155178
# If available, enable Position Independent Code
156-
if(CMAKE_POSITION_INDEPENDENT_CODE)
179+
get_target_property(target_pic ${target} POSITION_INDEPENDENT_CODE)
180+
if(target_pic)
157181
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fPIC>")
158182
target_link_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fPIC>")
183+
target_compile_definitions(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:SZ_PIC>")
159184
endif()
160185

161186
# Avoid builtin functions where we know what we are doing.
162187
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fno-builtin-memcmp>")
163188
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fno-builtin-memchr>")
164189
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fno-builtin-memcpy>")
165190
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-fno-builtin-memset>")
191+
target_compile_options(${target} PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/Oi->")
166192

167193
# Check for ${target_arch} and set it or use the current system if not defined
168194
if("${target_arch}" STREQUAL "")
@@ -202,17 +228,19 @@ function(set_compiler_flags target cpp_standard target_arch)
202228

203229
# Sanitizer options for Debug mode
204230
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
205-
target_compile_options(
206-
${target}
207-
PRIVATE
208-
"$<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address;-fsanitize=leak>"
209-
"$<$<CXX_COMPILER_ID:MSVC>:/fsanitize=address>")
210-
211-
target_link_options(
212-
${target}
213-
PRIVATE
214-
"$<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address;-fsanitize=leak>"
215-
"$<$<CXX_COMPILER_ID:MSVC>:/fsanitize=address>")
231+
if(NOT target_type STREQUAL "SHARED_LIBRARY")
232+
target_compile_options(
233+
${target}
234+
PRIVATE
235+
"$<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address;-fsanitize=leak>"
236+
"$<$<CXX_COMPILER_ID:MSVC>:/fsanitize=address>")
237+
238+
target_link_options(
239+
${target}
240+
PRIVATE
241+
"$<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address;-fsanitize=leak>"
242+
"$<$<CXX_COMPILER_ID:MSVC>:/fsanitize=address>")
243+
endif()
216244

217245
# Define SZ_DEBUG macro based on build configuration
218246
target_compile_definitions(
@@ -248,7 +276,7 @@ if(${STRINGZILLA_BUILD_TEST})
248276

249277
# Check system architecture to avoid complex cross-compilation workflows, but
250278
# compile multiple backends: disabling all SIMD, enabling only AVX2, only AVX-512, only Arm Neon.
251-
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
279+
if(SZ_PLATFORM_X86)
252280
# x86 specific backends
253281
if (MSVC)
254282
define_launcher(stringzilla_test_cpp20_x86_serial scripts/test.cpp 20 "AVX")
@@ -259,37 +287,60 @@ if(${STRINGZILLA_BUILD_TEST})
259287
define_launcher(stringzilla_test_cpp20_x86_avx2 scripts/test.cpp 20 "haswell")
260288
define_launcher(stringzilla_test_cpp20_x86_avx512 scripts/test.cpp 20 "sapphirerapids")
261289
endif()
262-
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
290+
elseif(SZ_PLATFORM_ARM)
263291
# ARM specific backends
264292
define_launcher(stringzilla_test_cpp20_arm_serial scripts/test.cpp 20 "armv8-a")
265293
define_launcher(stringzilla_test_cpp20_arm_neon scripts/test.cpp 20 "armv8-a+simd")
266294
endif()
267295
endif()
268296

269297
if(${STRINGZILLA_BUILD_SHARED})
270-
add_library(stringzilla_shared SHARED c/lib.c)
271-
set_compiler_flags(stringzilla_shared "" "${STRINGZILLA_TARGET_ARCH}")
298+
299+
function(define_shared target)
300+
add_library(${target} SHARED c/lib.c)
301+
302+
set_target_properties(${target} PROPERTIES
303+
VERSION ${PROJECT_VERSION}
304+
SOVERSION 1
305+
POSITION_INDEPENDENT_CODE ON
306+
PUBLIC_HEADER include/stringzilla/stringzilla.h)
307+
308+
if (SZ_PLATFORM_X86)
309+
if (MSVC)
310+
set_compiler_flags(${target} "" "SSE2")
311+
else()
312+
set_compiler_flags(${target} "" "ivybridge")
313+
endif()
314+
315+
target_compile_definitions(${target} PRIVATE
316+
"SZ_USE_X86_AVX512=1"
317+
"SZ_USE_X86_AVX2=1"
318+
"SZ_USE_ARM_NEON=0"
319+
"SZ_USE_ARM_SVE=0")
320+
elseif(SZ_PLATFORM_ARM)
321+
set_compiler_flags(${target} "" "armv8-a")
322+
323+
target_compile_definitions(${target} PRIVATE
324+
"SZ_USE_X86_AVX512=0"
325+
"SZ_USE_X86_AVX2=0"
326+
"SZ_USE_ARM_NEON=1"
327+
"SZ_USE_ARM_SVE=1")
328+
endif()
329+
endfunction()
330+
331+
define_shared(stringzilla_shared)
272332
target_compile_definitions(stringzilla_shared PRIVATE "SZ_AVOID_LIBC=0")
273333
target_compile_definitions(stringzilla_shared PRIVATE "SZ_OVERRIDE_LIBC=1")
274-
set_target_properties(stringzilla_shared PROPERTIES
275-
VERSION ${PROJECT_VERSION}
276-
SOVERSION 1
277-
POSITION_INDEPENDENT_CODE ON
278-
PUBLIC_HEADER include/stringzilla/stringzilla.h)
279-
334+
280335
# Try compiling a version without linking the LibC
281-
add_library(stringzillite SHARED c/lib.c)
282-
set_compiler_flags(stringzillite "" "${STRINGZILLA_TARGET_ARCH}")
336+
define_shared(stringzillite)
283337
target_compile_definitions(stringzillite PRIVATE "SZ_AVOID_LIBC=1")
284338
target_compile_definitions(stringzillite PRIVATE "SZ_OVERRIDE_LIBC=1")
285-
set_target_properties(stringzillite PROPERTIES
286-
VERSION ${PROJECT_VERSION}
287-
SOVERSION 1
288-
POSITION_INDEPENDENT_CODE ON
289-
PUBLIC_HEADER include/stringzilla/stringzilla.h)
290339

291340
# Avoid built-ins on MSVC and other compilers, as that will cause compileration errors
292341
target_compile_options(stringzillite PRIVATE
293342
"$<$<CXX_COMPILER_ID:GNU,Clang>:-fno-builtin;-nostdlib>"
294-
"$<$<CXX_COMPILER_ID:MSVC>:/Oi->")
295-
endif()
343+
"$<$<CXX_COMPILER_ID:MSVC>:/Oi-;/GS->")
344+
target_link_options(stringzillite PRIVATE "$<$<CXX_COMPILER_ID:GNU,Clang>:-nostdlib>")
345+
target_link_options(stringzillite PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/NODEFAULTLIB>")
346+
endif()

c/lib.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,14 @@ BOOL WINAPI DllMain(HINSTANCE hints, DWORD forward_reason, LPVOID lp) {
224224
case DLL_PROCESS_DETACH: return TRUE;
225225
}
226226
}
227+
228+
#if SZ_AVOID_LIBC
229+
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hints, DWORD forward_reason, LPVOID lp) {
230+
DllMain(hints, forward_reason, lp);
231+
return TRUE;
232+
}
233+
#endif
234+
227235
#else
228236
__attribute__((constructor)) static void sz_dispatch_table_init_on_gcc_or_clang(void) { sz_dispatch_table_init(); }
229237
#endif
@@ -356,30 +364,54 @@ SZ_DYNAMIC void sz_generate(sz_cptr_t alphabet, sz_size_t alphabet_size, sz_ptr_
356364
sz_generate_serial(alphabet, alphabet_size, result, result_length, generator, generator_user_data);
357365
}
358366

359-
// It's much harder to override the C standard library on Windows and MSVC,
360-
// so we'll just provide the symbols for other Operating Systems.
361-
#if SZ_OVERRIDE_LIBC && !(defined(_WIN32) || defined(__CYGWIN__))
367+
// Provide overrides for the libc mem* functions
368+
#if SZ_OVERRIDE_LIBC && !(defined(__CYGWIN__))
362369

370+
// SZ_DYNAMIC can't be use here for MSVC, because MSVC complains about different linkage (C2375), probably due to to the
371+
// CRT headers specifying the function as __declspec(dllimport), there might be a combination of defines that works. But
372+
// for now they will be manually exported using linker flags
373+
374+
#if defined(_MSC_VER)
375+
#pragma comment(linker, "/export:memchr")
376+
void *__cdecl memchr(void const *s, int c_wide, size_t n) {
377+
#else
363378
SZ_DYNAMIC void *memchr(void const *s, int c_wide, size_t n) {
379+
#endif
364380
sz_u8_t c = (sz_u8_t)c_wide;
365381
return (void *)sz_find_byte(s, n, (sz_cptr_t)&c);
366382
}
367383

384+
#if defined(_MSC_VER)
385+
#pragma comment(linker, "/export:memcpy")
386+
void *__cdecl memcpy(void *dest, void const *src, size_t n) {
387+
#else
368388
SZ_DYNAMIC void *memcpy(void *dest, void const *src, size_t n) {
389+
#endif
369390
sz_copy(dest, src, n);
370391
return (void *)dest;
371392
}
372393

394+
#if defined(_MSC_VER)
395+
#pragma comment(linker, "/export:memmove")
396+
void *__cdecl memmove(void *dest, void const *src, size_t n) {
397+
#else
373398
SZ_DYNAMIC void *memmove(void *dest, void const *src, size_t n) {
399+
#endif
374400
sz_move(dest, src, n);
375401
return (void *)dest;
376402
}
377403

404+
#if defined(_MSC_VER)
405+
#pragma comment(linker, "/export:memset")
406+
void *__cdecl memset(void *s, int c, size_t n) {
407+
#else
378408
SZ_DYNAMIC void *memset(void *s, int c, size_t n) {
409+
#endif
379410
sz_fill(s, n, c);
380411
return (void *)s;
381412
}
382413

414+
#if !defined(_MSC_VER)
383415
SZ_DYNAMIC void *memmem(void const *h, size_t h_len, void const *n, size_t n_len) {
384416
return (void *)sz_find(h, h_len, n, n_len);
385417
}
@@ -393,5 +425,5 @@ SZ_DYNAMIC void memfrob(void *s, size_t n) {
393425
char const *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
394426
sz_generate(base64, 64, s, n, SZ_NULL, SZ_NULL);
395427
}
396-
428+
#endif
397429
#endif // SZ_OVERRIDE_LIBC

0 commit comments

Comments
 (0)