Konwersja C source do c++

Jak zrobiłbyś konwersję dość dużej (>300k), dość dojrzałej bazy kodu C na C++?

Rodzaj C, jaki mam na myśli, jest podzielony na pliki z grubsza odpowiadające modułom (tzn. mniej ziarniste niż typowy rozkład oparty na klasach OO), używając wewnętrznego powiązania zamiast prywatnych funkcji i danych oraz zewnętrznego powiązania dla publicznych funkcji i danych. Zmienne globalne są szeroko wykorzystywane do komunikacji między modułami. Istnieje bardzo obszerny test integracji pakiet dostępny, ale bez testów poziomu jednostki (tj. modułu).

Mam na myśli ogólną strategię:

  1. Skompiluj wszystko w podzbiorze C++i zacznij działać.
  2. Konwertuj Moduły na ogromne klasy, tak aby wszystkie odsyłacze były objęte nazwą klasy, ale pozostawiając wszystkie funkcje i dane jako statyczne elementy, i to działa.
  3. Konwertuj ogromne klasy na instancje z odpowiednimi konstruktorami i zainicjalizowanymi odsyłaczami; zamień statyczny element dostęp z dostępem pośrednim w zależności od potrzeb; i uzyskać, że działa.
  4. teraz podejdźcie do projektu jako źle rozwiniętej aplikacji OO i napiszcie testy jednostkowe, w których zależności są tractable, i rozkładajcie je na osobne klasy, gdzie ich nie ma; celem tutaj byłoby przejście z jednego programu roboczego do drugiego przy każdej transformacji.

Oczywiście, to byłoby sporo pracy. Czy istnieją jakieś studia przypadków / historie wojenne na ten rodzaj tłumaczenia? Alternatywa strategie? Inne przydatne rady?

Uwaga 1: program jest kompilatorem i prawdopodobnie miliony innych programów polegają na tym, że jego zachowanie się nie zmienia, więc hurtowe przepisywanie nie wchodzi w grę.

Uwaga 2: Źródło ma prawie 20 lat i ma być może 30% utraty kodu (linie zmodyfikowane + dodane / poprzednie linie ogółem) rocznie. Jest mocno utrzymany i rozbudowany, innymi słowy. Tak więc jednym z celów byłoby zwiększenie możliwości obsługi.

[Ze względu na pytanie, Załóżmy, że tłumaczenie do C++ jest obowiązkowe, a pozostawienie go w C jest , a nie opcją. Celem dodania tego warunku jest wyeliminowanie odpowiedzi "leave it in C".]

Author: Charles Stewart, 2008-10-14

11 answers

Po tym, jak kilka miesięcy temu zacząłem pracować nad tym samym projektem (w 10-letnim projekcie komercyjnym, pierwotnie napisanym z filozofią "C++ is nothing but C with smart struct s"), sugerowałbym użycie tej samej strategii, której używasz do zjedzenia słonia: weź go jeden kęs na raz. :-)

W miarę możliwości podziel go na etapy, które można wykonać przy minimalnym wpływie na inne części. Budowa systemu elewacyjnego, jak zasugerował Federico Ramponi, to dobry początek-raz wszystko ma fasadę C++ i komunikuje się przez nią, można zmienić wewnętrzne moduły z dużą pewnością, że nie mogą wpływać na nic poza nimi.

Mieliśmy już częściowy system interfejsu C++ (ze względu na wcześniejsze mniejsze wysiłki refaktoryzacji), więc takie podejście nie było trudne w naszym przypadku. Kiedyś mieliśmy wszystko komunikujące się jako obiekty C++ (co trwało kilka tygodni, pracując nad zupełnie oddzielną gałęzią kodu źródłowego i integrując wszystkie zmiany w główna gałąź, ponieważ zostały zatwierdzone), bardzo rzadko nie mogliśmy skompilować całkowicie działającej wersji przed wyjazdem na dzień.

Zmiana nie jest jeszcze zakończona -- zatrzymaliśmy się dwa razy na tymczasowe wydania( staramy się o wydanie punktowe co kilka tygodni), ale jest już na dobrej drodze i żaden klient nie skarżył się na żadne problemy. Nasi ludzie z QA znaleźli tylko jeden problem, który pamiętam. :-)

 15
Author: Head Geek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:00:01

A co z:

  1. Kompilowanie wszystkiego w C++'S C podzbiór I get that working, and
  2. implementacja zestawufasad pozostawiając kod C bez zmian?

Dlaczego "tłumaczenie na język C++ jest obowiązkowe"? Możesz owinąć kod C bez bólu przekształcania go w ogromne klasy i tak dalej.

 11
Author: Federico A. Ramponi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 01:06:06

Twoja aplikacja ma dużo ludzi pracujących nad nią, i trzeba nie-być-złamane. Jeśli poważnie myślisz o konwersji na dużą skalę do stylu OO, co potrzebujesz ogromnych narzędzi transformacji, aby zautomatyzować pracę.

Podstawową ideą jest wyznaczenie grup danych jako klas, a następnie Pobierz narzędzie do refaktoryzacji kodu, aby przenieść te dane do klas, przenoszenie funkcji na tych danych do tych klas, I zmienić wszystkie dostępy do tych danych, aby wywołać na zajęciach.

You can do zautomatyzowana preanaliza w celu utworzenia klastrów statystycznych, aby uzyskać kilka pomysłów, ale nadal będziesz potrzebować inżyniera applicaiton aware, aby zdecydować, co elementy danych powinny być grupowane.

Narzędziem, które jest w stanie wykonać to zadanie jest nasze Reengineering oprogramowania DMS Toolkit . DMS ma silne parsery C do odczytu kodu, przechwytuje kod C jako kompilator abstrakcyjnych drzew składni, (i w przeciwieństwie do konwencjonalnego kompilatora) może obliczać analizy przepływu w całym 300K SLOC. DMS ma c++ front end który może być używany jako "tył"; pisze się transformacje, które mapują składnię C do składni C++.

Główne zadanie reengineeringu C++ na dużym systemie awioniki daje jakiś pomysł na to, jak wygląda używanie DMS do tego rodzaju aktywności. Zobacz dokumenty techniczne na www.semdesigns.com/Products/DMS/DMSToolkit.html, w szczególności Re-engineering C++ Component Models Via Automatic Program Transformation

Ten proces nie jest dla osób o słabym sercu. Ale niż ktokolwiek inny to rozważyłoby ręczne refaktoryzacja dużego zastosowania już nie boi się ciężkiej pracy.

Tak, jestem związany z firmą, będąc jej głównym architektem.

 7
Author: Ira Baxter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-24 02:55:34

Pisałbym klasy C++ nad interfejsem C. Nie dotknięcie kodu C zmniejszy szansę na zepsucie i znacznie przyspieszy proces.

Po uruchomieniu interfejsu C++ jest to trywialne zadanie kopiowania + wklejania kodu do klas. Jak już wspomnieliście-na tym etapie niezbędne jest wykonanie testów jednostkowych.

 5
Author: nlaq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 00:54:57

GCC jest obecnie w połowie drogi do C++ z C. zaczęli od przeniesienia wszystkiego do wspólnego podzbioru C i C++, Oczywiście. Gdy to zrobili, dodali ostrzeżenia do GCC dla wszystkiego, co znaleźli, znalezionego pod -Wc++-compat. To powinno ci pomóc w pierwszej części podróży.

W przypadku tych ostatnich Części, kiedy już wszystko będzie kompilowane kompilatorem C++, skupię się na zastąpieniu rzeczy, które mają idiomatyczne odpowiedniki C++. Na przykład, jeśli używasz list, map, sets, bitvectors, hashtables, etc, które są definiowane za pomocą makr C, prawdopodobnie zyskasz dużo przenosząc je do C++. Podobnie jak w przypadku oo, prawdopodobnie znajdziesz korzyści tam, gdzie już używasz idiomu C OO (jak struct inheritence), i gdzie C++ zapewni większą przejrzystość i lepsze sprawdzanie typu kodu.

 4
Author: Paul Biggar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-29 15:06:47

Twoja lista wygląda w porządku, ale sugerowałbym najpierw przejrzenie pakietu testowego i spróbowanie uzyskać to tak mocno, jak to możliwe przed wykonaniem jakiegokolwiek kodowania.

 3
Author: Paul Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 01:19:39

Rzućmy kolejny głupi pomysł:

  1. Skompiluj wszystko w podzbiorze C++i zacznij działać.
  2. Zacznij od modułu, przekonwertuj go w ogromną klasę, A następnie w instancję i zbuduj interfejs C (identyczny z tym, od którego zacząłeś) z tej instancji. Pozwól pozostałemu kodowi C pracować z tym interfejsem C.
  3. Refaktor w razie potrzeby, rozwijając podsystem OO z kodu C po jednym module na raz, i upuszczając części interfejsu C, gdy staną się bezużyteczne.
 3
Author: Federico A. Ramponi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 02:50:51

Prawdopodobnie dwie rzeczy do rozważenia oprócz tego, jak chcesz zacząć, to to, co chcesz skupić i gdzie chcesz zatrzymać .

Twierdzisz, że istnieje duży kod, może to być klucz do skupienia twoich wysiłków. Sugeruję wybrać części kodu, w których wymagana jest duża konserwacja, Dojrzałe / stabilne części najwyraźniej działają wystarczająco dobrze, więc lepiej zostawić je tak, jak są, z wyjątkiem prawdopodobnie jakiegoś opatrunku okiennego z fasadami itd.

To, gdzie chcesz się zatrzymać, zależy od tego, jaki jest powód, dla którego chcesz przekonwertować do C++. To nie może być cel sam w sobie. Jeśli jest to spowodowane jakąś zależnością od strony trzeciej, skoncentruj swoje wysiłki na interfejsie do tego komponentu.

Oprogramowanie, nad którym pracuję, to ogromna, stara baza kodu ,która została' przekonwertowana ' z C na C++ lata temu. Myślę, że to dlatego, że GUI został przekonwertowany na Qt. Nawet teraz nadal wygląda jak program w C z klasami. Przełamanie zależności wywołanych przez publicznych członków danych i refaktoryzację ogromnych klas z proceduralnymi metodami potworów na mniejsze metody i klasy nigdy tak naprawdę nie wystartowały, myślę, że z następujących powodów:]}

  1. nie ma potrzeby zmiany kodu, który działa i nie wymaga ulepszania. W ten sposób wprowadza się nowe błędy bez dodawania funkcjonalności, a użytkownicy końcowi tego nie doceniają; {]}
  2. bardzo, bardzo trudno jest zrobić refaktor niezawodnie. Wiele fragmentów kodu jest tak dużych i tak ważnych że ludzie nie ośmielają się jej dotykać. Mamy dość obszerny zestaw testów funkcjonalnych, ale wystarczające informacje o zasięgu kodu są trudne do uzyskania. W rezultacie trudno jest ustalić, czy istnieją już wystarczające testy, aby wykryć problemy podczas refaktoryzacji.]} Zwrot z inwestycji jest trudny do ustalenia. Użytkownik końcowy nie skorzysta z refaktoryzacji, więc musi być w obniżonych kosztach utrzymania, które początkowo wzrosną, ponieważ poprzez refaktoryzację wprowadzasz nowe błędy w dojrzały, czyli dość wolny od błędów kod. Samo refaktoryzacja też będzie kosztowna ...

NB. Przypuszczam, że znasz książkę "Working effectively with Legacy code"?

 3
Author: andreas buykx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 07:42:42

Wspominasz, że Twoje narzędzie jest kompilatorem, i że: "właściwie dopasowanie wzorca, a nie tylko dopasowanie typu, w wielu wysyłkach byłoby jeszcze lepsze".

Możesz rzucić okiem na maketea . Zapewnia dopasowanie wzorców dla ASTs, a także definicję AST z gramatyki abstrakcyjnej, a także odwiedzających, tranformatorów itp.

 2
Author: Paul Biggar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-29 15:12:36

Jeśli masz mały lub akademicki projekt (powiedzmy, mniej niż 10 000 linii), przepisanie jest prawdopodobnie najlepszą opcją. Możesz to uwzględnić, jak chcesz, i nie zajmie to zbyt wiele czasu.

Jeśli masz aplikację w realnym świecie, sugerowałbym, aby skompilować ją jako C++ (co zwykle oznacza przede wszystkim naprawianie prototypów funkcji i tym podobne), a następnie popracować nad refaktoryzacją i owijaniem OO. Oczywiście nie zgadzam się z filozofią, że kod musi być oo skonstruowany, aby był akceptowalny kod C++. Zrobiłbym konwersję kawałek po kawałku, przepisanie i refaktoryzację, jak trzeba (dla funkcjonalności lub dla włączenia testów jednostkowych).

 1
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 01:01:18

Oto co bym zrobił:

  • ponieważ kod ma 20 lat, Usuń parser / analizator składni i zastąp go jednym z nowszych kodów C++ opartych na lex/yacc/bison(lub czymś podobnym) itp. Szybciej się rozwijać, jeśli masz BNF pod ręką.
  • po doposażeniu w stary kod, zacznij owijać Moduły w klasy. Zastąp zmienne globalne/współdzielone interfejsami.
  • Teraz to co masz będzie kompilatorem w C++ (nie do końca).
  • Narysuj diagram klas wszystkich klas w Twoim systemie i zobacz, jak się komunikują.
  • narysuj inną używając tych samych klas i zobacz, jak powinny się komunikować.
  • Przeformułuj kod, aby przekształcić pierwszy diagram na drugi. (to może być brudne i trudne)
  • pamiętaj, aby używać kodu C++ dla wszystkich nowych dodanych kodów.
  • Jeśli masz jeszcze trochę czasu, spróbuj zastąpić struktury danych jeden po drugim, aby użyć bardziej znormalizowanego STL lub Boost.
 1
Author: Sridhar Iyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 16:41:55