koffi 2.5.9 → 2.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/packaging.md +30 -19
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +125 -9
- package/src/core/libcc/libcc.hh +42 -16
- package/src/index.js +3 -3
- package/src/koffi/CMakeLists.txt +6 -2
- package/src/koffi/examples/electron-builder/README.md +0 -12
- package/src/koffi/examples/electron-builder/package.json +2 -2
- package/src/koffi/examples/electron-forge/package.json +2 -2
- package/src/koffi/examples/electron-forge/src/main.js +1 -1
- package/src/koffi/examples/node-esbuild/README.md +19 -0
- package/src/koffi/examples/node-esbuild/index.js +2 -0
- package/src/koffi/examples/node-esbuild/package.json +16 -0
- package/src/koffi/examples/nwjs/src/package.json +3 -2
- package/src/koffi/src/call.cc +16 -6
- package/src/koffi/src/ffi.cc +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
### Koffi 2.5
|
|
6
6
|
|
|
7
|
+
#### Koffi 2.5.11
|
|
8
|
+
|
|
9
|
+
- Support casting function pointers with [koffi.as()](parameters.md#input-polymorphism)
|
|
10
|
+
- Build in C++20 mode
|
|
11
|
+
|
|
12
|
+
#### Koffi 2.5.10
|
|
13
|
+
|
|
14
|
+
- Fix CMake regression when client has to build Koffi
|
|
15
|
+
|
|
7
16
|
#### Koffi 2.5.9
|
|
8
17
|
|
|
9
18
|
**Main changes:**
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/packaging.md
CHANGED
|
@@ -6,42 +6,43 @@
|
|
|
6
6
|
|
|
7
7
|
Koffi uses native modules to work. The NPM package contains binaries for various platforms and architectures, and the appropriate module is selected at runtime.
|
|
8
8
|
|
|
9
|
-
In theory, the bundlers should be able to find
|
|
9
|
+
In theory, the **packagers/bundlers should be able to find all native modules** because they are explictly listed in the Javascript file (as static strings) and package them somehow.
|
|
10
10
|
|
|
11
11
|
If that is not the case, you can manually arrange to copy the `node_modules/koffi/build/koffi` directory next to your bundled script.
|
|
12
12
|
|
|
13
13
|
Here is an example that would work:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
koffi/
|
|
17
|
+
win32_x64/
|
|
18
|
+
koffi.node
|
|
19
|
+
linux_x64/
|
|
20
|
+
koffi.node
|
|
21
|
+
...
|
|
22
|
+
MyBundle.js
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
When running in Electron, Koffi will also try to find the native module in `process.resourcesPath`. For an Electron app you could do something like this
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
locales/
|
|
29
|
+
resources/
|
|
30
|
+
koffi/
|
|
31
|
+
win32_ia32/
|
|
32
|
+
koffi.node
|
|
33
|
+
win32_x64/
|
|
34
|
+
koffi.node
|
|
35
|
+
...
|
|
36
|
+
MyApp.exe
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
## Packaging examples
|
|
39
40
|
|
|
40
41
|
### Electron with electron-builder
|
|
41
42
|
|
|
42
|
-
Packaging with electron-builder should work as-is
|
|
43
|
+
Packaging with electron-builder should work as-is.
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
Take a look at the full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/electron-builder).
|
|
45
46
|
|
|
46
47
|
### Electron Forge
|
|
47
48
|
|
|
@@ -51,10 +52,20 @@ Packaging with Electron Force should work as-is, even when using webpack as conf
|
|
|
51
52
|
npm init electron-app@latest my-app -- --template=webpack
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
Take a look at the full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/electron-forge).
|
|
55
56
|
|
|
56
57
|
### NW.js
|
|
57
58
|
|
|
58
59
|
Packagers such as nw-builder should work as-is.
|
|
59
60
|
|
|
60
61
|
You can find a full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/nwjs).
|
|
62
|
+
|
|
63
|
+
### Node.js and esbuild
|
|
64
|
+
|
|
65
|
+
You can easily tell esbuild to copy the native files with the copy loader and things should just work. Use something like:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
esbuild index.js --platform=node --bundle --loader:.node=copy --outdir=dist/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
You can find a full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/node-esbuild).
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -801,6 +801,108 @@ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags,
|
|
|
801
801
|
return false;
|
|
802
802
|
}
|
|
803
803
|
|
|
804
|
+
bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags, Span<const char> *out_remaining)
|
|
805
|
+
{
|
|
806
|
+
uint64_t size = 0;
|
|
807
|
+
|
|
808
|
+
if (!ParseInt(str, &size, flags & ~(int)ParseFlag::End, &str))
|
|
809
|
+
return false;
|
|
810
|
+
if (size > INT64_MAX) [[unlikely]]
|
|
811
|
+
goto overflow;
|
|
812
|
+
|
|
813
|
+
if (str.len) {
|
|
814
|
+
uint64_t multiplier = 1;
|
|
815
|
+
int next = 1;
|
|
816
|
+
|
|
817
|
+
switch (str[0]) {
|
|
818
|
+
case 'B': { multiplier = 1; } break;
|
|
819
|
+
case 'k': { multiplier = 1000; } break;
|
|
820
|
+
case 'M': { multiplier = 1000000; } break;
|
|
821
|
+
case 'G': { multiplier = 1000000000; } break;
|
|
822
|
+
case 'T': { multiplier = 1000000000000; } break;
|
|
823
|
+
default: { next = 0; } break;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if ((flags & (int)ParseFlag::End) && str.len > next) [[unlikely]] {
|
|
827
|
+
if (flags & (int)ParseFlag::Log) {
|
|
828
|
+
LogError("Unknown size unit '%1'", str[0]);
|
|
829
|
+
}
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
str = str.Take(next, str.len - next);
|
|
833
|
+
|
|
834
|
+
uint64_t total = size * multiplier;
|
|
835
|
+
if ((size && total / size != multiplier) || total > INT64_MAX) [[unlikely]]
|
|
836
|
+
goto overflow;
|
|
837
|
+
size = total;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
*out_size = (int64_t)size;
|
|
841
|
+
if (out_remaining) {
|
|
842
|
+
*out_remaining = str;
|
|
843
|
+
}
|
|
844
|
+
return true;
|
|
845
|
+
|
|
846
|
+
overflow:
|
|
847
|
+
if (flags & (int)ParseFlag::Log) {
|
|
848
|
+
LogError("Size value is too high");
|
|
849
|
+
}
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags, Span<const char> *out_remaining)
|
|
854
|
+
{
|
|
855
|
+
uint64_t duration = 0;
|
|
856
|
+
|
|
857
|
+
if (!ParseInt(str, &duration, flags & ~(int)ParseFlag::End, &str))
|
|
858
|
+
return false;
|
|
859
|
+
if (duration > INT64_MAX) [[unlikely]]
|
|
860
|
+
goto overflow;
|
|
861
|
+
|
|
862
|
+
if (str.len) {
|
|
863
|
+
uint64_t multiplier = 1;
|
|
864
|
+
int next = 1;
|
|
865
|
+
|
|
866
|
+
switch (str[0]) {
|
|
867
|
+
case 's': { multiplier = 1000; } break;
|
|
868
|
+
case 'm': { multiplier = 60000; } break;
|
|
869
|
+
case 'h': { multiplier = 3600000; } break;
|
|
870
|
+
case 'd': { multiplier = 86400000; } break;
|
|
871
|
+
default: { next = 0; } break;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if ((flags & (int)ParseFlag::End) && str.len > next) [[unlikely]] {
|
|
875
|
+
if (flags & (int)ParseFlag::Log) {
|
|
876
|
+
LogError("Unknown duration unit '%1'", str[0]);
|
|
877
|
+
}
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
str = str.Take(next, str.len - next);
|
|
881
|
+
|
|
882
|
+
uint64_t total = duration * multiplier;
|
|
883
|
+
if ((duration && total / duration != multiplier) || total > INT64_MAX) [[unlikely]]
|
|
884
|
+
goto overflow;
|
|
885
|
+
duration = total;
|
|
886
|
+
} else {
|
|
887
|
+
uint64_t total = duration * 1000;
|
|
888
|
+
if ((duration && total / duration != 1000) || total > INT64_MAX) [[unlikely]]
|
|
889
|
+
goto overflow;
|
|
890
|
+
duration = total;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
*out_duration = (int64_t)duration;
|
|
894
|
+
if (out_remaining) {
|
|
895
|
+
*out_remaining = str;
|
|
896
|
+
}
|
|
897
|
+
return true;
|
|
898
|
+
|
|
899
|
+
overflow:
|
|
900
|
+
if (flags & (int)ParseFlag::Log) {
|
|
901
|
+
LogError("Duration value is too high");
|
|
902
|
+
}
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
|
|
804
906
|
// ------------------------------------------------------------------------
|
|
805
907
|
// Format
|
|
806
908
|
// ------------------------------------------------------------------------
|
|
@@ -4832,7 +4934,8 @@ const char *GetTemporaryDirectory()
|
|
|
4832
4934
|
|
|
4833
4935
|
#endif
|
|
4834
4936
|
|
|
4835
|
-
const char *FindConfigFile(const char *
|
|
4937
|
+
const char *FindConfigFile(Span<const char *const> names, Allocator *alloc,
|
|
4938
|
+
LocalArray<const char *, 4> *out_possibilities)
|
|
4836
4939
|
{
|
|
4837
4940
|
decltype(GetUserConfigPath) *funcs[] = {
|
|
4838
4941
|
[](const char *name, Allocator *alloc) {
|
|
@@ -4850,16 +4953,19 @@ const char *FindConfigFile(const char *name, Allocator *alloc, LocalArray<const
|
|
|
4850
4953
|
const char *filename = nullptr;
|
|
4851
4954
|
|
|
4852
4955
|
for (const auto &func: funcs) {
|
|
4853
|
-
const char *
|
|
4956
|
+
for (const char *name: names) {
|
|
4957
|
+
const char *path = func(name, alloc);
|
|
4854
4958
|
|
|
4855
|
-
|
|
4856
|
-
|
|
4959
|
+
if (!path)
|
|
4960
|
+
continue;
|
|
4857
4961
|
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4962
|
+
if (TestFile(path, FileType::File)) {
|
|
4963
|
+
filename = path;
|
|
4964
|
+
}
|
|
4965
|
+
if (out_possibilities) {
|
|
4966
|
+
out_possibilities->Append(path);
|
|
4967
|
+
break;
|
|
4968
|
+
}
|
|
4863
4969
|
}
|
|
4864
4970
|
}
|
|
4865
4971
|
|
|
@@ -6756,6 +6862,16 @@ bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer)
|
|
|
6756
6862
|
return true;
|
|
6757
6863
|
}
|
|
6758
6864
|
|
|
6865
|
+
bool IsCompressorAvailable(CompressionType compression_type)
|
|
6866
|
+
{
|
|
6867
|
+
return CompressorFunctions[(int)compression_type];
|
|
6868
|
+
}
|
|
6869
|
+
|
|
6870
|
+
bool IsDecompressorAvailable(CompressionType compression_type)
|
|
6871
|
+
{
|
|
6872
|
+
return DecompressorFunctions[(int)compression_type];
|
|
6873
|
+
}
|
|
6874
|
+
|
|
6759
6875
|
// ------------------------------------------------------------------------
|
|
6760
6876
|
// INI
|
|
6761
6877
|
// ------------------------------------------------------------------------
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -3315,41 +3315,38 @@ static inline int CmpStr(const char *str1, Span<const char> str2)
|
|
|
3315
3315
|
static inline int CmpStr(const char *str1, const char *str2)
|
|
3316
3316
|
{ return strcmp(str1, str2); }
|
|
3317
3317
|
|
|
3318
|
-
static inline
|
|
3318
|
+
static inline bool StartsWith(Span<const char> str, Span<const char> prefix)
|
|
3319
3319
|
{
|
|
3320
3320
|
Size i = 0;
|
|
3321
3321
|
while (i < str.len && i < prefix.len) {
|
|
3322
3322
|
if (str[i] != prefix[i])
|
|
3323
|
-
return
|
|
3324
|
-
|
|
3323
|
+
return false;
|
|
3325
3324
|
i++;
|
|
3326
3325
|
}
|
|
3327
3326
|
|
|
3328
|
-
return (i == prefix.len)
|
|
3327
|
+
return (i == prefix.len);
|
|
3329
3328
|
}
|
|
3330
|
-
static inline
|
|
3329
|
+
static inline bool StartsWith(Span<const char> str, const char *prefix)
|
|
3331
3330
|
{
|
|
3332
3331
|
Size i = 0;
|
|
3333
3332
|
while (i < str.len && prefix[i]) {
|
|
3334
3333
|
if (str[i] != prefix[i])
|
|
3335
|
-
return
|
|
3336
|
-
|
|
3334
|
+
return false;
|
|
3337
3335
|
i++;
|
|
3338
3336
|
}
|
|
3339
3337
|
|
|
3340
|
-
return !prefix[i]
|
|
3338
|
+
return !prefix[i];
|
|
3341
3339
|
}
|
|
3342
|
-
static inline
|
|
3340
|
+
static inline bool StartsWith(const char *str, const char *prefix)
|
|
3343
3341
|
{
|
|
3344
3342
|
Size i = 0;
|
|
3345
3343
|
while (str[i] && prefix[i]) {
|
|
3346
3344
|
if (str[i] != prefix[i])
|
|
3347
|
-
return
|
|
3348
|
-
|
|
3345
|
+
return false;
|
|
3349
3346
|
i++;
|
|
3350
3347
|
}
|
|
3351
3348
|
|
|
3352
|
-
return !prefix[i]
|
|
3349
|
+
return !prefix[i];
|
|
3353
3350
|
}
|
|
3354
3351
|
|
|
3355
3352
|
static inline bool EndsWith(Span<const char> str, const char *suffix)
|
|
@@ -3703,6 +3700,31 @@ overflow:
|
|
|
3703
3700
|
bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
|
|
3704
3701
|
Span<const char> *out_remaining = nullptr);
|
|
3705
3702
|
|
|
3703
|
+
bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
|
|
3704
|
+
Span<const char> *out_remaining = nullptr);
|
|
3705
|
+
#if RG_SIZE_MAX < INT64_MAX
|
|
3706
|
+
static inline bool ParseSize(Span<const char> str, Size *out_size,
|
|
3707
|
+
unsigned int flags = RG_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
|
|
3708
|
+
{
|
|
3709
|
+
int64_t size = 0;
|
|
3710
|
+
if (!ParseSize(str, &size, flags, out_remaining))
|
|
3711
|
+
return false;
|
|
3712
|
+
|
|
3713
|
+
if (size > RG_SIZE_MAX) [[unlikely]] {
|
|
3714
|
+
if (flags & (int)ParseFlag::Log) {
|
|
3715
|
+
LogError("Size value is too high");
|
|
3716
|
+
}
|
|
3717
|
+
return false;
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
*out_size = (Size)size;
|
|
3721
|
+
return true;
|
|
3722
|
+
}
|
|
3723
|
+
#endif
|
|
3724
|
+
|
|
3725
|
+
bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
|
|
3726
|
+
Span<const char> *out_remaining = nullptr);
|
|
3727
|
+
|
|
3706
3728
|
static inline Size EncodeUtf8(int32_t c, char out_buf[4])
|
|
3707
3729
|
{
|
|
3708
3730
|
if (c < 0x80) {
|
|
@@ -4096,11 +4118,11 @@ bool NotifySystemd();
|
|
|
4096
4118
|
})()
|
|
4097
4119
|
#endif
|
|
4098
4120
|
|
|
4121
|
+
void InitRG();
|
|
4122
|
+
int Main(int argc, char **argv);
|
|
4123
|
+
|
|
4099
4124
|
static inline int RunApp(int argc, char **argv)
|
|
4100
4125
|
{
|
|
4101
|
-
void InitRG();
|
|
4102
|
-
int Main(int argc, char **argv);
|
|
4103
|
-
|
|
4104
4126
|
InitRG();
|
|
4105
4127
|
return Main(argc, argv);
|
|
4106
4128
|
}
|
|
@@ -4114,7 +4136,8 @@ const char *GetUserCachePath(const char *name, Allocator *alloc); // Can return
|
|
|
4114
4136
|
const char *GetSystemConfigPath(const char *name, Allocator *alloc);
|
|
4115
4137
|
const char *GetTemporaryDirectory();
|
|
4116
4138
|
|
|
4117
|
-
const char *FindConfigFile(const char *
|
|
4139
|
+
const char *FindConfigFile(Span<const char *const> names, Allocator *alloc,
|
|
4140
|
+
LocalArray<const char *, 4> *out_possibilities = nullptr);
|
|
4118
4141
|
|
|
4119
4142
|
const char *CreateUniqueFile(Span<const char> directory, const char *prefix, const char *extension,
|
|
4120
4143
|
Allocator *alloc, FILE **out_fp = nullptr);
|
|
@@ -4657,6 +4680,9 @@ public:
|
|
|
4657
4680
|
|
|
4658
4681
|
bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer);
|
|
4659
4682
|
|
|
4683
|
+
bool IsCompressorAvailable(CompressionType compression_type);
|
|
4684
|
+
bool IsDecompressorAvailable(CompressionType compression_type);
|
|
4685
|
+
|
|
4660
4686
|
// For convenience, don't close them
|
|
4661
4687
|
extern StreamReader stdin_st;
|
|
4662
4688
|
extern StreamWriter stdout_st;
|
package/src/index.js
CHANGED
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
|
|
22
22
|
'use strict';
|
|
23
23
|
|
|
24
|
-
const cnoke = require('./cnoke/src/index.js');
|
|
25
24
|
const util = require('util');
|
|
26
25
|
const fs = require('fs');
|
|
26
|
+
const { get_napi_version, determine_arch } = require('./cnoke/src/tools.js');
|
|
27
27
|
const pkg = require('../package.json');
|
|
28
28
|
|
|
29
29
|
if (process.versions.napi == null || process.versions.napi < pkg.cnoke.napi) {
|
|
30
30
|
let major = parseInt(process.versions.node, 10);
|
|
31
|
-
let required =
|
|
31
|
+
let required = get_napi_version(pkg.cnoke.napi, major);
|
|
32
32
|
|
|
33
33
|
if (required != null) {
|
|
34
34
|
throw new Error(`Project ${pkg.name} requires Node >= ${required} in the Node ${major}.x branch (N-API >= ${pkg.cnoke.napi})`);
|
|
@@ -37,7 +37,7 @@ if (process.versions.napi == null || process.versions.napi < pkg.cnoke.napi) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
let arch =
|
|
40
|
+
let arch = determine_arch();
|
|
41
41
|
let triplet = `${process.platform}_${arch}`;
|
|
42
42
|
|
|
43
43
|
let native = null;
|
package/src/koffi/CMakeLists.txt
CHANGED
|
@@ -28,7 +28,7 @@ include(CheckCXXCompilerFlag)
|
|
|
28
28
|
|
|
29
29
|
find_package(CNoke)
|
|
30
30
|
|
|
31
|
-
set(CMAKE_CXX_STANDARD
|
|
31
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
32
32
|
if(MSVC)
|
|
33
33
|
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
|
|
34
34
|
|
|
@@ -47,7 +47,11 @@ endif()
|
|
|
47
47
|
|
|
48
48
|
# ---- Koffi ----
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/package.json)
|
|
51
|
+
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/package.json PKG)
|
|
52
|
+
else()
|
|
53
|
+
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../../package.json PKG)
|
|
54
|
+
endif()
|
|
51
55
|
string(REGEX MATCH "\"version\": \"([^\"]+)\"" XX "${PKG}")
|
|
52
56
|
set(KOFFI_VERSION ${CMAKE_MATCH_1})
|
|
53
57
|
|
|
@@ -3,18 +3,6 @@ This is a simple example shows:
|
|
|
3
3
|
- How to communicate with Koffi from a renderer window
|
|
4
4
|
- How to use electron-builder with an application that uses Koffi
|
|
5
5
|
|
|
6
|
-
One of the important piece for the packaging is in `package.json`, specifically this part:
|
|
7
|
-
|
|
8
|
-
```json
|
|
9
|
-
"build": {
|
|
10
|
-
"extraResources": [
|
|
11
|
-
{ "from": "node_modules/koffi/build", "to": "koffi" }
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
This instructs electron-builder to copy the native koffi modules to a place where your application will find them.
|
|
17
|
-
|
|
18
6
|
Use the following commands to package the app for your system:
|
|
19
7
|
|
|
20
8
|
```sh
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "KoffiConfig",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Koffi Electron Example",
|
|
5
5
|
"main": "src/app.js",
|
|
@@ -16,6 +16,6 @@
|
|
|
16
16
|
"esbuild": "^0.18.17"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"koffi": "^2.5.
|
|
19
|
+
"koffi": "^2.5.9"
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "KoffiConfig",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Koffi Electron Example",
|
|
5
5
|
"main": ".webpack/main",
|
|
@@ -32,6 +32,6 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"electron-squirrel-startup": "^1.0.0",
|
|
35
|
-
"koffi": "^2.5.
|
|
35
|
+
"koffi": "^2.5.9"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -21,7 +21,7 @@ const createWindow = () => {
|
|
|
21
21
|
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
|
|
22
22
|
|
|
23
23
|
// Open the DevTools.
|
|
24
|
-
mainWindow.webContents.openDevTools();
|
|
24
|
+
// mainWindow.webContents.openDevTools();
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
// This method will be called when Electron has finished
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
This is a simple example to bundle a CLI node.js app that uses Koffi, using esbuild.
|
|
2
|
+
|
|
3
|
+
To run the app, execute the following:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
cd examples/node-esbuild
|
|
7
|
+
npm install
|
|
8
|
+
npm start
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
You can bundle the script and the native modules with the following command
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
cd examples/node-esbuild
|
|
15
|
+
npm install
|
|
16
|
+
npm run bundle
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Internally, this uses the esbuild copy loader to handle the native `.node` modules.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "KoffiConfig",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node index.js",
|
|
8
|
+
"bundle": "esbuild index.js --platform=node --bundle --loader:.node=copy --outdir=dist/"
|
|
9
|
+
},
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"esbuild": "^0.18.17",
|
|
14
|
+
"koffi": "^2.5.9"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -1043,12 +1043,6 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
|
|
|
1043
1043
|
out_kind = OutArgument::Kind::Buffer;
|
|
1044
1044
|
} else if (type->ref.type->primitive == PrimitiveKind::Record ||
|
|
1045
1045
|
type->ref.type->primitive == PrimitiveKind::Union) [[likely]] {
|
|
1046
|
-
if (!type->ref.type->size) [[unlikely]] {
|
|
1047
|
-
ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
|
|
1048
|
-
type->ref.type != instance->void_type ? "opaque" : "ambiguous", type->name);
|
|
1049
|
-
return false;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
1046
|
Napi::Object obj = value.As<Napi::Object>();
|
|
1053
1047
|
RG_ASSERT(IsObject(value));
|
|
1054
1048
|
|
|
@@ -1108,6 +1102,22 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
|
|
|
1108
1102
|
}
|
|
1109
1103
|
} break;
|
|
1110
1104
|
|
|
1105
|
+
case napi_function: {
|
|
1106
|
+
if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
|
|
1107
|
+
ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
1112
|
+
|
|
1113
|
+
void *ptr = ReserveTrampoline(type->ref.proto, func);
|
|
1114
|
+
if (!ptr) [[unlikely]]
|
|
1115
|
+
return false;
|
|
1116
|
+
|
|
1117
|
+
*out_ptr = (void *)ptr;
|
|
1118
|
+
return true;
|
|
1119
|
+
} break;
|
|
1120
|
+
|
|
1111
1121
|
case napi_number: {
|
|
1112
1122
|
Napi::Number number = value.As<Napi::Number>();
|
|
1113
1123
|
intptr_t ptr = (intptr_t)number.Int32Value();
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -1775,8 +1775,9 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
|
1775
1775
|
if (!type) [[unlikely]]
|
|
1776
1776
|
return env.Null();
|
|
1777
1777
|
if (type->primitive != PrimitiveKind::Pointer &&
|
|
1778
|
+
type->primitive != PrimitiveKind::Callback &&
|
|
1778
1779
|
type->primitive != PrimitiveKind::String &&
|
|
1779
|
-
type->primitive != PrimitiveKind::String16) {
|
|
1780
|
+
type->primitive != PrimitiveKind::String16) [[unlikely]] {
|
|
1780
1781
|
ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
|
|
1781
1782
|
return env.Null();
|
|
1782
1783
|
}
|