הבלוג של ארתיום
בלוג על לינוקס, תוכנה חופשית, מוזיקה, סלסה, ומה לא!
מאמרים בנושא C++.
שוחררה גרסת בטא ראשונה של CppCMS 1.x.x
בשעה טובה, אחרי כשנה של פיתוח שוחררה גרסת בטא חדשה של CppCMS (הורדה), מעבר לשינויים מעמיקים ושכתוב מחצית מהקוד שהוסיפו תכונות מתקדמות רבות כמו תמיכה מובנית ב־Comet, היא מביאה את CppCMS לשלב תפיסתי אחר - בשלות פיתוחית.
כשהפרויקט התחיל, היה קשה מאוד להרים משהו עובד מבלי להיעזר בכמות עצומה של ספריות צד ג' ולהתחשב בנזק התחזוקתי והתפיסתי הן יגרמו לי בהמשך. אבל בלעדיהן לא הייתי מצליח להרים פרויקט כפישהו היום. אחרי ניסיון שצברתי יכולתי לשכתוב חצי מהמערכת כדי להגיע למצב בו היא נמצאת היום.
אז היום, הייתי מגדיר את CppCMS 1.x.x כגרסת תיקון גדולה לכל הטעויות התכנוניות שעשיתי בגרסאות הראשונות של CppCMS ושיפורים מהותיים שיכלו להיכנס לעקבות התיקונים האלה.
- הכנסתי event-loop מרכזי שמנהל את כל המערכת ומאפשר הרצת יישומי comet אסינכרוניים. דבר שדרש ממני להפתר מספריות כמו libfcgi ו־cgicc (וטוב שכך).
- בניתי מערכת שיודעת לשמור על ABI יציב בין הגרסאות
- העפתי את Boost שהופך תחזוקת ABI לסיוט מתמשך
- הוספתי תמיכה טבעית בפלטפורמות רבות בפרט ב־Windows ובקומפיילר MSVC.
ועוד, ועוד ועוד: רשימת השינויים העיקריים.
במילים אחרות... זאת בהחלט הגרסה המשמעותית ביותר מאז הבטא הראשונה של הפרויקט שוחררה.
יש עוד דרך ארוכה לגרסה יציבה, אבל אני מקווה שלקראת סוף 2010 תחילת 2011 היא תשוחרר.
קישורים
- הורדה
- הוראות בניה
- רשימת התיעוד המלאה (התיעוד עדיין חלקי)
- תיעוד מפורט - Doxygen.
לשרוד פיתוח תואם "Windows" בעידן Unicode...
אם פיתחתם מעט עבור Windows אתם בוודאי מכירים את המושג שנקרא Wide-API. קרי לכל פונקציית המערכת יש שתי גרסאות: "ANSI" ו־"Wide", למשל: DeleteFileA ו־DeleteFileW, כאשר אחת מהן מקבלת char const *
והשניה wchar_t const *
.
נחמד לא? יש לך שני סוגי API שנוח לך, או לעבוד עם המחרוזות הפשוטות או לעבוד עם מחרוזות מבוססות "תווים־רחבים". אבל, לא בדיוק.
למעשה, לפי מדיניות של Microsoft, כדי לגשת לכל הכוח של מערכת ההפעלה אתה חייב להשתמש ב־Wide API אחרת... אתה אפילו לא תוכל ליצור קובץ "שלום.txt". נחמד, לא?
הבעיה שלא C99 ולא, C++, וגם לא C++0x לא מכירים במושג העמעום של wide-path ולמעשה, לפי התקן אין, דרך לפתוח קובץ שהשם לו הוא "שלום.txt" מקודד כמחרוזת של wchar_t
(רק char). כמובן חבר'ה ב־MS הם "ידידותיים" למפתחים והם הציע API חילופי: _wfopen(wchar_t const *,wchar_t const *);
וגם הוסיפו הרחבה לסטנדרט ב־Visual Studio: std::fstream::open(wchar_t const *,...);
הכל לטובת המפתח (הם כנראה לא שמעו בכלל על UTF-8)...
כאן, מתחיל הסיוט, למעשה למפתח יש שתי אופציות:
- להתעלם מהטמטום של Wide-API ולעבוד רק עם "ANSI-API" ו... התוכנה תפסיק לעבוד באופן אקראי על קבצים אקראיים, והמשתמשים המסכנים ישברו את הראש מה לא עובד.
- להתחיל לשכפל את כל הקוד שלך למקרה wide ולמקרה נורמלי.
סיוט. לא פלא, שרבים בורחים באופציה הראשונה, ולכן בשנת 2010, אנחנו נתקלים יישומים כמו Thunderbird, שלא עובד כשתיקיית המשתמש שלך בחלונות מכילה תוים עבריים.
כך גם, אני כשהתחלתי תמיכה בחלונות ב־CppCMS החלטתי להתעלם מהעובדה ש־fopen
או std::fstream::open
לא יעבדו לי. אבל בסוף ייסורי מצפון הזיזו את כף־המאזניים: מספיק לכתוב קוד גרוע... והכנתי ספריית עזר קטנה, קראתי לה booster::nowide. כל מה שהיא עושה זה: להעביר ל־namespace שלך את הכלים סטנדרטיים שקיימים ב־stdio וב־STL בכל מערכות ההפעלה נורמליות. ובחלונות, היא פשוט עוטפת אתה API _w*
עם פונקציות משלה שממירות UTF-8 ל־UTF-16 ואז קוראות לפונקציות המתאימות.
בנוסף יצרתי מחלקות תואמות ל־std::fstream שעובדות מעל stdio (ועל הדרך סוף־סוף הבנתי כיצד לממש streambuf משלך).
התוצאה? אם אתה מתכוון לתמוך בחלונו, במקום לכתוב
std::ofstream f("שלום.txt")
שמייצרת ג'יבריש במקרה הטוב אתה כותב:
booster::nowide::ofstream f("שלום.txt")
וזה עובד בצורה שקופה, כנ"ל, std::fopen, std::freopen, std::remove, std::rename - רק החלף std::
ב־booster::nowide::
.
במילים אחרות: no-more-wide-crap!
הספרייה היא חלק מ־booster של CppCMS ומופצת תחת רישיון Boost (משהו סגנון MIT). אם מישהו ירצה ספריה בלתי תלויה ב־booster, אז תגידו ואני אגזור אחת (לא מסובך בכלל).
קריאה נוספת: "Should UTF-16 be considered harmful?"
גרסת הספרית nowide התלויה בקומפיילר C++ לבלבד ניתנת להורדה כאן:
http://art-blog.no-ip.info/files/nowide.zip
Wikipp רץ על CppCMS 1.x.x !
בשעה טובה, המרתי את Wikipp לגרסת אלפה של CppCMS 1.x.x והיא רצה סוף־סוף ב"ייצור".
עוד שלב חשוב לשחרור גרסת בטא של CppCMS 1.x.x - שבו תוכננו מחדש ושוכתבתו מחצית מהרכיבים פנימיים שלו.
עדכנו אותי אם אתם נתקלים בבעיות.
ספריית Boost.Locale הוגשה לביקורת רשימית
בשעה טובה, הגשתי את הספריית לוקליזציה Boost.Locale לביקורת רשמית (formal review) של קהילת ה־Boost. אם היא תעבור אותה היא תתקבל כחלק רשמי של Boost.
קישורים:
אעדכן אתכם על התפתחויות בהמשך.
עדכון: זה רשמי -- Boost.Locale התווספה לרשימת הספריות הממתינות לביקורת. עכשיו צריך שמישהו מהקהילה יתנדב להיות מנהל הביקורת (review manager).
Boost חסרת תועלת למפתחי ספריות
Boost חסרת תועלת למפתחי הספריות, או ליתר דיוק מפתחי ספריות שמנסים לשמור על ABI יציב של הספריות שלהן. זהו שם הדיון שפתחתי ברשימת תפוצה של Boost שאני חושב שעוררה סערה קטנה בקרב המפתחים שלה. אני מאוד מקווה שזה יגרום לשינויים בתפיסה של Boost ובסופו של דבר יגרום ליצירת Boost-stable, או boost::abi.
רקע קצר: ספרית Boost היא אוסף ספריות C++ עשיר שנותן כלים מצוינים למפתחים. אפשר להשוואות אותה ל־JDK של Java שנותן לך כלים כמעט לכל דבר. בעיקר היא ממלא חורים רבים שחסרים בספרית C++ סטנדרטית: טבלאות hash, ביטויים רגולריים, מצביעים חכמים, תמיכה בחוטים (threads), ועוד ועוד ועוד.
למעשה החלקים הגדולים שלה כבר נמצאים בסטנדרט C++ הבא שישוחרר (בתקווה) בקרוב. למעשה, אם רוב הקומפיילרים היו תומכים ב־C++0x כבר לא הייתי זקוק למחצית הכלים שזמינים לי היום דרך Boost.
למעשה, Boost היא ספריה המנוהלת כמדיניות ע"י דחפים אבולוציוניים משפרת את התכנון שלה כל הזמן, אפיל רכיבים יסודיים ביותר כמו boost::shared_ptr
עוברים שיפורים משמעותיים. וכאן מתחילה בעיה:
- כל שלושה חודשים משוחררת גרסה חדשה של Boost.
- כל גרסה חדש אינה מבטיחה תאימות כלשהי הן של ABI ואפילו API.
בפועל זה גורם לכך ש:
- רוב החברות שעובדות עם Boost בד"כ תקועות עם גרסה מיושנות כי מפחדים לשדרג אותה
ישנים מקרים רבים של טעויות בהן שתי ספריות צד ג' בנויות עם גרסאות שונות של Boost פשוט קורסות ברגע שהן עבדות באותה יחידה (קובץ ריצה).
מה שבהחלט לא עוזר להטמעה של Boost לפרויקטים רבים, במיוחד ספריות, כי מטילות עליהן מגבלת תאימות גרסה קשות.
העליתי את זה (בפעם העשירית אולי) ברשימת התפוצה של Boost. אבל נראה לי הפעם זה יצר הד מסוים וגם נראה לי שקיר ה"אי־הבנה" התחיל להישבר, לפחות הרגשתי את זה ממספר מפתחי Boost מרכזיים.
כך או אחרת, בגלל הבעיות האלה וצרכים קיומיים של CppCMS:
- הסתרתי חלקי Boost שהייתי מוכרח להשתמש בהם תחת namespace חילופי.
- יצרתי ספריה חלופית Booster שבנויה עם API מאוד דומה ל־API של Boost אבל משתמשת ברכיבים אחרים: למשל, לתמיכה בביטויים רגולריים אני משתמש ב־PCRE ל־threadים אני משתמש ב־pthreads (גם בחלונות).
- חלקים קריטיים כמו
shared_ptr
פשוט לקחתי מ־Boost והתאמתי ליציבות בינארית. - חלקים שכתבתי כמו
booster::function
.
בגדול כל דבר שהייתי משתמש בו והייתי זקוק לו ב־API הכנסתי ל־Booster מ־Boost בצורה כזו או אחרת.
האמת? זאת הייתה החלט מאוד קשה ועצובה מבחינתי. כי ללא ספק Boost היא ספריה מצוינת, שאי אפשר בלעדיה ואני כל כך שונא "להמציא גלגל מחדש", מצד שני, Boost יכולה להפוך לסיוט בתנאים מסוימים ו־CppCMS זה בדיוק המקרה בו תלות ב־Boost היא סיוט מתמשך.
מי שמעוניין יכול לקחת Booster מ־svn כאן:
https://cppcms.svn.sourceforge.net/svnroot/cppcms/framework/branches/refactoring/booster
אבל תהיו מודעים לעובדה ש־Booster איננה Boost, והיא נבנתה לצורכי CppCMS בלבד.