From 15b413f505565ef00c0138e88fd129a3cc6f3135 Mon Sep 17 00:00:00 2001 From: towneh <25694892+towneh@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:58:48 -0500 Subject: [PATCH 1/2] fix: add /WHOLEARCHIVE to Windows DLL link step so opus functions are exported Without /WHOLEARCHIVE, MSVC link does not export symbols from the static opus.lib into the DLL, resulting in a DLL with zero exports. Linux and macOS already used --whole-archive/-force_load equivalents. --- .github/workflows/OpusCompile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/OpusCompile.yml b/.github/workflows/OpusCompile.yml index 3a61fd1..75d16e4 100644 --- a/.github/workflows/OpusCompile.yml +++ b/.github/workflows/OpusCompile.yml @@ -214,7 +214,7 @@ jobs: if "${{ env.ARCH }}"=="Win32" (set "VCARCH=x86") else if "${{ env.ARCH }}"=="x64" (set "VCARCH=amd64") else if "${{ env.ARCH }}"=="ARM64" (set "VCARCH=amd64_arm64") else if "${{ env.ARCH }}"=="ARM" (set "VCARCH=amd64_arm") call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VCARCH% cl /O2 /MD /I..\opus\include /c ..\OpusSharp.Natives\opus_shim.c /Foopus_shim.obj - link /DLL /OUT:opus.dll opus_shim.obj Release\opus.lib ucrt.lib vcruntime.lib msvcrt.lib + link /DLL /OUT:opus.dll opus_shim.obj /WHOLEARCHIVE:Release\opus.lib ucrt.lib vcruntime.lib msvcrt.lib - name: Upload Artifact uses: actions/upload-artifact@v4 From 505b769a196d196123ce3cf92c8b823c80363d3e Mon Sep 17 00:00:00 2001 From: towneh <25694892+towneh@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:10:18 -0500 Subject: [PATCH 2/2] fix: export shim functions and opus symbols from Windows DLL MSVC link does not auto-export symbols from static libs into DLLs (unlike Linux --whole-archive / macOS -force_load). Two changes fix this: - Add SHIM_EXPORT (__declspec(dllexport) on Windows) to all opussharp_* functions in opus_shim.c so they are exported from the DLL. - Generate a .def file from dumpbin /symbols output in the CI Windows build step, listing all opus_* symbols from the static lib, so they are also exported. Replaces the non-functional /WHOLEARCHIVE flag. --- .github/workflows/OpusCompile.yml | 4 ++- OpusSharp.Natives/opus_shim.c | 46 +++++++++++++++++-------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/.github/workflows/OpusCompile.yml b/.github/workflows/OpusCompile.yml index 75d16e4..36b9d95 100644 --- a/.github/workflows/OpusCompile.yml +++ b/.github/workflows/OpusCompile.yml @@ -214,7 +214,9 @@ jobs: if "${{ env.ARCH }}"=="Win32" (set "VCARCH=x86") else if "${{ env.ARCH }}"=="x64" (set "VCARCH=amd64") else if "${{ env.ARCH }}"=="ARM64" (set "VCARCH=amd64_arm64") else if "${{ env.ARCH }}"=="ARM" (set "VCARCH=amd64_arm") call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VCARCH% cl /O2 /MD /I..\opus\include /c ..\OpusSharp.Natives\opus_shim.c /Foopus_shim.obj - link /DLL /OUT:opus.dll opus_shim.obj /WHOLEARCHIVE:Release\opus.lib ucrt.lib vcruntime.lib msvcrt.lib + dumpbin /symbols Release\opus.lib > opus_symbols.txt + powershell -NoProfile -Command "$s = (gc opus_symbols.txt) | Where-Object {$_ -match 'External\s+\|\s+(opus_\S+)'} | ForEach-Object { [regex]::Match($_, 'External\s+\|\s+(\S+)').Groups[1].Value -replace '^_','' } | Sort-Object -Unique; [IO.File]::WriteAllText('opus.def', \"EXPORTS`r`n\" + ($s -join \"`r`n\") + \"`r`n\")" + link /DLL /OUT:opus.dll /DEF:opus.def opus_shim.obj Release\opus.lib ucrt.lib vcruntime.lib msvcrt.lib - name: Upload Artifact uses: actions/upload-artifact@v4 diff --git a/OpusSharp.Natives/opus_shim.c b/OpusSharp.Natives/opus_shim.c index 34cd1b8..93c1e7f 100644 --- a/OpusSharp.Natives/opus_shim.c +++ b/OpusSharp.Natives/opus_shim.c @@ -18,112 +18,118 @@ #include #include +#ifdef _WIN32 +# define SHIM_EXPORT __declspec(dllexport) +#else +# define SHIM_EXPORT +#endif + /* === Encoder CTL === */ -int opussharp_encoder_ctl(OpusEncoder *st, int request) +SHIM_EXPORT SHIM_EXPORT int opussharp_encoder_ctl(OpusEncoder *st, int request) { return opus_encoder_ctl(st, request); } -int opussharp_encoder_ctl_i(OpusEncoder *st, int request, int value) +SHIM_EXPORT int opussharp_encoder_ctl_i(OpusEncoder *st, int request, int value) { return opus_encoder_ctl(st, request, value); } -int opussharp_encoder_ctl_p(OpusEncoder *st, int request, void *value) +SHIM_EXPORT int opussharp_encoder_ctl_p(OpusEncoder *st, int request, void *value) { return opus_encoder_ctl(st, request, value); } -int opussharp_encoder_ctl_pi(OpusEncoder *st, int request, void *data, int data2) +SHIM_EXPORT int opussharp_encoder_ctl_pi(OpusEncoder *st, int request, void *data, int data2) { return opus_encoder_ctl(st, request, data, data2); } -int opussharp_encoder_ctl_ip(OpusEncoder *st, int request, int data, void *data2) +SHIM_EXPORT int opussharp_encoder_ctl_ip(OpusEncoder *st, int request, int data, void *data2) { return opus_encoder_ctl(st, request, data, data2); } -int opussharp_encoder_ctl_pp(OpusEncoder *st, int request, void *data, void *data2) +SHIM_EXPORT int opussharp_encoder_ctl_pp(OpusEncoder *st, int request, void *data, void *data2) { return opus_encoder_ctl(st, request, data, data2); } /* === Decoder CTL === */ -int opussharp_decoder_ctl(OpusDecoder *st, int request) +SHIM_EXPORT int opussharp_decoder_ctl(OpusDecoder *st, int request) { return opus_decoder_ctl(st, request); } -int opussharp_decoder_ctl_i(OpusDecoder *st, int request, int value) +SHIM_EXPORT int opussharp_decoder_ctl_i(OpusDecoder *st, int request, int value) { return opus_decoder_ctl(st, request, value); } -int opussharp_decoder_ctl_p(OpusDecoder *st, int request, void *value) +SHIM_EXPORT int opussharp_decoder_ctl_p(OpusDecoder *st, int request, void *value) { return opus_decoder_ctl(st, request, value); } /* === DRED Decoder CTL === */ -int opussharp_dred_decoder_ctl(OpusDREDDecoder *dred_dec, int request) +SHIM_EXPORT int opussharp_dred_decoder_ctl(OpusDREDDecoder *dred_dec, int request) { return opus_dred_decoder_ctl(dred_dec, request); } -int opussharp_dred_decoder_ctl_p(OpusDREDDecoder *dred_dec, int request, void *value) +SHIM_EXPORT int opussharp_dred_decoder_ctl_p(OpusDREDDecoder *dred_dec, int request, void *value) { return opus_dred_decoder_ctl(dred_dec, request, value); } /* === Multistream Encoder CTL === */ -int opussharp_ms_encoder_ctl(OpusMSEncoder *st, int request) +SHIM_EXPORT int opussharp_ms_encoder_ctl(OpusMSEncoder *st, int request) { return opus_multistream_encoder_ctl(st, request); } -int opussharp_ms_encoder_ctl_i(OpusMSEncoder *st, int request, int value) +SHIM_EXPORT int opussharp_ms_encoder_ctl_i(OpusMSEncoder *st, int request, int value) { return opus_multistream_encoder_ctl(st, request, value); } -int opussharp_ms_encoder_ctl_p(OpusMSEncoder *st, int request, void *value) +SHIM_EXPORT int opussharp_ms_encoder_ctl_p(OpusMSEncoder *st, int request, void *value) { return opus_multistream_encoder_ctl(st, request, value); } -int opussharp_ms_encoder_ctl_pi(OpusMSEncoder *st, int request, void *data, int data2) +SHIM_EXPORT int opussharp_ms_encoder_ctl_pi(OpusMSEncoder *st, int request, void *data, int data2) { return opus_multistream_encoder_ctl(st, request, data, data2); } -int opussharp_ms_encoder_ctl_ip(OpusMSEncoder *st, int request, int data, void *data2) +SHIM_EXPORT int opussharp_ms_encoder_ctl_ip(OpusMSEncoder *st, int request, int data, void *data2) { return opus_multistream_encoder_ctl(st, request, data, data2); } -int opussharp_ms_encoder_ctl_pp(OpusMSEncoder *st, int request, void *data, void *data2) +SHIM_EXPORT int opussharp_ms_encoder_ctl_pp(OpusMSEncoder *st, int request, void *data, void *data2) { return opus_multistream_encoder_ctl(st, request, data, data2); } /* === Multistream Decoder CTL === */ -int opussharp_ms_decoder_ctl(OpusMSDecoder *st, int request) +SHIM_EXPORT int opussharp_ms_decoder_ctl(OpusMSDecoder *st, int request) { return opus_multistream_decoder_ctl(st, request); } -int opussharp_ms_decoder_ctl_i(OpusMSDecoder *st, int request, int value) +SHIM_EXPORT int opussharp_ms_decoder_ctl_i(OpusMSDecoder *st, int request, int value) { return opus_multistream_decoder_ctl(st, request, value); } -int opussharp_ms_decoder_ctl_p(OpusMSDecoder *st, int request, void *value) +SHIM_EXPORT int opussharp_ms_decoder_ctl_p(OpusMSDecoder *st, int request, void *value) { return opus_multistream_decoder_ctl(st, request, value); }