Czy powinienem dodać źródło bibliotek zamiast linkować do nich?

14

Jestem względnie nowy w C ++, więc nie jestem pewien, jak najlepiej radzić sobie z małymi zależnościami (np. Język skryptowy lub parser JSON / YAML / XML).

Czy powinienem tworzyć osobne projekty i łączyć je jako bibliotekę statyczną, czy też są wady samego umieszczania plików .h / .cpp w moim głównym projekcie?

To drugie wydaje się o wiele łatwiejsze, ponieważ spędziłem kilka godzin na radzeniu sobie z niekompatybilnymi bibliotekami (inne ustawienia kompilatora podczas budowania biblioteki), ale nie chcę zaczynać nauki C ++ w niewłaściwy sposób.

Jeśli lepiej jest przechowywać je jako osobne biblioteki, to jak najlepiej synchronizować flagi kompilacji, aby pliki .lib / .a z powodzeniem łączyły się z moją aplikacją?

(Obecnie pracuję z MSVC 2015, ale celem jest kompilacja w systemie Mac OS X i iOS przy użyciu XCode / clang, dzięki czemu mam do czynienia z co najmniej 3 różnymi typami bibliotek (Win x86, Mac x64, ARM) )

Michael Stum
źródło
5
Spójrz na ABIss, a oni popatrzą na ciebie
Basilevs
1
Należy pamiętać, że niektóre biblioteki są przeznaczone do wykorzystania w ten sposób. W SQLite biblioteki preferowanym Wykorzystanie wzór jest upuścić połączone źródła i plik nagłówka w drzewie źródłowym aplikacji C lub C ++ do skompilowany do pliku wykonywalnego.
Mark Benningfield,

Odpowiedzi:

6

TLDR;

Powinien pan dodać źródła? TAK
Czy X powinien dodać źródło? ZALEŻY

Oto dlaczego ...

Wcześniej czas kompilacji był problemem, który miały nawet mniejsze projekty. Kompilowanie źródeł i nigdy nie martwienie się o buforowanie wyników kompilatora było zdecydowanie dla niektórych atrakcyjne. To jeden punkt dla bibliotek, które są dla ciebie nieistotne.

Kolejnym ważnym jest wersjonowanie. Czy naprawdę potrzebujesz wersji każdej biblioteki osobno? Czy przeprowadzić testy na każdym z nich? Czy rozdzielić go wśród wielu członków zespołu? Biblioteki są świetne, jeśli tak, i wygodne do poruszania się, ale wydaje się, że nie przejmujesz się tym.

Ostatnim punktem jest to, że jest to dodatkowy narzut, a upuszczanie plików źródłowych jest łatwiejsze w twoim przypadku, co daje bardzo mocny punkt do upuszczania źródeł, zamiast korzystania z bibliotek. Jak zauważyłeś, po wprowadzeniu jednej zmiany ustawienia kompilatora, musisz przeszukać wszystkie zależności w inny sposób.

Wiem to wszystko z doświadczenia:

W przypadku projektów Swift zdecydowanie używam frameworków (bibliotek) i łączę się z nimi, ponieważ łatwo go skonfigurować za pomocą Xcode. Naprawdę potrzebuję też wersji, testów i odsprzęgania, więc dlatego.

W przypadku projektów Mono (C #), w przypadku Unity, zacząłem od modnego podejścia do podziału projektu na biblioteki, skompilowałem i przetestowałem każdy z nich, co było świetne ... ale kiedy upuściłem biblioteki do Unity, pojawiły się różnego rodzaju problemy , od zhakowanej wersji Mono Unity, po zwykłe czasami inne zachowanie, które kod wykazuje przy zmianie platformy. Brak jednego IDE do zarządzania wszystkimi bibliotekami był prawdziwym bólem, więc umieszczenie wszystkich źródeł w Unity było ogromną wygraną pod względem produktywności.

Wreszcie najbardziej odpowiedni dla ciebie projekt gry w C ++, nad którym pracowałem. Silnik gry, sieciowy klient czasu rzeczywistego, sieciowy klient HTTP, sztuczna inteligencja i sklep trwałości zostały napisane dla tej gry, po stronie klienta. Co wybrałem? CLion + Biblioteki. Mimo że korzystałem z bibliotek, nie czułem się tak, jakbym był. Wszystkie źródła były w projekcie CLion IDE, a komponując CMakeLists, byłem w stanie uruchomić wszystkie kompilacje i połączyć je jednym pociągnięciem.

Podsumowując , powiedziałbym, że używanie bibliotek jest rozwiązaniem przyszłościowym, ale także przedwczesną optymalizacją, jeśli nie jest potrzebna. O ile mogłem ustalić z twojej sytuacji, przejście z MSVC na Xcode będzie uciążliwe, jeśli będziesz miał wiele celów kompilacji. Więc po prostu go upuść i zachowaj jak największą izolację, kiedy może zajść potrzeba korzystania z bibliotek.

PS: Mam dzisiaj podobny dylemat z dokerem. Czy powinienem komponować? Czy powinienem po prostu uruchomić lokalnie? .. itp. Również Elixir, ponieważ umożliwia tworzenie aplikacji w ramach tej samej aplikacji .. Czy powinienem to zrobić? Lub oddzielić aplikację do tak zwanych mikrousług? ... itd. Nie ma srebrnej kuli, zawsze mierz siebie, jak YMMV.

Mazyod
źródło
2

Łączenie z bibliotekami C ++ wymaga wielu kłopotów i wymaga dużej wiedzy i wysiłku, aby zrobić to poprawnie. Może to być zastraszające dla osób uczących się w C ++.


Często autorzy / opiekunowie konkretnej biblioteki C ++ mają to na uwadze i zalecają tę lub inną metodę.

Innymi słowy, jeśli autorzy / opiekunowie zamierzają włączyć bibliotekę do nagłówków (tylko * .h i .hpp) lub do źródła ( .h * lub .c ), to tak jasno powiedzieliby w readme lub dokumentacja.


Biblioteki zaprojektowane i utrzymywane jako wieloplatformowe (i kompatybilne z wieloma dostawcami i środowiskami kompilatorów C ++) często będą miały system plików makefile lub system konfiguracji kompilacji (taki jak CMake). Systemy te są używane do generowania podkładek wyrównujących, które wyrównują różnice między platformami, oraz do generowania skryptów, które wywołują kompilator i linker w plikach źródłowych przy użyciu odpowiednich opcji wiersza polecenia i we właściwej kolejności. W zależności od platformy i konfiguracji, te systemy kompilacji mogą zawierać lub wykluczać niektóre nagłówki lub pliki źródłowe, lub mogą definiować lub niezdefiniować pewne symbole preprocesora.


Wbrew zaleceniom autorów / opiekunów jest możliwe, ale zawsze wymaga to dużego wysiłku w zakresie przenoszenia. Ilość pracy wymaganej do przeniesienia może być porównywalna z przeniesieniem do innego środowiska C ++.


Ponieważ Visual C ++ używa własnego systemu kompilacji opartego na pliku opisu projektu (częściowo opartego na XML), jest to zupełnie odmienne od systemu kompilacji opartego na skryptach używanego w systemie Linux. Podejście stosowane przez CMake polega na tym, że CMake przyjmuje ustawienia konfiguracji, a następnie emituje całą strukturę projektu Visual C ++, z opcjami konfiguracji zapisanymi w plikach * .vcxproj.

Jeśli pojawią się problemy podczas łączenia C ++ z Visual C ++, ustawienia kompilacji w plikach * .vcxproj można modyfikować za pomocą graficznego interfejsu użytkownika Visual Studio (używając okna dialogowego stron właściwości projektu). Zakłada się, że dokładnie rozumiesz znaczenie i konsekwencje kilkunastu ważnych ustawień kompilowania i łączenia w C ++.

Teraz jest najgłupsza część używania Visual C ++: jeśli używasz tuzina różnych bibliotek firm trzecich, zmiana ustawień kompilacji dla wszystkich z nich oznacza przejście do każdego pliku * .vcxproj i powtórzenie tej samej zmiany w GUI przez tuzin czasy. Kłopot, ale można to zrobić, jeśli wiesz, jak to zrobić poprawnie.

Większość osób uczących się języka Visual C ++ nauczy się tych ustawień w sposób trudny, obserwując błędy kompilatora i linkera Visual C ++, identyfikowane przez ich kod błędu. Na przykład, można spojrzeć w górę LNK2005, o powierzchownym znaczeniu „Symbol symbolu został zdefiniowany więcej niż raz”, ale rozumiejąc, że zduplikowana definicja nie wynika z nieostrożnego błędu programowania, zamiast tego mogła się zdarzyć z powodu niektórych konflikty lub błędne zastosowania opcji kompilacji i łączenia.


Aby udzielić bardziej szczegółowej i użytecznej odpowiedzi na swoją sytuację, musisz znać nazwy bibliotek, których zamierzasz używać, a także błędy w łączeniu lub inne napotkane trudności. Istniejące odpowiedzi na te pytania można znaleźć na forach dyskusyjnych odpowiednich bibliotek. Pytania te zazwyczaj są oznaczone „problemami z łączeniem”, „oknami” i „wizualnym C ++”.

Przewodnik dla początkujących i ekspertów na ten temat jest możliwy, ale będzie on specyficzny dla konkretnego projektu. Różne preferencje wybrane przez różne projekty będą wymagały pełnego przepisania przewodnika.

rwong
źródło
Jeśli używasz CMake do emitowania .vcxproj, zamiast modyfikować .vcxproj, możesz zmodyfikować konfigurację CMake
Caleth
1

Powiedziałbym tak, o ile jest to łatwiejsze. Istnieje wiele korzyści:

  1. Spowoduje to szybszy i lepszy kod, zwłaszcza jeśli włączysz Optymalizację czasu łącza.

  2. Twoje IDE polubi go bardziej, np. Pozwoli (skądś) przejść do implementacji (.cpp) kodu biblioteki, a nie tylko interfejsu (.h), co jest niezwykle przydatne podczas pracy ze źle udokumentowanym kodem (tj. większość kodu).

  3. Często pozwala ci dodać zależność jako podmoduł git, co jest nieco zuchwałym, ale w rzeczywistości całkiem dobrym sposobem na posiadanie zależności (w każdym razie w C ++, w którym praktycznie nie ma rozsądnych systemów kompilacji). Ułatwia to aktualizację biblioteki i testowanie różnych wersji.

  4. Nie musisz się martwić kompilacją zależności z MSVC ++ 2013, podczas gdy na przykład używasz 2017. Lub wspólny vs statyczny MSVCRT.

  5. Możesz łatwo zbudować w trybie debugowania i wejść do biblioteki.

Jedynym powodem, dla którego uważam, że nie chcesz tego robić, jest to, że biblioteka jest duża i ma złożony system kompilacji, którego nie chcesz replikować w swoim, np. Boost lub LLVM. Ale w przypadku prostych bibliotek tak naprawdę nie ma wad.

Jako przykład używam libusb w kilku projektach i muszę obsługiwać system Windows. libusb używa autotools, co jest żartem systemu kompilacji i tak naprawdę nie działa w systemie Windows. Zapewniają one wstępnie skompilowane pliki binarne, ale są zbudowane z MSVC ++ 2013 i nie będą działać z 2017 r. Jak dotąd najłatwiejszym rozwiązaniem było dodanie wszystkich odpowiednich plików .c i .h do mojego projektu.

Timmmm
źródło
2
1) naprawdę? Biblioteka statyczna to tylko zbiór plików obiektowych, tak jakbyś właśnie je skompilował.
Baldrickk
Możesz utworzyć archiwum .oplików, które zostały skompilowane, -fltoale tak naprawdę nie są to biblioteki statyczne - dla Clanga są to pliki kodów bitowych LLVM. I oczywiście nie zadziała, jeśli użyjesz bibliotek statycznych udostępnianych przez kogoś innego.
Timmmm
ok, ulepszmy tę dyskusję - nie mogę się doczekać, aby dowiedzieć się czegoś więcej :)
Baldrickk