לא רק GCC, או הניסיון הקצר עם קומפיילר של Intel.

ב־22.2.2009, מאת ארתיום; פורסם תחת: לינוקס, תכנה ומחשבים, C++‎‏; ‏0 תגובות

בד"כ אני לא נוהג לכתוב כאן הרבה על טכנולוגיות סגורות, במיוחד לכתוב דברים טובים. אבל הפעם יהיה קצת שונה. אעשה סקירה קצרה של קומפיילר של אינטל.

רקע

אף אחד לא אוהב Vendor Lock In אפילו עם מדובר במשהו טוב כמו GCC או Linux. לכן, אני מוודא כי CppCMS ירוץ גם על BSD וגם על Solaris. אבל עם קומפיילר היו לי קצת יותר בעיות. יש מעט מאוד קומפיילרים טובים והנפוץ בין כולם הוא כמובן GCC.

הרבה זמן היו לי תהיות לגבי זה, אפילו ניסיתי להתקין SUN Studio על OpenSolaris ב־Virtual Box, אבל... בינתיים Solaris לא מתנהג יפה אפילו עם GCC.

אז בסופו של דבר אחרי הרבה ייסורים והתקלויות החלטתי לעשות בדיקה ל־icc. התהליך היה מייגע, אבל בסופו של דבר קיבלתי כמה דברים ממש נחמדים שאספר עליהם כאן.

התקנה

פה התהליך די מעצבן, כמו התקנה של כל תכנה קניינית:

  • הרשם לאתר, קבל רישיון
  • הורד קובץ בגודל של 1/2G
  • תתחיל התקנה, תסכים לרישיון, לעשה אימות.
  • תגלה של Pentium III כבר לא נתמך ע"י הגרסה האחרונה של קומפיילר.

הסבר, רציתי לעשות התקנה והפעלה על המחשב הנייד הישן שלי מתוצרת Interl במקום לעשות את זה של Amd64 החדש. אבל, התסבר שבגרסה האחרונה הם שדרגו את דרישות הסף והמחשב הישן והטוב שרץ על Pentium III כבר לא מספיק.

טוב, אז ניסיתי להתקין את הגרסה (של 32bit) על Debian 64. הכל עבד חלק עד שהוא התלונן על העדר ספריה libstdc++5. אבל היא ישנה? ‎/usr/lib32/libstdc++.so.5 נמצא! אחרי מלחמות, הורדתי גרסת 64 ביט של הקומפייר (עוד 1/2G ועוד שעה לחכות).

לאחר מכן ההתקנה הייתה סבירה... אם כי, אפשר היה לסדר לינקים סימבוליים באופן אוטומטי? למה אני צריך לשחק עם PATH?

ניסיון לקמפל "שלום עולם" נכשל!

Catastrophic error: could not set locale "" to allow processing of multibyte characters

לא מעודד... גיגול קצת גילה שיש מעקף פשוט לבעיה הוא export LANG=C.

אחרי שסגרתי את הפינה הזו... נגמרו פחות או יותר כל הבעיות.

בניית תכנה

תאימות ממשק ABI

אחת הבעיות הידועות של C++‎ זה העדר ממשק ABI מסודר ואחיד. זה אומר פחות או יותר, אם קמפלת ספריה עם מהדר א', זאת לא אומרת שתוכל להשתמש בה עם מהדר ב'.

פה החבר'ה של Intel הפריכו את הטענות. לא שיכולתי להשתמש בספריות קיימות כפישהן, אפילו ספריות מאוד מסובכות של boost עבדו באופן שקוף עם icpc. למעשה, לא היה שום צורך לבנות boost או cgicc מחדש! ה־ABI של icpc תואם gcc לגמרי!

למרות זאת, כניסיון בניתי את cgicc עם icpc ו־boost ולא היו שום בעיות --- קרי עבדתי גם עם ספריות המערכת שנבנו ע"י gcc וגם עם בנייה ייחודית עבור icpc.

תאימות ל־GCC.

אני חושב שזאת הייתה ההפתעה הגדולה ביותר שהייתה לי. לא הייתי צריך תקן שורה אחת בכל הקוד של CppCMS (ושל יישומים שלו) כדי להתאים אותו ל־icpc... זה פשוט עבד!

למעשה, היו לי הרבה יותר בעיות במעבר מ־gcc-4.1 ל־4.3 מאשר במעבר מ־g++‎ ל־icpc.

ייאמר לזכותם, הם עשו עבודה יפה. מצד שני, כנראה תאימות ל־gcc היא הייתה דרישה מאוד חזקה כדי שיתשמשו בו בלינוקס.

אזהרות קומפילצייה.

פה, הייתי קצת יותר זהיר. עבודה עם ‎-Wall גורמת לפליטה אינסופית של הערות. למשל הקוד התקין לחלוטין הבא

    list<int> l;
    l.push_back(10);

גורם להערות:

remark #383: value copied to temporary, reference to temporary used

שזה מיותר לחלוטין ומקשה על הפרדה בין עיקר לטפל.

תמיכה ב־C++0x

זאת אולי הנקודה המעניינת ביותר. אני אדגים שני דברים שהם הנחוצים ביותר בעיני ועדיין לא נמצאים ב־GCC.

תמיכה ב־auto

נגיד יש לנו אוסף:

multimap<int,string> values;

ועכשיו רוצים להדפיס את כל ערכים המשוייכים למפתח מסוים. איך עושים את זה היום?

typedef multimap<int,string>::iterator mm_iterator;
pair<mm_iterator,mm_iterator> range=values.equal_range(10);
for(mm_iterator p=range.first;p!=range.second;++p)
  cout<<p->second<<endl;

מייגע? עכשיו, כך אפשר לעשות ב־C++0x:

auto range=values.equal_range(10);
for(auto p=range.first;p!=range.second;++p)
  cout<<p->second<<endl;

הרבה יותר קצר ופשוט. שימוש ב־auto זאת אחת התכונות המבוקשות ביותר של C++0x. למעשה, יש כבר תמיכה בה ב־gcc-4.4 שעוד לא שוחרר לציבור הרחב. ב־icpc זה כבר קיים!

ביטויי למבדא

זאת אחת התכונות היפות של C++0x שכבר מזמן קיימת בשפות תכנות רבות. למה זה טוב? דוגמה פשוטה - Factory Design Pattern: כיצד עושים את זה היום:

נגיד יש לנו מחלקה base ו־derived שהבונה שלה מקבל איזשהו פרמטר. איך אפשר לבנות factory עבורו היום?

struct factory {
  int y;
  factory(int y_) : y(y_) {}
  base *operator()() { return new derived(y); }
};
...

int x=15;
function<base *()> f = factory(x);

למעשה אנחנו בונים מחלקה, שתשמור ערך התחלתי עבור אובייקטים שהיא תייצר. ואז אנחנו יכולים לתת אותה לפונקציה שמייצרת אובייקטים.

כיצד עושים את זה ב־C++0x?‏

int x=15;
function<base *()> f = [=]() { return new derived(x); };

אנחנו מייצרים פונקציית למבדא שמעתיקה של הערך של x (סימון [=]) ומייצר אובייקט חדש בקריאה.

הקוד מכיל שורה אחת במקום 6 שורות. הפונקיצה הזו קיימת כבר ב־icpc, אבל נמצאת רק בענף הפיתוח ב־gcc.

סיכום

הקומפיילר של אינטל הוא מאוד מעניין. אומנם הוא לא נטול בעיות, אבל הוא בהחלט נמצא בקדמת טכנולוגיית C++‎ שקיימת היום.

הוסף תגובה:

 
 כתובת דוא"ל לא תוצג
 

ניתן לכתוב תגובות עם שימוש בתחביר Markdown.

חובה לאפשר JavaScript כדי להגיב.

דפים

נושאים