c++ - source - vcpkg protobuf



Errori durante il collegamento a protobuf 3 su MS Visual C (1)

Incontrato su Visual Studio 2013 , ma è riproducibile con qualsiasi versione.

Ho clonato la libreria di buffer di protocollo da github, ho eseguito CMake-gui su di esso (ho lasciato tutto di default, quindi è la versione statica), ho creato solo libprotobuf (altri progetti falliti per qualche motivo, errore cmd.exe, potrebbero avere qualcosa da fare con i test, ma libprotobuf funziona bene).

Il mio progetto utilizza le intestazioni generate con il file .proto trovato nel github delle specifiche delle tessere vettoriali mapbox.

Quando collego, ho prima questo errore

Error 1 error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' s:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility

Ho provato a disabilitarlo con -D_SCL_SECURE_NO_WARNINGS in ulteriori argomenti della riga di comando, ma poi ho altri errori:

Error 1 error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' in main.obj S:\eiogit3\misc-projs\mapload\mapload\libprotobufd.lib(common.obj)


Non corrisponde a come la libreria di runtime VStudio C (e C ++) ( VCRTLib - controlla [SO]: come aggirare la dipendenza delle intestazioni CRT universali di Windows da vcruntime.h (la risposta di @ CristiFati) ) viene utilizzata dal progetto e dal progetto libprotobuf . Fammi un dettaglio:

Diciamo che c'è del codice C ( C ++ ). Lo scopo di quel codice è di essere eseguito. Di quanto si può ottenere:

  • Direttamente: incluso quel codice in un progetto di tipo VC Application - che genererà un .exe
  • Indirettamente: includendo il codice in un progetto di tipo VC Library - che genererà una libreria che sarà in grado di essere eseguita solo se chiamata da un altro .exe (che chiama quella libreria). La libreria può essere:
    • statico : tutto il codice C ( C ++ ) verrà compilato e memorizzato in un file .lib . Sarà necessario quel file quando si utilizza la libreria in un altro progetto (che si tratti di un'applicazione o di una libreria) - al momento del collegamento . Nota che tutto il codice necessario dal tuo .lib verrà "copiato" nell'altro progetto
    • dinamico : ora avrai 2 file: un file .dll che conterrà il codice compilato (e collegato) e un file .lib 1 che conterrà "puntatori" (se vuoi) al codice nel file .dll . Quando si utilizza la libreria in un altro progetto, sarà necessario anche il file .lib al momento del collegamento , ma ora non conterrà il codice, quindi non verrà copiato nell'altra libreria (l'altra libreria sarà più piccola), ma in fase di esecuzione l'altra libreria avrà bisogno del file .dll

È possibile controllare [SO]: Errore LNK2005 in Windows Form CLR (risposta di @ CristiFati) per i dettagli su come il codice C ( C ++ ) può essere trasformato in formato eseguibile. Inoltre, Google è piena di articoli sulle differenze tra librerie statiche e dinamiche, quando usare l'una o l'altra, un esempio può essere trovato su [SO]: Quando usare le librerie dinamiche o statiche .

Come hai indovinato, la libreria di runtime CRT o C (che contiene il sistema sottostante che rende il codice C in grado di funzionare - un esempio sono le funzioni di gestione della memoria: malloc , free ) non fa eccezione - è l'equivalente di libc.a di Nix ( statico o di archivio) vs. libc.so (oggetto dinamico o condiviso) - ma in VStudio è un po 'più complicato:

  • CRT statico risiede in libcmt.lib
  • CRT dinamico risiede in msvcrt.lib che "punta" a msvcr ###. Dll 2 ( msvcr120.dll per VStudio 2013 )

Note :

  • Una " d " alla fine del nome della libreria ( msvcr d .lib ) significa che è compilata con simboli di debug
  • La libreria di runtime C ++ è nella situazione esatta; i nomi hanno un extra p : libc p mt.lib , msvc p rt.lib , msvc p 120.dll
  • Per ulteriori dettagli, selezionare [MS.Docs]: Funzionalità della libreria CRT

Ora, le parti VCRTLib non sono incluse nel progetto come qualsiasi altra libreria ( Proprietà progetto -> Linker -> Input -> Dipendenze aggiuntive ), ma poiché la loro natura (statica o dinamica) è richiesta al momento della compilazione, sono configurate da: [ MS.Docs]: / MD, / MT, / LD (Usa libreria runtime) , dove sono disponibili 4 opzioni:

  1. Multi-thread ( / MT )
  2. Debug multi-thread ( / MTd )
  3. DLL multi-thread ( / MD )
  4. DLL di debug multi-thread ( / MDd )

Ovviamente, quelli che contengono "Debug" sono quando si costruisce per la configurazione di Debug mentre gli altri per Release ; il punto chiave è che quelli che hanno DLL stanno usando la versione di runtime dinamica , mentre gli altri la versione statica .

Torna al tuo errore : il linker lamenta che main.obj (parte del tuo progetto) ha MDd_DynamicDebug (collegamento contro la versione di debug dinamico ), mentre common.obj (parte del progetto libprotobuf ) ha MTd_StaticDebug (collegamento contro la versione di debug statico ), quindi ti colleghi contro 2 runtime nello stesso eseguibile (o .dll ) - il che non è possibile.

Per risolverlo, è necessario assicurarsi che libprotobuf e il progetto principale abbiano lo stesso valore per VCRTLib .
Ovviamente è più semplice modificare le impostazioni del progetto principale in modo che corrispondano a quelle di libprotobuf , ma si consiglia di utilizzare la versione di runtime dinamica (le cose possono diventare disordinate in progetti più grandi in cui sono coinvolti .dll ) anche se ciò richiede di ricompilare libprotobuf (bene , se la modifica di questa opzione genera errori che rendono molto difficile costruire libprotobuf e il tuo progetto rimarrà così semplice, puoi usare il VCRTLib statico).

Nota : per non confondere il tipo di VCRTLib (statico / dinamico) con il modo in cui viene costruito libprotobuf (statico a questo punto, ma sono sicuro che può essere costruito anche come dinamico).

@ EDIT0 :

Aggiunta di alcune informazioni aggiuntive sulla nota sopra, come richiesto da alcuni commenti, e potrebbe essere utile per altri utenti.

Ci sono 2 aspetti di una libreria (incluso libprotobuf ), che sono totalmente indipendenti :

  1. Tipo di libreria (il modo in cui viene costruita): dinamica / statica
  2. Tipo VCRTLib (il modo in cui utilizza VCRTLib ): di nuovo, dinamico / statico

Quindi, ci sono 4 combinazioni perfettamente valide:

  1. Libreria dinamica che utilizza VCRTLib dinamico
  2. Libreria dinamica che utilizza VCRTLib statico
  3. Libreria statica che utilizza VCRTLib dinamico
  4. Libreria statica che utilizza VCRTLib statico

Per libprotobuf , ciascuno degli aspetti è controllato da un'opzione booleana di cmake :

  1. Tipo di libreria: protobuf_BUILD_SHARED_LIBS
  2. Tipo VCRTLib : protobuf_MSVC_STATIC_RUNTIME

I 2 flag possono essere impostati tramite:

  • cmake-gui
  • cmake cmdline (passando come argomenti - ad es .: -Dprotobuf_BUILD_SHARED_LIBS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF )

Le suddette 4 combinazioni sono quindi possibili (almeno in v 3.5 ), ma # 2. è disabilitato di default (specificando -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_MSVC_STATIC_RUNTIME=ON costruirà un .dll che si collegherà al VCRTLib dinamico ), al fine di evitare possibili problemi di runtime e abilitandolo richiede un intervento manuale.

Per maggiori dettagli sulle istruzioni di compilazione (tramite cmake ), controllare: [GitHub]: protocolbuffers / protobuf - (master) protobuf / cmake / README.md .


1 : Il file .lib verrà creato solo se la libreria esporta simboli , altrimenti non avrebbe senso altrimenti (nulla di necessario al momento del collegamento e il file .dll verrà creato, ma praticamente inutilizzabile)

2 : Per le versioni più recenti di VStudio (a partire da v2015 ), la parte msvcr (t) è stata sostituita da vcruntime (o almeno questo è il punto di accesso, poiché è stato diviso in parti logiche più piccole (controllare l' URL all'inizio))





protocol-buffers