Skip to content

Commit 39133c1

Browse files
committed
Add a new target which generates a C-only API shared library.
This can be compiled for both Linux and Windows. If the chosen target is a Windows DLL, the library is compatible with MSVC and It is self-contained, i.e. there are no other DLL dependencies (other than the kernel) and exceptions and memory allocations do not cross the DLL boundary. Signed-off-by: Fabio Cannizzo <[email protected]>
1 parent 058f913 commit 39133c1

15 files changed

+1049
-10
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,35 @@ xss_dep = xss.get_variable('x86simdsortcpp_dep')
109109
For more detailed instructions please refer to Meson
110110
[documentation](https://mesonbuild.com/Subprojects.html#using-a-subproject).
111111

112+
## Build with C-only API, targeting Windows and MSVC
113+
114+
The folder `make-c-api` contains a `Makefile` to build a shared library exporting only C-symbols.
115+
This avoid potential conflicts of inconsistent mangling and calling convention across compilers.
116+
117+
Only a reduced set of functions are exported (`qselect`, `qsort`, `partial_qsort`, `keyvalue_qsort`, `keyvalue_partial_qsort`, `keyvalue_qselect`)
118+
and only for a reduces set of types (`int32`, `uint32`, `int64`, `uint64`, `float`, `double`).
119+
120+
In the subfolder `make-c-api` a `Makefile` is provided which supports the following combinations of operating systems, compilers and targets:
121+
122+
+--------------+------------------+------------+----------------------+---------------------+
123+
| Compilation | Compiler | Target | Files Generated | Build Command line |
124+
| Platform | | Platform | | |
125+
+--------------+------------------+------------+----------------------+---------------------+
126+
| LINUX | g++ | LINUX | libx86simdsort.so | make |
127+
+--------------+------------------+------------+----------------------+---------------------+
128+
| CYGWIN | clang++ | CYGWIN | libx86simdsort.so | make |
129+
+--------------+------------------+------------+----------------------+---------------------+
130+
| ANY | mingw32 clang++ | Windows | x86simdsort.dll | make TARGET=DLL |
131+
| | | | x86simdsort.dll.lib | |
132+
+--------------+------------------+------------+----------------------+---------------------+
133+
134+
In all cases, exceptions and memory allocations never cross the shared library boundary.
135+
In particular, if the target is a DLL, the library is self-contained, i.e. it does not depend on any other DLL.
136+
137+
Compilation is tested with clang 20 and gcc 15.
138+
139+
An include header `x86simdsort-c-api.h` and a `smoke.exe` executable test are also generated.
140+
112141
## Example usage
113142

114143
#### Sort an array of floats

lib/c-api-def.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include "c-api-headers.h"
2+
3+
LIBRARY x86simdsortcpp
4+
EXPORTS
5+
6+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(qsort,n)
7+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(qsort,n)
8+
#include "x-macro1.h"
9+
10+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(qselect,n)
11+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(qselect,n)
12+
#include "x-macro1.h"
13+
14+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(partial_qsort,n)
15+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(partial_qsort,n)
16+
#include "x-macro1.h"
17+
18+
19+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2)
20+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2)
21+
#include "x-macro2.h"
22+
23+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2)
24+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2)
25+
#include "x-macro2.h"
26+
27+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2)
28+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2)
29+
#include "x-macro2.h"

lib/c-api-export.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "c-api-headers.h"
2+
3+
#ifdef XSS_EXPORTING
4+
# if defined(__MINGW64__)
5+
# define XSS_C_EXPORT __declspec(dllexport)
6+
# else
7+
# define XSS_C_EXPORT __attribute__((visibility("default")))
8+
# endif
9+
# define XSS_C_BODY(body) { try { body; return true; } catch(...) { return false; } }
10+
#else
11+
# define XSS_C_EXPORT XSS_DLL_IMPORT
12+
# define XSS_C_BODY(body) ;
13+
#endif
14+
15+
#define XSS_XI1(n,t) XSS_C_EXPORT XSS_QSORT_HEADER_INT(n,t) XSS_C_BODY(x86simdsort::qsort(ar, size, false, descending))
16+
#define XSS_XF1(n,t) XSS_C_EXPORT XSS_QSORT_HEADER_FLT(n,t) XSS_C_BODY(x86simdsort::qsort(ar, size, hasnan, descending))
17+
#include "x-macro1.h"
18+
19+
#define XSS_XI1(n,t) XSS_C_EXPORT XSS_QSELECT_HEADER_INT(n,t) XSS_C_BODY(x86simdsort::qselect(ar, k, size, false, descending))
20+
#define XSS_XF1(n,t) XSS_C_EXPORT XSS_QSELECT_HEADER_FLT(n,t) XSS_C_BODY(x86simdsort::qselect(ar, k, size, hasnan, descending))
21+
#include "x-macro1.h"
22+
23+
#define XSS_XI1(n,t) XSS_C_EXPORT XSS_QPSORT_HEADER_INT(n,t) XSS_C_BODY(x86simdsort::partial_qsort(ar, k, size, false, descending))
24+
#define XSS_XF1(n,t) XSS_C_EXPORT XSS_QPSORT_HEADER_FLT(n,t) XSS_C_BODY(x86simdsort::partial_qsort(ar, k, size, hasnan, descending))
25+
#include "x-macro1.h"
26+
27+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVSORT_HEADER_INT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_qsort(keys, vals, size, false, descending))
28+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVSORT_HEADER_FLT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_qsort(keys, vals, size, hasnan, descending))
29+
#include "x-macro2.h"
30+
31+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVSEL_HEADER_INT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_select(keys, vals, k, size, false, descending))
32+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVSEL_HEADER_FLT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_select(keys, vals, k, size, hasnan, descending))
33+
#include "x-macro2.h"
34+
35+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVPSORT_HEADER_INT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_partial_sort(keys, vals, k, size, false, descending))
36+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXPORT XSS_QKVPSORT_HEADER_FLT(n1,t1,n2,t2) XSS_C_BODY(x86simdsort::keyvalue_partial_sort(keys, vals, k, size, hasnan, descending))
37+
#include "x-macro2.h"

lib/c-api-headers.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#define XSS_C_EXP_NAME1(name, ty) c_xss_##name##_##ty
4+
#define XSS_C_EXP_NAME2(name, ty1, ty2) c_xss_##name##_##ty1##_##ty2
5+
6+
#define XSS_QSORT_HEADER_INT(n,t) bool XSS_C_EXP_NAME1(qsort, n)(t *ar, uint64_t size, bool descending)
7+
#define XSS_QSORT_HEADER_FLT(n,t) bool XSS_C_EXP_NAME1(qsort, n)(t *ar, uint64_t size, bool hasnan, bool descending)
8+
9+
#define XSS_QSELECT_HEADER_INT(n,t) bool XSS_C_EXP_NAME1(qselect, n)(t *ar, uint64_t k, uint64_t size, bool descending)
10+
#define XSS_QSELECT_HEADER_FLT(n,t) bool XSS_C_EXP_NAME1(qselect, n)(t *ar, uint64_t k, uint64_t size, bool hasnan, bool descending)
11+
12+
#define XSS_QPSORT_HEADER_INT(n,t) bool XSS_C_EXP_NAME1(partial_qsort, n)(t *ar, uint64_t k, uint64_t size, bool descending)
13+
#define XSS_QPSORT_HEADER_FLT(n,t) bool XSS_C_EXP_NAME1(partial_qsort, n)(t *ar, uint64_t k, uint64_t size, bool hasnan, bool descending)
14+
15+
#define XSS_QKVSORT_HEADER_INT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2)(t1 *keys, t2* vals, uint64_t size, bool descending)
16+
#define XSS_QKVSORT_HEADER_FLT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2)(t1 *keys, t2* vals, uint64_t size, bool hasnan, bool descending)
17+
18+
#define XSS_QKVSEL_HEADER_INT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2)(t1 *keys, t2* vals, uint64_t k, uint64_t size, bool descending)
19+
#define XSS_QKVSEL_HEADER_FLT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2)(t1 *keys, t2* vals, uint64_t k, uint64_t size, bool hasnan, bool descending)
20+
21+
#define XSS_QKVPSORT_HEADER_INT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2)(t1 *keys, t2* vals, uint64_t k, uint64_t size, bool descending)
22+
#define XSS_QKVPSORT_HEADER_FLT(n1,t1,n2,t2) bool XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2)(t1 *keys, t2* vals, uint64_t k, uint64_t size, bool hasnan, bool descending)
23+
24+
25+

lib/c-api-ver.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "c-api-headers.h"
2+
3+
{
4+
global:
5+
6+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(qsort,n);
7+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(qsort,n);
8+
#include "x-macro1.h"
9+
10+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(qselect,n);
11+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(qselect,n);
12+
#include "x-macro1.h"
13+
14+
#define XSS_XI1(n,t) XSS_C_EXP_NAME1(partial_qsort,n);
15+
#define XSS_XF1(n,t) XSS_C_EXP_NAME1(partial_qsort,n);
16+
#include "x-macro1.h"
17+
18+
19+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2);
20+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qsort, n1, n2);
21+
#include "x-macro2.h"
22+
23+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2);
24+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_qselect, n1, n2);
25+
#include "x-macro2.h"
26+
27+
#define XSS_XI2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2);
28+
#define XSS_XF2(n1,t1, n2,t2) XSS_C_EXP_NAME2(keyvalue_partial_qsort, n1, n2);
29+
#include "x-macro2.h"
30+
31+
local:
32+
*;
33+
};

lib/mk-c-api.sed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/sh
2+
3+
s|PRAGMA \(.*\)|#\1|g
4+
s|COMMENT\(.*\)|//\1|g
5+
s/EMPTYLINE//g
6+
s/^XSS_DLL_IMPORT/ XSS_DLL_IMPORT/g
7+
s/^inline/ inline/g

lib/x-macro1.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
#ifndef XSS_XI1
3+
# error XSS_XI1 must be defined
4+
#endif
5+
6+
#ifndef XSS_XF1
7+
# error XSS_XF1 must be defined
8+
#endif
9+
10+
XSS_XI1(uint32, uint32_t)
11+
XSS_XI1(uint64, uint64_t)
12+
XSS_XI1(int64, int64_t)
13+
XSS_XI1(int32, int32_t)
14+
XSS_XF1(float, float)
15+
XSS_XF1(double, double)
16+
17+
#undef XSS_XI1
18+
#undef XSS_XF1

lib/x-macro2.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef XSS_XI2
2+
# error XSS_XI3 must be defined
3+
#endif
4+
5+
#ifndef XSS_XF2
6+
# error XSS_XF2 must be defined
7+
#endif
8+
9+
#define XSS_XI1(n,t) XSS_XI2(int32, int32_t, n, t)
10+
#define XSS_XF1(n,t) XSS_XI1(n, t)
11+
#include "x-macro1.h"
12+
13+
#define XSS_XI1(n,t) XSS_XI2(uint32, uint32_t, n, t)
14+
#define XSS_XF1(n,t) XSS_XI1(n, t)
15+
#include "x-macro1.h"
16+
17+
#define XSS_XI1(n,t) XSS_XI2(int64, int64_t, n, t)
18+
#define XSS_XF1(n,t) XSS_XI1(n, t)
19+
#include "x-macro1.h"
20+
21+
#define XSS_XI1(n,t) XSS_XI2(uint64, uint64_t, n, t)
22+
#define XSS_XF1(n,t) XSS_XI1(n, t)
23+
#include "x-macro1.h"
24+
25+
#define XSS_XI1(n,t) XSS_XF2(float, float, n, t)
26+
#define XSS_XF1(n,t) XSS_XI1(n, t)
27+
#include "x-macro1.h"
28+
29+
#define XSS_XI1(n,t) XSS_XF2(double, double, n, t)
30+
#define XSS_XF1(n,t) XSS_XI1(n, t)
31+
#include "x-macro1.h"
32+
33+
#undef XSS_XI2
34+
#undef XSS_XF2
35+
36+
37+

lib/x86simdsort-gen-c-api.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
COMMENT This is an auto-generated file
2+
COMMENT This header is intended to be used for shared libraries (so or dll) compiled to the shared_c_api target
3+
4+
PRAGMA pragma once
5+
EMPTYLINE
6+
PRAGMA include <cstdint>
7+
EMPTYLINE
8+
/*
9+
PRAGMA if defined(_MSC_VER)
10+
PRAGMA define XSS_DLL_IMPORT __declspec(dllimport) // cpp transforms __declspec(dllimport) to __attribute__((dllimport))
11+
PRAGMA elif defined(__MINGW64__)
12+
PRAGMA define XSS_DLL_IMPORT __attribute__((dllimport))
13+
PRAGMA else
14+
PRAGMA define XSS_DLL_IMPORT
15+
PRAGMA endif
16+
*/
17+
PRAGMA define XSS_DLL_IMPORT
18+
19+
#include "c-api-headers.h"
20+
21+
EMPTYLINE
22+
COMMENT DLL import declarations
23+
extern "C"
24+
{
25+
#include "c-api-export.h"
26+
} COMMENT extern "C"
27+
28+
EMPTYLINE
29+
COMMENT Dispatchers with identical names using C overloads
30+
namespace xss
31+
{
32+
33+
#define XSS_XI1(n,t) inline bool qsort(t* ar, uint64_t sz, bool desc) { return XSS_C_EXP_NAME1(qsort,n)( ar, sz, desc ); }
34+
#define XSS_XF1(n,t) inline bool qsort(t* ar, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME1(qsort,n)( ar, sz, hasnan, desc ); }
35+
#include "x-macro1.h"
36+
37+
#define XSS_XI1(n,t) inline bool qselect(t* ar, uint64_t k, uint64_t sz, bool desc) { return XSS_C_EXP_NAME1(qselect,n)( ar, k, sz, desc ); }
38+
#define XSS_XF1(n,t) inline bool qselect(t* ar, uint64_t k, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME1(qselect,n)( ar, k, sz, hasnan, desc ); }
39+
#include "x-macro1.h"
40+
41+
#define XSS_XI1(n,t) inline bool partial_qsort(t* ar, uint64_t k, uint64_t sz, bool desc) { return XSS_C_EXP_NAME1(partial_qsort,n)( ar, k, sz, desc ); }
42+
#define XSS_XF1(n,t) inline bool partial_qsort(t* ar, uint64_t k, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME1(partial_qsort,n)( ar, k, sz, hasnan, desc ); }
43+
#include "x-macro1.h"
44+
45+
#define XSS_XI2(n1,t1, n2,t2) inline bool keyvalue_qsort(t1* keys, t2* vals, uint64_t sz, bool desc) { return XSS_C_EXP_NAME2(keyvalue_qsort,n1, n2)( keys, vals, sz, desc ); }
46+
#define XSS_XF2(n1,t1, n2,t2) inline bool keyvalue_qsort(t1* keys, t2* vals, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME2(keyvalue_qsort,n1, n2)( keys, vals, sz, hasnan, desc ); }
47+
#include "x-macro2.h"
48+
49+
#define XSS_XI2(n1,t1, n2,t2) inline bool keyvalue_qselect(t1* keys, t2* vals, uint64_t k, uint64_t sz, bool desc) { return XSS_C_EXP_NAME2(keyvalue_qselect,n1, n2)( keys, vals, k, sz, desc ); }
50+
#define XSS_XF2(n1,t1, n2,t2) inline bool keyvalue_qselect(t1* keys, t2* vals, uint64_t k, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME2(keyvalue_qselect,n1, n2)( keys, vals, k, sz, hasnan, desc ); }
51+
#include "x-macro2.h"
52+
53+
#define XSS_XI2(n1,t1, n2,t2) inline bool keyvalue_partial_qsort(t1* keys, t2* vals, uint64_t k, uint64_t sz, bool desc) { return XSS_C_EXP_NAME2(keyvalue_partial_qsort,n1, n2)( keys, vals, k, sz, desc ); }
54+
#define XSS_XF2(n1,t1, n2,t2) inline bool keyvalue_partial_qsort(t1* keys, t2* vals, uint64_t k, uint64_t sz, bool hasnan, bool desc) { return XSS_C_EXP_NAME2(keyvalue_partial_qsort,n1, n2)( keys, vals, k, sz, hasnan, desc ); }
55+
#include "x-macro2.h"
56+
57+
} COMMENT namespace xss
58+
EMPTYLINE

lib/x86simdsort.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ DISPATCH_KEYVALUE_SORT_FORTYPE(float)
296296
//
297297

298298
extern "C" {
299+
300+
#ifndef C_API_ONLY
301+
299302
XSS_EXPORT_SYMBOL
300303
void keyvalue_qsort_float_uint32(float *key, uint32_t *val, size_t size)
301304
{
@@ -336,4 +339,12 @@ void keyvalue_qsort_uint32_uint64(uint32_t *key, uint64_t *val, size_t size)
336339
{
337340
x86simdsort::keyvalue_qsort(key, val, size, true);
338341
}
339-
}
342+
343+
#else // C_API_ONLY is defined
344+
345+
#define XSS_EXPORTING
346+
#include "c-api-export.h"
347+
348+
#endif // C_API_ONLY
349+
350+
} // extern "C"

0 commit comments

Comments
 (0)