אנגליתצרפתיתספרדי

Ad


סמל OnWorks

makepp_cookbook - מקוון בענן

הפעל makepp_cookbook בספק אירוח חינמי של OnWorks על אובונטו אונליין, פדורה אונליין, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

זוהי הפקודה makepp_cookbook שניתן להריץ בספק האירוח החינמי של OnWorks באמצעות אחת מתחנות העבודה המקוונות המרובות שלנו, כגון Ubuntu Online, Fedora Online, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

תָכְנִית:

שֵׁם


makepp_cookbook -- הדרך הטובה ביותר להגדיר קבצי makepp עבור מצבים שונים

תיאור


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

בִּניָן ספריות
Do אתה בֶּאֱמֶת צורך a סִפְרִיָה?

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

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

1. כאשר יש לך חבורה של תתי שגרות שצריכות להיות מקושרות לכמה שונות
תוכניות, ואף תוכנית לא משתמשת בפועל ב-100% מתתי-השגרה - כל תוכנית משתמשת ב-
תת-קבוצה שונה. במקרה זה, כנראה שזה רעיון טוב להשתמש בספרייה סטטית (א
.a קובץ, או קובץ ארכיון).

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

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

לשימוש בספריות סטטיות יש חיסרון עיקרי אחד: במערכות מסוימות (למשל לינוקס), הסדר
שבו אתה מקשר את הספריות חשוב מאוד. המקשר מעבד ספריות
בסדר המצוין בשורת הפקודה שלו. זה תופס את כל מה שהוא חושב שהוא צריך ממנו
כל ספרייה, ואז עוברת לספרייה הבאה. אם ספרייה שלאחר מכן מתייחסת לא
סמל שעדיין לא שולב מספרייה קודמת, המקשר לא
יודע לחזור ולתפוס אותו מהספרייה הקודמת. כתוצאה מכך, זה יכול להיות נחוץ
כדי לרשום את הספרייה מספר פעמים בשורת הפקודה המקשרת. (עבדתי על פרויקט
שבו היינו צריכים לחזור על כל רשימת הספריות שלוש פעמים. הפרויקט הזה הוא מה שיצר
אני מעדיף את הגישה החלופית המוצעת להלן, זו של קישור מצטבר.)

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

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

הנה איך אתה יכול לעשות זאת בלינוקס:

my_module.o : $(filter_out my_module.o, $(Wildcard *.o))
ld -r -o $(פלט) $(כניסות)

מה שזה יעשה זה ליצור אחר .o קובץ שנקרא my_module.o, שיורכב מ
כל .o קבצים בספריית המשנה הזו. המקשר יפתור כמה שיותר מה
הפניות ככל שניתן, וישאיר את שאר ההפניות להיפתר ב-a
השלב הבא של הקישור. ברמה העליונה, כאשר אתה סוף סוף בונה את התוכנית שלך,
במקום לקשר עם libmy_module.a or libmy_module.so, פשוט הייתם מקשרים אליו
my_module.o. כשאתה מקשר .o קבצים, אין לך בעיות עם תלות הזמנה ב-
שורת הפקודה מקשר.

מאפשרים makepp להבין הַחוּצָה אשר ספריה מודולים יש לו נחוץ

גם אם יש לך ספרייה אמיתית, שבה תוכנית מסוימת צריכה רק כמה קבצים ממנה
(במקום כל מודול בודד), ייתכן ש-makep יוכל להבין אילו מודולים הם
הדרושים מהספרייה וכוללים רק את אלה ב-build. זה יכול לחסוך קומפילציה
זמן אם אתה מפתח את הספרייה יחד עם תוכנית, כי אתה לא טורח
הידור מודולי ספרייה שאינם נחוצים עבור התוכנית הספציפית עליה אתה עובד.

אם הספרייה שלך מקפידה על האמנה שבה הצהירו כל הפונקציות או המחלקות
קובץ xyz.h מיושמים לחלוטין בקובץ מקור שמתחבר ל xyz.o (כלומר, אתה
אל תחלק את היישום ל xyz1.o ו xyz2.o), אז אתה יכול להשתמש ב-
פונקציית "$(infer_objects)" כדי לומר ל-makepp לשלוף רק את המודולים הרלוונטיים מה-
סִפְרִיָה. זה יכול לעבוד בצורה מפתיעה עבור ספריות עם אפילו עשרות קבצי כלול.
בעיקרון, "$(infer_objects)" בוחן את הרשימה של .h קבצים הכלולים, ומראה
להתכתבות .o קבצים. אם אתה מפתח במהירות ספרייה ותוכנית
יחד, זה יכול לחסוך זמן הידור, כי אתה אף פעם לא טורח להדר מודולים של
הספרייה שהתוכנית לא משתמשת בה.

הנה דוגמה לדרך שבה אני משתמש בו:

my_program: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(כניסות) -o $(פלט) $(SYSTEM_LIBRARIES)

הפונקציה "$(infer_objects )" מחזירה את הארגומנט הראשון שלה (לאחר ביצוע תו כללי
הרחבה עליו), וגם מעיין ברשימת הקבצים בארגומנט השני שלו, עבור
קבצים ששמם זהה לשם של כל אחד מהם .h קבצים הנכללים על ידי כל קובץ בראשון שלו
טַעֲנָה. אם נמצאו קבצים כאלה, הם מתווספים לרשימה.

בִּניָן a סטטי ספריה

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

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(פלט)
$(AR) cr $(פלט) $(כניסות)
ranlib $(פלט) # ייתכן שלא יהיה צורך, תלוי במערכת ההפעלה שלך.

ה-&rm היא פקודת "rm" המובנית של makepp. אם אתה רגיל לכתוב קבצי makefile, ייתכן שכן
קצת מופתע מהפקודה הזו; אולי אתה רגיל למשהו יותר כזה:

libmine.a: $(LIBRARY_FILES).o
$(AR) ru $@ $? # לא מומלץ!!!!!!!
ranlib $(פלט)

איפה $? (ידוע גם בשם "$(changed_inputs)") הוא משתנה אוטומטי שפירושו כל קבצים
שהשתנו מאז הפעם האחרונה שהספרייה נבנתה, ו-$@ זהה בערך
בתור "$(פלט)".

גישה זו אינה מומלצת מכמה סיבות:

· נניח שאתה מסיר קובץ מקור מהספרייה הנוכחית. זה עדיין ב-
הספרייה, כי לא בנית מחדש את הספרייה מאפס. כתוצאה מכך, כל דבר
שלקישורים עם ספרייה זו יהיה הישן .o קובץ, וזה יכול להרוס לך
בונה. (פעם התבלבלתי ביסודיות מזה כשניסיתי להסיר קוד מת
מפרויקט: המשכתי למחוק קבצים וזה עדיין מקושר, אז חשבתי שהקוד הוא
מֵת. עם זאת, כשמישהו אחר בנה מחדש את הפרויקט מאפס, זה לא קישר שום דבר
יותר! הבעיה הייתה שהישן .o קבצים עדיין היו בארכיון.)

כמו כן, בהתאם לאפשרויות שלך "ar" והטמעת "ar" (למשל, אם אתה
השתמש באפשרות "q" במקום "r"), אתה יכול בסופו של דבר לקבל כמה גרסאות של
אותו .o בתוך .a קוֹבֶץ. אם הגרסאות השונות מגדירות גלובלים שונים, ה
המקשר עשוי לנסות למשוך את שניהם. זה כנראה דבר רע.

זו הסיבה שאנו מסירים תחילה את קובץ הספרייה, ויוצרים אותו מאפס. זה יהיה
לוקח קצת יותר זמן מסתם עדכון מודולים בספרייה, אבל לא הרבה יותר זמן; עַל
מחשב מודרני, כמות הזמן הנצרכת על ידי ar התוכנית היא זעירה בהשוואה
למה שהקומפיילר C תופס במבנה טיפוסי, אז זה פשוט לא שווה לדאוג
על אודות.

· אחת הדרכים ש-makepp מנסה להבטיח בנייה נכונה היא כך
בנייה מחדש אוטומטית אם שורת הפקודה לבניית יעד נתון השתנתה. אבל
באמצעות ה-$? משתנה יכול לגרום לבעיות, מכיוון שבכל פעם שהספרייה מתעדכנת,
פקודת הבנייה שונה. (אתה יכול לדכא את זה באמצעות
":build_check ignore_action"; ראה makepp_build_check לפרטים.)

· עדכון הארכיון במקום בנייה מחדש יאפשר ל-makepp לעשות זאת
הכנס את הקובץ כראוי ל-build cache (ראה makepp_build_cache לפרטים).

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

libmine.a: $(only_targets *.o)
&rm $(פלט)
$(AR) cr $(פלט) $(כניסות)

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

הפונקציה "רק_מטרות" משמשת לאי הכללה .o קבצים שאין להם תואמים
עוד קבצי מקור. נניח שהיה לך קובץ שנקרא xyz.c שנהגת להכניס לתוך שלך
סִפְרִיָה. זה אומר שיש xyz.o קובץ שוכב. עכשיו אתה מוחק xyz.c
כי זה מיושן, אבל אתה שוכח למחוק xyz.o. ללא ה"רק_מטרות"
פוּנקצִיָה, xyz.o עדיין ייכלל ברשימה של .o קבצים הכלולים בספרייה.

בִּניָן a דינמי ספריה

תהליך בניית ספריות דינמיות תלוי לחלוטין במערכת. הייתי מאוד
ממליץ להשתמש ב-libtool כדי לבנות ספרייה דינמית (ראה
<http://www.gnu.org/software/libtool/>), אז אתה לא צריך להבין איך לעשות את זה על
הפלטפורמה שלך, וכדי שה-makefile שלך ​​ימשיך לעבוד גם כשאתה עובר ל-a
מערכת הפעלה שונה. עיין בתיעוד libtool לפרטים. הנה דוגמה של Makefile:

LIBTOOL := libtool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=קישור $(CC) $(כניסות) -o $(פלט)

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

בִּניָן on כמה אחר מכונות or רשתות
אחת הבעיות הכי מעצבנות עם קבצי makefile היא שהם כמעט אף פעם לא עובדים כשאתה
לעבור למכונה אחרת או לרשת אחרת. אם ה-makefiles שלך צריכים לעבוד
כל מכונה אפשרית על פני כדור הארץ, אז כנראה שאתה צריך איזושהי תצורה
תַסרִיט. אבל אם אתה צריך לעבוד רק על כמה מכונות שונות, יש כמה דרכים
אתה יכול לגשת לבעיה הזו:

השתמש a אחר לכלול פילה in את כל מה היא סביבות

בתחילת כל makefile, אתה יכול לכלול שורה כזו:

כולל system_defs.mk

הקובץ system_defs.mk בדרך כלל יהיה ממוקם במקום אחר עבור כל אחד
סביבה. אם אתה רוצה שספריות הבנייה שלך יהיו זהות בכל המכונות, שים
system_defs.mk בספרייה מעל ספריות ה-build, או לספק נתיב כולל
ל-makepp באמצעות אפשרות שורת הפקודה "-I".

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

השתמש if הצהרות

זו הדרך הכי מכוערת לעשות את זה, אבל זה בדרך כלל יעבוד.

ifsys i386
CC := gcc
אחרת ifsys sun4u
CC := cc
אחר ifsys hpux11
CC = c89
ח

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

find_program, first_available, מצא קובץ

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

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# בחר מהדר C++ הראשון שזמין ב-PATH.
# (אגב, אם אתה לא מגדיר CXX בכלל, זה
# הוא הדרך בה הוא מוגדר.)
TCL_INCLUDE ;= -I$(dir_noslash $(findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile) מחפש את tcl.h בכל אחד מהמצוינים
# ספריות ומחזיר את הנתיב המלא. זהו אז
# הומר לאפשרות קומפילציה על ידי הפשטת ה-
שם קובץ # (יציאה מהספרייה) וקידומת -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(קלט) -o $(פלט)

TCL_LIB ;= $((first_available
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# מצא היכן נמצאת ספריית Tcl. אז זה במפורש
# רשום בפקודת הקישור:
my_program : *.o
$(CXX) $(CXXFLAGS) $(כניסות) -o $(פלט) $(TCL_LIB)

לקחת יתרון of פרל config מידע

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

סקריפט התצורה האוטומטית של Perl הופך את כל מידע התצורה שלו לזמין דרך
הגיבוב של %Config. אין תחביר לגשת ל-hash של Perl ישירות ב-makepp, אבל אתה יכול
היכנס ל-Perl והגדר משתנים סקלרים, הנגישים ישירות מ-makepp:

perl_begin
# אחזר ערכים מתוך ה-hash של התצורה.
השתמש ב-Config;
$CC = $Config{'cc'}; # מהדר C ש-perl השתמש בו;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

כמו כן, לאחר שעשית את 'השתמש ב-Config', אתה יכול להשתמש בהצהרה "$(perl )", כמו
זֶה:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

הקלד "perldoc Config" כדי לראות איזה מידע זמין דרך ה-hash %Config.

התצורה של Perl היא מקום טוב לקבל דברים כמו מידע על סוגי מספרים שלמים, בתים
order, ודברים אחרים שבדרך כלל דורשים סקריפט תצורה נפרד לאיתור. חלק מ
ייתכן שהמידע שלו המתייחס לנוכחות של דברים במערכת הקבצים לא
תָקֵף. לדוגמה, $Config{'cc'} מתייחס למהדר C שאיתו perl נבנה,
שאולי אינו אותו מהדר C שאתה רוצה להשתמש בו. למעשה, ייתכן שהוא אפילו לא קיים
במערכת שלך, מכיוון שכנראה התקנת את Perl דרך חבילה בינארית.

טיפים ל באמצעות כתוביות בעברית
תואם את כל קבצים אלא a מסוים תת-קבוצה

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

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

libproduction.a: $(filter_out test*, $(wildcard *.o))

הפונקציות "$(filter )" ו-"$(filter_out )" הן קבוצה חזקה מאוד של מסננים לעשות
כל מיני פעולות צומת והבדל מוגדרות. לדוגמה,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(Shell find . -type d -print))
# מחזירה את כל ספריות המשנה שאין להן
# "מבחן" או $(ARCH) בהם.

$(filter $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(תו כללי *.o))
# מחזירה רשימה של קבצי .o בקובץ הנוכחי
ספרייה אחת שעבורה קיימת התאמה
# test_*.o קובץ בספריית המשנה test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(Wildcard man/man3/*.3)), \
$(תו כללי *.o))
# מחזירה רשימה של קבצי .o בקובץ הנוכחי
# ספרייה שאין לה דף ידני
# עם אותו שם קובץ בספריית המשנה man/man3.

שימוש מה היא "$(רק_מטרות )" פונקציה ל בוטל מעופש .o קבצים

נניח שאתה בונה תוכנית או ספריה עם פקודת build כמו זו:

תוכנית: *.o
$(CC) $(inputs) -o $(output)

נניח שאתה מוחק כעת קובץ מקור. אם תשכח למחוק את התואם .o קובץ,
הוא עדיין יהיה מקושר למרות שאין דרך לבנות אותו יותר. בתוך ה
בעתיד, makepp כנראה יזהה את המצב הזה באופן אוטומטי ותחריג אותו
את רשימת התווים הכלליים, אבל כרגע, אתה צריך לומר לה לא לכלול אותה באופן ידני:

תוכנית: $(only_targets *.o)
$(CC) $(inputs) -o $(outputs)

Makepp לא יודע שום דרך לבנות את הישן .o קובץ יותר מכיוון שקובץ המקור שלו הוא
נעלם, כך שהפונקציה "$(only_targets )" תוציא אותה מרשימת התלות.

טיפים ל מספר ספריות
אחת הסיבות העיקריות לכתיבת makepp הייתה לפשט את הטיפול בריבוי
ספריות. Makepp מסוגל לשלב פקודות בנייה ממספר קבצי makepp, כך שהיא יכולה
להתמודד כראוי עם כלל בקובץ makefile אחד שתלוי בקובץ אשר נבנה על ידי a
makefile שונה.

מה ל do in מקום of רקורסיבית לעשות

Makepp תומך ב-make רקורסיבי לתאימות לאחור, אבל זה מומלץ מאוד
שאתה לֹא תשתמש בזה. אם אתה לא יודע מה זה, טוב.

ראה "מערכת טובה יותר לבנייה היררכית" ב-makepp לפרטים מדוע אינך רוצה
השתמש ב-recursive make, או חפש באינטרנט "עשה רקורסיבי שנחשב כמזיק".

במקום לעשות יצירה רקורסיבית כדי להפוך את המטרה של "הכל" בכל קובץ makefile, זה כן
בדרך כלל קל יותר לתת ל-makepp להבין אילו מטרות באמת יצטרכו לבנות.
יתר על כן, אם תשים את כל שלך .o וקבצי ספרייה באותה ספרייה כמו ה-
makefiles, אז makepp יבין אוטומטית אילו קבצי makepp יש צורך גם--ה
הדבר היחיד שנדרש הוא להגדיר את הקבצים הדרושים ברמה העליונה שלך
לשלב הקישור האחרון. ראה את הדוגמאות למטה.

אחת קובץ מיידי ל כל אחד Directory: עם משתמע טוען

הדרך הנפוצה ביותר לטפל במספר ספריות היא לשים קובץ makefile בכל ספרייה
שמתאר כיצד לבנות הכל בספרייה או ממנה. אם תשים .o קבצים ב
אותה ספרייה כמו קבצי המקור, ולאחר מכן טעינה מרומזת (ראה "טעינה מרומזת" ב
makepp_build_algorithm) ימצא אוטומטית את כל קבצי המייקאפ. אם תשים את שלך .o
קבצים בספרייה אחרת (למשל, בספריית משנה תלויה בארכיטקטורה), ואז אתה
ככל הנראה יצטרך לטעון את כל ה-makefile הרלוונטיים באמצעות ההצהרה "load_makefile".

הנה דוגמה של קובץ makefile ברמה העליונה עבור היררכיית ספריות המשתמשת בטעינה מרומזת
לבנות תוכנית המורכבת מספריות משותפות רבות (אבל ראה "האם אתה באמת צריך א
ספריה?" ב-makepp_cookbook, כי יצירת תוכנית מתוך חבורה של ספריות משותפות
זה לא בהכרח רעיון טוב):

# Makefile ברמה העליונה:
תוכנית : main.o **/*.la # קישור בספריות משותפות מכל ספריות המשנה.
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) $(כניסות) -o $(פלט) $(LIBS)

זה פחות או יותר כל מה שאתה צריך בקובץ makefile ברמה העליונה. בכל ספריית משנה, אתה
כנראה יעשה משהו כזה:

# Makefile בכל ספריית משנה:
include standard_defs.mk # חיפושים ., .., ../ ..וכו' עד לזה
# מוצא את קובץ הכלול המצוין.
# תעקוף כמה הגדרות משתנים כאן
SPECIAL_FLAGS := -עשה_משהו_שונה

כל makefile יכול כנראה להיות די זהה אם הפקודות לבנות את המטרות
די דומים.

לבסוף, תכניס את הדברים הבאים לתוך standard_defs.mk קובץ (שכנראה צריך
להיות ממוקם בספרייה ברמה העליונה):

# הגדרות משתנים נפוצות וחוקי בנייה עבור כל הספריות.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards כולל)
# חיפושים ., .., ../ ..וכו' לקובץ או
ספרייה # שנקראת כוללת, אז אם אתה שם
# כל הקבצים כוללים שם, זה יעשה זאת
# מצא אותם.
כולל := -I$(INCLUDE_DIR)

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) -o $(פלט) $(כניסות)
# $(relative_to ., ..) מחזיר את השם של הנוכחי
# ספריית משנה ביחס לרמה העליונה
# ספריית משנה. אז אם ה-makefile הזה הוא xyz/Makefile,
# כלל זה יבנה את xyz/libxyz.la.

# פרסם קבצי include public לתוך ספריית include ברמה העליונה:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(קלט) $(פלט)

אחת קובץ מיידי ל כל אחד Directory: מפורש טוען

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

# Makefile ברמה העליונה:
MAKEFILES := $(Wildcard **/Makeppfile) # רשימה של כל ספריות המשנה אל
# קבל מאת קבצים.

load_makefile $(MAKEFILES) # טען את כולם פנימה.

include standard_defs.mk # קבל פקודת קומפיל עבור main.o.

תוכנית : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) $(כניסות) -o $(פלט) $(LIBS)
# */**/$(ARCH) אינו כולל את ספריית המשנה
# $(ARCH), שבו אנחנו לא רוצים לבנות
# ספרייה משותפת.

כל makefile יהיה בדיוק כמו קודם:

# Makefile בכל ספריית משנה:
כולל standard_defs.mk
# ... משתנים כאן

ולבסוף, standard_defs.mk יכיל משהו כמו הבא:

# הגדרות משתנים נפוצות וחוקי בנייה עבור כל הספריות.
ARCH ;= $(shell uname -s)-$(shell uname -m)-$(shell uname -r)
# לפעמים אנשים משתמשים רק ב-$(shell uname -m), אבל
# זה יהיה זהה עבור FreeBSD ו-Linux
# an x86. ה-r לא ממש שימושי בלינוקס,
# אבל חשוב עבור מערכות הפעלה אחרות: בינאריים עבור
# SunOS 5.8 בדרך כלל לא יפעל על SunOS 5.7.
&mkdir -p $(ARCH) # ודא שספריית הפלט קיימת.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards כולל)
# חיפושים ., .., ../ ..וכו' לקובץ או
ספרייה # שנקראת כוללת, אז אם אתה שם
# כל הקבצים כוללים שם, זה יעשה זאת
# מצא אותם.
כולל := -I$(INCLUDE_DIR)

$(ARCH)/%lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

$(ARCH)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) -o $(פלט) $(כניסות)
# $(relative_to ., ..) מחזיר את השם של הנוכחי
# ספריית משנה ביחס לרמה העליונה
# ספריית משנה. אז אם ה-makefile הזה הוא xyz/Makefile,
# כלל זה יבנה את xyz/$(ARCH)/libxyz.la.

# העתק קבצי include public לתוך ספריית include ברמה העליונה:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(קלט) $(פלט)

באופן אוטומטי ביצוע מה היא makefiles

אם קבצי ה-makefil שלך דומים מאוד (כמו בדוגמה לעיל), אתה יכול להגיד ל-Makepp
לבנות אותם באופן אוטומטי אם הם לא קיימים. פשוט הוסף את הדברים הבאים לרמה העליונה שלך
makefile:

SUBDIRS := $(filter_out unwanted_dir1 unwanted_dir2, $(wildcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "include standard_defs.mk" -o $(פלט)
&echo "_include additional_defs.mk" -o >>$(פלט)
# אם הקובץ additional_defs.mk קיים, אז
# זה ייכלל, אבל אם הוא לא קיים,
# תתעלם מהמשפט _include.

כעת ה-makefiles עצמם ייבנו באופן אוטומטי.

אחת קובץ מיידי רק at מה היא חלק עליון רָמָה

אם כל הקבצים שלך זהים, אתה יכול לשאול: למה אני צריך לעשות קובץ בכל אחד
רָמָה? למה לא להכניס את כל זה לקובץ המייקאפ ברמה העליונה?

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

הנה דוגמה לעשות בדיוק את זה:

# קובץ make-up ברמה העליונה להיררכיית ספריות. בונה את התוכנית
# מתוך קבוצה של ספריות משותפות כדוגמה. (ראה אזהרות למעלה
# מדוע אולי תרצה להשתמש בקישור מצטבר או בקישור אחר
# גישה במקום ספריות משותפות.)
makepp_percent_subdirs := 1 # אפשר % להתאים מספר ספריות.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CFLAGS := -g -O2
כולל:= -Iכולל

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(CFLAGS) -c $(input) -o $(output)

$(foreach)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) -o $(פלט) $(כניסות)
# כלל ליצור את כל הספריות.

תוכנית: main.o **/*.la
$(LIBTOOL) --mode=קישור $(CC) $(CFLAGS) -o $(פלט) $(כניסות)

כולל/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(קלט) $(פלט)
# כלל לדוגמה להעתקה פומבית
# קבצי .h נגישים למקום הנכון.

A לְנַקוֹת יעד

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

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

2. אנשים ינסו לפעמים לחסוך זמן על ידי עשיית שני דברים סותרים בבת אחת:
"לנקות הכל". זה יכול לבלבל את מערכת התווים הכלליים החכמה של makepp, כי זה יקרה
קודם כל קבל את העובדות לפני שאתה עושה משהו. ואז מגיעה הפעולה הנקייה, שעושה זאת
אל תספר למייקפ מה הוא עושה (אכן הוא לא יכול, כי הוא מבטל משהו -- ה
בניגוד למה שמיועד כלי בנייה). ואז מגיע "הכל", אבל הקבצים המעודכנים,
אשר היכן שם, נעלמו באופן מסתורי.

3. יש את הפקודה "makeppclean", שעושה את אותו הדבר, ויעילה יותר.

עם זאת, אנו שומרים על הקטע ההיסטורי הזה, מכיוון שהוא אומר לך משהו על
אופן פעולתו של makepp: יעד מזויף שנקרא "נקי" הוא רק שם לקבוצת פקודות
להסיר את כל הקבצים הנובעים מתהליך היצירה. בדרך כלל נראית מטרה נקייה
משהו כזה:

$(נקי מזויף):
&rm -fm $(Wildcard *.o .makepp_log)
# -m ו-.makepp_log מסירים את כל הזבל של makepp.

במקום לרשום במפורש את הקבצים שברצונך למחוק, אתה יכול גם לומר ל-makepp
הסר את כל מה שהוא יודע לבנות, ככה:

$(נקי מזויף):
&rm -fm .makepp_log $(only_targets *)

יש לזה יתרון שאם ניתן לבנות כל אחד מקבצי המקור שלך מקבצים אחרים,
גם הם יימחקו; מצד שני, מעופש .o קבצים (קבצים שהיו פעם
ניתן לבנייה אך שקובץ המקור שלו הוסר מאז) לא יימחק.

אם יש לך מבנה הכולל קבצי makefile בכמה ספריות שונות,
level makefile עשוי להתייחס ליעד ה"נקי" (או כל יעד מזויף אחר) בשדה אחר
makefile:

# קובץ makefile ברמה העליונה
SUBDIRS:= sub1 sub2

# בניית חוקים כאן

# ניקוי לאחר הבנייה:
$(נקי מזויף): $(SUBDIRS)/נקי
&rm -fm .makepp_log $(only_targets *)

לחלופין, אתה יכול לשים את היעד ה"נקי" שלך רק בקובץ המייקאפ ברמה העליונה, ולקבל אותו
עבד את כל הספריות, כך:

$(נקי מזויף):
&rm -fm $(only_targets **/*)

שימוש של Qt מוק מעבד מקדים
דוגמה זו מציגה קובץ makefile עבור תוכנית שירות המשתמשת בספריית ה-Qt GUI של Nokia (ראה
<http://qt.nokia.com>). הדבר היחיד שקצת יוצא דופן בזה הוא שאתה
חייב להריץ מעבד מקדים בשם "moc" ברוב קבצי ".h" המכילים הגדרות ווידג'ט,
אך אינך רוצה להפעיל "moc" על אף קבצי ".h" שאינם משתמשים במאקרו "Q_OBJECT".

באופן אוטומטי קביעה אשר קבצים צורך מוק קבצים

אתה יכול, כמובן, פשוט לרשום את כל הקבצים ".h" שצריכים להפעיל עליהם "moc".
עם זאת, אם אתה מפתח ווידג'טים חדשים במהירות, זה עשוי להיות מטרד
המשיכו לעדכן את הרשימה ב-makefile. אתה יכול לעקוף את הצורך לרשום את ה-Moc
מודולים במפורש עם משהו כזה:

MOC := $(QTDIR)/bin/moc
מודולים:= כל המודולים שיש לך במקרה בתוכנית שלך
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# סורק את כל קבצי ה-.h עבור המאקרו Q_OBJECT.

my_program: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(כניסות) -o $(פלט)

moc_%.cxx: %.h # יוצר את קבצי ה-moc מקבצי ה-.h.
$(MOC) $(input) -o $(output)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(קלט) -o $(פלט)

גישה זו סורקת כל אחד מכם .h קבצים בכל פעם ש-makepp מופעל, מחפש את
מאקרו "Q_OBJECT". זה נשמע יקר, אבל זה כנראה לא ייקח הרבה זמן בכלל. (ה .h
כל הקבצים יצטרכו להיטען מהדיסק בכל מקרה בתהליך הקומפילציה, אז הם יעשו זאת
להישמר במטמון.)

#include מה היא .moc פילה

גישה נוספת היא "#include" את הפלט מהקדם-processor "moc" בווידג'ט שלך
קובץ יישום. זה אומר שאתה צריך לזכור לכתוב את ה-"#include", אבל זה קרה
היתרון שיש פחות מודולים להידור, ולכן ההידור הולך מהר יותר.
(עבור רוב הקומפילציה של C++, רוב הזמן מוקדש לקריאת קבצי הכותרות, ו
הפלט מהמעבד המוקדם צריך לכלול כמעט קבצים רבים כמו הווידג'ט שלך
בכל מקרה.) לדוגמה:

// my_widget.h
class MyWidget: ציבורי QWidget {
Q_OBJECT
...
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc הוא הפלט מה-
// מעבד מקדים של moc.
// דברים אחרים ליישום כאן.
MyWidget::MyWidget(QWidget * אב, const char * name) :
QWidget (הורה, שם)
{
...
}

עכשיו אתה צריך שיהיה לך כלל ב-makefile שלך ​​כדי ליצור את כל קבצי ".moc", כך:

MOC := $(QTDIR)/bin/moc
# כלל ליצירת קובצי .moc:
%.moc: %.h
$(MOC) $(input) -o $(output)

Makepp חכמה מספיק כדי להבין שהיא צריכה ליצור "my_widget.moc" אם לא
כבר קיים, או אם הוא לא מעודכן.

הגישה השנייה הזו היא הגישה שבה אני משתמש בדרך כלל מכיוון שהיא מזרזת את ההידור.

מחליפים ל הוצא משימוש לעשות ניבים
MAKECMDGOALS

לפעמים לאנשים יש חוקים בקובץ המייקאפ שלהם תלויים באיזו מטרה הם בונים,
באמצעות המשתנה המיוחד "MAKECMDGOALS". למשל, לפעמים רואים דברים כמו
זֶה:

ifneq ($(ייצור מסנן, $(MAKECMDGOALS)),)
CFLAGS := -O2
אחר
CFLAGS := -ג
ח

זה יעבוד מצוין עם makepp. עם זאת, אני ממליץ לא להשתמש ב-"MAKECMDGOALS" עבור כאלה
מקרים (וכך עושה המדריך של GNU). עדיף לך לשים את האופטימיזציה שלך ואת
הידור באגים .o קבצים בספריות נפרדות, או לתת להם קידומות שונות או
סיומות, או שימוש במאגרים, כדי לשמור ביניהן נפרדות.

כנראה שהפעם היחידה שבה אולי תרצה להתייחס ל"MAKECMDGOALS" היא אם זה
לוקח הרבה זמן לטעון את ה-makefiles שלך, ואתה לא צריך את זה בשביל היעד ה"נקי" שלך
(אבל לא צריך מטרה נקייה). לדוגמה,

ifneq ($(MAKECMDGOALS),נקי)
load_makefile $(Wildcard **/Makeppfile)
אחר
no_implicit_load . # מנע טעינה אוטומטית של כל קבצי מייקאפ אחרים.
ח

$(נקי מזויף):
&rm -f $(תו כללי **/*.o)

רקורסיבי לעשות ל לִבנוֹת in אחר ספריות

ראה "טיפים למספר ספריות" ב-makepp_cookbook.

רקורסיבי לעשות ל שינוי ערך of a משתנה

כמה קבצי make-מעוררים את עצמם מחדש עם ערך שונה של משתנה, למשל, ניפוי הבאגים
target בקטע ה-makefile הבא

.PHONY: הכל ניפוי באגים

אופטימיזציה:
$(MAKE) תוכנית CFLAGS=-O2

לנפות:
$(MAKE) תוכנית CFLAGS=-g

תוכנית: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

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

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

CFLAGS := -O2
DEBUG_FLAGS := -g
מודולים := ab

תוכנית: $(MODULES).o
$(CC) $(CFLAGS) $(כניסות) -o $(פלט)

debug/program: debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(כניסות) -o $(פלט)

%.o : %.c
$(CC) $(CFLAGS) -c $(קלט) -o $(פלט)

debug/%o : %.c
$(CC) $(DEBUG_FLAGS) -c $(קלט) -o $(פלט)

$(ניפוי באגים מזויף): באגים/תוכנית

היתרון של לעשות את זה בדרך זו הוא (א) אתה לא צריך לבנות הכל מחדש כאשר אתה
לעבור מ-debug למוטב וחוזר חלילה; (ב)

ניתן לכתוב את האמור לעיל בצורה קצת יותר תמציתית באמצעות מאגרים. הבאים
makefile שווה בדיוק:

מאגר באגים=. # גורם לתת-ספריית ניפוי הבאגים להיראות כמו עותק של
# ספריית המשנה הנוכחית.
load_makefile באגים CFLAGS=-g
# עוקף CFLAGS כאשר הוא מופעל בספריית המשנה של ניפוי באגים
CFLAGS := -O2 # ערך CFLAGS כאשר מופעל בספריית המשנה הזו

תוכנית: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

$(ניפוי באגים מזויף): באגים/תוכנית
# אם המשתמש מקליד "makepp debug", בונה
# איתור באגים/תוכנית במקום תוכנית.

שונות טיפים
איך do I לִבנוֹת אחד חלק באופן שונה רק פַּעַם?

Makepp מקשה על כך מכיוון שהתוצאה אינה עקבית עם הכללים.
אבל יש מצבים שבהם אתה עשוי להזדקק לזה, למשל כדי להדר רק מודול אחד איתו
מידע כבד על ניפוי באגים. אתה יכול להשיג זאת בשני שלבים על ידי בניית ה-
תלות בנפרד, ולאחר מכן אי הכללה משלב הקישור:

makepp DEBUG=3 buggy.o # בנה אותו עם אפשרות אחרת.
makepp --dont-build=buggy.o buggy # השתמש בו, למרות אפשרות בנייה "שגויה".

איך do I לעשות בטוח my תפוקה ספריות קיימים?

אתה יכול לציין כלל לבניית ספריית הפלט, ולאחר מכן לוודא שכל קובץ זה
נכנס לספריית הפלט תלוי בזה. אבל בדרך כלל קל יותר לעשות משהו כמו
זֶה:

# הדרך הקלאסית
dummy := $(בדיקת מעטפת -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# זה בדרך כלל קל יותר מאשר לגרום לכל הקבצים להיות תלויים
# $(OUTPUT_DIRECTORY) ויש כלל לעשות את זה.
# שים לב שאתה חייב להשתמש ב-:= במקום = כדי לאלץ אותו
# לבצע מיד.
# גישה חלופית: שימוש בקוד Perl, OUTPUT_DIRECTORY var
perl_begin
-d $OUTPUT_DIRECTORY או mkdir $OUTPUT_DIRECTORY;
perl_end
# הדרך המודרנית, לא עושה דבר עבור ספריות קיימות
&mkdir -p $(OUTPUT_DIRECTORY)

אחת מההצהרות הללו צריכה להיות קרובה לחלק העליון של קובץ ה-makefile שלך, אז הן מבוצעות
לפני כל דבר שאולי צריך את הספרייה.

איך do I כּוֹחַ a הפקודה ל לבצע on כל לִבנוֹת?

הדרך הקלה ביותר היא לא להשתמש בכלל במנגנון הכלל, אלא פשוט לבצע אותו, כמו
זֶה:

דמה := $(תאריך מעטפת > last_build_timestamp)

או לשים את זה בבלוק perl, ככה:

perl_begin
system("פקודה לביצוע");
perl_end

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

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

איך do I לקצר מה היא מוצג לִבנוֹת פקודות?

לעתים קרובות יש כל כך הרבה אפשרויות לפקודות קומפילציה שמה שמוצג ב-
המסך אינו קריא. אתה יכול לשנות את מה שמוצג על ידי דיכוי התצוגה של
כל הפקודה, ולאחר מכן הדפס במפורש את החלק המעניין של הפקודה. שֶׁלָה
קל להדפיס רק את החלק הרלוונטי של הפקודה באמצעות "$(filter_out )", כמו
זֶה:

ALL_CFLAGS = $(CFLAGS) $(INCLUDES) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(קלט)
@$(CC) $(ALL_CFLAGS) -c $(קלט) -o $(פלט)

(ה-"@" לפני הפקודה מדכא את הדפסת הפקודה.)

זה יאפשר לך לראות את רוב האפשרויות המעניינות אבל לא יציג את כולן
כוללים ספריות (שלרוב יש הרבה מאוד מהם!). אם החלק שאתה מעוניין
in רציף בפקודה שלך, אתה יכול גם להשתמש בפונקציה "הדפסה" (המוסיפה א
קו חדש, אז אתה לא רוצה כמה מהם):

יַעַד:
@... $(הדפס חלק מעניין) ...

איך do I להמיר a פילה אל תוך תלות?

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


א
ב
ג


החלטנו לדבוק בפריסה הפשוטה הזו, כך שלא נצטרך לנתח xml. עם ה
מובנה &sed, הנה מה שאנחנו עושים עם שלושה תחליפים פשוטים לשלושת הסוגים של
שורות:

%.d: %.xml
&sed של! !$(stem).out: \\! || s! (.+) !$$1 \\! || s! !# ריק!' \
$(קלט) -o $(פלט)

כוללים foobar.d

ניסיון לכלול את זה, מייצר תחילה "foobar.d":

foobar.out: \
א \
ב \
ג \
# ריק

שורה ריקה (סתם הערה או ממש ריקה) מונעת את הצורך לדאוג לגבי הנגרר
מַהֲלָך סְרָק. חלופה להפקת רשימה מרובת שורות היא:

%.d: %.xml
&sed של! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(קלט) -o $(פלט)

כוללים foobar.d

זה מייצר מקבילה:

foobar.out: $((
a
b
c
))

אם יש לך שכתוב מורכב יותר לעשות, הגדר פונקציה בתוך ה-makefile או ב-a
מודול שאתה כולל. למשל ביטול ההגדרה של $_ ידלג על שורות קלט:

sub myfilter {
החזר undef $_ אם /
my $stem = f_stem;
s! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed של! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(קלט) -o $(פלט)

כוללים foobar.d

השתמש ב-makepp_cookbook באינטרנט באמצעות שירותי onworks.net


שרתים ותחנות עבודה בחינם

הורד אפליקציות Windows & Linux

  • 1
    ניקוי עמוק
    ניקוי עמוק
    תסריט קוטלין שכולו בנוי גרעינים
    מטמונים מפרויקטים של Gradle/Android.
    שימושי כאשר Gradle או ה-IDE מאפשרים לך
    מטה. התסריט נבדק על
    macOS, אבל...
    הורד ניקוי עמוק
  • 2
    Eclipse Checkstyle Plug-in
    Eclipse Checkstyle Plug-in
    הפלאגין Eclipse Checkstyle
    משלב את קוד ה-Java Checkstyle
    אודיטור לתוך Eclipse IDE. ה
    תוסף מספק משוב בזמן אמת ל
    המשתמש על הפרה...
    הורד את הפלאגין Eclipse Checkstyle
  • 3
    AstrOrzPlayer
    AstrOrzPlayer
    AstrOrz Player הוא נגן מדיה חינמי
    תוכנה, חלקה מבוססת על WMP ו-VLC. ה
    שחקן הוא בסגנון מינימליסטי, עם
    יותר מעשרה צבעי נושא, ויכולים גם
    ב ...
    הורד את AstrOrzPlayer
  • 4
    movistartv
    movistartv
    Kodi Movistar+ TV es un ADDON עבור XBMC/
    Kodi que permite disponer de un
    decodificador de los servicios IPTV de
    Movistar integrado en uno de los
    mediacenters מא...
    הורד את movistartv
  • 5
    קוד :: חסימות
    קוד :: חסימות
    Code::Blocks הוא קוד פתוח בחינם,
    חוצה פלטפורמות C, C++ ו-Fortran IDE
    נבנה כדי לענות על הצרכים התובעניים ביותר
    של המשתמשים שלה. זה נועד להיות מאוד
    מרחיב ...
    קוד הורדה::בלוקים
  • 6
    בין
    בין
    בין ממשק Minecraft או מתקדם
    ומעקב אחר נתונים/מבנה הוא כלי ל
    להציג סקירה כללית של מיינקראפט
    העולם, מבלי ליצור אותו בפועל. זה
    פחית ...
    הורד בין
  • עוד »

פקודות לינוקס

Ad