Export symbols with dead code stripping enabled?

My App can load plugins (with dlopen). If i enable LTO and dead code stripping (default in Projucer) in Release build, it fails to open them. Interface required (exported symbols) is removed for the App binary. Of course, it works without those optimizations. Is it possible to get both (i.e. dead code optimizations AND force stubs to be generated)?

To clarify, what are you building with LTO and dead code stripping? Both host and plugins, or just one or the other? I’d be surprised if the problem is missing symbols in the host binary, it sounds more likely that the plugin entry point is missing. Have you tried checking the exported symbols in the plugin using e.g. dumpbin on Windows, or nm on macOS? Are you marking functions that are intended to be exported appropriately, e.g. with JUCE_API and JUCE_CALLTYPE?

To clarify, what are you building with LTO and dead code stripping?

It is the host only (my App is a fork of PureData).

it sounds more likely that the plugin entry point is missing.

Nope ; it seems OK (_hello_setup).

nicolasdanet@Air-de-Nicolas Objects % nm hello.pdobject
0000000000008030 d __dyld_private
0000000000003ef0 t _hello_bang
0000000000008038 b _hello_class
0000000000003f20 T _hello_destroy
0000000000003ed0 t _hello_new
0000000000003e60 T _hello_setup
U _spaghettis_classAddBang
U _spaghettis_classFree
U _spaghettis_classNew
U _spaghettis_objectNew
U _spaghettis_post
U _spaghettis_symbol
U dyld_stub_binder

With LTO and DCE host symbols below are not exported anymore.

000000010058a050 T _spaghettis_atomGetFloat
000000010058a070 T _spaghettis_atomGetFloatAtIndex
000000010058a0a0 T _spaghettis_atomGetSymbol
000000010058a0c0 T _spaghettis_atomGetSymbolAtIndex
000000010058a030 T _spaghettis_atomSetFloat
000000010058a020 T _spaghettis_atomSetSymbol
000000010058a010 T _spaghettis_atomsToString
0000000100588b70 T _spaghettis_bind
0000000100589b10 T _spaghettis_bufferAppend
0000000100589f30 T _spaghettis_bufferAppendComma
0000000100589c90 T _spaghettis_bufferAppendFloat
0000000100589e50 T _spaghettis_bufferAppendSemicolon
0000000100589d70 T _spaghettis_bufferAppendSymbol
0000000100589b00 T _spaghettis_bufferClear
0000000100589ad0 T _spaghettis_bufferFree
0000000100589ac0 T _spaghettis_bufferGetAtoms
0000000100589af0 T _spaghettis_bufferGetSize
0000000100589a70 T _spaghettis_bufferNew
0000000100588ad0 T _spaghettis_classAddAnything
0000000100588a90 T _spaghettis_classAddBang
0000000100588ae0 T _spaghettis_classAddDsp
0000000100588aa0 T _spaghettis_classAddFloat
0000000100588ac0 T _spaghettis_classAddList
0000000100588a80 T _spaghettis_classAddMethod
0000000100588a60 T _spaghettis_classAddMethodWithArguments
0000000100588ab0 T _spaghettis_classAddSymbol
0000000100588a40 T _spaghettis_classFree
0000000100588a00 T _spaghettis_classNew
0000000100588a10 T _spaghettis_classNewWithArguments
0000000100588b20 T _spaghettis_classRequirePending
0000000100588b00 T _spaghettis_classSetDataFunction
0000000100588b10 T _spaghettis_classSetDismissFunction
00000001005889f0 T _spaghettis_clockDelay
0000000100588920 T _spaghettis_clockFree
00000001005888d0 T _spaghettis_clockNew
0000000100588930 T _spaghettis_clockUnset
00000001005898e0 T _spaghettis_dspAdd1
0000000100589910 T _spaghettis_dspAdd2
0000000100589940 T _spaghettis_dspAdd3
0000000100589970 T _spaghettis_dspAdd4
00000001005899b0 T _spaghettis_dspAdd5
00000001005899f0 T _spaghettis_dspAdd6
0000000100588cf0 T _spaghettis_getRestoreSymbol
0000000100588c00 T _spaghettis_handleBang
0000000100588c10 T _spaghettis_handleFloat
0000000100588c30 T _spaghettis_handleList
0000000100588c60 T _spaghettis_handleMessage
0000000100588c20 T _spaghettis_handleSymbol
000000010058a0f0 T _spaghettis_initializerNew
0000000100588da0 T _spaghettis_memoryFree
0000000100588d10 T _spaghettis_memoryGet
0000000100588d40 T _spaghettis_memoryResize
0000000100588f70 T _spaghettis_objectCopySignalValues
0000000100588f50 T _spaghettis_objectDspNeedInitializer
0000000100588f90 T _spaghettis_objectFetchAndCopySignalValuesIfRequired
0000000100589010 T _spaghettis_objectFlagIsUndoOrEncaspulate
0000000100588e20 T _spaghettis_objectFree
0000000100588f00 T _spaghettis_objectGetNewSpace
0000000100588f80 T _spaghettis_objectGetSignalValues
0000000100588e30 T _spaghettis_objectGetTemporary
0000000100589020 T _spaghettis_objectInletNewFloat
00000001005891c0 T _spaghettis_objectInletNewSignal
00000001005890f0 T _spaghettis_objectInletNewSymbol
0000000100588db0 T _spaghettis_objectNew
0000000100589410 T _spaghettis_objectOutletNewAnything
0000000100589290 T _spaghettis_objectOutletNewBang
00000001005892f0 T _spaghettis_objectOutletNewFloat
00000001005893b0 T _spaghettis_objectOutletNewList
0000000100589470 T _spaghettis_objectOutletNewMixed
00000001005894d0 T _spaghettis_objectOutletNewSignal
0000000100589350 T _spaghettis_objectOutletNewSymbol
0000000100589820 T _spaghettis_outletAnything
0000000100589530 T _spaghettis_outletBang
00000001005895d0 T _spaghettis_outletFloat
0000000100589750 T _spaghettis_outletList
0000000100589690 T _spaghettis_outletSymbol
0000000100588b40 T _spaghettis_post
0000000100588b60 T _spaghettis_postError
0000000100588b50 T _spaghettis_postWarning
0000000100589a50 T _spaghettis_signalGetOverlap
0000000100589a30 T _spaghettis_signalGetSampleRate
0000000100589a60 T _spaghettis_signalGetVector
0000000100589a40 T _spaghettis_signalGetVectorSize
000000010058a150 T _spaghettis_spaceGetFloat0
000000010058a160 T _spaghettis_spaceGetFloat1
000000010058a170 T _spaghettis_spaceGetFloat2
000000010058a180 T _spaghettis_spaceGetFloat3
000000010058a190 T _spaghettis_spaceGetFloat4
000000010058a1a0 T _spaghettis_spaceGetFloat5
000000010058a1b0 T _spaghettis_spaceGetFloat6
000000010058a1c0 T _spaghettis_spaceGetFloat7
000000010058a1d0 T _spaghettis_spaceSetFloat0
000000010058a1e0 T _spaghettis_spaceSetFloat1
000000010058a1f0 T _spaghettis_spaceSetFloat2
000000010058a200 T _spaghettis_spaceSetFloat3
000000010058a210 T _spaghettis_spaceSetFloat4
000000010058a220 T _spaghettis_spaceSetFloat5
000000010058a230 T _spaghettis_spaceSetFloat6
000000010058a240 T _spaghettis_spaceSetFloat7
0000000100588c70 T _spaghettis_symbol
0000000100588c80 T _spaghettis_symbolGetName
0000000100588c90 T _spaghettis_symbolGetThing
0000000100588ca0 T _spaghettis_symbolHasThing
0000000100588b90 T _spaghettis_unbind

Results from nm with and without LTO/DCE.

Without.txt (2.9 MB)

With.txt (1.5 MB)

Interesting, perhaps you need to mark these functions as retained + used in order for them to be emitted in the final linked image:

https://clang.llvm.org/docs/AttributeReference.html#retain

https://clang.llvm.org/docs/AttributeReference.html#used

1 Like

For now i use a custom macro (compilable in pure C without JUCE).

#define PD_DLLattribute((visibility (“default”)))

I’ll make some test adding attributes suggested. Thanks.

Is the proper syntax is __attribute__((used)) and __attribute__((retain))or is there a more modern/portable one? I can not find any example using C++ [[ ]]syntax for instance. Probably [[gnu::used]] or [[gnu::retain]]?

You should be able to combine them both into a single attribute specifier sequence like [[gnu::used, gnu::retain]] or potentially even [[using gnu: used, retain]]

1 Like

I added __attribute__((used)) only (as retain is not supported on my old compiler).

Tada: it works! :partying_face:

Thanks.

1 Like