2010-05-11 18 views
13

Sto costruendo una libreria dinamica di Windows utilizzando la toolchain MinGW.Come dire al linker MinGW di non esportare tutti i simboli?

Per creare questa libreria sto collegando staticamente ad altri 2 che offrono un'API e ho un file .def in cui ho scritto l'unico simbolo che voglio esportare nella mia libreria.

Il problema è che GCC sta esportando tutti i simboli, compresi quelli delle librerie a cui sto collegando. C'è comunque da dire al linker solo per esportare i simboli nel file def?

So che c'è l'opzione --export-all-symbols ma non sembra esserci il contrario.

In questo momento l'ultima riga dello script di build ha questa struttura:

g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \ 
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup 

EDIT: Nel docs circa il linker si dice che --export-all-symbols è il comportamento predefinito e che è disattivata quando non si utilizza questa opzione esplicitamente se si fornisce un file def, tranne quando non lo fa; i simboli nelle librerie di terze parti vengono comunque esportati.

MODIFICA: l'aggiunta dell'opzione --exclude-libs LIBS o –exclude-symbols SYMBOLS non impedisce l'esportazione dei simboli dalle librerie.

risposta

1

È possibile utilizzare dllwrap se la distribuzione di binutils (nativa o incrociata) lo fornisce.

Può produrre DLL utilizzando l'interfaccia in un file DEF (sotto il cofano chiama gcc, ld e dlltool per farlo). La differenza tra l'utilizzo di questo e il passaggio diretto di un file DEF a GCC è che le definizioni nel file vengono trattate in modo diverso.

Ad esempio, se si dispone di un simbolo rinominare nel file di esportazione:

_SomeFuntion = [email protected] 

GCC creerà 2 esportazioni, uno con il nome di _SomeFunction e l'altra con il nome decorato mentre dllwrap sarà solo l'esportazione _SomeFuntion. Quindi se aggiungi al file DEF solo i simboli che vuoi esportare finirai solo con loro nella libreria.

dllwrap per impostazione predefinita utilizza il driver del compilatore C poiché non ha modo di sapere altrimenti.Poiché stai collegando il codice C++, devi utilizzare l'opzione --driver-name c++ per impostare il driver. Se ti capita di avere gli eseguibili MinGW con un prefisso devi includerlo anche nel nome del driver (ad esempio i686-mingw32-c++ anziché c++) e potresti dover utilizzare anche l'opzione --dlltool-name.

Provare a utilizzare queste due linee al posto di quello che hai postato:

g++ -c CXXFLAGS DEFINES INCLUDES -o library.o library.cpp 
dllwrap -o library.dll --driver-name c++ --def DEF_FILE OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup 

Il primo genera un file oggetto dal codice della library.cpp e la seconda assembla la libreria dinamica. La cosa OBJECT_FILES (che presumo essere altri file oggetto precedentemente generati) dovrebbe avere anche library.o.

Detto questo, devo dire che dllwrap era già deprecated nel 2006 e non c'è documentazione su di esso nel pacchetto ufficiale di binutils; per ottenere alcune informazioni puoi chiamarlo con il --help come al solito. Può generare una libreria di importazione nel caso ne abbiate bisogno.

+0

Grazie per la risposta! Funziona, a meno che i simboli non siano specificati nel file 'def' che non vengono esportati, anche quelli delle librerie. Userò dllwrap, sto usando binutils 2.20 e dllwrap è ancora lì, quindi forse è ancora mantenuto. Se è deprecato ... non dovrebbe esserci un modo per fare la stessa cosa usando solo gcc e cia? –

+0

@James il modo preferito è contrassegnare i simboli nel sorgente con 'dllexport/dllimport' e avere la visibilità dei simboli gestita in questo modo. – rubenvb

0

Disclaimer: io ho fatto solo questo su Linux, ma per quanto ne so dovrebbe funzionare su Windows così

È possibile utilizzare l'opzione -fvisibility=hidden; Per maggiori informazioni visita http://gcc.gnu.org/wiki/Visibility

+2

Temo che non aiuta in un ambiente Windows (almeno con il mio compilatore). Ricevo "attributo visibilità non supportato in questa configurazione, ignorati" avvisi anche in un test di prova, ma grazie comunque! –

1

hai letto questo nella pagina che hai fornito alink a, per quanto riguarda il comportamento se-tutti-i simboli --export non viene utilizzata in modo esplicito - esportazione automatica è disabilitata se:

Qualsiasi simbolo in qualsiasi file oggetto era contrassegnato con l'attributo __declspec (dllexport) .

Avete provato ad esportare esplicitamente solo le funzioni a cui siete interessati? È molto facile ottenere nomi errati nel file DEF, a causa della maneggevolezza, quindi questo metodo dovrebbe essere più affidabile.

+0

Ho contrassegnato in questo modo i simboli che voglio esportare, e lo sono, ma non posso accedere ai sorgenti delle librerie a cui sto collegando. Non posso togliere quel segno da lì. –

+0

@James Non puoi portare via le esportazioni una volta che è stato fatto, temo. –

+0

Aha, grazie allora, quindi i simboli esportati da altre librerie devono rimanere. –

1

È possibile utilizzare l'opzione -Wl,--retain-symbols-file=file e quindi elencare i simboli che si desidera conservare (uno per riga) in file. Questo farà sì che il linker scarti tutti gli altri simboli, mantenendo solo quelli che vuoi.

+0

Dove sono i documenti per --retain-symbols-file? – paulm

+0

@paulm: nel [docs per GNU ld] (https://sourceware.org/binutils/docs/ld/Options.html#Options) –

2

Questo è un problema ricorrente. Qui ci sono due questioni correlate a SO:

e all'esterno SO:

ovvero esportazione globale/locale sulla piattaforma Windows non gestita a livello di linker ma fornitura di un file .def che integra lo .dll.

In mancanza di una buona risposta, ho fatto uno script Python che si occupa di rimuovere elementi dalla tabella di esportazione DLL, è possibile trovarlo here.

3
Non

sicuro perché non c'è una risposta reale a questo, ma qui è quello che ha funzionato per me:

  1. Compilazione dei file oggetto:

    g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o 
    
  2. Linking (-Wl,--exclude-all-symbols è importante):

    g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll 
    
.210

poi si sceglie quali funzioni di esportare direttamente nel codice sorgente della DLL:

#include <windows.h> 

__declspec(dllexport) void someExportedFunction() { 
    MessageBox(NULL, "msgbox", "msgbox", MB_OK); 
} 

void nonExportedFunction() { 
    MessageBox(NULL, "notexported", "notexported", MB_OK); 
} 

di verifica:

C:\libtest>pedump -E somelib.dll 

=== EXPORTS === 

# module "somelib.dll" 
# flags=0x0 ts="2014-02-20 08:37:48" version=0.0 ord_base=1 
# nFuncs=1 nNames=1 

    ORD ENTRY_VA NAME 
    1  1570 _Z20someExportedFunctionv 

(pedump = http://pedump.me)

Problemi correlati