Portál AbcLinuxu, 30. dubna 2025 15:26
Do diplomky potřebuji trošku grafického uživatelského rozhraní. Budu tam mít taky nějaký legacy (češtináři prominou) kód v plain C. Své rozšíření budu psát v C++. Chci si to vyvíjet v Linuxu, ale musí to běžet i na Windows, protože s tím budou pracovat studenti a nemůžu nikoho diskriminovat.
Původně jsem to chtěl udělát v GTK, teď jsem ale objevil gtkmm, což není nic jiného, než tenký C++ wrapper nad plaincéčkovým GTK. Musím říct, že se mi to dost líbí, protože:
Takže jsem vzal nejjednodušší appku, co jde napsat a zkusil to přeložit pod Windows.
// Simple gtkmm app - simple.cpp #include <gtkmm.h> int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Gtk::Window window; Gtk::Main::run(window); return 0; }
Pak se to trochu podobalo hackování xchatu. Jen jsem musel kromě GTK nahodit ještě port gtkmm a všechny závislosti (gdk, pango, cairo, atk, ...), což je po rozbalení přes 7000 souborů a z disku to ukousne čtvrt giga. Výše uvedený zdroják se přeloží jednoduše
c:\dev-cpp\bin\g++ -o simple.exe simple.cpp -Ic:/gtk/include/gtk-2.0 -Ic:/gtk/lib/gtk-2.0/include -Ic:/gtk/include/atk-1.0 -Ic:/gtk/include/pango-1.0 -Ic:/gtk/include/glib-2.0 -Ic:/gtk/lib/glib-2.0/include -Lc:/gtk/lib -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lgdi32 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -liconv -mms-bitfields -mwindows -Ic:/gtk/include/gtkmm-2.4 -Ic:/gtk/include/gdkmm-2.4 -Ic:/gtk/include/glibmm-2.4 -Ic:/gtk/include/pangomm-1.4 -Ic:/gtk/include/atkmm-1.6 -Ic:/gtk/include/sigc++-2.0 -latkmm-1.6 -lgtkmm-2.4 -lglibmm-2.4 -latkmm-1.6 -lgdkmm-2.4 -lpangomm-1.4 -lsigc-2.0 -Ic:/gtk/lib/glibmm-2.4/include -Ic:/gtk/lib/sigc++-2.0/include -Ic:/gtk/lib/gdkmm-2.4/include -Ic:/gtk/lib/gtkmm-2.4/include -I/gtk/include/cairo
Z těch závislostí opravdu moc happy nejsem. V c:/GTK/bin
je 70 mega DLL-ek, asi nebudu potřebovat všechno, ale jen libgtkmm-2.4-1.dll
má 13 mega. Už se těším, až to budu instalovat svému vedoucímu
simple.exe
stačí "jenom" tyto knihovny.
iconv.dll
intl.dll
libatk-1.0-0.dll
libatkmm-1.6-1.dll
libcairo-2.dll
libfontconfig-1.dll
libfreetype-6.dll
libgdk-win32-2.0-0.dll
libgdkmm-2.4-1.dll
libgdk_pixbuf-2.0-0.dll
libglib-2.0-0.dll
libglibmm-2.4-1.dll
libgmodule-2.0-0.dll
libgobject-2.0-0.dll
libgtk-win32-2.0-0.dll
libgtkmm-2.4-1.dll
libpango-1.0-0.dll
libpangocairo-1.0-0.dll
libpangomm-1.4-1.dll
libpangowin32-1.0-0.dll
libpng13.dll
libsigc-2.0-0.dll
xmlparse.dll
xmltok.dll
zlib1.dll
Což je "jen" 30 mega, prohnáno RARem necelých 6. Takže to přežiju.
Tiskni
Sdílej:
-IC:\...
. open, creat, fopen, mkdir
a dalších, aby se snáze přenášely unixové programy. Ale WinAPI jsem nikdy do hloubky nezkoumal.
paskma@paskma:~/tmp/gladepok/two$ g++ simple.cpp -o simple `pkg-config gtkmm-2.4 --cflags --libs` --static
/usr/bin/ld: cannot find -lgtkmm-2.4
collect2: ld returned 1 exit status
Nevím, co je všechno v tvé windowsí instalaci Gtkmm, ale Gtk+ (bez devel) má cca těch 13 MB celé.Já mluvím o hotovém, slinkovaném EXE (pomocí VS.NET 2005).
A to, že Trolltech začal vyvíjet v programovacím jazyce C++ v době, kdy ten programovací jazyk ještě neměl žádný standard považuji za jeho blbost. Já bych to rozhodně u velkého projektu neudělal. Toť celé.
I C++ bez STL je pořád výkonnější, než plain C. Na 99% věcí stačí "C s třídami" - omezení viditelnosti, virtuální metody a sem tam jednoduchá dědičnost.
Tedy, abys mě netahal za slovíčka. Dobré kontejnery se hodí vždy, do je jasné. Ale i bez nich se to dá zkousnout, protože si je můžeš napsat. V C si je nenapíšeš, protože tam není zapouzdření.
První OO programovací jazyk s de jure standardem byla Ada95, to jen tak na okrajNe, to byl ANSI Common Lisp z roku 1994..
bcc
). Pokud k tomu dělal MS také lepší kód, byla asi spokojenost na místě.
GCC mi spadlo jenom jednou (3.4.0) u nějaké zprasené šablony.
(Ja snad jeste prestanu myslet na to, ze na me jde asi chripka. Tohle me zacina bavit a stejne nic lepsiho delat nemuzu.)
> [Vicemene nicnerikajici zblebt o C++ preprocesoru.]
...
> Opravdu si myslíte, že nelze naimplemetovat seznam properties bez standardních věcí C++? Já si to nemyslím.
No, tak tohle me presvedcilo, ted uz verim. Ne, moment, ja vlastne myslel spis "prijatelne jednoduse implementovat", ne jen "implementovat". Jako treba ze se nekam pripise jednoduchy radek, nebo tak neco.
> for_each se mě osobně velice líbí a nevím, co je na tom nepřehledného, nečitelného, komplikovaného, atd..
Kde zacit? Takze
- telo for_each je napsano nekde uplne jinde nez ten samotny for_each
- ten functor pro for_each je na nekolik radku, protoze to je struct, ktery obsahuje operator - viz. treba ten priklad z cppreference.com - pricitani jednicky na 5 radku???
- coz samo o sobe je odpoved na to, co je na tom komplikovaneho, necitelneho a narocneho
- pro cokoliv narocnejsiho clovek si bud ten functor pro for_each musi napsat sam, nebo musi pouzivat podivne konstrukce jako bind2nd
A nebo, proc rovnou ne priklad, nejake hypoteticke cokoliv, treba provedeni operace foo u vsech objektu, ktere ji potrebuji. V Qt pomoci foreach (nebo Q_FOREACH, jak kdo chce):
foreach( Object* object, objects ) if( object->needsFoo()) object->foo();Tak, ted STL, podle toho navodu na cppreference.com :
struct foo_if_needed : public unary_function<Object*, void> { void operator() (Object* object) { if( object->needsFoo()) object->foo(); } }; ... for_each( objects.begin(), objects.end(), foo_if_needed );
> A řešení, které je ve standardu C++ je zatím vždycky o několik tříd lepší > O tom jsem naprosto přesvědčen. Zatím vše, co je ve standardu C++, zejména kontejnery jsou podle mě daleko více na výši. Ale vzhledem k tomu, že jste nepodal žádný argument, nelze s Vámi o tom konstruktivně diskutovat.
(Mimochodem, dalsi hezky priklad toho, ze kdyby bylo nejhur, nekdo se tady vzdycky dokaze uzivit alespon v PR.)
Jako argument jsem uvedl treba to, ze Gtkmm pouziva vlastni tridu pro string, protoze tomu v STL (minimalne podle nich) chybi funcionalita. Schvalne jsem jenom citoval a schvalne jsem si vybral projekt, ktery je primo vysazeny na to, ze vsechno dela "spravne" podle C++. To, ze je tady nekdo ochotny se vsadit, ze to preci jen nekde v tom C++ je, je sice hezke, ale to je tak vsechno. Bud to tam tedy nekde je, ale Gtkmm vyvojari to tam, pres vsechnu jejich (docela bych hadal velkou) snahu nenasli a tak to asi nejde snadno najit, nebo to tam mozna je, ale nejde to v praxi vlastne snadno pouzit, no a nebo to tam neni. At uz je to jakkoliv, jestli si projekt jako Gtkmm nakonec udelal vlastni tridu pro string, neco s tou v C++ je spatne.
Pokud me moje vzpominky na hodiny matematiky a logiky ze skoly neklamou, na prokazani nepravdivosti tvrzeni "A řešení, které je ve standardu C++ je zatím vždycky o několik tříd lepší", tj. "plati pro vsechny", staci najit jeden priklad, kdy to neplati. Takze to bychom meli.
> No a co? Můžu Vám třeba prozradit sladké tajemství, že takové C++ třeba nepodporuje ani třeba octoniony, což je určitě hrozná vizitka pro standardní knihovnu C++.
Az to bude, treba jako v pripade utf8, na Linuxu pouzivat minimalne kazdy druhy, tak to tak nejspis bude.
> Mě by třeba zajímalo, kdy Qt knihovna opraví chybné zamykání objektů v mnoha třídách, zejména ve třídě QString. Když jsem se díval do zdrojáků Qt4, tak jsem zjistil, že pro multithredové programování to bude dělat bordel a Trolltech asi neumí programovat. Zajímavé je, že ve standardní knihovnách C++ je zamykání napsáno správně.
Jestli to nebude spis tak, ze nekdo asi neumi cist. V dokumetaci pro tridu QString je hned jako treti radek napsano, jak na tom QString ve vztahu k threadum je, dokonce tam je i link na podrobnejsi vysvetleni. Mozna bych mohl i vysvetlit, proc to je jak to je, ale neco mi rika, ze to uz mi za tu srandu nestoji. (Mimochodem, neda mi sem necitovat kousek shora: "Ale vzhledem k tomu, že jste nepodal žádný argument, nelze s Vámi o tom konstruktivně diskutovat.").
> Ale no tak. O tom Objective C to přímo píšou ve zdůvodnění, proč použili preprocessor. Najdete to přímo na webových stránkách Trolltechu.
Zase problem se ctenim. V tom dokumentu, proc pouzili moc (coz je ten dokument, ktery jsem drive linkoval), je slovo 'objective' jen dvakrat. V prvnim pripade se rika, ze staticke typy v C++ maji nektere nevyhody proti tomu vice dynamickemu systemu jako v Objective C. V druhem pripade se rika, ze moc dava Qt flexibilitu podobnou Objective C. Nikde se tam vubec nepise o tom, ze by TrollTech kdy premyslel o pouziti Objective C.
> Bohužel Trolltech by možná měl standard C++ trochu nastudovat, aby alespoň trochu zběžně poznal programovací jazyk, který používá.
No, ono ani ty "pseudoreseni", "zprzneni", "pokrytectvi" a podobne nenastavili latku nijak zvlast vysoko, ale tohle uz je dost ubohy. (Krom toho, spis to plati to lidi, kteri kritizuji neco, o cem vlastne nic nevi.)
moc
zpracuje hlavičkový soubor, který se pak spolu s výstupem z moc
a zdrojovým kódem, do nějž se vkládá, zpracuje dalším preprocesorem a překladačem.
a.cpp -> g++ -> a.o ---------- ^ | | v a.h -- #include ld ----> a.out | | ^ | v | -> moc -> a.moc.cpp -> g++ -> a.moc.o ---Tohle je normální použití moc. Zdrojový soubor se přeloží úplně normálně, bez jakéhokoliv preprocessingu. I a.h se použije úplně normálně, bez jakéhokoliv preprocessingu. Navíc se pomocí moc z a.h vygeneruje a.moc.cpp, který se normálně přeloží a slinkuje. Je tam naprosto evidentně vidět, že:
a.cpp -> g++ -> a.o ------ ld ----> a.out ^ ^ | | a.h -- #include ----- | | | | | v | -> moc -> a.moc -> #includeJe to optimalizace jen v tom, že se volá g++ jen jednou místo dvakrát, protože g++ je pomalé. Je to stejné, jako kdyby bylo a.cpp a b.cpp a místo překladu obou by a.cpp udělalo #include "b.cpp" a g++ by se volalo jen na a.cpp (a tím automaticky i na b.cpp). Nic to nemění na tom, že princip je ten obrázek nahoře a tam se moc jako preprocesor nechová. A kdyby ještě pořád s tím někdo měl náhodou problém, tak poradí Wikipedia: In computer science, a preprocessor is a program that takes source code and performs transformations on it, before the step of compilation or interpretation. Moc nedělá transformace a.h, a.h se používá přímo, bez moc. Stejně tak se a.cpp používá přímo, bez nějakého předchozího kroku.
for_each
hned na dva způsoby a ještě jednou totéž přímo přes itetátory:
#include <iostream> #include <vector> #include <cmath> using namespace std; template<typename T> void pohrajeme_si_s_vektorem_poprve(vector<T>& v) { for (typename vector<T>::iterator vi = v.begin(); vi != v.end(); vi++) { cout << "poprvé - " << *vi << endl; } } template<typename T> void vypis(T& t) { cout << "podruhé - " << t << endl; } template<typename T> void pohrajeme_si_s_vektorem_podruhe(vector<T>& v) { for_each(v.begin(), v.end(), vypis<T>); } template<typename T> class Cvypis { public: void operator()(T& t) { cout << "potřetí - " << t << endl; } }; template<typename T> void pohrajeme_si_s_vektorem_potreti(vector<T>& v) { for_each(v.begin(), v.end(), Cvypis<T>()); } int main() { vector<double> hodnoty; hodnoty.push_back(3); hodnoty.push_back(M_PI); hodnoty.push_back(exp(-1)); cout << "První cyklus..." << endl; pohrajeme_si_s_vektorem_poprve(hodnoty); cout << "Druhý cyklus..." << endl; pohrajeme_si_s_vektorem_podruhe(hodnoty); cout << "Třetí cyklus..." << endl; pohrajeme_si_s_vektorem_potreti(hodnoty); return 0; }
Bezdecne jste tu nadherne ilustroval, proc pouzivat bud standardni std::for_each, nebo lepe BOOST_FOREACH.
template<typename T> void pohrajeme_si_s_vektorem_poprve(vector<T>& v) { for (typename vector<T>::iterator vi = v.begin(); vi != v.end(); vi++) { cout << "poprvé - " << *vi << endl; } }
Ma byt ++vi
. (A to sou lidi schopni napsat daleko vetsi zverstva, jako vi < v.end()
)
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.