2012-01-31 19 views
23

Czytałem o propozycji modułów C++ (latest draft), ale nie do końca rozumiem, jaki problem (problemy) ma rozwiązać.Moduły C++ i C++ ABI

Czy jego celem jest umożliwienie użycia modułu zbudowanego przez jeden kompilator przez inny kompilator (oczywiście w tym samym systemie operacyjnym/architekturze)? To znaczy, czy wniosek równa się standaryzacji ABI w C++?

Jeśli nie, czy rozważa się inną propozycję, która standaryzuje ABI w C++ i umożliwi kompilatorom współdziałanie?

Odpowiedz

31

Wstępnie skompilowane nagłówki (PCH) to specjalne pliki, które niektóre kompilatory mogą generować dla pliku .cpp. To, czym one są, to: wstępnie skompilowany kod źródłowy. Są to kod źródłowy, który został załadowany przez kompilator i wbudowany w format zależny od kompilatora.

PCH są powszechnie używane do przyspieszenia kompilacji. Możesz umieścić powszechnie używane nagłówki w PCH, a następnie dołączyć PCH. Gdy wykonasz numer #include na PCH, Twój kompilator nie wykona zwykłej pracy z #include. Zamiast tego ładuje te wstępnie skompilowane symbole bezpośrednio do kompilatora. Bez uruchamiania preprocesora C++. Nie działa kompilator C++. Nie # z milionem różnych plików. Jeden plik jest ładowany, a symbole pojawiają się w pełni uformowane bezpośrednio w obszarze roboczym kompilatora.

Wspominam o tym wszystkim, ponieważ moduły są PCH w ich idealnym formularzu. PCH to w zasadzie gigantyczny hack zbudowany na systemie, który nie pozwala na faktyczne moduły. Celem modułów jest ostatecznie umożliwienie pobrania pliku, wygenerowanie pliku modułu specyficznego dla kompilatora, który zawiera symbole, a następnie kilka innych plików ładuje ten moduł w razie potrzeby. Symbole są wstępnie skompilowane, więc znowu nie ma potrzeby, aby # zawierać kilka rzeczy, uruchamiać kompilator, itp. Twój kod mówi, import thing.foo i pojawia się.

Zobacz wszystkie nagłówki standardowych bibliotek pochodnych STL. Weźmy na przykład <map>. Szanse są dobre, że ten plik jest albo gigantyczny, albo ma wiele #inclusions innych plików, które sprawiają, że wynikowy plik jest gigantyczny. To dużo analizowania w C++, które musi się wydarzyć. To musi się zdarzyć dla każdego pliku, który zawiera #include <map>. Za każdym razem, gdy kompilujesz plik źródłowy, kompilator musi przekompilować to samo. Koniec. I koniec. I znowu.

Czy <map> zmienia się między kompilacjami? Nie, ale twój kompilator nie może tego wiedzieć. Musi więc kontynuować rekompilację.Za każdym razem, gdy dotykasz pliku .cpp, musisz skompilować każdy nagłówek, który zawiera ten plik .cpp. Nawet jeśli nie dotknąłeś tych nagłówków ani plików źródłowych, które mają wpływ na te nagłówki.

Pliki PCH były sposobem na obejście tego problemu. Ale są ograniczone, bo to tylko hack. Możesz dołączyć tylko jeden plik .cpp, ponieważ musi to być pierwsza rzecz dołączona przez pliki .cpp. A ponieważ istnieje tylko jeden PCH, jeśli zrobisz coś, co zmienia PCH (jak dodaj do niego nowy nagłówek), musisz przekompilować wszystko, co w tym PCH.

Moduły zasadniczo nie mają nic wspólnego z kompilatorem krzyżowym ABI (chociaż jedno z nich byłoby miłe, a moduły uczyniłyby go nieco prostszym). Ich podstawowym celem jest przyspieszenie czasów kompilacji.

+1

Zasadniczy cel wykracza poza samo przyspieszenie czasu kompilacji .....: D –

10

Moduły to to, co oferuje Java, C# i wiele innych nowoczesnych języków. Znacznie skracają czas kompilacji po prostu dlatego, że kod, który znajduje się w nagłówku dzisiejszego, nie musi być przetwarzany w kółko za każdym razem, gdy jest dołączony. Gdy powiesz #include <vector>, zawartość <vector> zostanie skopiowana do bieżącego pliku. #include to naprawdę nic innego jak kopiowanie i wklejanie.

W świecie modułów po prostu mówimy na przykład import std.vector;, a kompilator ładuje tabelę zapytań/symboli tego modułu. Plik modułu ma format, który ułatwia analizowanie i używanie go przez kompilator. Jest również analizowany tylko po raz, kiedy moduł jest kompilowany. Następnie plik modułu generowany przez kompilator jest po prostu pytany o potrzebne informacje.

Ponieważ pliki modułu są kompilator generowane, zostaną one dość ściśle związane z wewnętrznej reprezentacji kompilatora kodu C++ (AST), a nie jako taki najprawdopodobniej przenośne (podobnie jak dzisiejsze .o/.so/.a plików , z powodu wymieszania nazw itp.).

7

Moduły w C++ muszą być przede wszystkim lepsze od dzisiejszych rozwiązań, to znaczy, gdy biblioteka składa się z pliku * .so i * .h z interfejsem API. Mają one na celu rozwiązanie problemów, które są dzisiaj z dyrektywami #INCLUDE, czyli:

  • wymagają macroguards (makra, które uniemożliwiają że definicje są wielokrotnie)
  • są ściśle oparty na tekście (a więc można je oszukać i w normalnych warunkach są one reinterpretowane, co daje również szansę spojrzenia inaczej w różnych jednostkach kompilacji, które mają być następnie połączone)
  • nie rozróżniają bibliotek zależnych tylko instrumentalnie używanych i pochodzących od (w szczególności, jeśli nagłówek zapewnia funkcję inline szablony)

Pomimo tego, co mówi Xeo, moduły nie istnieją w Javie lub C#. W rzeczywistości w tych językach "moduły ładujące" polegają na tym, że "ok, tutaj masz CLASSPATH i przeszukuj ją, aby znaleźć, co moduły mogą dostarczać symbole, które plik źródłowy faktycznie używa". Deklaracja "import" w Javie wcale nie jest "żądaniem modułu" - takim samym jak "używanie" w C++ ("import ns.ns2. *" W Javie jest taki sam jak "używanie przestrzeni nazw ns :: ns2" w C++) . Nie sądzę, aby takie rozwiązanie można było zastosować w C++. Najbliższe przybliżenie jakie mogę sobie wyobrazić to pakiety w Vala lub moduły w Tcl (te z wersji 8.5).

Wyobrażam sobie, że moduły C++ raczej nie mogą być wieloplatformowe, ani dynamicznie ładowane (wymaga dedykowanego modułu ładującego dynamiczne C++ - nie jest to niemożliwe, ale dziś trudne do zdefiniowania). Z pewnością zależą one od platformy i na żądanie powinny być konfigurowalne. Ale stabilny ABI ABI jest praktycznie wymagany tylko w zakresie jednego systemu, tak jak teraz jest z C++ ABI.