??xml version="1.0" encoding="utf-8" standalone="yes"?>99久久久国产精品免费无卡顿,欧美精品福利视频一区二区三区久久久精品 ,伊人久久五月天http://www.shnenglu.com/ivenher/category/318.htmlzh-cnTue, 20 May 2008 17:12:48 GMTTue, 20 May 2008 17:12:48 GMT60OTL性能http://www.shnenglu.com/ivenher/articles/39973.html爱饭?/dc:creator>爱饭?/author>Sat, 29 Dec 2007 16:18:00 GMThttp://www.shnenglu.com/ivenher/articles/39973.htmlhttp://www.shnenglu.com/ivenher/comments/39973.htmlhttp://www.shnenglu.com/ivenher/articles/39973.html#Feedback1http://www.shnenglu.com/ivenher/comments/commentRss/39973.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/39973.html今天在做一个程序性能提升时发现otl_stream.W一个参数buffer size Ҏ能影响很大,以下是几个测试数?
参? http://otl.sourceforge.net/otl3_stream_class.htm
50   2.06
<1:536704> 18:31:58.068 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:536704> 18:34:04.713 [00001] There are 3612066 records is loaded!

100 1.38
<1:2085112> 18:36:23.727 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2085112> 18:38:01.923 [00001] There are 3612066 records is loaded!
1.23
<1:2085112> 18:38:06.941 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2085112> 18:39:29.849 [00001] There are 3612066 records is loaded!

200  1.02
<1:1499250> 18:41:47.711 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1499250> 18:42:49.300 [00001] There are 3612066 records is loaded!
<1:1499250> 18:42:54.312 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1499250> 18:43:53.717 [00001] There are 3612066 records is loaded!
500  0.43
<1:1978536> 18:45:57.790 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1978536> 18:46:40.685 [00001] There are 3612066 records is loaded!
<1:1978536> 18:45:09.982 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1978536> 18:45:52.787 [00001] There are 3612066 records is loaded!
1000  0.35
<1:1597632> 18:47:42.973 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:48:17.715 [00001] There are 3612066 records is loaded!
<1:1597632> 18:48:22.718 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:49:01.119 [00001] There are 3612066 records is loaded!
<1:1597632> 18:51:17.837 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:51:24.416 [10001] Signal 31 recieved.
<1:1597632> 18:49:49.976 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:50:28.192 [00001] There are 3612066 records is loaded!

2000  0.34
<1:2883830> 18:51:47.365 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2883830> 18:52:21.163 [00001] There are 3612066 records is loaded!
<1:2883830> 18:52:26.166 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2883830> 18:53:01.576 [00001] There are 3612066 records is loaded!

另外,~译时定?a >OTL_STREAM_POOLING_ON 也会Ҏ能有所提升.
参? http://otl.sourceforge.net/otl3_ex113.htm


]]>
C语言中对旉和日期的处理http://www.shnenglu.com/ivenher/articles/33195.html爱饭?/dc:creator>爱饭?/author>Sat, 29 Sep 2007 07:35:00 GMThttp://www.shnenglu.com/ivenher/articles/33195.htmlhttp://www.shnenglu.com/ivenher/comments/33195.htmlhttp://www.shnenglu.com/ivenher/articles/33195.html#Feedback3http://www.shnenglu.com/ivenher/comments/commentRss/33195.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/33195.html

C语言中对旉和日期的处理

Chuck Allison

Chuck Allison是盐湖城?/span>Latter Day教堂总部下耶稣教堂家族历史研究处的软g体系设计?/span>。他拥有数学学士和数学硕士学位。他?/span>1975qv开始编E,?/span>1984qv他开始从?/span>c语言的教学和开发。他目前的兴是面向对象的技术及其教肌Ӏ他?/span>X3J16Q?/span>ANSI C ++标准化委员会的一员?/span>发?/span>e-mail?/span>allison@decus.orgQ或者拨打电话到(801)240-4510均可以与他取得联pR?/span>

大部分的操作pȝ有办法得到当前的日期和时间。通过定义?em>time.h的库函数Q?span>ANSI C能以许多不同的Ş式得到这个信息。函?em>timeq回一个类型ؓtime_t的|通常为longQ,该函数在q行期间对当前的日期和时间进行编码。然后你可以这个返回g递给其他能对该D行解码和格式化的函数?/span>

Listing 1中的E序使用函数timeQ?em>localtime?em>strftime以不同的形式输出当前的日期和旉。函?em>localtime把已l编码的旉解码成如下的structQ?/font>

struct tm
{
   int tm_sec;     /* (0 - 61) */
   int tm_min;     /* (0 - 59) */
   int tm_hour;    /* (0 - 23) */
   int tm_mday;    /* (1 - 31) */
   int tm_mon;     /* (0 - 11) */
   int tm_year;    /* past 1900 */
   int tm_wday;    /* (0 - 6) */
   int tm_yday;    /* (0 - 365) */
   int tm_isdst;   /* daylight savings flag */
};

每次当你调用localtime的时候,它会重写一个静态的l构q返回该l构的地址Q因此同一时刻在一个程序中只能取得一个这Ll构Q而不能做明显的拷贝)。函?/font>ctimeq回一个指向静态字W串的指针,该字W串以标准的格式包含了完整的旉和日期?/font>strftimeҎ用户的指定格式格式化字符Ԍ例如Q?/span>%A代表一周中每一天的名称Q?/span>Table 1列出了格式描q符的完整列表?/span>

/日期q算

通过改变tml构里的|可对旉/日期q行q算?a >Listing 2中的E序展示了如何计将来某天的日期和以Uؓ单位所计算出的E序执行旉。注意函?em>time的语法(参数time_t由地址传入Qƈ非作为函数的q回|。函?em>mktime改变tml构的|以便日期和时间在一个合适的范围内,之后day-of-week (tm_wday)和day-of-year (tm_yday)域进行相应的更新?em>mktime?em>tml构中日期和旉的值置于合适的范围之内Q相应的更新day of week (tm-wday)和day of year (tm-yday)的倹{这U情况发生在当一个日期超Z你的实现能够支持的范围的时候。例如,我的MS-DOS的编译器不能~码1970q?月䆾之前的日期。函?em>asctimeq回tm参数所描述旉的标准字W串Q因?em>ctime (&tval)与asctime (localtime(&tval)是相{的)。函?em>difftimeq回用秒做单位的两个time_t的差?/span>

如果需要处理超出系l范围的日期Q或者需要计两个日期的间隔又不是用U来做单位,那你需要设计自qdate~码?a >Listing 3 ?a >Listing 5中的应用E序通过使用一个简单的month-day-yearl构Q展CZ定两个日期间隔的年数、月份数和天数的技术。日期的相减像你在学里做的减法那P例如Q首先进行天数的相减Q如果需要就向月份数借位Q以此类推)。注意蟩q的q䆾都被计算q去了。ؓ了简略v见,date_interval函数假设日期都是有效的,q且W一个日期在W二个日期之前。函数返回一个指向静?em>Datel构的指针,该结构包含了我们惌的答案?/span>

文g旉/日期?/span>

大多数操作系lؓ文gl护旉/日期戟뀂至你能得知一个文件最后被修改的时间。(常用?em>make工具使用q一信息来决定一个文件是否需要被重新~译Q或者一个应用程序是否需要被重新q接Q。由于文件系l在不同q_上有所不同Q没有什么通用的函数得C个文件的旉/日期戻I因此ANSI 标准没有定义q样的函数。然而,大多数流行的操作pȝQ包括MS-DOS和VAX/VMSQ提供了UNIX函数statQ该函数q回相关的文件信息,包括?em>time_t表示的最后修Ҏ间?/span>

Listing 6中的E序使用stat?em>difftime来确定是?em>time1.c?em>time2.c更新Q例如,是否最q被修改q)?/font>

如果你需要更C个文件的旉/日期戛_当前旉Q可单的重写文g的第一个字节。虽然实际内容ƈ未改变,但你的文件系l会认ؓ文g已经被改变了Qƈ且会相应的更新时?日期戟뀂(知道你的文gpȝQ在VAX/VMS下,当你得到一个文件的新版本的时候,旧的版本仍会被保留)。这U技术叫?#8220;‘touching’一个文?#8221;?a >Listing 7?em>touch的实现在指定文g不存在的时候会创徏一个新文g。注意文件以“binary”模式打开Q在打开模式字符串中由字W?em>b军_—在来的专栏中我会详细讨论文g处理的问题)?/span>

?span>1Q?em>strftime的格式描q符

Code Sample Output
---------------------------------------------
%a    Wed
%A    Wednesday
%b    Oct
%B    October
%c    Wed Oct 07 13:24:27 1992
%d    07    (day of month [01-31])
%H    13    (hour in [00-23])
%I    01    (hour in [01-12])
%j    281   (day of year [001-366])
%m    10    (month [01-12])
%M    24    (minute [00-59])
%p    PM
%S    27    (second [00-59] )
%U    40    (Sunday week of year [00-52])
%w    3     (day of week [0-6])
%W    40    (Monday week of year [00-52])
%x    Wed Oct 7, 1992
%X    13:24:27
%y    92
%Y    1992
%Z    EDT   (daylight savings indicator)

Listing 1 time1.c ?采用不同格式输出当前的日期和旉

#include <stdio.h>
#include <time.h>
 
#define BUFSIZE 128
 
main()
{
   time_t tval;
   struct tm *now;
   char buf[BUFSIZE];
   char *fancy_format =
     "Or getting really fancy:\n"
     "%A, %B %d, day %j of %Y.\n"
     "The time is %I:%M %p.";
 
   /* Get current date and time */
   tval = time(NULL);
   now = localtime(&tval);
   printf("The current date and time:\n"
         "%d/%02d/%02d %d:%02d:%02d\n\n",
     now->tm_mon+1, now->tm_mday, now->tm_year,
     now->tm_hour, now->tm_min, now->tm_sec);
   printf("Or in default system format:\n%s\n",
         ctime(&tval));
   strftime(buf,sizeof buf,fancy_format,now);
   puts(buf);
 
   return 0;
}
 
/* Output
The current date and time:
10/06/92 12:58:00
 
Or in default system format:
Tue Oct 06 12:58:00 1992
 
Or getting really fancy:
Tuesday, October 06, day 280 of 1992.
The time is 12:58 PM.
*/
 
/* End of File */

Listing 2 time2.c ?em>展示如何计算来某一天的日期以及以秒为单位计出的执行时?/em>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
main()
{
   time_t start, stop;
   struct tm *now;
   int ndays;
 
   /* Get current date and time */
   time(&start);
   now = localtime(&start);
 
   /* Enter an interval in days */
   fputs("How many days from now? ",stderr);
   if (scanf("%d",&ndays) !=1)
      return EXIT_FAILURE;
   now->tm_mday += ndays;
   if (mktime(now) != -1)
      printf("New date: %s",asctime(now));
   else
      puts("Sorry. Can't encode your date.");
 
   /* Calculate elapsed time */
   time(&stop);
   printf("Elapsed program time in seconds: %f\n",
     difftime(stop,start));
 
   return EXIT_SUCCESS;
}
 
/* Output
How many days from now? 45
New date: Fri Nov 20 12:40:32 1992
Elapsed program time in seconds: 1.000000
*/
 
/* End of File */

Listing 3 date.h ?一个简单的日期l构

struct Date
{
   int day;
   int month;
   int year;
};
typedef struct Date Date;
 
Date* date_interval(const Date *, const Date *);
/* End of File */

Listing 4 date_int.c ?计算两个日期的间?/em>

/* date_int.c: Compute duration between two dates */
 
#include "date.h"
 
#define isleap(y) \
 ((y)%4 == 0 && (y)%100 != 0 || (y)%400 == 0)
 
static int Dtab [2][13] =
{
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
 
Date *date_interval(const Date *d1, const Date *d2)
{
   static Date result;
   int months, days, years, prev_month;
 
   /* Compute the interval - assume d1 precedes d2 */
   years = d2->year - d1->year;
   months = d2->month - d1->month;
   days = d2->day - d1->day;
 
   /* Do obvious corrections (days before months!)
    *
    * This is a loop in case the previous month is
    * February, and days < -28.
    */
   prev_month = d2->month - 1;
   while (days < 0)
   {
      /* Borrow from the previous month */
      if (prev_month == 0)
         prev_month = 12;
      --months;
      days += Dtab[isleap(d2->year)][prev_month--];
   }
 
   if (months < 0)
   {
      /* Borrow from the previous year */
      --years;
      months += 12;
   }
 
   /* Prepare output */
   result.month = months;
   result.day = days;
   result.year = years;
   return &result;
}
/* End of File */

Listing 5 tdate.c ?举例说明日期间隔函数的?/em>

/* tdate.c: Test date_interval() */
 
#include <stdio.h>
#include <stdlib.h>
#include "date.h"
 
main()
{
   Date d1, d2, *result;
   int nargs;
 
   /* Read in two dates - assume 1st precedes 2nd */
   fputs("Enter a date, MM/DD/YY> ",stderr);
   nargs = scanf("%d/%d/%d%*c", &d1.month,
     &d1.day, &d1.year);
   if (nargs != 3)
      return EXIT_FAILURE;
 
   fputs("Enter a later date, MM/DD/YY> ",stderr);
   nargs = scanf("%d/%d/%d%*c", &d2.month,
     &d2.day, &d2.year);
   if (nargs != 3)
      return EXIT_FAILURE;
 
   /* Compute interval in years, months, and days */
   result = date_interval(&d1, &d2);
   printf("years: %d, months: %d, days: %d\n",
      result->year, result->month, result->day);
   return EXIT_SUCCESS;
 
}
/* Sample Execution:
Enter a date, MM/DD/YY> 10/1/51
Enter a later date, MM/DD/YY> 10/6/92
years: 41, months: 0, days: 5 */
/* End of File */

Listing 6 ftime.c ?定是否time1.c?/em>time2.c更新

/* ftime.c: Compare file time stamps */
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
 
main()
{
   struct stat fs1, fs2;
 
   if (stat("time1.c",&fs1) == 0 &&
      stat("time2.c",&fs2) == 0)
   {
      double interval =
        difftime(fs2.st_mtime,fs1.st_mtime);
 
      printf("time1.c %s newer than time2.c\n",
        (interval < 0.0) ? "is" : "is not");
      return EXIT_SUCCESS;
   }
   else
      return EXIT_FAILURE;
}
/* Output
time1.c is not newer than time2.c */
/* End of File */

Listing 7 touch.c ?em>通过覆盖旧文件或者创Z个新的文件来更新旉?/em>

/* touch.c: Update a file's time stamp */
 
#include <stdio.h>
 
void touch(char *fname)
{
   FILE *f = fopen(fname,"r+b");
   if (f != NULL)
   {
      char c = getc(f);
      rewind(f);
      putc(c,f);
   }
   else
      fopen(fname,"wb");
 
   fclose(f);
}
 
/* End of File */

 



]]>
makefile详解 使用make更新函数库文?l束) 二十?/title><link>http://www.shnenglu.com/ivenher/articles/22113.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 03:22:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22113.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22113.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22113.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22113.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22113.html</trackback:ping><description><![CDATA[使用make更新函数库文?<br>——————————?<br><br>函数库文件也是对Object文gQ程序编译的中间文gQ的打包文g。在Unix下,一般是由命?ar"来完成打包工作?<br><br>一、函数库文g的成?<br><br>一个函数库文g由多个文件组成。你可以以如下格式指定函数库文g及其l成Q?<br><br>    archive(member) <br><br>q个不是一个命令,而一个目标和依赖的定义。一般来_q种用法基本上就是ؓ?ar"命o来服务的。如Q?<br><br>    foolib(hack.o) : hack.o <br>            ar cr foolib hack.o <br><br>如果要指定多个memberQ那׃I格分开Q如Q?<br><br>    foolib(hack.o kludge.o) <br><br>其等价于Q?<br><br>    foolib(hack.o) foolib(kludge.o) <br><br>你还可以使用Shell的文仉配W来定义Q如Q?<br><br>    foolib(*.o) <br><br><br>二、函数库成员的隐含规?<br><br>当make搜烦一个目标的隐含规则Ӟ一个特D的Ҏ是Q如果这个目标是"a(m)"形式的,其会把目标变?(m)"。于是,如果我们的成员是"%.o"的模式定义,q且如果我们使用"make foo.a(bar.o)"的Ş式调用MakefileӞ隐含规则会去?bar.o"的规则,如果没有定义bar.o的规则,那么内徏隐含规则生效Qmake会去找bar.c文g来生成bar.oQ如果找得到的话Qmake执行的命令大致如下: <br><br>    cc -c bar.c -o bar.o <br>    ar r foo.a bar.o <br>    rm -f bar.o <br><br>q有一个变量要注意的是"$%"Q这是专属函数库文g的自动化变量Q有兛_说明请参?自动化变?一节?<br><br><br>三、函数库文g的后~规则 <br><br>你可以?后缀规则"?隐含规则"来生成函数库打包文gQ如Q?<br><br>    .c.a: <br>            $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o <br>            $(AR) r $@ $*.o <br>            $(RM) $*.o <br><br>其等效于Q?<br><br>    (%.o) : %.c <br>            $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o <br>            $(AR) r $@ $*.o <br>            $(RM) $*.o <br><br><br>四、注意事?<br><br>在进行函数库打包文g生成Ӟ请小心用make的ƈ行机Ӟ"-j"参数Q。如果多个ar命o在同一旉q行在同一个函数库打包文g上,很有可以损坏这个函数库文g。所以,在make未来的版本中Q应该提供一U机制来避免q行操作发生在函数打包文件上?<br><br>但就目前而言Q你q是应该不要量不要使用"-j"参数?<br><br><br>最最后,我还想介l一下makeE序的设计开发者?<br><br>  <br><br>首当其冲的是Q?nbsp;Richard Stallman   <br><br>开源Y件的领袖和先驱,从来没有领过一天工资,从来没有使用qWindows操作pȝ。对于他的事q和他的软g以及他的思想Q我无需说过多的话,怿大家对这个hq不比我陌生Q这是他的主:http://www.stallman.org/ 。这里只贴上一张他的近照:<br> <table class=attachtable cellSpacing=4 cellPadding=1 align=center border=3> <tbody> <tr> <td align=middle colSpan=2><br><img src="http://bbs.chinaunix.net/attachments/rms.jpg" border=0 twffan="done"><br><br></td> </tr> <tr> <td> <table cellSpacing=4 cellPadding=0 width="100%" align=center border=0> <tbody> <tr> <td class=attachrow><span id="f39nh9h" class=genmed twffan="done"></span></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br><br><br> <hr> <strong> <a target=_blank><u><font color=#0000ff>gunguymadman</font></u></a> 回复于:2004-09-16 12:27:15</strong><br><br>W二位是QRoland McGrath   <br><br>个h主页是:http://www.frob.com/~roland/ Q下面是他的一些事q: <br><br>1Q?nbsp; 合作~写了ƈl护GNU make?<br><br>2Q?nbsp; 和Thomas Bushnell一同编写了GNU Hurd?<br><br>3Q?nbsp; ~写q维护着GNU C library?nbsp; <br><br>4Q?nbsp; 合作~写q维护着部分的GNU Emacs?nbsp; <br><br>  <br><br>在此Q向q两位开源项目的斗士致以最真切的敬意?<br><br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22113.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 11:22 <a href="http://www.shnenglu.com/ivenher/articles/22113.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 定义模式规则 二十?/title><link>http://www.shnenglu.com/ivenher/articles/22111.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 03:20:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22111.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22111.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22111.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22111.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22111.html</trackback:ping><description><![CDATA[五、定义模式规?<br><br>你可以用模式规则来定义一个隐含规则。一个模式规则就好像一个一般的规则Q只是在规则中,目标的定义需要有"%"字符?%"的意思是表示一个或多个L字符。在依赖目标中同样可以?%"Q只是依赖目标中?%"的取|取决于其目标?<br><br>有一炚w要注意的是,"%"的展开发生在变量和函数的展开之后Q变量和函数的展开发生在make载入MakefileӞ而模式规则中?%"则发生在q行时?<br><br><br>1、模式规则介l?<br><br>模式规则中,臛_在规则的目标定义中要包含"%"Q否则,是一般的规则。目标中?%"定义表示Ҏ件名的匹配,"%"表示长度L的非I字W串。例如:"%.c"表示?.c"l尾的文件名Q文件名的长度至ؓ3Q,?s.%.c"则表CZ"s."开_".c"l尾的文件名Q文件名的长度至ؓ5Q?<br><br>如果"%"定义在目标中Q那么,目标中的"%"的值决定了依赖目标中的"%"的|也就是说Q目标中的模式的"%"军_了依赖目标中"%"的样子。例如有一个模式规则如下: <br><br>    %.o : %.c ; <command ......>; <br><br>其含义是Q指Z怎么从所有的[.c]文g生成相应的[.o]文g的规则。如果要生成的目标是"a.o b.o"Q那?%c"是"a.c b.c"?<br><br>一旦依赖目标中?%"模式被确定,那么Qmake会被要求d配当前目录下所有的文g名,一旦找刎ͼmake׃规则下的命oQ所以,在模式规则中Q目标可能会是多个的Q如果有模式匚w出多个目标,make׃产生所有的模式目标Q此Ӟmake兛_的是依赖的文件名和生成目标的命oq两件事?<br><br><br>2、模式规则示?<br><br>下面q个例子表示?把所有的[.c]文g都编译成[.o]文g. <br><br>    %.o : %.c <br>            $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ <br><br>其中Q?$@"表示所有的目标的挨个|"$<"表示了所有依赖目标的挨个倹{这些奇怪的变量我们?自动化变?Q后面会详细讲述?<br><br>下面的这个例子中有两个目标是模式的: <br><br>    %.tab.c %.tab.h: %.y <br>            bison -d $< <br><br>q条规则告诉make把所有的[.y]文g都以"bison -d <n>;.y"执行Q然后生?<n>;.tab.c"?<n>;.tab.h"文g。(其中Q?<n>;"表示一个Q意字W串Q。如果我们的执行E序"foo"依赖于文?parse.tab.o"?scan.o"Qƈ且文?scan.o"依赖于文?parse.tab.h"Q如?parse.y"文g被更CQ那么根据上q的规则Q?bison -d parse.y"׃被执行一ơ,于是Q?parse.tab.o"?scan.o"的依赖文件就齐了。(假设Q?parse.tab.o"?parse.tab.c"生成Q和"scan.o"?scan.c"生成Q?foo"?parse.tab.o"?scan.o"链接生成Q而且foo和其[.o]文g的依赖关pM写好Q那么,所有的目标都会得到满Q?<br><br><br>3、自动化变量 <br><br>在上q的模式规则中,目标和依赖文仉是一pM的文Ӟ那么我们如何书写一个命令来完成从不同的依赖文g生成相应的目标?因ؓ在每一ơ的Ҏ式规则的解析Ӟ都会是不同的目标和依赖文件?<br><br>自动化变量就是完成这个功能的。在前面Q我们已l对自动化变量有所提涉Q相信你看到q里已对它有一个感性认识了。所谓自动化变量Q就是这U变量会把模式中所定义的一pd的文件自动地挨个取出Q直x有的W合模式的文仉取完了。这U自动化变量只应出现在规则的命o中?<br><br>下面是所有的自动化变量及其说明: <br><br>$@ <br>    表示规则中的目标文g集。在模式规则中,如果有多个目标,那么Q?$@"是匚w于目标中模式定义的集合?<br><br>$% <br>    仅当目标是函数库文g中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)"Q那么,"$%"是"bar.o"Q?$@"是"foo.a"。如果目标不是函数库文gQUnix下是[.a]QWindows下是[.lib]Q,那么Q其gؓI?<br><br>$< <br>    依赖目标中的W一个目标名字。如果依赖目标是以模式(?%"Q定义的Q那?$<"是W合模式的一pd的文仉。注意,其是一个一个取出来的?<br><br>$? <br>    所有比目标新的依赖目标的集合。以I格分隔?<br><br>$^ <br>    所有的依赖目标的集合。以I格分隔。如果在依赖目标中有多个重复的,那个q个变量会去除重复的依赖目标Q只保留一份?<br><br>$+ <br>    q个变量很像"$^"Q也是所有依赖目标的集合。只是它不去除重复的依赖目标?<br><br>$*  <br>   q个变量表示目标模式?%"及其之前的部分。如果目标是"dir/a.foo.b"Qƈ且目标的模式?a.%.b"Q那么,"$*"的值就?dir/a.foo"。这个变量对于构造有兌的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出Q但是,如果目标文g的后~是make所识别的,那么"$*"是除了后缀的那一部分。例如:如果目标?foo.c"Q因?.c"是make所能识别的后缀名,所以,"$*"的值就?foo"。这个特性是GNU make的,很有可能不兼容于其它版本的makeQ所以,你应该尽量避免?$*"Q除非是在隐含规则或是静态模式中。如果目标中的后~是make所不能识别的,那么"$*"是I倹{?<br><br>当你希望只对更新q的依赖文gq行操作Ӟ"$?"在显式规则中很有用,例如Q假设有一个函数库文g?lib"Q其由其它几个object文g更新。那么把object文g打包的比较有效率的Makefile规则是: <br><br>    lib : foo.o bar.o lose.o win.o <br>            ar r lib $? <br><br>在上q所列出来的自动量变量中。四个变量($@?<?%?*Q在扩展时只会有一个文Ӟ而另三个的值是一个文件列表。这七个自动化变量还可以取得文g的目录名或是在当前目录下的符合模式的文g名,只需要搭配上"D"?F"字样。这是GNU make中老版本的Ҏ,在新版本中,我们使用函数"dir"?notdir"可以做C?D"的含义就是DirectoryQ就是目录,"F"的含义就是FileQ就是文件?<br><br>下面是对于上面的七个变量分别加上"D"或是"F"的含义: <br><br>$(@D) <br>    表示"$@"的目录部分(不以斜杠作ؓl尾Q,如果"$@"值是"dir/foo.o"Q那?$(@D)"是"dir"Q而如?$@"中没有包含斜杠的话,其值就?."Q当前目录)?<br><br>$(@F) <br>    表示"$@"的文仉分,如果"$@"值是"dir/foo.o"Q那?$(@F)"是"foo.o"Q?$(@F)"相当于函?$(notdir $@)"?<br><br>"$(*D)" <br>"$(*F)" <br>    和上面所q的同理Q也是取文g的目录部分和文g部分。对于上面的那个例子Q?$(*D)"q回"dir"Q?$(*F)"q回"foo" <br><br>"$(%D)" <br>"$(%F)" <br>    分别表示了函数包文g成员的目录部分和文g部分。这对于形同"archive(member)"形式的目标中?member"中包含了不同的目录很有用?<br><br>"$(<D)" <br>"$(<F)" <br>    分别表示依赖文g的目录部分和文g部分?<br><br>"$(^D)" <br>"$(^F)" <br>    分别表示所有依赖文件的目录部分和文仉分。(无相同的Q?<br><br>"$(+D)" <br>"$(+F)" <br>    分别表示所有依赖文件的目录部分和文仉分。(可以有相同的Q?<br><br>"$(?D)" <br>"$(?F)" <br>    分别表示被更新的依赖文g的目录部分和文g部分?<br><br>最后想提醒一下的是,对于"$<"Qؓ了避免生不必要的麻烦,我们最好给$后面的那个特定字W都加上圆括P比如Q?$(<)"p?$<"要好一些?<br><br>q得要注意的是,q些变量只用在规则的命令中Q而且一般都?昑ּ规则"?静态模式规?Q参见前?书写规则"一章)。其在隐含规则中q没有意义?<br><br>4、模式的匚w <br><br>一般来_一个目标的模式有一个有前缀或是后缀?%"Q或是没有前后缀Q直接就是一?%"。因?%"代表一个或多个字符Q所以在定义好了的模式中Q我们把"%"所匚w的内容叫??Q例?%.c"所匚w的文?test.c"?test"是"?。因为在目标和依赖目标中同时?%"Ӟ依赖目标??会传l目标,当做目标中的"??<br><br>当一个模式匹配包含有斜杠Q实际也不经常包含)的文件时Q那么在q行模式匚wӞ目录部分会首先被UdQ然后进行匹配,成功后,再把目录加回厅R在q行"?的传递时Q我们需要知道这个步骤。例如有一个模?e%t"Q文?src/eat"匚w于该模式Q于?src/a"是??Q如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r"Q那么,目标是"src/car"。("?被传递) <br><br><br>5、重载内建隐含规?<br><br>你可以重载内建的隐含规则Q或是定义一个全新的Q,例如你可以重新构造和内徏隐含规则不同的命令,如: <br><br>    %.o : %.c <br>            $(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date) <br><br>你可以取消内建的隐含规则Q只要不在后面写命op。如Q?<br><br>    %.o : %.s <br><br>同样Q你也可以重新定义一个全新的隐含规则Q其在隐含规则中的位|取决于你在哪里写下q个规则。朝前的位置靠前?<br><br><br>六、老式风格?后缀规则" <br><br>后缀规则是一个比较老式的定义隐含规则的Ҏ。后~规则会被模式规则逐步地取代。因为模式规则更强更清晰。ؓ了和老版本的Makefile兼容QGNU make同样兼容于这些东ѝ后~规则有两U方式:"双后~"?单后~"?<br><br>双后~规则定义了一对后~Q目标文件的后缀和依赖目标(源文Ӟ的后~。如".c.o"相当?%o : %c"。单后缀规则只定义一个后~Q也是源文件的后缀。如".c"相当?% : %.c"?<br><br>后缀规则中所定义的后~应该是make所认识的,如果一个后~是make所认识的,那么q个规则是单后~规则Q而如果两个连在一L后缀都被make所认识Q那是双后~规则。例如:".c"?.o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则Q意义就?.c"是源文g的后~Q?.o"是目标文件的后缀。如下示例: <br><br>    .c.o: <br>            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< <br><br>后缀规则不允怓Q何的依赖文gQ如果有依赖文g的话Q那׃是后~规则Q那些后~l统被认为是文g名,如: <br><br>    .c.o: foo.h <br>            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< <br><br>q个例子Q就是说Q文?.c.o"依赖于文?foo.h"Q而不是我们想要的q样Q?<br><br>    %.o: %.c foo.h <br>            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< <br><br>后缀规则中,如果没有命oQ那是毫无意义的。因Z也不会移d建的隐含规则?<br><br>而要让make知道一些特定的后缀Q我们可以用伪目标".SUFFIXES"来定义或是删除,如: <br><br>    .SUFFIXES: .hack .win <br><br>把后~.hack?win加入后缀列表中的末尾?<br><br>    .SUFFIXES:              # 删除默认的后~ <br>    .SUFFIXES: .c .o .h   # 定义自己的后~ <br><br>先清楚默认后~Q后定义自己的后~列表?<br><br>make的参?-r"?-no-builtin-rules"也会使用得默认的后缀列表为空。而变?SUFFIXE"被用来定义默认的后缀列表Q你可以?.SUFFIXES"来改变后~列表Q但请不要改变变?SUFFIXE"的倹{?<br><br><br>七、隐含规则搜索算?<br><br>比如我们有一个目标叫 T。下面是搜烦目标T的规则的法。请注意Q在下面Q我们没有提到后~规则Q原因是Q所有的后缀规则在Makefile被蝲入内存时Q会被{换成模式规则。如果目标是"archive(member)"的函数库文g模式Q那么这个算法会被运行两ơ,W一ơ是扄标TQ如果没有找到的话,那么q入W二ơ,W二ơ会?member"当作T来搜索?<br><br>1、把T的目录部分分d来。叫DQ而剩余部分叫N。(如:如果T?src/foo.o"Q那么,D是"src/"QN是"foo.o"Q?<br><br>2、创建所有匹配于T或是N的模式规则列表?<br><br>3、如果在模式规则列表中有匚w所有文件的模式Q如"%"Q那么从列表中移除其它的模式?<br><br>4、移除列表中没有命o的规则?<br><br>5、对于第一个在列表中的模式规则Q?<br>    1Q推导其"?SQS应该是T或是N匚w于模式中"%"非空的部分?<br>    2Q计依赖文件。把依赖文g中的"%"都替换成"?S。如果目标模式中没有包含斜框字符Q而把D加在W一个依赖文件的开头?<br>3Q测试是否所有的依赖文g都存在或是理当存在。(如果有一个文件被定义成另外一个规则的目标文gQ或者是一个显式规则的依赖文gQ那么这个文件就?理当存在"Q?<br>    4Q如果所有的依赖文g存在或是理当存在Q或是就没有依赖文g。那么这条规则将被采用,退法?<br><br>6、如果经q第5步,没有模式规则被找刎ͼ那么做更进一步的搜烦。对于存在于列表中的W一个模式规则: <br>    1Q如果规则是l止规则Q那忽略它Ql下一条模式规则?<br>2Q计依赖文件。(同第5步) <br>3Q测试所有的依赖文g是否存在或是理当存在?<br>4Q对于不存在的依赖文Ӟ递归调用q个法查找他是否可以被隐含规则扑ֈ?<br>5Q如果所有的依赖文g存在或是理当存在Q或是就Ҏ没有依赖文g。那么这条规则被采用Q退法?<br><br>7、如果没有隐含规则可以用,查看".DEFAULT"规则Q如果有Q采用,?.DEFAULT"的命令给T使用?<br><br>一旦规则被扑ֈQ就会执行其相当的命令,而此Ӟ我们的自动化变量的值才会生成?br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 11:20 <a href="http://www.shnenglu.com/ivenher/articles/22111.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 隐含规则 二十?/title><link>http://www.shnenglu.com/ivenher/articles/22110.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 03:19:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22110.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22110.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22110.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22110.html</trackback:ping><description><![CDATA[隐含规则 <br>———?<br><br>在我们用MakefileӞ有一些我们会l常使用Q而且使用频率非常高的东西Q比如,我们~译C/C++的源E序Z间目标文ӞUnix下是[.o]文gQWindows下是[.obj]文gQ。本章讲q的是一些在Makefile中的“隐含?#8221;Q早先约定了的,不需要我们再写出来的规则?<br><br>“隐含规则”也就是一U惯例,make会按照这U?#8220;惯例”心照不喧地来q行Q那怕我们的Makefile中没有书写这L规则。例如,把[.c]文g~译成[.o]文gq一规则Q你Ҏ׃用写出来Qmake会自动推导出q种规则Qƈ生成我们需要的[.o]文g?<br><br>“隐含规则”会用一些我们系l变量,我们可以改变q些pȝ变量的值来定制隐含规则的运行时的参数。如pȝ变量“CFLAGS”可以控制~译时的~译器参数?<br><br>我们q可以通过“模式规则”的方式写下自q隐含规则。用“后缀规则”来定义隐含规则会有许多的限制。?#8220;模式规则”会更回得和清楚,?#8220;后缀规则”可以用来保证我们Makefile的兼Ҏ?<br>我们了解?#8220;隐含规则”Q可以让其ؓ我们更好的服务,也会让我们知道一?#8220;U定俗成”了的东西Q而不至于使得我们在运行Makefile时出C些我们觉得莫名其妙的东西。当ӞM事物都是矛盾的,水能载舟Q亦可覆舟,所以,有时?#8220;隐含规则”也会l我们造成不小的麻烦。只有了解了它,我们才能更好C用它?<br><br><br>一、用隐含规?<br><br>如果要用隐含规则生成你需要的目标Q你所需要做的就是不要写个目标的规则。那么,make会试囑֎自动推导产生q个目标的规则和命oQ如果make可以自动推导生成q个目标的规则和命oQ那么这个行为就是隐含规则的自动推导。当Ӟ隐含规则是make事先U定好的一些东ѝ例如,我们有下面的一个MakefileQ?<br><br>    foo : foo.o bar.o <br>            cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS) <br><br>我们可以注意刎ͼq个Makefile中ƈ没有写下如何生成foo.o和bar.oq两目标的规则和命o。因为make?#8220;隐含规则”功能会自动ؓ我们自动LD两个目标的依赖目标和生成命o?<br><br>make会在自己?#8220;隐含规则”库中L可以用的规则Q如果找刎ͼ那么׃使用。如果找不到Q那么就会报错。在上面的那个例子中Qmake调用的隐含规则是Q把[.o]的目标的依赖文g|成[.c]Qƈ使用C的编译命?#8220;cc –c $(CFLAGS) [.c]”来生成[.o]的目标。也是_我们完全没有必要写下下面的两条规则: <br><br>    foo.o : foo.c <br>            cc –c foo.c $(CFLAGS) <br>    bar.o : bar.c <br>        cc –c bar.c $(CFLAGS) <br><br>因ؓQ这已经?#8220;U定”好了的事了,make和我们约定好了用C~译?#8220;cc”生成[.o]文g的规则,q就是隐含规则?<br><br>当然Q如果我们ؓ[.o]文g书写了自q规则Q那么make׃会自动推导ƈ调用隐含规则Q它会按照我们写好的规则忠实地执行?<br><br>q有Q在make?#8220;隐含规则?#8221;中,每一条隐含规则都在库中有光序,靠前的则是被l常使用的,所以,q会D我们有些时候即使我们显C地指定了目标依赖,make也不会管。如下面q条规则Q没有命令)Q?<br><br>    foo.o : foo.p <br><br>依赖文g“foo.p”QPascalE序的源文gQ有可能变得没有意义。如果目录下存在?#8220;foo.c”文gQ那么我们的隐含规则一样会生效Qƈ会通过“foo.c”调用C的编译器生成foo.o文g。因为,在隐含规则中QPascal的规则出现在C的规则之后,所以,make扑ֈ可以生成foo.o的C的规则就不再L下一条规则了。如果你实不希望Q何隐含规则推|那么Q你׃要只写出“依赖规则”Q而不写命令?<br><br><br>二、隐含规则一?<br><br>q里我们讲q所有预先设|(也就是make内徏Q的隐含规则Q如果我们不明确地写下规则,那么Qmake׃在这些规则中L所需要规则和命o。当Ӟ我们也可以用make的参?#8220;-r”?#8220;--no-builtin-rules”选项来取消所有的预设|的隐含规则?<br><br>当然Q即使是我们指定?#8220;-r”参数Q某些隐含规则还是会生效Q因为有许多的隐含规则都是用了“后缀规则”来定义的Q所以,只要隐含规则中有“后缀列表”Q也׃pȝ定义在目?SUFFIXES的依赖目标)Q那么隐含规则就会生效。默认的后缀列表是:.out, .a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el。具体的l节Q我们会在后面讲q?<br><br>q是先来看一看常用的隐含规则吧?<br><br>1、编译CE序的隐含规则?<br>“<n>;.o”的目标的依赖目标会自动推gؓ“<n>;.c”Qƈ且其生成命o?#8220;$(CC) –c $(CPPFLAGS) $(CFLAGS)” <br><br>2、编译C++E序的隐含规则?<br>“<n>;.o”的目标的依赖目标会自动推gؓ“<n>;.cc”或是“<n>;.C”Qƈ且其生成命o?#8220;$(CXX) –c $(CPPFLAGS) $(CFLAGS)”。(使用“.cc”作ؓC++源文件的后缀Q而不?#8220;.C”Q?<br><br>3、编译PascalE序的隐含规则?<br>“<n>;.o”的目标的依赖目标会自动推gؓ“<n>;.p”Qƈ且其生成命o?#8220;$(PC) –c  $(PFLAGS)”?<br><br>4、编译Fortran/RatforE序的隐含规则?<br>“<n>;.o”的目标的依赖目标会自动推gؓ“<n>;.r”?#8220;<n>;.F”?#8220;<n>;.f”Qƈ且其生成命o? <br>    “.f”  “$(FC) –c  $(FFLAGS)” <br>    “.F”  “$(FC) –c  $(FFLAGS) $(CPPFLAGS)” <br>    “.f”  “$(FC) –c  $(FFLAGS) $(RFLAGS)” <br><br>5、预处理Fortran/RatforE序的隐含规则?<br>“<n>;.f”的目标的依赖目标会自动推gؓ“<n>;.r”?#8220;<n>;.F”。这个规则只是{换Ratfor或有预处理的FortranE序C个标准的FortranE序。其使用的命令是Q?<br>    “.F”  “$(FC) –F $(CPPFLAGS) $(FFLAGS)” <br>    “.r”  “$(FC) –F $(FFLAGS) $(RFLAGS)” <br><br>6、编译Modula-2E序的隐含规则?<br>“<n>;.sym”的目标的依赖目标会自动推gؓ“<n>;.def”Qƈ且其生成命o是:“$(M2C) $(M2FLAGS) $(DEFFLAGS)”?#8220;<n.o>;” 的目标的依赖目标会自动推gؓ“<n>;.mod”Qƈ且其生成命o是:“$(M2C) $(M2FLAGS) $(MODFLAGS)”?<br><br>7、汇~和汇编预处理的隐含规则?<br>“<n>;.o” 的目标的依赖目标会自动推gؓ“<n>;.s”Q默认用编译品“as”Qƈ且其生成命o是:“$(AS) $(ASFLAGS)”?#8220;<n>;.s” 的目标的依赖目标会自动推gؓ“<n>;.S”Q默认用C预编译器“cpp”Qƈ且其生成命o是:“$(AS) $(ASFLAGS)”?<br><br>8、链接Object文g的隐含规则?<br>“<n>;”目标依赖?#8220;<n>;.o”Q通过q行C的编译器来运行链接程序生成(一般是“ld”Q,其生成命令是Q?#8220;$(CC) $(LDFLAGS) <n>;.o $(LOADLIBES) $(LDLIBS)”。这个规则对于只有一个源文g的工E有效,同时也对多个Object文gQ由不同的源文g生成Q的也有效。例如如下规则: <br><br>    x : y.o z.o <br><br>q且“x.c”?#8220;y.c”?#8220;z.c”都存在时Q隐含规则将执行如下命oQ?<br><br>    cc -c x.c -o x.o <br>    cc -c y.c -o y.o <br>    cc -c z.c -o z.o <br>    cc x.o y.o z.o -o x <br>    rm -f x.o <br>    rm -f y.o <br>    rm -f z.o <br><br>如果没有一个源文gQ如上例中的x.cQ和你的目标名字Q如上例中的xQ相兌Q那么,你最好写q生成规则Q不Ӟ隐含规则会报错的?<br><br>9、Yacc CE序时的隐含规则?<br>“<n>;.c”的依赖文件被自动推导?#8220;n.y”QYacc生成的文ӞQ其生成命o是:“$(YACC) $(YFALGS)”。(“Yacc”是一个语法分析器Q关于其l节h看相兌料) <br><br>10、Lex CE序时的隐含规则?<br>“<n>;.c”的依赖文件被自动推导?#8220;n.l”QLex生成的文ӞQ其生成命o是:“$(LEX) $(LFALGS)”。(关于“Lex”的细节请查看相关资料Q?<br><br>11、Lex RatforE序时的隐含规则?<br>“<n>;.r”的依赖文件被自动推导?#8220;n.l”QLex生成的文ӞQ其生成命o是:“$(LEX) $(LFALGS)”?<br><br>12、从CE序、Yacc文g或Lex文g创徏Lint库的隐含规则?<br>“<n>;.ln” Qlint生成的文Ӟ的依赖文件被自动推导?#8220;n.c”Q其生成命o是:“$(LINT) $(LINTFALGS) $(CPPFLAGS) -i”。对?#8220;<n>;.y”?#8220;<n>;.l”也是同样的规则?<br><br><br>三、隐含规则用的变量 <br><br>在隐含规则中的命令中Q基本上都是使用了一些预先设|的变量。你可以在你的makefile中改变这些变量的|或是在make的命令行中传入这些|或是在你的环境变量中讄q些|无论怎么P只要讄了这些特定的变量Q那么其׃寚w含规则v作用。当Ӟ你也可以利用make?#8220;-R”?#8220;--no–builtin-variables”参数来取消你所定义的变量对隐含规则的作用?<br><br>例如Q第一条隐含规则——编译CE序的隐含规则的命o?#8220;$(CC) –c $(CFLAGS) $(CPPFLAGS)”。Make默认的编译命令是“cc”Q如果你把变?#8220;$(CC)”重定义成“gcc”Q把变量“$(CFLAGS)”重定义成“-g”Q那么,隐含规则中的命o全部会以“gcc –c -g $(CPPFLAGS)”的样子来执行了?<br><br>我们可以把隐含规则中使用的变量分成两U:一U是命o相关的,?#8220;CC”Q一U是参数相的养I?#8220;CFLAGS”。下面是所有隐含规则中会用到的变量Q?<br><br>1、关于命令的变量?<br><br>AR  <br>    函数库打包程序。默认命令是“ar”?nbsp; <br>AS  <br>    汇编语言~译E序。默认命令是“as”?<br>CC  <br>    C语言~译E序。默认命令是“cc”?<br>CXX  <br>    C++语言~译E序。默认命令是“g++”?<br>CO  <br>    ?nbsp;RCS文g中扩展文件程序。默认命令是“co”?<br>CPP  <br>    CE序的预处理器(输出是标准输备)。默认命令是“$(CC) –E”?<br>FC  <br>    Fortran ?nbsp;Ratfor 的编译器和预处理E序。默认命令是“f77”?<br>GET  <br>    从SCCS文g中扩展文件的E序。默认命令是“get”?nbsp; <br>LEX  <br>    LexҎ分析器程序(针对于C或RatforQ。默认命令是“lex”?<br>PC  <br>    Pascal语言~译E序。默认命令是“pc”?<br>YACC  <br>    Yacc文法分析器(针对于CE序Q。默认命令是“yacc”?<br>YACCR  <br>    Yacc文法分析器(针对于RatforE序Q。默认命令是“yacc –r”?<br>MAKEINFO  <br>    转换Texinfo源文Ӟ.texiQ到Info文gE序。默认命令是“makeinfo”?<br>TEX  <br>    从TeX源文件创建TeX DVI文g的程序。默认命令是“tex”?<br>TEXI2DVI  <br>    从Texinfo源文件创建军TeX DVI 文g的程序。默认命令是“texi2dvi”?<br>WEAVE  <br>    转换Web到TeX的程序。默认命令是“weave”?<br>CWEAVE  <br>    转换C Web ?nbsp;TeX的程序。默认命令是“cweave”?<br>TANGLE  <br>    转换Web到Pascal语言的程序。默认命令是“tangle”?<br>CTANGLE  <br>    转换C Web ?nbsp;C。默认命令是“ctangle”?<br>RM  <br>    删除文g命o。默认命令是“rm –f”?<br><br>2、关于命令参数的变量 <br><br>下面的这些变量都是相关上面的命o的参数。如果没有指明其默认|那么光认值都是空?<br><br>ARFLAGS  <br>    函数库打包程序AR命o的参数。默认值是“rv”?<br>ASFLAGS  <br>    汇编语言~译器参数。(当明昑֜调用“.s”?#8220;.S”文gӞ?nbsp; <br>CFLAGS  <br>    C语言~译器参数?<br>CXXFLAGS  <br>    C++语言~译器参数?<br>COFLAGS  <br>    RCS命o参数?nbsp; <br>CPPFLAGS  <br>    C预处理器参数。( C ?nbsp;Fortran ~译器也会用刎ͼ?<br>FFLAGS  <br>    Fortran语言~译器参数?<br>GFLAGS  <br>    SCCS “get”E序参数?<br>LDFLAGS  <br>    链接器参数。(如:“ld”Q?<br>LFLAGS  <br>    Lex文法分析器参数?<br>PFLAGS  <br>    Pascal语言~译器参数?<br>RFLAGS  <br>    Ratfor E序的Fortran ~译器参数?<br>YFLAGS  <br>    Yacc文法分析器参数?nbsp; <br><br><br>四、隐含规则链 <br><br>有些时候,一个目标可能被一pd的隐含规则所作用。例如,一个[.o]的文件生成,可能会是先被Yacc的[.y]文g先成[.c]Q然后再被C的编译器生成。我们把q一pd的隐含规则叫?#8220;隐含规则?#8221;?<br><br>在上面的例子中,如果文g[.c]存在Q那么就直接调用C的编译器的隐含规则,如果没有[.c]文gQ但有一个[.y]文gQ那么Yacc的隐含规则会被调用,生成[.c]文gQ然后,再调用C~译的隐含规则最l由[.c]生成[.o]文gQ达到目标?<br><br>我们把这U[.c]的文Ӟ或是目标Q,叫做中间目标。不怎么Pmake会努力自动推导生成目标的一切方法,不管中间目标有多,光会执着地把所有的隐含规则和你书写的规则全部合h分析Q努力达到目标,所以,有些时候,可能会让你觉得奇怪,怎么我的目标会这L成?怎么我的makefile发疯了? <br><br>在默认情况下Q对于中间目标,它和一般的目标有两个地Ҏ不同Q第一个不同是除非中间的目标不存在Q才会引发中间规则。第二个不同的是Q只要目标成功生,那么Q生最l目标过E中Q所产生的中间目标文件会被以“rm -f”删除?<br><br>通常Q一个被makefile指定成目标或是依赖目标的文g不能被当作中介。然而,你可以明昑֜说明一个文件或是目标是中介目标Q你可以使用伪目?#8220;.INTERMEDIATE”来强制声明。(如:.INTERMEDIATE Q?nbsp;mid Q?<br><br>你也可以Lmake自动删除中间目标Q要做到q一点,你可以用伪目标“.SECONDARY”来强制声明(如:.SECONDARY : secQ。你q可以把你的目标Q以模式的方式来指定Q如Q?.oQ成伪目?#8220;.PRECIOUS”的依赖目标,以保存被隐含规则所生成的中间文件?<br><br>?#8220;隐含规则?#8221;中,止同一个目标出Cơ或两次以上Q这样一来,可防止在make自动推导时出现无限递归的情c?<br><br>Make会优化一些特D的隐含规则Q而不生成中间文g。如Q从文g“foo.c”生成目标E序“foo”Q按道理Qmake会编译生成中间文?#8220;foo.o”Q然后链接成“foo”Q但在实际情况下Q这一动作可以被一?#8220;cc”的命令完成(cc –o foo foo.cQ,于是优化q的规则׃会生成中间文件?br><br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 11:19 <a href="http://www.shnenglu.com/ivenher/articles/22110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 make 的运? 二十?/title><link>http://www.shnenglu.com/ivenher/articles/22108.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 03:17:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22108.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22108.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22108.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22108.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22108.html</trackback:ping><description><![CDATA[make 的运?<br>—————?<br><br>一般来_最单的是直接在命令行下输入make命oQmake命o会找当前目录的makefile来执行,一切都是自动的。但也有时你也许只想让make重编译某些文Ӟ而不是整个工E,而又有的时候你有几套编译规则,你想在不同的时候用不同的~译规则Q等{。本章节是讲述如何使用make命o的?<br><br>一、make的退出码 <br><br>make命o执行后有三个退出码Q?<br><br>    0 —?nbsp;表示成功执行?<br>    1 —?nbsp;如果makeq行时出CQ何错误,其返??<br>    2 —?nbsp;如果你用了make?#8220;-q”选项Qƈ且make使得一些目标不需要更斎ͼ那么q回2?<br><br>Make的相兛_数我们会在后l章节中讲述?<br><br><br>二、指定Makefile <br><br>前面我们说过QGNU make扑֯默认的Makefile的规则是在当前目录下依次找三个文件—?#8220;GNUmakefile”?#8220;makefile”?#8220;Makefile”。其按顺序找q三个文Ӟ一旦找刎ͼ开始读取这个文件ƈ执行?<br><br>当前Q我们也可以lmake命o指定一个特D名字的Makefile。要辑ֈq个功能Q我们要使用make?#8220;-f”或是“--file”参数Q?#8220;--makefile”参数也行Q。例如,我们有个makefile的名字是“hchen.mk”Q那么,我们可以q样来让make来执行这个文Ӟ <br><br>    make –f hchen.mk <br><br>如果在make的命令行是,你不只一ơ地使用?#8220;-f”参数Q那么,所有指定的makefile会被连在一起传递给make执行?<br><br><br>三、指定目?<br><br>一般来_make的最l目标是makefile中的W一个目标,而其它目标一般是p个目标连带出来的。这是make的默认行为。当Ӟ一般来_你的makefile中的W一个目标是p多个目标l成Q你可以指示makeQ让其完成你所指定的目标。要辑ֈq一目的很简单,需在make命o后直接跟目标的名字就可以完成Q如前面提到?#8220;make clean”形式Q?<br><br>M在makefile中的目标都可以被指定成终极目标,但是除了?#8220;-”打头Q或是包含了“=”的目标,因ؓ有这些字W的目标Q会被解析成命o行参数或是变量。甚x有被我们明确写出来的目标也可以成为make的终极目标,也就是说Q只要make可以扑ֈ光含规则推D则,那么q个隐含目标同样可以被指定成l极目标?<br><br>有一个make的环境变量叫“MAKECMDGOALS”Q这个变量中会存放你所指定的终极目标的列表Q如果在命o行上Q你没有指定目标Q那么,q个变量是空倹{这个变量可以让你用在一些比较特D的情Ş下。比如下面的例子Q?<br><br>    sources = foo.c bar.c <br>    ifneq ( $(MAKECMDGOALS),clean) <br>    include $(sources:.c=.d) <br>    endif <br><br>Z上面的这个例子,只要我们输入的命令不?#8220;make clean”Q那么makefile会自动包?#8220;foo.d”?#8220;bar.d”q两个makefile?<br><br>使用指定l极目标的方法可以很方便地让我们~译我们的程序,例如下面q个例子Q?<br><br>    .PHONY: all <br>    all: prog1 prog2 prog3 prog4 <br><br>从这个例子中Q我们可以看刎ͼq个makefile中有四个需要编译的E序—?#8220;prog1”Q?nbsp;“prog2”Q?nbsp;“prog3”?nbsp;“prog4”Q我们可以?#8220;make all”命o来编译所有的目标Q如果把all|成W一个目标,那么只需执行“make”Q,我们也可以?#8220;make prog2”来单独编译目?#8220;prog2”?<br><br>即然make可以指定所有makefile中的目标Q那么也包括“伪目?#8221;Q于是我们可以根据这U性质来让我们的makefileҎ指定的不同的目标来完成不同的事。在Unix世界中,软g发布Ӟ特别是GNUq种开源Y件的发布Ӟ其makefile都包含了~译、安装、打包等功能。我们可以参照这U规则来书写我们的makefile中的目标?<br><br>     “all” <br>        q个伪目标是所有目标的目标Q其功能一般是~译所有的目标?<br>     “clean” <br>        q个伪目标功能是删除所有被make创徏的文件?<br>     “install” <br>        q个伪目标功能是安装已编译好的程序,其实是把目标执行文件拷贝到指定的目标中厅R?<br>     “print” <br>        q个伪目标的功能是例出改变过的源文g?<br>     “tar” <br>        q个伪目标功能是把源E序打包备䆾。也是一个tar文g?<br>     “dist” <br>        q个伪目标功能是创徏一个压~文Ӟ一般是把tar文g压成Z文g。或是gz文g?<br>     “TAGS” <br>        q个伪目标功能是更新所有的目标Q以备完整地重编译用?<br>     “check”?#8220;test” <br>        q两个伪目标一般用来测试makefile的流E?<br><br>当然一个项目的makefile中也不一定要书写q样的目标,q些东西都是GNU的东西,但是我想QGNU搞出q些东西一定有其可取之处({你的UNIX下的E序文g一多时你就会发现这些功能很有用了)Q这里只不过是说明了Q如果你要书写这U功能,最好用这U名字命名你的目标,q样规范一些,规范的好处就是——不用解释,大家都明白。而且如果你的makefile中有q些功能Q一是很实用Q二是可以显得你的makefile很专业(不是那种初学者的作品Q?<br><br><br>四、检查规?<br><br>有时候,我们不想让我们的makefile中的规则执行hQ我们只x查一下我们的命oQ或是执行的序列。于是我们可以用make命o的下q参敎ͼ <br><br>    “-n” <br>    “--just-print” <br>    “--dry-run” <br>    “--recon” <br>    不执行参敎ͼq些参数只是打印命oQ不目标是否更斎ͼ把规则和q带规则下的命o打印出来Q但不执行,q些参数对于我们调试makefile很有用处?<br><br>    “-t” <br>    “--touch” <br>    q个参数的意思就是把目标文g的时间更斎ͼ但不更改目标文g。也是_make假装~译目标Q但不是真正的编译目标,只是把目标变成已~译q的状态?<br><br>    “-q” <br>    “--question” <br>    q个参数的行为是扄标的意思,也就是说Q如果目标存在,那么其什么也不会输出Q当然也不会执行~译Q如果目标不存在Q其会打印出一条出错信息?<br><br>    “-W <file>;” <br>    “--what-if=<file>;” <br>    “--assume-new=<file>;” <br>    “--new-file=<file>;” <br>    q个参数需要指定一个文件。一般是是源文gQ或依赖文gQ,Make会根据规则推导来q行依赖于这个文件的命oQ一般来_可以?#8220;-n”参数一同用,来查看这个依赖文件所发生的规则命令?<br><br>另外一个很有意思的用法是结?#8220;-p”?#8220;-v”来输出makefile被执行时的信息(q个在后面讲述Q?<br><br><br>五、make的参?<br><br>下面列D了所有GNU make 3.80版的参数定义。其它版本和产商的make大同异Q不q其它商的make的具体参数还是请参考各自的产品文档?<br><br>“-b” <br>“-m” <br>q两个参数的作用是忽略和其它版本make的兼Ҏ?<br><br>“-B” <br>“--always-make” <br>认ؓ所有的目标都需要更斎ͼ重编译)?<br><br>“-C <dir>;” <br>“--directory=<dir>;” <br>指定dmakefile的目录。如果有多个“-C”参数Qmake的解释是后面的\径以前面的作为相对\径,q以最后的目录作ؓ被指定目录。如Q?#8220;make –C ~hchen/test –C prog”{h?#8220;make –C ~hchen/test/prog”?<br><br>“—debug[=<options>;]” <br>输出make的调试信息。它有几U不同的U别可供选择Q如果没有参敎ͼ那就是输出最单的调试信息。下面是<options>;的取| <br>    a —?nbsp;也就是allQ输出所有的调试信息。(会非常的多) <br>    b —?nbsp;也就是basicQ只输出单的调试信息。即输出不需要重~译的目标?<br>    v —?nbsp;也就是verboseQ在b选项的别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文gQ或是依赖目标){?<br>    i —?nbsp;也就是implicitQ输出所以的隐含规则?<br>    j —?nbsp;也就是jobsQ输出执行规则中命o的详l信息,如命令的PID、返回码{?<br>    m —?nbsp;也就是makefileQ输出makedmakefileQ更新makefileQ执行makefile的信息?<br><br>“-d” <br>相当?#8220;--debug=a”?<br><br>“-e” <br>“--environment-overrides” <br>指明环境变量的D盖makefile中定义的变量的倹{?<br><br>“-f=<file>;” <br>“--file=<file>;” <br>“--makefile=<file>;” <br>指定需要执行的makefile?<br><br>“-h” <br>“--help” <br>昄帮助信息?<br><br>“-i” <br>“--ignore-errors” <br>在执行时忽略所有的错误?<br><br>“-I <dir>;” <br>“--include-dir=<dir>;” <br>指定一个被包含makefile的搜索目标。可以用多?#8220;-I”参数来指定多个目录?<br><br>“-j [<jobsnum>;]” <br>“--jobs[=<jobsnum>;]” <br>指同时运行命令的个数。如果没有这个参敎ͼmakeq行命o时能q行多少p行多。如果有一个以上的“-j”参数Q那么仅最后一?#8220;-j”才是有效的。(注意q个参数在MS-DOS中是无用的) <br><br>“-k” <br>“--keep-going” <br>出错也不停止q行。如果生成一个目标失败了Q那么依赖于其上的目标就不会被执行了?<br><br>“-l <load>;” <br>“--load-average[=<load]” <br>“—max-load[=<load>;]” <br>指定makeq行命o的负载?<br><br>“-n” <br>“--just-print” <br>“--dry-run” <br>“--recon” <br>仅输出执行过E中的命令序列,但ƈ不执行?<br><br>“-o <file>;” <br>“--old-file=<file>;” <br>“--assume-old=<file>;” <br>不重新生成的指定?lt;file>;Q即使这个目标的依赖文gC它?<br><br>“-p” <br>“--print-data-base” <br>输出makefile中的所有数据,包括所有的规则和变量。这个参C让一个简单的makefile都会输出一堆信息。如果你只是惌Z息而不x行makefileQ你可以使用“make -qp”命o。如果你x看执行makefile前的预设变量和规则,你可以?#8220;make –p –f /dev/null”。这个参数输出的信息会包含着你的makefile文g的文件名和行P所以,用这个参数来调试你的makefile会是很有用的Q特别是当你的环境变量很复杂的时候?<br><br>“-q” <br>“--question” <br>不运行命令,也不输出。仅仅是查所指定的目标是否需要更新。如果是0则说明要更新Q如果是2则说明有错误发生?<br><br>“-r” <br>“--no-builtin-rules” <br>止make使用M隐含规则?<br><br>“-R” <br>“--no-builtin-variabes” <br>止make使用M作用于变量上的隐含规则?<br><br>“-s” <br>“--silent” <br>“--quiet” <br>在命令运行时不输出命令的输出?<br><br>“-S” <br>“--no-keep-going” <br>“--stop” <br>取消“-k”选项的作用。因为有些时候,make的选项是从环境变量“MAKEFLAGS”中承下来的。所以你可以在命令行中用这个参数来让环境变量中?#8220;-k”选项失效?<br><br>“-t” <br>“--touch” <br>相当于UNIX的touch命oQ只是把目标的修Ҏ期变成最新的Q也是L生成目标的命令运行?<br><br>“-v” <br>“--version” <br>输出makeE序的版本、版权等关于make的信息?<br><br>“-w” <br>“--print-directory” <br>输出q行makefile之前和之后的信息。这个参数对于跟t嵌套式调用make时很有用?<br><br>“--no-print-directory” <br>止“-w”选项?<br><br>“-W <file>;” <br>“--what-if=<file>;” <br>“--new-file=<file>;” <br>“--assume-file=<file>;” <br>假定目标<file>;需要更斎ͼ如果?#8220;-n”选项使用Q那么这个参C输出该目标更新时的运行动作。如果没?#8220;-n”那么像q行UNIX?#8220;touch”命o一P使得<file>;的修Ҏ间ؓ当前旉?<br><br>“--warn-undefined-variables” <br>只要make发现有未定义的变量,那么p告信息?br><br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22108.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 11:17 <a href="http://www.shnenglu.com/ivenher/articles/22108.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 函数 foreach if call origin shell 控制make函数 二十?/title><link>http://www.shnenglu.com/ivenher/articles/22107.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 03:15:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22107.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22107.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22107.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22107.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22107.html</trackback:ping><description><![CDATA[四、foreach 函数 <br>  <br><br>foreach函数和别的函数非常的不一栗因个函数是用来做@环用的,Makefile中的foreach函数几乎是仿照于Unix标准ShellQ?bin/shQ中的for语句Q或是C-ShellQ?bin/cshQ中的foreach语句而构建的。它的语法是Q?<br><br>  <br><br>    $(foreach <var>;,<list>;,<text>;) <br><br>  <br><br>q个函数的意思是Q把参数<list>;中的单词逐一取出攑ֈ参数<var>;所指定的变量中Q然后再执行<text>;所包含的表辑ּ。每一?lt;text>;会返回一个字W串Q@环过E中Q?lt;text>;的所q回的每个字W串会以I格分隔Q最后当整个循环l束Ӟ<text>;所q回的每个字W串所l成的整个字W串Q以I格分隔Q将会是foreach函数的返回倹{?<br><br>  <br><br>所以,<var>;最好是一个变量名Q?lt;list>;可以是一个表辑ּQ?lt;text>;中一般会使用<var>;q个参数来依ơ枚?lt;list>;中的单词。D个例子: <br><br>  <br><br>    names := a b c d <br><br>    files := $(foreach n,$(names),$(n).o) <br><br>  <br><br>上面的例子中Q?(name)中的单词会被挨个取出Qƈ存到变量“n”中,“$(n).o”每次Ҏ“$(n)”计算Z个|q些gI格分隔Q最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”?<br><br>  <br><br>注意Qforeach中的<var>;参数是一个时的局部变量,foreach函数执行完后Q参?lt;var>;的变量将不在作用Q其作用域只在foreach函数当中?<br><br>  <br><br>  <br><br>五、if 函数 <br>  <br><br>if函数很像GNU的make所支持的条件语句——ifeqQ参见前面所q的章节Q,if函数的语法是Q?<br><br>  <br><br>    $(if <condition>;,<then-part>;)  <br><br>  <br><br>或是 <br><br>  <br><br>    $(if <condition>;,<then-part>;,<else-part>;) <br><br>  <br><br>可见Qif函数可以包含“else”部分Q或是不含。即if函数的参数可以是两个Q也可以是三个?lt;condition>;参数是if的表辑ּQ如果其q回的ؓ非空字符Ԍ那么q个表达式就相当于返回真Q于是,<then-part>;会被计算Q否?lt;else-part>;会被计算?<br><br>  <br><br>而if函数的返回值是Q如?lt;condition>;为真Q非I字W串Q,那个<then-part>;会是整个函数的返回|如果<condition>;为假Q空字符ԌQ那?lt;else-part>;会是整个函数的返回|此时如果<else-part>;没有被定义,那么Q整个函数返回空字串?<br><br>  <br><br>所以,<then-part>;?lt;else-part>;只会有一个被计算?<br><br>  <br><br>  <br><br>六、call函数 <br>  <br><br>call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,q个表达式中Q你可以定义许多参数Q然后你可以用call函数来向q个表达式传递参数。其语法是: <br><br>  <br><br>    $(call <expression>;,<parm1>;,<parm2>;,<parm3>;...) <br><br>  <br><br>当make执行q个函数Ӟ<expression>;参数中的变量Q如$(1)Q?(2)Q?(3){,会被参数<parm1>;Q?lt;parm2>;Q?lt;parm3>;依次取代。?lt;expression>;的返回值就是call函数的返回倹{例如: <br><br>    reverse =  $(1) $(2) <br><br>    foo = $(call reverse,a,b) <br><br><br><br>那么Qfoo的值就?#8220;a b”。当Ӟ参数的次序是可以自定义的Q不一定是序的,如: <br><br>  <br><br>    reverse =  $(2) $(1) <br><br>    foo = $(call reverse,a,b) <br><br><br><br>此时的foo的值就?#8220;b a”?<br><br>  <br><br>  <br><br>七、origin函数 <br>origin函数不像其它的函敎ͼ他ƈ不操作变量的|他只是告诉你你的q个变量是哪里来的?其语法是Q?<br><br>  <br><br>    $(origin <variable>;) <br><br>  <br><br>注意Q?lt;variable>;是变量的名字Q不应该是引用。所以你最好不要在<variable>;中?#8220;$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”Q下面,是origin函数的返回? <br><br>  <br><br>“undefined” <br><br>      如果<variable>;从来没有定义q,origin函数q回q个?#8220;undefined”?<br><br>  <br><br>“default” <br><br>      如果<variable>;是一个默认的定义Q比?#8220;CC”q个变量Q这U变量我们将在后面讲q?<br><br>  <br><br>“environment” <br><br>      如果<variable>;是一个环境变量,q且当Makefile被执行时Q?#8220;-e”参数没有被打开?<br><br>  <br><br>“file” <br><br>      如果<variable>;q个变量被定义在Makefile中?<br><br>  <br><br>“command line” <br><br>      如果<variable>;q个变量是被命o行定义的?<br><br>  <br><br>“override” <br><br>      如果<variable>;是被override指示W重新定义的?<br><br>  <br><br>“automatic” <br><br>      如果<variable>;是一个命令运行中的自动化变量。关于自动化变量在后面讲述?<br><br>  <br><br>q些信息对于我们~写Makefile是非常有用的Q例如,假设我们有一个Makefile其包了一个定义文件Make.defQ在Make.def中定义了一个变?#8220;bletch”Q而我们的环境中也有一个环境变?#8220;bletch”Q此Ӟ我们惛_断一下,如果变量来源于环境,那么我们把之重定义了,如果来源于Make.def或是命o行等非环境的Q那么我们就不重新定义它。于是,在我们的Makefile中,我们可以q样写: <br><br>  <br><br>    ifdef bletch <br><br>    ifeq "$(origin bletch)" "environment" <br><br>    bletch = barf, gag, etc. <br><br>    endif <br><br>    endif <br><br>  <br><br>当然Q你也许会说Q用override关键字不可以重新定义环境中的变量了吗?Z么需要用这L步骤Q是的,我们用override是可以达到这L效果Q可是overrideq于_暴Q它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的Q而不想重新定义命令行传来的?<br><br>  <br><br>  <br><br>八、shell函数 <br>  <br><br>shell函数也不像其它的函数。顾名思义Q它的参数应该就是操作系lShell的命令。它和反引号“`”是相同的功能。这是_shell函数把执行操作系l命令后的输Z为函数返回。于是,我们可以用操作系l命令以及字W串处理命oawkQsed{等命o来生成一个变量,如: <br><br>  <br><br>    contents := $(shell cat foo) <br><br>  <br><br>    files := $(shell echo *.c) <br><br>  <br><br>注意Q这个函C新生成一个ShellE序来执行命令,所以你要注意其q行性能Q如果你的Makefile中有一些比较复杂的规则Qƈ大量使用了这个函敎ͼ那么对于你的pȝ性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多?<br><br>  <br><br>  <br><br>九、控制make的函?<br>  <br><br>make提供了一些函数来控制make的运行。通常Q你需要检一些运行Makefile时的q行时信息,q且Ҏq些信息来决定,你是让makel箋执行Q还是停止?<br><br>  <br><br>$(error <text ...>;) <br><br>  <br><br>    产生一个致命的错误Q?lt;text ...>;是错误信息。注意,error函数不会在一被用就会生错误信息,所以如果你把其定义在某个变量中Qƈ在后l的脚本中用这个变量,那么也是可以的。例如: <br><br>  <br><br>    CZ一Q?<br><br>    ifdef ERROR_001 <br><br>    $(error error is $(ERROR_001)) <br><br>    endif <br><br>  <br><br>    CZ二: <br><br>    ERR = $(error found an error!) <br><br>    .PHONY: err <br><br>    err: ; $(ERR) <br><br>  <br><br>    CZ一会在变量ERROR_001定义了后执行时生error调用Q而示例二则在目录err被执行时才发生error调用?<br><br>  <br><br>$(warning <text ...>;) <br><br>  <br><br>     q个函数很像error函数Q只是它q不会让make退出,只是输出一D警告信息,而makel箋执行? <img src ="http://www.shnenglu.com/ivenher/aggbug/22107.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 11:15 <a href="http://www.shnenglu.com/ivenher/articles/22107.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 函数 字符?文g?二十一http://www.shnenglu.com/ivenher/articles/22105.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:11:00 GMThttp://www.shnenglu.com/ivenher/articles/22105.htmlhttp://www.shnenglu.com/ivenher/comments/22105.htmlhttp://www.shnenglu.com/ivenher/articles/22105.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22105.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22105.html

一、函数的调用语法

函数调用Q很像变量的使用Q也是以“$”来标识的Q其语法如下Q?

    $(<function>; <arguments>;)

或是

    ${<function>; <arguments>;}

q里Q?lt;function>;是函数名,make支持的函C多?lt;arguments>;是函数的参数Q参数间以逗号“,”分隔Q而函数名和参C间以“I格”分隔。函数调用以“$”开_以圆括号或花括号把函数名和参数括赗感觉很像一个变量,是不是?函数中的参数可以使用变量Qؓ了风格的l一Q函数和变量的括h好一P如?#8220;$(subst a,b,$(x))”q样的Ş式,而不?#8220;$(subst a,b,${x})”的Ş式。因为统一会更清楚Q也会减一些不必要的麻烦?

q是来看一个示例:

    comma:= ,
    empty:=
    space:= $(empty) $(empty)
    foo:= a b c
    bar:= $(subst $(space),$(comma),$(foo))

在这个示例中Q?(comma)的值是一个逗号?(space)使用?(empty)定义了一个空|$(foo)的值是“a b c”Q?(bar)的定义用Q调用了函数“subst”Q这是一个替换函敎ͼq个函数有三个参敎ͼW一个参数是被替换字ԌW二个参数是替换字串Q第三个参数是替换操作作用的字串。这个函C是?(foo)中的I格替换成逗号Q所?(bar)的值是“a,b,c”?


二、字W串处理函数

$(subst <from>;,<to>;,<text>;) 

    名称Q字W串替换函数——subst?
    功能Q把字串<text>;中的<from>;字符串替换成<to>;?
    q回Q函数返回被替换q后的字W串?

    CZQ?
        
        $(subst ee,EE,feet on the street)Q?
        
        ?#8220;feet on the street”中的“ee”替换?#8220;EE”Q返回结果是“fEEt on the strEEt”?


$(patsubst <pattern>;,<replacement>;,<text>;) 

    名称Q模式字W串替换函数——patsubst?
    功能Q查?lt;text>;中的单词Q单词以“I格”?#8220;Tab”?#8220;回R”“换行”分隔Q是否符合模?lt;pattern>;Q如果匹配的话,则以<replacement>;替换。这里,<pattern>;可以包括通配W?#8220;%”Q表CZQ意长度的字串。如?lt;replacement>;中也包含“%”Q那么,<replacement>;中的q个“%”是<pattern>;中的那个“%”所代表的字丌Ӏ(可以?#8220;\”来{义,?#8220;\%”来表C真实含义的“%”字符Q?
    q回Q函数返回被替换q后的字W串?

    CZQ?

        $(patsubst %.c,%.o,x.c.c bar.c)

        把字?#8220;x.c.c bar.c”W合模式[%.c]的单词替换成[%.o]Q返回结果是“x.c.o bar.o”

    备注Q?

        q和我们前面“变量章节”说过的相关知识有点相伹{如Q?

        “$(var:<pattern>;=<replacement>;)”
         相当?
        “$(patsubst <pattern>;,<replacement>;,$(var))”Q?

         ?#8220;$(var: <suffix>;=<replacement>;)”
         则相当于
         “$(patsubst %<suffix>;,%<replacement>;,$(var))”?

         例如有:objects = foo.o bar.o baz.oQ?
         那么Q?#8220;$(objects:.o=.c)”?#8220;$(patsubst %.o,%.c,$(objects))”是一L?

$(strip <string>;)

    名称Q去I格函数——strip?
    功能Q去?lt;string>;字串中开头和l尾的空字符?
    q回Q返回被LI格的字W串倹{?
    CZQ?
        
        $(strip a b c )

        把字?#8220;a b c ”d开头和l尾的空|l果?#8220;a b c”?

$(findstring <find>;,<in>;)

    名称Q查扑֭W串函数——findstring?
    功能Q在字串<in>;中查?lt;find>;字串?
    q回Q如果找刎ͼ那么q回<find>;Q否则返回空字符丌Ӏ?
    CZQ?

        $(findstring a,a b c)
        $(findstring a,b c)

        W一个函数返?#8220;a”字符ԌW二个返?#8220;”字符ԌI字W串Q?

$(filter <pattern...>;,<text>;)

    名称Q过滤函数——filter?
    功能Q以<pattern>;模式qo<text>;字符串中的单词,保留W合模式<pattern>;的单词。可以有多个模式?
    q回Q返回符合模?lt;pattern>;的字丌Ӏ?
    CZQ?

        sources := foo.c bar.c baz.s ugh.h
        foo: $(sources)
                cc $(filter %.c %.s,$(sources)) -o foo

        $(filter %.c %.s,$(sources))q回的值是“foo.c bar.c baz.s”?

$(filter-out <pattern...>;,<text>;)

    名称Q反qo函数——filter-out?
    功能Q以<pattern>;模式qo<text>;字符串中的单词,去除W合模式<pattern>;的单词。可以有多个模式?
    q回Q返回不W合模式<pattern>;的字丌Ӏ?
    CZQ?

        objects=main1.o foo.o main2.o bar.o
        mains=main1.o main2.o
        
        $(filter-out $(mains),$(objects)) q回值是“foo.o bar.o”?
        
$(sort <list>;)

    名称Q排序函数——sort?
    功能Q给字符?lt;list>;中的单词排序Q升序)?
    q回Q返回排序后的字W串?
    CZQ?(sort foo bar lose)q回“bar foo lose” ?
    备注Qsort函数会去?lt;list>;中相同的单词?

$(word <n>;,<text>;)

    名称Q取单词函数——word?
    功能Q取字符?lt;text>;中第<n>;个单词。(从一开始)
    q回Q返回字W串<text>;中第<n>;个单词。如?lt;n>;?lt;text>;中的单词数要大,那么q回I字W串?
    CZQ?(word 2, foo bar baz)q回值是“bar”?

$(wordlist <s>;,<e>;,<text>;)  

    名称Q取单词串函数——wordlist?
    功能Q从字符?lt;text>;中取?lt;s>;开始到<e>;的单词串?lt;s>;?lt;e>;是一个数字?
    q回Q返回字W串<text>;中从<s>;?lt;e>;的单词字丌Ӏ如?lt;s>;?lt;text>;中的单词数要大,那么q回I字W串。如?lt;e>;大于<text>;的单词数Q那么返回从<s>;开始,?lt;text>;l束的单词串?
    CZQ?nbsp;$(wordlist 2, 3, foo bar baz)q回值是“bar baz”?

$(words <text>;)

    名称Q单词个数统计函数——words?
    功能Q统?lt;text>;中字W串中的单词个数?
    q回Q返?lt;text>;中的单词数?
    CZQ?(words, foo bar baz)q回值是“3”?
    备注Q如果我们要?lt;text>;中最后的一个单词,我们可以q样Q?(word $(words <text>;),<text>;)?

$(firstword <text>;)

    名称Q首单词函数——firstword?
    功能Q取字符?lt;text>;中的W一个单词?
    q回Q返回字W串<text>;的第一个单词?
    CZQ?(firstword foo bar)q回值是“foo”?
    备注Q这个函数可以用word函数来实玎ͼ$(word 1,<text>;)?

以上Q是所有的字符串操作函敎ͼ如果搭配混合使用Q可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指?#8220;依赖文g”的搜索\径。于是,我们可以利用q个搜烦路径来指定编译器对头文g的搜索\径参数CFLAGSQ如Q?

    override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))

    如果我们?#8220;$(VPATH)”值是“src:../headers”Q那?#8220;$(patsubst %,-I%,$(subst :, ,$(VPATH)))”返?#8220;-Isrc -I../headers”Q这正是cc或gcc搜烦头文件\径的参数?


三、文件名操作函数

下面我们要介l的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一pd的文件名来对待?

$(dir <names...>;) 

    名称Q取目录函数——dir?
    功能Q从文g名序?lt;names>;中取出目录部分。目录部分是指最后一个反斜杠Q?#8220;/”Q之前的部分。如果没有反斜杠Q那么返?#8220;./”?
    q回Q返回文件名序列<names>;的目录部分?
    CZQ?nbsp;$(dir src/foo.c hacks)q回值是“src/ ./”?

$(notdir <names...>;) 

    名称Q取文g函数——notdir?
    功能Q从文g名序?lt;names>;中取出非目录部分。非目录部分是指最后一个反斜杠Q?#8220;/”Q之后的部分?
    q回Q返回文件名序列<names>;的非目录部分?
    CZQ?nbsp;$(notdir src/foo.c hacks)q回值是“foo.c hacks”?
 
$(suffix <names...>;) 
    
    名称Q取后缀函数——suffix?
    功能Q从文g名序?lt;names>;中取出各个文件名的后~?
    q回Q返回文件名序列<names>;的后~序列Q如果文件没有后~Q则q回I字丌Ӏ?
    CZQ?(suffix src/foo.c src-1.0/bar.c hacks)q回值是“.c .c”?

$(basename <names...>;)

    名称Q取前缀函数——basename?
    功能Q从文g名序?lt;names>;中取出各个文件名的前~部分?
    q回Q返回文件名序列<names>;的前~序列Q如果文件没有前~Q则q回I字丌Ӏ?
    CZQ?(basename src/foo.c src-1.0/bar.c hacks)q回值是“src/foo src-1.0/bar hacks”?

$(addsuffix <suffix>;,<names...>;) 

    名称Q加后缀函数——addsuffix?
    功能Q把后缀<suffix>;加到<names>;中的每个单词后面?
    q回Q返回加q后~的文件名序列?
    CZQ?(addsuffix .c,foo bar)q回值是“foo.c bar.c”?

$(addprefix <prefix>;,<names...>;) 

    名称Q加前缀函数——addprefix?
    功能Q把前缀<prefix>;加到<names>;中的每个单词后面?
    q回Q返回加q前~的文件名序列?
    CZQ?(addprefix src/,foo bar)q回值是“src/foo src/bar”?

$(join <list1>;,<list2>;)

    名称Q连接函数——join?
    功能Q把<list2>;中的单词对应地加?lt;list1>;的单词后面。如?lt;list1>;的单词个数要?lt;list2>;的多Q那么,<list1>;中的多出来的单词保持原栗如?lt;list2>;的单词个数要?lt;list1>;多,那么Q?lt;list2>;多出来的单词被复制?lt;list2>;中?
    q回Q返回连接过后的字符丌Ӏ?
    CZQ?(join aaa bbb , 111 222 333)q回值是“aaa111 bbb222 333”?br>


]]>
makefile详解 条g判断 二十http://www.shnenglu.com/ivenher/articles/22104.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:09:00 GMThttp://www.shnenglu.com/ivenher/articles/22104.htmlhttp://www.shnenglu.com/ivenher/comments/22104.htmlhttp://www.shnenglu.com/ivenher/articles/22104.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22104.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22104.html—————?

使用条g判断Q可以让makeҎq行时的不同情况选择不同的执行分支。条件表辑ּ可以是比较变量的|或是比较变量和常量的倹{?

一、示?

下面的例子,判断$(CC)变量是否“gcc”Q如果是的话Q则使用GNU函数~译目标?

    libs_for_gcc = -lgnu
    normal_libs =

    foo: $(objects)
    ifeq ($(CC),gcc)
            $(CC) -o foo $(objects) $(libs_for_gcc)
    else
            $(CC) -o foo $(objects) $(normal_libs)
    endif

可见Q在上面CZ的这个规则中Q目?#8220;foo”可以Ҏ变量“$(CC)”值来选取不同的函数库来编译程序?

我们可以从上面的CZ中看C个关键字Qifeq、else和endif。ifeq的意思表C条件语句的开始,q指定一个条件表辑ּQ表辑ּ包含两个参数Q以逗号分隔Q表辑ּ以圆括号括v。else表示条g表达式ؓ假的情况。endif表示一个条件语句的l束QQ何一个条件表辑ּ都应该以endifl束?

当我们的变量$(CC)值是“gcc”Ӟ目标foo的规则是Q?

    foo: $(objects)
            $(CC) -o foo $(objects) $(libs_for_gcc)

而当我们的变?(CC)g?#8220;gcc”Ӟ比如“cc”Q,目标foo的规则是Q?

    foo: $(objects)
            $(CC) -o foo $(objects) $(normal_libs)

当然Q我们还可以把上面的那个例子写得更简z一些:

    libs_for_gcc = -lgnu
    normal_libs =

    ifeq ($(CC),gcc)
      libs=$(libs_for_gcc)
    else
      libs=$(normal_libs)
    endif

    foo: $(objects)
            $(CC) -o foo $(objects) $(libs)


二、语?

条g表达式的语法为:

    <conditional-directive>;
    <text-if-true>;
    endif

以及Q?

    <conditional-directive>;
    <text-if-true>;
    else
    <text-if-false>;
    endif

其中<conditional-directive>;表示条g关键字,?#8220;ifeq”。这个关键字有四个?

W一个是我们前面所见过?#8220;ifeq”

    ifeq (<arg1>;, <arg2>;) 
    ifeq '<arg1>;' '<arg2>;' 
    ifeq "<arg1>;" "<arg2>;" 
    ifeq "<arg1>;" '<arg2>;' 
    ifeq '<arg1>;' "<arg2>;" 

比较参数“arg1”?#8220;arg2”的值是否相同。当Ӟ参数中我们还可以使用make的函数。如Q?

    ifeq ($(strip $(foo)),)
    <text-if-empty>;
    endif

q个CZ中用了“strip”函数Q如果这个函数的q回值是I(EmptyQ,那么<text-if-empty>;q效?

W二个条件关键字?#8220;ifneq”。语法是Q?

    ifneq (<arg1>;, <arg2>;) 
    ifneq '<arg1>;' '<arg2>;' 
    ifneq "<arg1>;" "<arg2>;" 
    ifneq "<arg1>;" '<arg2>;' 
    ifneq '<arg1>;' "<arg2>;" 

其比较参?#8220;arg1”?#8220;arg2”的值是否相同,如果不同Q则为真。和“ifeq”cM?

W三个条件关键字?#8220;ifdef”。语法是Q?

    ifdef <variable-name>; 

如果变量<variable-name>;的值非I,那到表达式ؓ真。否则,表达式ؓ假。当Ӟ<variable-name>;同样可以是一个函数的q回倹{注意,ifdef只是试一个变量是否有|其ƈ不会把变量扩展到当前位置。还是来看两个例子:

    CZ一Q?
    bar =
    foo = $(bar)
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    endif

    CZ二:
    foo =
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    endif

W一个例子中Q?#8220;$(frobozz)”值是“yes”Q第二个则是“no”?

W四个条件关键字?#8220;ifndef”。其语法是:

    ifndef <variable-name>;

q个我就不多说了Q和“ifdef”是相反的意思?

?lt;conditional-directive>;q一行上Q多余的I格是被允许的,但是不能以[Tab]键做为开始(不然p认ؓ是命令)。而注释符“#”同样也是安全的?#8220;else”?#8220;endif”也一P只要不是以[Tab]键开始就行了?

特别注意的是Qmake是在dMakefile时就计算条g表达式的|q根据条件表辑ּ的值来选择语句Q所以,你最好不要把自动化变量(?#8220;$@”{)攑օ条g表达式中Q因动化变量是在q行时才有的?

而且Qؓ了避免؜乱,make不允许把整个条g语句分成两部分放在不同的文g中?br>

]]>
makefile详解 多行变量 环境变量 目标变量 模式变量 十九http://www.shnenglu.com/ivenher/articles/22103.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:08:00 GMThttp://www.shnenglu.com/ivenher/articles/22103.htmlhttp://www.shnenglu.com/ivenher/comments/22103.htmlhttp://www.shnenglu.com/ivenher/articles/22103.html#Feedback1http://www.shnenglu.com/ivenher/comments/commentRss/22103.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22103.html 
q有一U设|变量值的Ҏ是用define关键字。用define关键字设|变量的值可以有换行Q这有利于定义一pd的命令(前面我们讲过“命o?#8221;的技术就是利用这个关键字Q?

define指示W后面跟的是变量的名字,而重起一行定义变量的|定义是以endef关键字结束。其工作方式?#8220;=”操作W一栗变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开_所以如果你用define定义的命令变量中没有以[Tab]键开_那么make׃会把其认为是命o?

下面的这个示例展CZdefine的用法:

    define two-lines
    echo foo
    echo $(bar)
    endef


七、环境变?

makeq行时的pȝ环境变量可以在make开始运行时被蝲入到Makefile文g中,但是如果Makefile中已定义了这个变量,或是q个变量由make命o行带入,那么pȝ的环境变量的值将被覆盖。(如果make指定?#8220;-e”参数Q那么,pȝ环境变量覆盖Makefile中定义的变量Q?

因此Q如果我们在环境变量中设|了“CFLAGS”环境变量Q那么我们就可以在所有的Makefile中用这个变量了。这对于我们使用l一的编译参数有比较大的好处。如果Makefile中定义了CFLAGSQ那么则会用Makefile中的q个变量Q如果没有定义则使用pȝ环境变量的|一个共性和个性的l一Q很?#8220;全局变量”?#8220;局部变?#8221;的特性?

当make嵌套调用Ӟ参见前面?#8220;嵌套调用”章节Q,上层Makefile中定义的变量会以pȝ环境变量的方式传递到下层的Makefile中。当Ӟ默认情况下,只有通过命o行设|的变量会被传递。而定义在文g中的变量Q如果要向下层Makefile传递,则需要用exprot关键字来声明。(参见前面章节Q?

当然Q我q不推荐把许多的变量都定义在pȝ环境中,q样Q在我们执行不用的MakefileӞ拥有的是同一套系l变量,q可能会带来更多的麻烦?


八、目标变?

前面我们所讲的在Makefile中定义的变量都是“全局变量”Q在整个文gQ我们都可以讉Kq些变量。当Ӟ“自动化变?#8221;除外Q如“$<”{这U类量的自动化变量就属于“规则型变?#8221;Q这U变量的g赖于规则的目标和依赖目标的定义?

当然Q我样同样可以ؓ某个目标讄局部变量,q种变量被称?#8220;Target-specific Variable”Q它可以?#8220;全局变量”同名Q因为它的作用范围只在这条规则以及连带规则中Q所以其g只在作用范围内有效。而不会媄响规则链以外的全局变量的倹{?

其语法是Q?

    <target ...>; : <variable-assignment>;

    <target ...>; : overide <variable-assignment>;

<variable-assignment>;可以是前面讲q的各种赋D辑ּQ如“=”?#8220;:=”?#8220;+=”或是“Q?”。第二个语法是针对于make命o行带入的变量Q或是系l环境变量?

q个Ҏ非常的有用Q当我们讄了这样一个变量,q个变量会作用到p个目标所引发的所有的规则中去。如Q?

    prog : CFLAGS = -g
    prog : prog.o foo.o bar.o
            $(CC) $(CFLAGS) prog.o foo.o bar.o

    prog.o : prog.c
            $(CC) $(CFLAGS) prog.c

    foo.o : foo.c
            $(CC) $(CFLAGS) foo.c

    bar.o : bar.c
            $(CC) $(CFLAGS) bar.c
 
在这个示例中Q不全局?(CFLAGS)的值是什么,在prog目标Q以及其所引发的所有规则中Qprog.o foo.o bar.o的规则)Q?(CFLAGS)的值都?#8220;-g”


九、模式变?

在GNU的make中,q支持模式变量(Pattern-specific VariableQ,通过上面的目标变量中Q我们知道,变量可以定义在某个目标上。模式变量的好处是Q我们可以给定一U?#8220;模式”Q可以把变量定义在符合这U模式的所有目标上?

我们知道Qmake?#8220;模式”一般是臛_含有一?#8220;%”的,所以,我们可以以如下方式给所有以[.o]l尾的目标定义目标变量:

    %.o : CFLAGS = -O

同样Q模式变量的语法?#8220;目标变量”一P

    <pattern ...>; : <variable-assignment>;

    <pattern ...>; : override <variable-assignment>;

override同样是针对于pȝ环境传入的变量,或是make命o行指定的变量?nbsp;
 


]]>
makefile详解 变量高用法 q加变量?override 十八http://www.shnenglu.com/ivenher/articles/22102.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:07:00 GMThttp://www.shnenglu.com/ivenher/articles/22102.htmlhttp://www.shnenglu.com/ivenher/comments/22102.htmlhttp://www.shnenglu.com/ivenher/articles/22102.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22102.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22102.html
q里介绍两种变量的高U用方法,W一U是变量值的替换?

我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”Q其意思是Q把变量“var”中所有以“a”字串“l尾”?#8220;a”替换?#8220;b”字串。这里的“l尾”意思是“I格”或是“l束W?#8221;?

q是看一个示例吧Q?

    foo := a.o b.o c.o
    bar := $(foo:.o=.c)

q个CZ中,我们先定义了一?#8220;$(foo)”变量Q而第二行的意思是?#8220;$(foo)”中所有以“.o”字串“l尾”全部替换?#8220;.c”Q所以我们的“$(bar)”的值就?#8220;a.c b.c c.c”?

另外一U变量替换的技术是?#8220;静态模?#8221;Q参见前面章节)定义的,如:

    foo := a.o b.o c.o
    bar := $(foo:%.o=%.c)

q依赖于被替换字串中的有相同的模式,模式中必d含一?#8220;%”字符Q这个例子同栯$(bar)变量的gؓ“a.c b.c c.c”?nbsp;

W二U高U用法是—?#8220;把变量的值再当成变量”。先看一个例子:

    x = y
    y = z
    a := $($(x))

在这个例子中Q?(x)的值是“y”Q所?($(x))是$(y)Q于?(a)的值就?#8220;z”。(注意Q是“x=y”Q而不?#8220;x=$(y)”Q?

我们q可以用更多的层次Q?

    x = y
    y = z
    z = u
    a := $($($(x)))

q里?(a)的值是“u”Q相关的推导留给读者自己去做吧?

让我们再复杂一点,使用?#8220;在变量定义中使用变量”的第一个方式,来看一个例子:

    x = $(y)
    y = z
    z = Hello
    a := $($(x))

q里?($(x))被替换成?($(y))Q因?(y)值是“z”Q所以,最l结果是Qa:=$(z)Q也是“Hello”?

再复杂一点,我们再加上函敎ͼ

    x = variable1
    variable2 := Hello
    y = $(subst 1,2,$(x))
    z = y
    a := $($($(z)))

q个例子中,“$($($(z)))”扩展?#8220;$($(y))”Q而其再次被扩展ؓ“$($(subst 1,2,$(x)))”?(x)的值是“variable1”Qsubst函数?#8220;variable1”中的所?#8220;1”字串替换?#8220;2”字串Q于是,“variable1”变成“variable2”Q再取其|所以,最l,$(a)的值就?(variable2)的值—?#8220;Hello”。(喔,好不ҎQ?

在这U方式中Q或要可以用多个变量来l成一个变量的名字Q然后再取其|

    first_second = Hello
    a = first
    b = second
    all = $($a_$b)

q里?#8220;$a_$b”l成?#8220;first_second”Q于是,$(all)的值就?#8220;Hello”?

再来看看l合W一U技术的例子Q?

    a_objects := a.o b.o c.o
    1_objects := 1.o 2.o 3.o

    sources := $($(a1)_objects:.o=.c)

q个例子中,如果$(a1)的值是“a”的话Q那么,$(sources)的值就?#8220;a.c b.c c.c”Q如?(a1)的值是“1”Q那?(sources)的值是“1.c 2.c 3.c”?

再来看一个这U技术和“函数”?#8220;条g语句”一同用的例子Q?

    ifdef do_sort
    func := sort
    else
    func := strip
    endif

    bar := a d b g q c

    foo := $($(func) $(bar))

q个CZ中,如果定义?#8220;do_sort”Q那么:foo := $(sort a d b g q c)Q于?(foo)的值就?#8220;a b c d g q”Q而如果没有定?#8220;do_sort”Q那么:foo := $(sort a d b g q c)Q调用的是strip函数?

当然Q?#8220;把变量的值再当成变量”q种技术,同样可以用在操作W的左边Q?

    dir = foo
    $(dir)_sources := $(wildcard $(dir)/*.c)
    define $(dir)_print
    lpr $($(dir)_sources)
    endef

q个例子中定义了三个变量Q?#8220;dir”Q?#8220;foo_sources”?#8220;foo_print”?


四、追加变量?

我们可以使用“+=”操作W给变量q加|如:

    objects = main.o foo.o bar.o utils.o
    objects += another.o

于是Q我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”Qanother.o被追加进MQ?

使用“+=”操作W,可以模拟Z面的q种例子Q?

    objects = main.o foo.o bar.o utils.o
    objects := $(objects) another.o

所不同的是Q用“+=”更ؓz?

如果变量之前没有定义q,那么Q?#8220;+=”会自动变?#8220;=”Q如果前面有变量定义Q那?#8220;+=”会承于前次操作的赋值符。如果前一ơ的?#8220;:=”Q那?#8220;+=”会以“:=”作ؓ其赋值符Q如Q?

    variable := value
    variable += more

{h于:

    variable := value
    variable := $(variable) more

但如果是q种情况Q?nbsp;

    variable = value
    variable += more

׃前次的赋值符?#8220;=”Q所?#8220;+=”也会?#8220;=”来做|那么岂不会发生变量的递补归定义,q是很不好的Q所以make会自动ؓ我们解决q个问题Q我们不必担心这个问题?


五、override 指示W?

如果有变量是通常make的命令行参数讄的,那么Makefile中对q个变量的赋g被忽略。如果你惛_Makefile中设|这cd数的|那么Q你可以使用“override”指示W。其语法是:

    override <variable>; = <value>;

    override <variable>; := <value>;

当然Q你q可以追加:

    override <variable>; += <more text>;

对于多行的变量定义,我们用define指示W,在define指示W前Q也同样可以使用ovveride指示W,如:

    override define foo
    bar
    endef


]]>
makefile详解 使用变量 十七http://www.shnenglu.com/ivenher/articles/22101.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:05:00 GMThttp://www.shnenglu.com/ivenher/articles/22101.htmlhttp://www.shnenglu.com/ivenher/comments/22101.htmlhttp://www.shnenglu.com/ivenher/articles/22101.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22101.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22101.html———?

在Makefile中的定义的变量,像是C/C++语言中的宏一P他代表了一个文本字Ԍ在Makefile中执行的时候其会自动原模原样地展开在所使用的地斏V其与C/C++所不同的是Q你可以在Makefile中改变其倹{在Makefile中,变量可以使用?#8220;目标”Q?#8220;依赖目标”Q?#8220;命o”或是Makefile的其它部分中?

变量的命名字可以包含字符、数字,下划U(可以是数字开_Q但不应该含?#8220;:”?#8220;#”?#8220;=”或是I字W(I格、回车等Q。变量是大小写敏感的Q?#8220;foo”?#8220;Foo”?#8220;FOO”是三个不同的变量名。传l的Makefile的变量名是全大写的命名方式,但我推荐使用大小写搭配的变量名,如:MakeFlags。这样可以避免和pȝ的变量冲H,而发生意外的事情?

有一些变量是很奇怪字Ԍ?#8220;$<”?#8220;$@”{,q些是自动化变量Q我会在后面介绍?

一、变量的基础

变量在声明时需要给予初|而在使用Ӟ需要给在变量名前加?#8220;$”W号Q但最好用括?#8220;Q)”或是大括?#8220;{}”把变量给包括h。如果你要用真实的“$”字符Q那么你需要用“$$”来表C?

变量可以使用在许多地方,如规则中?#8220;目标”?#8220;依赖”?#8220;命o”以及新的变量中。先看一个例子:

    objects = program.o foo.o utils.o
    program : $(objects)
            cc -o program $(objects)

    $(objects) : defs.h

变量会在使用它的地方_地展开Q就像C/C++中的宏一P例如Q?

    foo = c
    prog.o : prog.$(foo)
            $(foo)$(foo) -$(foo) prog.$(foo)

展开后得刎ͼ

    prog.o : prog.c
            cc -c prog.c

当然Q千万不要在你的Makefile中这样干Q这里只是D个例子来表明Makefile中的变量在用处展开的真实样子。可见其是一?#8220;替代”的原理?

另外Q给变量加上括号完全是ؓ了更加安全地使用q个变量Q在上面的例子中Q如果你不想l变量加上括P那也可以Q但我还是强烈徏议你l变量加上括受?


二、变量中的变?

在定义变量的值时Q我们可以用其它变量来构造变量的|在Makefile中有两种方式来在用变量定义变量的倹{?

先看W一U方式,也就是简单的使用“=”P?#8220;=”左侧是变量,右侧是变量的|右侧变量的值可以定义在文g的Q何一处,也就是说Q右侧中的变量不一定非要是已定义好的|其也可以使用后面定义的倹{如Q?

    foo = $(bar)
    bar = $(ugh)
    ugh = Huh?

    all:
            echo $(foo)

我们执行“make all”会打出变量$(foo)的值是“Huh?”Q?nbsp;$(foo)的值是$(bar)Q?(bar)的值是$(ugh)Q?(ugh)的值是“Huh?”Q可见,变量是可以用后面的变量来定义的?

q个功能有好的地方,也有不好的地方,好的地方是,我们可以把变量的真实值推到后面来定义Q如Q?

    CFLAGS = $(include_dirs) -O
    include_dirs = -Ifoo -Ibar

?#8220;CFLAGS”在命令中被展开Ӟ会是“-Ifoo -Ibar -O”。但q种形式也有不好的地方,那就是递归定义Q如Q?

    CFLAGS = $(CFLAGS) -O

    或:

    A = $(B)
    B = $(A)

q会让make陷入无限的变量展开q程中去Q当Ӟ我们的make是有能力这L定义Qƈ会报错。还有就是如果在变量中用函敎ͼ那么Q这U方式会让我们的makeq行旉常慢Q更p糕的是Q他会用得两个make的函?#8220;wildcard”?#8220;shell”发生不可预知的错误。因Z不会知道q两个函C被调用多次?

Z避免上面的这U方法,我们可以使用make中的另一U用变量来定义变量的Ҏ。这U方法用的?#8220;:=”操作W,如:

    x := foo
    y := $(x) bar
    x := later

其等价于Q?

    y := foo bar
    x := later

值得一提的是,q种ҎQ前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是q样Q?

    y := $(x) bar
    x := foo

那么Qy的值是“bar”Q而不?#8220;foo bar”?

上面都是一些比较简单的变量使用了,让我们来看一个复杂的例子Q其中包括了make的函数、条件表辑ּ和一个系l变?#8220;MAKELEVEL”的用:

    ifeq (0,${MAKELEVEL})
    cur-dir   := $(shell pwd)
    whoami    := $(shell whoami)
    host-type := $(shell arch)
    MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
    endif

关于条g表达式和函数Q我们在后面再说Q对于系l变?#8220;MAKELEVEL”Q其意思是Q如果我们的make有一个嵌套执行的动作Q参见前面的“嵌套使用make”Q,那么Q这个变量会记录了我们的当前Makefile的调用层数?

下面再介l两个定义变量时我们需要知道的Q请先看一个例子,如果我们要定义一个变量,其值是一个空|那么我们可以q样来:

    nullstring :=
    space := $(nullstring) # end of the line

nullstring是一个Empty变量Q其中什么也没有Q而我们的space的值是一个空根{因为在操作W的双是很难描qC个空格的Q这里采用的技术很用Q先用一个Empty变量来标明变量的值开始了Q而后面采?#8220;#”注释W来表示变量定义的终止,q样Q我们可以定义出其值是一个空格的变量。请注意q里关于“#”的用,注释W?#8220;#”的这U特性值得我们注意Q如果我们这样定义一个变量:

    dir := /foo/bar    # directory to put the frobs in

dirq个变量的值是“/foo/bar”Q后面还跟了4个空|如果我们q样使用q样变量来指定别的目录—?#8220;$(dir)/file”那么完蛋了?

q有一个比较有用的操作W是“?=”Q先看示例:

    FOO ?= bar

其含义是Q如果FOO没有被定义过Q那么变量FOO的值就?#8220;bar”Q如果FOO先前被定义过Q那么这条语什么也不做Q其{h于:

    ifeq ($(origin FOO), undefined)
      FOO = bar
    endif


]]>
makefile详解 嵌套执行make,定义命o?十六http://www.shnenglu.com/ivenher/articles/22100.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:03:00 GMThttp://www.shnenglu.com/ivenher/articles/22100.htmlhttp://www.shnenglu.com/ivenher/comments/22100.htmlhttp://www.shnenglu.com/ivenher/articles/22100.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22100.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22100.html
在一些大的工E中Q我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的MakefileQ这有利于让我们的Makefile变得更加地简z,而不至于把所有的东西全部写在一个Makefile中,q样会很隄护我们的MakefileQ这个技术对于我们模块编译和分段~译有着非常大的好处?

例如Q我们有一个子目录叫subdirQ这个目录下有个Makefile文gQ来指明了这个目录下文g的编译规则。那么我们L的Makefile可以q样书写Q?

    subsystem:
            cd subdir && $(MAKE)

其等价于Q?

    subsystem:
            $(MAKE) -C subdir

定义$(MAKE)宏变量的意思是Q也许我们的make需要一些参敎ͼ所以定义成一个变量比较利于维护。这两个例子的意思都是先q入“subdir”目录Q然后执行make命o?

我们把这个Makefile叫做“LMakefile”QLMakefile的变量可以传递到下的Makefile中(如果你显C的声明Q,但是不会覆盖下层的Makefile中所定义的变量,除非指定?#8220;-e”参数?

如果你要传递变量到下Makefile中,那么你可以用这L声明Q?

    export <variable ...>;

如果你不惌某些变量传递到下Makefile中,那么你可以这样声明: 

    unexport <variable ...>;

如:
    
    CZ一Q?

        export variable = value

        其等价于Q?

        variable = value
        export variable

        其等价于Q?

        export variable := value

        其等价于Q?

        variable := value
        export variable

    CZ二:

        export variable += value

        其等价于Q?

        variable += value
        export variable

如果你要传递所有的变量Q那么,只要一个exportp了。后面什么也不用跟,表示传递所有的变量?

需要注意的是,有两个变量,一个是SHELLQ一个是MAKEFLAGSQ这两个变量不管你是否exportQ其L要传递到下层Makefile中,特别是MAKEFILES变量Q其中包含了make的参C息,如果我们执行“LMakefile”时有make参数或是在上层Makefile中定义了q个变量Q那么MAKEFILES变量会是这些参敎ͼq会传递到下层Makefile中,q是一个系l的环境变量?

但是make命o中的有几个参数ƈ不往下传递,它们?#8220;-C”,“-f”,“-h”“-o”?#8220;-W”Q有关Makefile参数的细节将在后面说明)Q如果你不想往下层传递参敎ͼ那么Q你可以q样来:

    subsystem:
            cd subdir && $(MAKE) MAKEFLAGS=

如果你定义了环境变量MAKEFLAGSQ那么你得确信其中的选项是大安会用到的Q如果其中有“-t”,“-n”,?#8220;-q”参数Q那么将会有让你意想不到的结果,或许会让你异常地恐慌?

q有一个在“嵌套执行”中比较有用的参数Q?#8220;-w”或是“--print-directory”会在make的过E中输出一些信息,让你看到目前的工作目录。比如,如果我们的下Umake目录?#8220;/home/hchen/gnu/make”Q如果我们?#8220;make -w”来执行,那么当进入该目录Ӟ我们会看刎ͼ

    make: Entering directory `/home/hchen/gnu/make'.

而在完成下层make后离开目录Ӟ我们会看刎ͼ

    make: Leaving directory `/home/hchen/gnu/make'

当你使用“-C”参数来指定make下层MakefileӞ“-w”会被自动打开的。如果参C?#8220;-s”Q?#8220;--slient”Q或?#8220;--no-print-directory”Q那么,“-w”L失效的?

五、定义命令包

如果Makefile中出C些相同命令序列,那么我们可以些相同的命o序列定义一个变量。定义这U命令序列的语法?#8220;define”开始,?#8220;endef”l束Q如Q?

    define run-yacc
    yacc $(firstword $^)
    mv y.tab.c $@
    endef

q里Q?#8220;run-yacc”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”?#8220;endef”中的两行是命o序列。这个命令包中的W一个命令是q行YaccE序Q因为YaccE序L生成“y.tab.c”的文Ӟ所以第二行的命令就是把q个文gҎ名字。还是把q个命o包放C个示例中来看看吧?

    foo.c : foo.y
            $(run-yacc)

我们可以看见Q要使用q个命o包,我们好像用变量一栗在q个命o包的使用中,命o?#8220;run-yacc”中的“$^”是“foo.y”Q?#8220;$@”是“foo.c”Q有兌U以“$”开头的Ҏ变量Q我们会在后面介l)Qmake在执行命令包Ӟ命o包中的每个命令会被依ơ独立执行?br>

]]>
makefile详解 书写命o 十五http://www.shnenglu.com/ivenher/articles/22099.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:02:00 GMThttp://www.shnenglu.com/ivenher/articles/22099.htmlhttp://www.shnenglu.com/ivenher/comments/22099.htmlhttp://www.shnenglu.com/ivenher/articles/22099.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22099.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22099.html———?

每条规则中的命o和操作系lShell的命令行是一致的。make会一按顺序一条一条的执行命oQ每条命令的开头必M[Tab]键开_除非Q命令是紧跟在依赖规则后面的分号后的。在命o行之间中的空格或是空行会被忽略,但是如果该空格或I是以Tab键开头的Q那么make会认为其是一个空命o?

我们在UNIX下可能会使用不同的ShellQ但是make的命令默认是?#8220;/bin/sh”——UNIX的标准Shell解释执行的。除非你特别指定一个其它的Shell。Makefile中,“#”是注释符Q很像C/C++中的“//”Q其后的本行字符都被注释?

一、显C命?

通常Qmake会把其要执行的命令行在命令执行前输出到屏q上。当我们?#8220;@”字符在命令行前,那么Q这个命令将不被make昄出来Q最具代表性的例子是,我们用这个功能来像屏q显CZ些信息。如Q?

    @echo 正在~译XXX模块......

当make执行Ӟ会输?#8220;正在~译XXX模块......”字串Q但不会输出命oQ如果没?#8220;@”Q那么,make输出:

    echo 正在~译XXX模块......
    正在~译XXX模块......

如果make执行Ӟ带入make参数“-n”?#8220;--just-print”Q那么其只是昄命oQ但不会执行命oQ这个功能很有利于我们调试我们的MakefileQ看看我们书写的命o是执行v来是什么样子的或是什么顺序的?

而make参数“-s”?#8220;--slient”则是全面止命o的显C?

 

二、命令执?

当依赖目标新于目标时Q也是当规则的目标需要被更新Ӟmake会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的l果应用在下一条命令时Q你应该使用分号分隔q两条命令。比如你的第一条命令是cd命oQ你希望W二条命令得在cd之后的基上运行,那么你就不能把这两条命o写在两行上,而应该把q两条命令写在一行上Q用分号分隔。如Q?

    CZ一Q?
        exec:
                cd /home/hchen
                pwd

    CZ二:
        exec:
                cd /home/hchen; pwd

当我们执?#8220;make exec”ӞW一个例子中的cd没有作用Qpwd会打印出当前的Makefile目录Q而第二个例子中,cdpv作用了,pwd会打印出“/home/hchen”?

make一般是使用环境变量SHELL中所定义的系lShell来执行命令,默认情况下用UNIX的标准Shell—?bin/sh来执行命令。但在MS-DOS下有点特D,因ؓMS-DOS下没有SHELL环境变量Q当然你也可以指定。如果你指定了UNIX风格的目录Ş式,首先Qmake会在SHELL所指定的\径中扑֯命o解释器,如果找不刎ͼ其会在当前盘W中的当前目录中LQ如果再找不刎ͼ其会在PATH环境变量中所定义的所有\径中L。MS-DOS中,如果你定义的命o解释器没有找刎ͼ其会l你的命令解释器加上诸如“.exe”?#8220;.com”?#8220;.bat”?#8220;.sh”{后~?



三、命令出?

每当命oq行完后Qmake会检每个命令的q回码,如果命oq回成功Q那么make会执行下一条命令,当规则中所有的命o成功q回后,q个规则q是成功完成了。如果一个规则中的某个命令出错了Q命令退出码非零Q,那么make׃l止执行当前规则Q这有可能l止所有规则的执行?

有些时候,命o的出错ƈ不表C就是错误的。例如mkdir命oQ我们一定需要徏立一个目录,如果目录不存在,那么mkdir成功执行,万事大吉Q如果目录存在,那么出错了。我们之所以用mkdir的意思就是一定要有这L一个目录,于是我们׃希望mkdir出错而终止规则的q行?

Z做到q一点,忽略命o的出错,我们可以在Makefile的命令行前加一个减?#8220;-”Q在Tab键之后)Q标Cؓ不管命oZ出错都认为是成功的。如Q?

   clean:
            -rm -f *.o

q有一个全局的办法是Q给make加上“-i”或是“--ignore-errors”参数Q那么,Makefile中所有命令都会忽略错误。而如果一个规则是?#8220;.IGNORE”作ؓ目标的,那么q个规则中的所有命令将会忽略错误。这些是不同U别的防止命令出错的ҎQ你可以Ҏ你的不同喜欢讄?

q有一个要提一下的make的参数的?#8220;-k”或是“--keep-going”Q这个参数的意思是Q如果某规则中的命o出错了,那么q目该规则的执行,但l执行其它规则?



]]>
makefile详解 自动生成依赖?十四http://www.shnenglu.com/ivenher/articles/22098.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:01:00 GMThttp://www.shnenglu.com/ivenher/articles/22098.htmlhttp://www.shnenglu.com/ivenher/comments/22098.htmlhttp://www.shnenglu.com/ivenher/articles/22098.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22098.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22098.html
在Makefile中,我们的依赖关pd能会需要包含一pd的头文gQ比如,如果我们的main.c中有一?#8220;#include "defs.h"”Q那么我们的依赖关系应该是:

    main.o : main.c defs.h

但是Q如果是一个比较大型的工程Q你必需清楚哪些C文g包含了哪些头文gQƈ且,你在加入或删除头文gӞ也需要小心地修改MakefileQ这是一个很没有l护性的工作。ؓ了避免这U繁重而又Ҏ出错的事情,我们可以使用C/C++~译的一个功能。大多数的C/C++~译器都支持一?#8220;-M”的选项Q即自动扑֯源文件中包含的头文gQƈ生成一个依赖关pR例如,如果我们执行下面的命令:

    cc -M main.c

其输出是Q?

    main.o : main.c defs.h

于是q译器自动生成的依赖关p,q样一来,你就不必再手动书写若q文件的依赖关系Q而由~译器自动生成了。需要提醒一句的是,如果你用GNU的C/C++~译器,你得?#8220;-MM”参数Q不Ӟ“-M”参数会把一些标准库的头文g也包含进来?

    gcc -M main.c的输出是Q?

    main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
         /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
         /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
         /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
         /usr/include/bits/sched.h /usr/include/libio.h \
         /usr/include/_G_config.h /usr/include/wchar.h \
         /usr/include/bits/wchar.h /usr/include/gconv.h \
         /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
         /usr/include/bits/stdio_lim.h


    gcc -MM main.c的输出则是:

    main.o: main.c defs.h

那么Q编译器的这个功能如何与我们的Makefile联系在一起呢。因样一来,我们的Makefile也要Ҏq些源文仉新生成,让Makefile自已依赖于源文gQ这个功能ƈ不现实,不过我们可以有其它手D|q回地实现这一功能。GNUl织把编译器为每一个源文g的自动生成的依赖关系攑ֈ一个文件中Qؓ每一?#8220;name.c”的文仉生成一?#8220;name.d”的Makefile文gQ[.d]文g中就存放对应[.c]文g的依赖关pR?

于是Q我们可以写出[.c]文g和[.d]文g的依赖关p,q让make自动更新或自成[.d]文gQƈ把其包含在我们的主Makefile中,q样Q我们就可以自动化地生成每个文g的依赖关pM?

q里Q我们给Z一个模式规则来产生[.d]文gQ?

    %.d: %.c
            @set -e; rm -f $@; \
             $(CC) -M $(CPPFLAGS) $< >; $@.$$$$; \
             sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ >; $@; \
             rm -f $@.$$$$


q个规则的意思是Q所有的[.d]文g依赖于[.c]文gQ?#8220;rm -f $@”的意思是删除所有的目标Q也是[.d]文gQ第二行的意思是Qؓ每个依赖文g“$<”Q也是[.c]文g生成依赖文gQ?#8220;$@”表示模式“%.d”文gQ如果有一个C文g是name.cQ那?#8220;%”是“name”Q?#8220;$$$$”意ؓ一个随机编PW二行生成的文g有可能是“name.d.12345”Q第三行使用sed命o做了一个替换,关于sed命o的用法请参看相关的用文档。第四行是删除临时文g?

总而言之,q个模式要做的事是在编译器生成的依赖关pM加入[.d]文g的依赖,x依赖关系Q?

    main.o : main.c defs.h

转成Q?

    main.o main.d : main.c defs.h

于是Q我们的[.d]文g也会自动更新了,q会自动生成了,当然Q你q可以在q个[.d]文g中加入的不只是依赖关p,包括生成的命令也可一q加入,让每个[.d]文g都包含一个完赖的规则。一旦我们完成这个工作,接下来,我们p把这些自动生成的规则放进我们的主Makefile中。我们可以用Makefile?#8220;include”命oQ来引入别的Makefile文gQ前面讲q)Q例如:

    sources = foo.c bar.c

    include $(sources:.c=.d)

上述语句中的“$(sources:.c=.d)”中的“.c=.d”的意思是做一个替换,把变?(sources)所有[.c]的字串都替换成[.d]Q关于这?#8220;替换”的内容,在后面我会有更ؓ详细的讲q。当Ӟ你得注意ơ序Q因为include是按ơ来载入文gQ最先蝲入的[.d]文g中的目标会成为默认目标?br>

]]>
makefile详解 多目?静态模?十三http://www.shnenglu.com/ivenher/articles/22097.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 03:00:00 GMThttp://www.shnenglu.com/ivenher/articles/22097.htmlhttp://www.shnenglu.com/ivenher/comments/22097.htmlhttp://www.shnenglu.com/ivenher/articles/22097.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22097.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22097.html
Makefile的规则中的目标可以不止一个,其支持多目标Q有可能我们的多个目标同时依赖于一个文Ӟq且其生成的命o大体cM。于是我们就能把其合qv来。当Ӟ多个目标的生成规则的执行命o是同一个,q可能会可我们带来麻烦,不过好在我们的可以用一个自动化变量“$@”Q关于自动化变量Q将在后面讲qͼQ这个变量表C着目前规则中所有的目标的集合,q样说可能很抽象Q还是看一个例子吧?

    bigoutput littleoutput : text.g
            generate text.g -$(subst output,,$@) >; $@

    上述规则{h于:

    bigoutput : text.g
            generate text.g -big >; bigoutput
    littleoutput : text.g
            generate text.g -little >; littleoutput

    其中Q?$(subst output,,$@)中的“$”表示执行一个Makefile的函敎ͼ函数名ؓsubstQ后面的为参数。关于函敎ͼ在后面讲述。这里的q个函数是截取字W串的意思,“$@”表示目标的集合,像一个数l,“$@”依次取出目标Qƈ执于命o?


七、静态模?

静态模式可以更加容易地定义多目标的规则Q可以让我们的规则变得更加的有弹性和灉|。我们还是先来看一下语法:

    <targets ...>;: <target-pattern>;: <prereq-patterns ...>;
            <commands>;
            ...


    targets定义了一pd的目标文Ӟ可以有通配W。是目标的一个集合?

    target-parrtern是指明了targets的模式,也就是的目标集模式?

    prereq-parrterns是目标的依赖模式Q它对target-parrtern形成的模式再q行一ơ依赖目标的定义?

q样描述q三个东西,可能q是没有说清楚,q是举个例子来说明一下吧。如果我们的<target-parrtern>;定义?#8220;%.o”Q意思是我们?lt;target>;集合中都是以“.o”l尾的,而如果我们的<prereq-parrterns>;定义?#8220;%.c”Q意思是?lt;target-parrtern>;所形成的目标集q行二次定义Q其计算Ҏ是,?lt;target-parrtern>;模式中的“%”Q也是L了[.o]q个l尾Q,qؓ其加上[.c]q个l尾QŞ成的新集合?

所以,我们?#8220;目标模式”或是“依赖模式”中都应该?#8220;%”q个字符Q如果你的文件名中有“%”那么你可以用反斜杠“\”q行转义Q来标明真实?#8220;%”字符?

看一个例子:

    objects = foo.o bar.o

    all: $(objects)

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


上面的例子中Q指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”l尾的目标,也就?#8220;foo.o bar.o”Q也是变量$object集合的模式,而依赖模?#8220;%.c”则取模式“%.o”?#8220;%”Q也是“foo bar”Qƈ为其加下“.c”的后~Q于是,我们的依赖目标就?#8220;foo.c bar.c”。而命令中?#8220;$<”?#8220;$@”则是自动化变量,“$<”表示所有的依赖目标集(也就?#8220;foo.c bar.c”Q,“$@”表示目标集(也就?#8220;foo.o bar.o”Q。于是,上面的规则展开后等价于下面的规则:

    foo.o : foo.c
            $(CC) -c $(CFLAGS) foo.c -o foo.o
    bar.o : bar.c
            $(CC) -c $(CFLAGS) bar.c -o bar.o

试想Q如果我们的“%.o”有几百个Q那U我们只要用q种很简单的“静态模式规?#8221;可以写完一堆规则,实在是太有效率了?#8220;静态模式规?#8221;的用法很灉|Q如果用得好Q那会一个很强大的功能。再看一个例子:


    files = foo.elc bar.o lose.o

    $(filter %.o,$(files)): %.o: %.c
            $(CC) -c $(CFLAGS) $< -o $@
    $(filter %.elc,$(files)): %.elc: %.el
            emacs -f batch-byte-compile $<


$(filter %.o,$(files))表示调用Makefile的filter函数Q过?#8220;$filter”集,只要其中模式?#8220;%.o”的内宏V其的它内容Q我׃用多说了吧。这个例字展CZMakefile中更大的Ҏ?


]]>
makefile详解 文g搜寻 十一http://www.shnenglu.com/ivenher/articles/22095.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 02:59:00 GMThttp://www.shnenglu.com/ivenher/articles/22095.htmlhttp://www.shnenglu.com/ivenher/comments/22095.htmlhttp://www.shnenglu.com/ivenher/articles/22095.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22095.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22095.html
在一些大的工E中Q有大量的源文gQ我们通常的做法是把这许多的源文g分类Qƈ存放在不同的目录中。所以,当make需要去扑֯文g的依赖关pLQ你可以在文件前加上路径Q但最好的Ҏ是把一个\径告诉makeQ让make在自动去找?

Makefile文g中的Ҏ变量“VPATH”是完成q个功能的,如果没有指明q个变量Qmake只会在当前的目录中去扑֯依赖文g和目标文件。如果定义了q个变量Q那么,make׃在当当前目录找不到的情况下,到所指定的目录中LL件了?

    VPATH = src:../headers

上面的的定义指定两个目录Q?#8220;src”?#8220;../headers”Qmake会按照这个顺序进行搜索。目录由“冒号”分隔。(当然Q当前目录永q是最高优先搜索的地方Q?

另一个设|文件搜索\径的Ҏ是用make?#8220;vpath”关键字(注意Q它是全写的)Q这不是变量Q这是一个make的关键字Q这和上面提到的那个VPATH变量很类|但是它更为灵zR它可以指定不同的文件在不同的搜索目录中。这是一个很灉|的功能。它的用方法有三种Q?

    1、vpath <pattern>; <directories>;

    为符合模?lt;pattern>;的文件指定搜索目?lt;directories>;?

    2、vpath <pattern>;

    清除W合模式<pattern>;的文件的搜烦目录?

    3、vpath

    清除所有已被设|好了的文g搜烦目录?

vapth使用Ҏ中的<pattern>;需要包?#8220;%”字符?#8220;%”的意思是匚w零或若干字符Q例如,“%.h”表示所有以“.h”l尾的文件?lt;pattern>;指定了要搜烦的文仉Q?lt;directories>;则指定了<pattern>;的文仉的搜索的目录。例如:

    vpath %.h ../headers

该语句表C,要求make?#8220;../headers”目录下搜索所有以“.h”l尾的文件。(如果某文件在当前目录没有扑ֈ的话Q?

我们可以q箋C用vpath语句Q以指定不同搜烦{略。如果连l的vpath语句中出C相同?lt;pattern>;Q或是被重复了的<pattern>;Q那么,make会按照vpath语句的先后顺序来执行搜烦。如Q?

    vpath %.c foo
    vpath %   blish
    vpath %.c bar

其表C?#8220;.c”l尾的文Ӟ先在“foo”目录Q然后是“blish”Q最后是“bar”目录?

    vpath %.c foo:bar
    vpath %   blish

而上面的语句则表C?#8220;.c”l尾的文Ӟ先在“foo”目录Q然后是“bar”目录Q最后才?#8220;blish”目录?



]]>
makefile详解 伪目?十二http://www.shnenglu.com/ivenher/articles/22096.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 02:59:00 GMThttp://www.shnenglu.com/ivenher/articles/22096.htmlhttp://www.shnenglu.com/ivenher/comments/22096.htmlhttp://www.shnenglu.com/ivenher/articles/22096.html#Feedback1http://www.shnenglu.com/ivenher/comments/commentRss/22096.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22096.html
最早先的一个例子中Q我们提到过一?#8220;clean”的目标,q是一?#8220;伪目?#8221;Q?

    clean:
            rm *.o temp

正像我们前面例子中的“clean”一P即然我们生成了许多文件编译文Ӟ我们也应该提供一个清除它们的“目标”以备完整地重~译而用?nbsp;Q以“make clean”来用该目标Q?

因ؓQ我们ƈ不生?#8220;clean”q个文g?#8220;伪目?#8221;q不是一个文Ӟ只是一个标{,׃“伪目?#8221;不是文gQ所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过昄地指明这?#8220;目标”才能让其生效。当Ӟ“伪目?#8221;的取名不能和文g名重名,不然其就失去?#8220;伪目?#8221;的意义了?

当然Qؓ了避免和文g重名的这U情况,我们可以使用一个特D的标记“.PHONY”来显C地指明一个目标是“伪目?#8221;Q向make说明Q不是否有q个文gQ这个目标就?#8220;伪目?#8221;?

    .PHONY : clean

只要有这个声明,不管是否?#8220;clean”文gQ要q行“clean”q个目标Q只?#8220;make clean”q样。于是整个过E可以这样写Q?

     .PHONY: clean
    clean:
            rm *.o temp

伪目标一般没有依赖的文g。但是,我们也可以ؓ伪目标指定所依赖的文件。伪目标同样可以作ؓ“默认目标”Q只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文gQ但你只想简单地敲一个make完事Qƈ且,所有的目标文g都写在一个Makefile中,那么你可以?#8220;伪目?#8221;q个Ҏ:

    all : prog1 prog2 prog3
    .PHONY : all

    prog1 : prog1.o utils.o
            cc -o prog1 prog1.o utils.o

    prog2 : prog2.o
            cc -o prog2 prog2.o

    prog3 : prog3.o sort.o utils.o
            cc -o prog3 prog3.o sort.o utils.o

我们知道QMakefile中的W一个目标会被作为其默认目标。我们声明了一?#8220;all”的伪目标Q其依赖于其它三个目标。由于伪目标的特性是QL被执行的Q所以其依赖的那三个目标L不如“all”q个目标新。所以,其它三个目标的规则L会被册。也pC我们一口气生成多个目标的目的?#8220;.PHONY : all”声明?#8220;all”q个目标?#8220;伪目?#8221;?

随便提一句,从上面的例子我们可以看出Q目标也可以成ؓ依赖。所以,伪目标同样也可成Z赖。看下面的例子:

    .PHONY: cleanall cleanobj cleandiff

    cleanall : cleanobj cleandiff
            rm program

    cleanobj :
            rm *.o

    cleandiff :
            rm *.diff

“make clean”清除所有要被清除的文g?#8220;cleanobj”?#8220;cleandiff”q两个伪目标有点?#8220;子程?#8221;的意思。我们可以输?#8220;make cleanall”?#8220;make cleanobj”?#8220;make cleandiff”命o来达到清除不同种cL件的目的?br>

]]>
makefile详解 书写规则 ?/title><link>http://www.shnenglu.com/ivenher/articles/22094.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:58:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22094.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22094.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22094.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22094.html</trackback:ping><description><![CDATA[书写规则 <br>———?<br><br>规则包含两个部分Q一个是依赖关系Q一个是生成目标的方法?<br><br>在Makefile中,规则的顺序是很重要的Q因为,Makefile中只应该有一个最l目标,其它的目标都是被q个目标所q带出来的,所以一定要让make知道你的最l目标是什么。一般来_定义在Makefile中的目标可能会有很多Q但是第一条规则中的目标将被确立ؓ最l的目标。如果第一条规则中的目标有很多个,那么Q第一个目标会成ؓ最l的目标。make所完成的也是q个目标?<br><br>好了Q还是让我们来看一看如何书写规则?<br><br><br>一、规则D?<br><br>    foo.o : foo.c defs.h       # foo模块 <br>            cc -c -g foo.c <br><br>看到q个例子Q各位应该不是很陌生了,前面也已说过Qfoo.o是我们的目标Qfoo.c和defs.h是目标所依赖的源文gQ而只有一个命?#8220;cc -c -g foo.c”Q以Tab键开_。这个规则告诉我们两件事Q?<br><br>    1、文件的依赖关系Qfoo.o依赖于foo.c和defs.h的文Ӟ如果foo.c和defs.h的文件日期要比foo.o文g日期要新Q或是foo.o不存在,那么依赖关系发生?<br>    2、如果生成(或更斎ͼfoo.o文g。也是那个cc命oQ其说明了,如何生成foo.oq个文g。(当然foo.c文ginclude了defs.h文gQ?<br><br><br>二、规则的语法 <br><br>      targets : prerequisites <br>        command <br>        ... <br><br>      或是q样Q?nbsp; <br><br>      targets : prerequisites ; command <br>            command <br>            ... <br><br>targets是文件名Q以I格分开Q可以用通配W。一般来_我们的目标基本上是一个文Ӟ但也有可能是多个文g?<br><br>command是命令行Q如果其不与“target:prerequisites”在一行,那么Q必M[Tab键]开_如果和prerequisites在一行,那么可以用分号做为分隔。(见上Q?<br><br>prerequisites也就是目标所依赖的文Ӟ或依赖目标)。如果其中的某个文g要比目标文g要新Q那么,目标p认ؓ?#8220;q时?#8221;Q被认ؓ是需要重生成的。这个在前面已经讲过了?<br><br>如果命o太长Q你可以使用反斜框(‘\’Q作为换行符。make对一行上有多个字符没有限制。规则告诉make两g事,文g的依赖关pd如何成成目标文g?<br><br>一般来_make会以UNIX的标准ShellQ也是/bin/sh来执行命令?<br><br><br>三、在规则中用通配W?<br><br>如果我们惛_义一pd比较cM的文Ӟ我们很自然地想起用通配W。make支持三各通配W:“*”Q?#8220;?”?#8220;[...]”。这是和Unix的B-Shell是相同的?<br><br>波浪P“~”Q字W在文g名中也有比较Ҏ的用途。如果是“~/test”Q这pC当前用L$HOME目录下的test目录。?#8220;~hchen/test”则表C用户hchen的宿ȝ录下的test目录。(q些都是Unix下的知识了Qmake也支持)而在Windows或是MS-DOS下,用户没有宿主目录Q那么L号所指的目录则根据环境变?#8220;HOME”而定?<br><br>通配W代替了你一pd的文Ӟ?#8220;*.c”表示所以后~为c的文件。一个需要我们注意的是,如果我们的文件名中有通配W,如:“*”Q那么可以用转义字符“\”Q如“\*”来表C真实的“*”字符Q而不是Q意长度的字符丌Ӏ?<br><br>好吧Q还是先来看几个例子吧: <br><br>    clean: <br>         rm -f *.o <br><br>    上面q个例子我不不多说了Q这是操作系lShell所支持的通配W。这是在命o中的通配W?<br><br>    print: *.c <br>         lpr -p $? <br>         touch print <br><br>    上面q个例子说明了通配W也可以在我们的规则中,目标print依赖于所有的[.c]文g。其中的“$?”是一个自动化变量Q我会在后面l你讲述?<br><br>    objects = *.o <br><br>    上面q个例子Q表CZQ通符同样可以用在变量中。ƈ不是说[*.o]会展开Q不Qobjects的值就?#8220;*.o”。Makefile中的变量其实是C/C++中的宏。如果你要让通配W在变量中展开Q也是让objects的值是所有[.o]的文件名的集合,那么Q你可以q样Q?<br><br>    objects := $(wildcard *.o) <br><br>q种用法由关键字“wildcard”指出Q关于Makefile的关键字Q我们将在后面讨论?<br><br><br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:58 <a href="http://www.shnenglu.com/ivenher/articles/22094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 环境变量 工作方式 ?/title><link>http://www.shnenglu.com/ivenher/articles/22093.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:56:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22093.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22093.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22093.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22093.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22093.html</trackback:ping><description><![CDATA[四、环境变?nbsp;MAKEFILES  <br><br>如果你的当前环境中定义了环境变量MAKEFILESQ那么,make会把q个变量中的值做一个类ginclude的动作。这个变量中的值是其它的MakefileQ用I格分隔。只是,它和include不同的是Q从q个环境变中引入的Makefile?#8220;目标”不会起作用,如果环境变量中定义的文g发现错误Qmake也会不理?<br><br>但是在这里我q是不要使用q个环境变量Q因为只要这个变量一被定义,那么当你使用makeӞ所有的Makefile都会受到它的影响Q这l不是你想看到的。在q里提这个事Q只是ؓ了告诉大Ӟ也许有时候你的Makefile出现了怪事Q那么你可以看看当前环境中有没有定义q个变量?<br><br><br>五、make的工作方?<br><br>GNU的make工作时的执行步骤入下Q(x其它的make也是cMQ?<br><br>    1、读入所有的Makefile?<br>    2、读入被include的其它Makefile?<br>    3、初始化文g中的变量?<br>    4、推导隐晦规则,q分析所有规则?<br>    5、ؓ所有的目标文g创徏依赖关系链?<br>    6、根据依赖关p,军_哪些目标要重新生成?<br>    7、执行生成命令?<br><br>1-5步ؓW一个阶D,6-7为第二个阶段。第一个阶D中Q如果定义的变量被用了Q那么,make会把其展开在用的位置。但makeq不会完全马上展开Qmake使用的是拖g战术Q如果变量出现在依赖关系的规则中Q那么仅当这条依赖被军_要用了Q变量才会在其内部展开?<br><br>当然Q这个工作方式你不一定要清楚Q但是知道这个方式你也会对make更ؓ熟悉。有了这个基Q后l部分也容易看懂了?br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:56 <a href="http://www.shnenglu.com/ivenher/articles/22093.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 包含内容 包含其他文g ?/title><link>http://www.shnenglu.com/ivenher/articles/22092.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:55:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22092.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22092.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22092.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22092.html</trackback:ping><description><![CDATA[一、Makefile里有什么? <br><br>Makefile里主要包含了五个东西Q显式规则、隐晦规则、变量定义、文件指C和注释?<br><br>1、显式规则。显式规则说明了Q如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文gQ文件的依赖文gQ生成的命o?<br><br>2、隐晦规则。由于我们的make有自动推导的功能Q所以隐晦的规则可以让我们比较粗p地略地书写MakefileQ这是由make所支持的?<br><br>3、变量的定义。在Makefile中我们要定义一pd的变量,变量一般都是字W串Q这个有点你C语言中的宏,当Makefile被执行时Q其中的变量都会被扩展到相应的引用位|上?<br><br>4、文件指C。其包括了三个部分,一个是在一个Makefile中引用另一个MakefileQ就像C语言中的include一P另一个是指根据某些情冉|定Makefile中的有效部分Q就像C语言中的预编?if一Pq有是定义一个多行的命o。有兌一部分的内容,我会在后l的部分中讲q?<br><br>5、注释。Makefile中只有行注释Q和UNIX的Shell脚本一P其注释是?#8220;#”字符Q这个就像C/C++中的“//”一栗如果你要在你的Makefile中?#8220;#”字符Q可以用反斜框进行{义,如:“\#”?<br><br>最后,q值得一提的是,在Makefile中的命oQ必要以[Tab]键开始?<br><br><br>二、Makefile的文件名 <br><br>默认的情况下Qmake命o会在当前目录下按序扑֯文g名ؓ“GNUmakefile”?#8220;makefile”?#8220;Makefile”的文Ӟ扑ֈ了解释这个文件。在q三个文件名中,最好?#8220;Makefile”q个文g名,因ؓQ这个文件名W一个字Wؓ大写Q这h一U显目的感觉。最好不要用“GNUmakefile”Q这个文件是GNU的make识别的。有另外一些make只对全小写的“makefile”文g名敏感,但是基本上来_大多数的make都支?#8220;makefile”?#8220;Makefile”q两U默认文件名?<br><br>当然Q你可以使用别的文g名来书写MakefileQ比如:“Make.Linux”Q?#8220;Make.Solaris”Q?#8220;Make.AIX”{,如果要指定特定的MakefileQ你可以使用make?#8220;-f”?#8220;--file”参数Q如Qmake -f Make.Linux或make --file Make.AIX?<br><br><br>三、引用其它的Makefile <br><br>在Makefile使用include关键字可以把别的Makefile包含q来Q这很像C语言?includeQ被包含的文件会原模原样的放在当前文件的包含位置。include的语法是Q?<br><br>    include <filename>; <br><br>    filename可以是当前操作系lShell的文件模式(可以保含路径和通配W) <br><br>在include前面可以有一些空字符Q但是绝不能是[Tab]键开始。include?lt;filename>;可以用一个或多个I格隔开。D个例子,你有q样几个MakefileQa.mk、b.mk、c.mkQ还有一个文件叫foo.makeQ以及一个变?(bar)Q其包含了e.mk和f.mkQ那么,下面的语句: <br><br>    include foo.make *.mk $(bar) <br><br>    {h于: <br><br>    include foo.make a.mk b.mk c.mk e.mk f.mk <br><br>make命o开始时Q会把找寻include所指出的其它MakefileQƈ把其内容安置在当前的位置。就好像C/C++?include指o一栗如果文仉没有指定l对路径或是相对路径的话Qmake会在当前目录下首先寻找,如果当前目录下没有找刎ͼ那么Qmakeq会在下面的几个目录下找Q?<br><br>    1、如果make执行Ӟ?#8220;-I”?#8220;--include-dir”参数Q那么make׃在这个参数所指定的目录下d找?<br>    2、如果目?lt;prefix>;/includeQ一般是Q?usr/local/bin?usr/includeQ存在的话,make也会L?<br><br>如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会l蝲入其它的文gQ一旦完成makefile的读取,make会再重试q些没有扑ֈQ或是不能读取的文gQ如果还是不行,make才会出现一条致命信息。如果你惌make不理那些无法d的文Ӟ而l执行,你可以在include前加一个减?#8220;-”。如Q?<br><br>    -include <filename>; <br>    其表C,无论includeq程中出C么错误,都不要报错l执行。和其它版本make兼容的相兛_令是sincludeQ其作用和这一个是一L? <img src ="http://www.shnenglu.com/ivenher/aggbug/22092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:55 <a href="http://www.shnenglu.com/ivenher/articles/22092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 清空目标文g的规??/title><link>http://www.shnenglu.com/ivenher/articles/22091.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:53:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22091.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22091.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22091.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22091.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22091.html</trackback:ping><description><![CDATA[七、清I目标文件的规则 <br><br>每个Makefile中都应该写一个清I目标文Ӟ.o和执行文Ӟ的规则,q不仅便于重~译Q也很利于保持文件的清洁。这是一?#8220;修养”Q呵呵,q记得我的《编E修充R吗Q。一般的风格都是Q?<br><br>        clean: <br>            rm edit $(objects) <br><br>更ؓE_的做法是Q?<br><br>        .PHONY : clean <br>        clean : <br>                -rm edit $(objects) <br><br>前面说过Q?PHONY意思表Cclean是一?#8220;伪目?#8221;Q。而在rm命o前面加了一个小减号的意思就是,也许某些文g出现问题Q但不要,l箋做后面的事。当Ӟclean的规则不要放在文件的开_不然Q这׃变成make的默认目标,怿谁也不愿意这栗不成文的规矩是—?#8220;clean从来都是攑֜文g的最?#8221;?<br><br><br>上面是一个makefile的概貌,也是makefile的基Q下面还有很多makefile的相关细节,准备好了吗?准备好了来?<br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:53 <a href="http://www.shnenglu.com/ivenher/articles/22091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 另类风格 ?/title><link>http://www.shnenglu.com/ivenher/articles/22090.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:52:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22090.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22090.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22090.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22090.html</trackback:ping><description><![CDATA[六、另c风格的makefile <br><br>即然我们的make可以自动推导命oQ那么我看到那堆[.o]和[.h]的依赖就有点不爽Q那么多的重复的[.h]Q能不能把其收拢hQ好吧,没有问题Q这个对于make来说很容易,谁叫它提供了自动推导命o和文件的功能呢?来看看最新风格的makefile吧?<br><br>    objects = main.o kbd.o command.o display.o \ <br>              insert.o search.o files.o utils.o <br><br>    edit : $(objects) <br>            cc -o edit $(objects) <br><br>    $(objects) : defs.h <br>    kbd.o command.o files.o : command.h <br>    display.o insert.o search.o files.o : buffer.h <br><br>    .PHONY : clean <br>    clean : <br>            rm edit $(objects) <br><br>q种风格Q让我们的makefile变得很简单,但我们的文g依赖关系显得有点凌׃。鱼和熊掌不可兼得。还看你的喜好了。我是不喜欢q种风格的,一是文件的依赖关系看不清楚Q二是如果文件一多,要加入几个新?o文gQ那q不清楚了?<br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:52 <a href="http://www.shnenglu.com/ivenher/articles/22090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 变量 ?http://www.shnenglu.com/ivenher/articles/22088.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 02:50:00 GMThttp://www.shnenglu.com/ivenher/articles/22088.htmlhttp://www.shnenglu.com/ivenher/comments/22088.htmlhttp://www.shnenglu.com/ivenher/articles/22088.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22088.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22088.html
在上面的例子中,先让我们看看edit的规则:

      edit : main.o kbd.o command.o display.o \
                  insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o \
                       insert.o search.o files.o utils.o

我们可以看到[.o]文g的字W串被重复了两次Q如果我们的工程需要加入一个新的[.o]文gQ那么我们需要在两个地方加(应该是三个地方,q有一个地方在clean中)。当Ӟ我们的makefileq不复杂Q所以在两个地方加也不篏Q但如果makefile变得复杂Q那么我们就有可能会忘掉一个需要加入的地方Q而导致编译失败。所以,Zmakefile的易l护Q在makefile中我们可以用变量。makefile的变量也是一个字W串Q理解成C语言中的宏可能会更好?

比如Q我们声明一个变量,叫objects, OBJECTS, objs, OBJS, obj, 或是 OBJQ反正不什么啦Q只要能够表Cobj文gp了。我们在makefile一开始就q样定义Q?

     objects = main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o

于是Q我们就可以很方便地在我们的makefile中以“$(objects)”的方式来使用q个变量了,于是我们的改良版makefile变成下面这个样子:

    objects = main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)
    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit $(objects)


于是如果有新?nbsp;.o 文g加入Q我们只需单地修改一?nbsp;objects 变量可以了?

关于变量更多的话题,我会在后l给你一一道来?



]]>
makefile详解 自动推导 ?/title><link>http://www.shnenglu.com/ivenher/articles/22089.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:50:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22089.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22089.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22089.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22089.html</trackback:ping><description><![CDATA[五、让make自动推导 <br><br>GNU的make很强大,它可以自动推导文件以及文件依赖关pd面的命oQ于是我们就没必要去在每一个[.o]文g后都写上cM的命令,因ؓQ我们的make会自动识别,q自己推导命令?<br><br>只要make看到一个[.o]文gQ它׃自动的把[.c]文g加在依赖关系中,如果make扑ֈ一个whatever.oQ那么whatever.cQ就会是whatever.o的依赖文件。ƈ?nbsp;cc -c whatever.c 也会被推导出来,于是Q我们的makefile再也不用写得q么复杂。我们的是新的makefile又出炉了?<br><br><br>    objects = main.o kbd.o command.o display.o \ <br>              insert.o search.o files.o utils.o <br><br>    edit : $(objects) <br>            cc -o edit $(objects) <br><br>    main.o : defs.h <br>    kbd.o : defs.h command.h <br>    command.o : defs.h command.h <br>    display.o : defs.h buffer.h <br>    insert.o : defs.h buffer.h <br>    search.o : defs.h buffer.h <br>    files.o : defs.h buffer.h command.h <br>    utils.o : defs.h <br><br>    .PHONY : clean <br>    clean : <br>            rm edit $(objects) <br><br>q种ҎQ也是make?#8220;隐晦规则”。上面文件内容中Q?#8220;.PHONY”表示Qclean是个伪目标文件?<br><br>关于更ؓ详细?#8220;隐晦规则”?#8220;伪目标文?#8221;Q我会在后箋l你一一道来?<br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22089.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:50 <a href="http://www.shnenglu.com/ivenher/articles/22089.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 如何工作 ?/title><link>http://www.shnenglu.com/ivenher/articles/22087.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:49:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22087.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22087.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22087.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22087.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22087.html</trackback:ping><description><![CDATA[三、make是如何工作的 <br><br>在默认的方式下,也就是我们只输入make命o。那么, <br><br>    1、make会在当前目录下找名字?#8220;Makefile”?#8220;makefile”的文件?<br>    2、如果找刎ͼ它会找文件中的第一个目标文ӞtargetQ,在上面的例子中,他会扑ֈ“edit”q个文gQƈ把这个文件作为最l的目标文g?<br>    3、如果edit文g不存在,或是edit所依赖的后面的 .o 文g的文件修Ҏ间要比editq个文g斎ͼ那么Q他׃执行后面所定义的命令来生成editq个文g?<br>    4、如果edit所依赖?o文g也存在,那么make会在当前文g中找目标?o文g的依赖性,如果扑ֈ则再Ҏ那一个规则生?o文g。(q有点像一个堆栈的q程Q?<br>    5、当Ӟ你的C文g和H文g是存在的啦,于是make会生?nbsp;.o 文gQ然后再?nbsp;.o 文g生命make的终极Q务,也就是执行文件edit了?<br><br>q就是整个make的依赖性,make会一层又一层地L文g的依赖关p,直到最l编译出W一个目标文件。在扑֯的过E中Q如果出现错误,比如最后被依赖的文件找不到Q那么make׃直接退出,q报错,而对于所定义的命令的错误Q或是编译不成功QmakeҎ不理。make只管文g的依赖性,卻I如果在我找了依赖关系之后Q冒号后面的文gq是不在Q那么对不vQ我׃工作啦?<br><br>通过上述分析Q我们知道,像cleanq种Q没有被W一个目标文件直接或间接兌Q那么它后面所定义的命令将不会被自动执行,不过Q我们可以显Cmake执行。即命o—?#8220;make clean”Q以此来清除所有的目标文gQ以侉K~译?<br><br>于是在我们编E中Q如果这个工E已被编译过了,当我们修改了其中一个源文gQ比如file.cQ那么根据我们的依赖性,我们的目标file.o会被重编译(也就是在q个依性关pd面所定义的命令)Q于是file.o的文件也是最新的啦,于是file.o的文件修Ҏ间要比edit要新Q所以edit也会被重新链接了Q详见edit目标文g后定义的命oQ?<br><br>而如果我们改变了“command.h”Q那么,kdb.o、command.o和files.o都会被重~译Qƈ且,edit会被重链接?<br><br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:49 <a href="http://www.shnenglu.com/ivenher/articles/22087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 规则 ?/title><link>http://www.shnenglu.com/ivenher/articles/22086.html</link><dc:creator>爱饭?/dc:creator><author>爱饭?/author><pubDate>Tue, 17 Apr 2007 02:48:00 GMT</pubDate><guid>http://www.shnenglu.com/ivenher/articles/22086.html</guid><wfw:comment>http://www.shnenglu.com/ivenher/comments/22086.html</wfw:comment><comments>http://www.shnenglu.com/ivenher/articles/22086.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/ivenher/comments/commentRss/22086.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/ivenher/services/trackbacks/22086.html</trackback:ping><description><![CDATA[make命o执行Ӟ需要一?nbsp;Makefile 文gQ以告诉make命o需要怎么Lȝ译和链接E序?<br><br>首先Q我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册Q在q个CZ中,我们的工E有8个C文gQ和3个头文gQ我们要写一个Makefile来告诉make命o如何~译和链接这几个文g。我们的规则是: <br>    1Q如果这个工E没有编译过Q那么我们的所有C文g都要~译q被链接?<br>    2Q如果这个工E的某几个C文g被修改,那么我们只编译被修改的C文gQƈ链接目标E序?<br>    3Q如果这个工E的头文件被改变了,那么我们需要编译引用了q几个头文g的C文gQƈ链接目标E序?<br><br>只要我们的Makefile写得够好Q所有的q一切,我们只用一个make命o可以完成,make命o会自动智能地Ҏ当前的文件修改的情况来确定哪些文仉要重~译Q从而自q译所需要的文g和链接目标程序?<br><br><br>一、Makefile的规?<br><br>在讲q这个Makefile之前Q还是让我们先来_略地看一看Makefile的规则?<br><br>    target ... : prerequisites ... <br>            command <br>            ... <br>            ... <br><br>    target也就是一个目标文Ӟ可以是Object FileQ也可以是执行文件。还可以是一个标{(LabelQ,对于标签q种Ҏ,在后l的“伪目?#8221;章节中会有叙q?<br><br>    prerequisites是Q要生成那个target所需要的文g或是目标?<br><br>    command也就是make需要执行的命o。(L的Shell命oQ?<br><br>q是一个文件的依赖关系Q也是_targetq一个或多个的目标文件依赖于prerequisites中的文gQ其生成规则定义在command中。说白一点就是说Qprerequisites中如果有一个以上的文g比target文g要新的话Qcommand所定义的命令就会被执行。这是Makefile的规则。也是Makefile中最核心的内宏V?<br><br>说到底,Makefile的东西就是这样一点,好像我的q篇文档也该l束了。呵c还不尽Ӟq是Makefile的主U和核心Q但要写好一个Makefileq不够,我会以后面一点一点地l合我的工作l验l你慢慢到来。内容还多着呢。:Q?<br><br><br>二、一个示?<br><br>正如前面所说的Q如果一个工E有3个头文gQ和8个C文gQ我们ؓ了完成前面所q的那三个规则,我们的Makefile应该是下面的q个样子的?<br><br>    edit : main.o kbd.o command.o display.o \ <br>           insert.o search.o files.o utils.o <br>            cc -o edit main.o kbd.o command.o display.o \ <br>                       insert.o search.o files.o utils.o <br><br>    main.o : main.c defs.h <br>            cc -c main.c <br>    kbd.o : kbd.c defs.h command.h <br>            cc -c kbd.c <br>    command.o : command.c defs.h command.h <br>            cc -c command.c <br>    display.o : display.c defs.h buffer.h <br>            cc -c display.c <br>    insert.o : insert.c defs.h buffer.h <br>            cc -c insert.c <br>    search.o : search.c defs.h buffer.h <br>            cc -c search.c <br>    files.o : files.c defs.h buffer.h command.h <br>            cc -c files.c <br>    utils.o : utils.c defs.h <br>            cc -c utils.c <br>    clean : <br>            rm edit main.o kbd.o command.o display.o \ <br>               insert.o search.o files.o utils.o <br><br>反斜杠(\Q是换行W的意思。这h较便于Makefile的易诅R我们可以把q个内容保存在文件ؓ“Makefile”?#8220;makefile”的文件中Q然后在该目录下直接输入命o“make”可以生成执行文件edit。如果要删除执行文g和所有的中间目标文gQ那么,只要单地执行一?#8220;make clean”可以了?<br><br>在这个makefile中,目标文gQtargetQ包含:执行文gedit和中间目标文Ӟ*.oQ,依赖文gQprerequisitesQ就是冒号后面的那些 .c 文g?nbsp;.h文g。每一?nbsp;.o 文g都有一l依赖文Ӟ而这?nbsp;.o 文g又是执行文g edit 的依赖文件。依赖关pȝ实质上就是说明了目标文g是由哪些文g生成的,换言之,目标文g是哪些文件更新的?<br><br>在定义好依赖关系后,后箋的那一行定义了如何生成目标文g的操作系l命令,一定要以一个Tab键作为开头。记住,makeq不命令是怎么工作的,他只执行所定义的命令。make会比较targets文g和prerequisites文g的修Ҏ期,如果prerequisites文g的日期要比targets文g的日期要斎ͼ或者target不存在的话,那么Qmake׃执行后箋定义的命令?<br><br>q里要说明一点的是,clean不是一个文Ӟ它只不过是一个动作名字,有点像C语言中的lable一P其冒号后什么也没有Q那么,make׃会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,p在make命o后明昑־指出q个lable的名字。这LҎ非常有用Q我们可以在一个makefile中定义不用的~译或是和编译无关的命oQ比如程序的打包Q程序的备䆾Q等{?br> <img src ="http://www.shnenglu.com/ivenher/aggbug/22086.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/ivenher/" target="_blank">爱饭?/a> 2007-04-17 10:48 <a href="http://www.shnenglu.com/ivenher/articles/22086.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>makefile详解 概述 一http://www.shnenglu.com/ivenher/articles/22085.html爱饭?/dc:creator>爱饭?/author>Tue, 17 Apr 2007 02:47:00 GMThttp://www.shnenglu.com/ivenher/articles/22085.htmlhttp://www.shnenglu.com/ivenher/comments/22085.htmlhttp://www.shnenglu.com/ivenher/articles/22085.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/22085.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/22085.htmlgunguymadman  发表于:2007-04-09 07:58:37

概述
—?

什么是makefileQ或许很多Winodws的程序员都不知道q个东西Q因为那些Windows的IDE都ؓ你做了这个工作,但我觉得要作一个好的和professional的程序员Qmakefileq是要懂。这好像现在有q么多的HTML的编辑器Q但如果你想成ؓ一个专业h士,你还是要了解HTML的标识的含义。特别在Unix下的软g~译Q你׃能不自己写makefile了,会不会写makefileQ从一个侧面说明了一个h是否具备完成大型工程的能力?

因ؓQmakefile关系C整个工程的编译规则。一个工E中的源文g不计敎ͼ其按cd、功能、模块分别放在若q个目录中,makefile定义了一pd的规则来指定Q哪些文仉要先~译Q哪些文仉要后~译Q哪些文仉要重新编译,甚至于进行更复杂的功能操作,因ؓmakefile像一个Shell脚本一P其中也可以执行操作系l的命o?

makefile带来的好处就是—?#8220;自动化编?#8221;Q一旦写好,只需要一个make命oQ整个工E完全自动编译,极大的提高了软g开发的效率。make是一个命令工P是一个解释makefile中指令的命o工具Q一般来_大多数的IDE都有q个命oQ比如:Delphi的makeQVisual C++的nmakeQLinux下GNU的make。可见,makefile都成Z一U在工程斚w的编译方法?

现在讲述如何写makefile的文章比较少Q这是我惛_q篇文章的原因。当Ӟ不同产商的make各不相同Q也有不同的语法Q但其本质都是在“文g依赖?#8221;上做文章Q这里,我仅对GNU的makeq行讲述Q我的环境是RedHat Linux 8.0Qmake的版本是3.80。必竟,q个make是应用最为广泛的Q也是用得最多的。而且其还是最遵@于IEEE 1003.2-1992 标准的(POSIX.2Q?

在这文档中Q将以C/C++的源码作为我们基Q所以必然涉及一些关于C/C++的编译的知识Q相关于q方面的内容Q还请各位查看相关的~译器的文档。这里所默认的编译器是UNIX下的GCC和CC?

 

关于E序的编译和链接
—————————?

在此Q我惛_说关于程序编译的一些规范和ҎQ一般来_无论是C、C++、还是pasQ首先要把源文g~译成中间代码文Ӟ在Windows下也是 .obj 文gQUNIX下是 .o 文gQ即 Object FileQ这个动作叫做编译(compileQ。然后再把大量的Object File合成执行文gQ这个动作叫作链接(linkQ?

~译Ӟ~译器需要的是语法的正确Q函C变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位|(头文件中应该只是声明Q而定义应该放在C/C++文g中)Q只要所有的语法正确Q编译器可以编译出中间目标文g。一般来_每个源文仉应该对应于一个中间目标文ӞO文g或是OBJ文gQ?

链接Ӟ主要是链接函数和全局变量Q所以,我们可以使用q些中间目标文gQO文g或是OBJ文gQ来链接我们的应用程序。链接器q不函数所在的源文Ӟ只管函数的中间目标文ӞObject FileQ,在大多数时候,׃源文件太多,~译生成的中间目标文件太多,而在链接旉要明昑֜指出中间目标文g名,q对于编译很不方便,所以,我们要给中间目标文g打个包,在Windows下这U包?#8220;库文?#8221;QLibrary File)Q也是 .lib 文gQ在UNIX下,是Archive FileQ也是 .a 文g?

ȝ一下,源文仉先会生成中间目标文gQ再׃间目标文件生成执行文件。在~译Ӟ~译器只程序语法,和函数、变量是否被声明。如果函数未被声明,~译器会l出一个警告,但可以生成Object File。而在链接E序Ӟ链接器会在所有的Object File中找d数的实现Q如果找不到Q那到就会报链接错误码(Linker ErrorQ,在VC下,q种错误一般是QLink 2001错误Q意思说是说Q链接器未能扑ֈ函数的实现。你需要指定函数的Object File.

好,a归正传,GNU的make有许多的内容Q闲a叙Q还是让我们开始吧?


]]>
什么代码才是线E安全的http://www.shnenglu.com/ivenher/articles/15815.html爱饭?/dc:creator>爱饭?/author>Thu, 30 Nov 2006 08:11:00 GMThttp://www.shnenglu.com/ivenher/articles/15815.htmlhttp://www.shnenglu.com/ivenher/comments/15815.htmlhttp://www.shnenglu.com/ivenher/articles/15815.html#Feedback4http://www.shnenglu.com/ivenher/comments/commentRss/15815.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/15815.html
所以学习多U程~程最重要的不是学习API,而是理解什么才是多U程安全的代?br />
从例子说?br />
#include <windows.h>
#include 
<process.h>

long global1 = 0;
volatile long global2 = 0;

class MyClass
{
public:
    MyClass() : m(
0)
    {
        
++m;
    }

    
int fun(int v)
    {
        
return m+v; //-----------9
    }

    
void set(int v)
    {
        m 
= v;   //-------------10
    }
    
int m;
};

MyClass global_object; 
//-------------8

unsigned 
int __stdcall thread_fun1(void *param)
{
    
static int static2 = 0;
    
static MyClass static_object; //--------6
    int local1 = 0;
    
    
++local1;     //-------1
    ++static2;    //-------2
    ++global1;    //-------3
    ++global2;    //-------4
    InterlockedIncrement(&global1); //--------5

    local1 
= global_object.fun(local1); //----------7

    global_object.
set(local1); //---------------11

    
return 0;
}


unsigned 
int __stdcall thread_fun2(void *param)
{
    
++global1;    //-------3
    ++global2;    //-------4
    InterlockedIncrement(&global1); //--------5

    global_object.
set(1); //-----------11
    return 0;
}


int main()
{
    HANDLE thread1 
= (HANDLE)_beginthreadex(0,0,&thread_fun1,0,0,0); //thread 1
    HANDLE thread2 = (HANDLE)_beginthreadex(0,0,&thread_fun1,0,0,0); //thread 2
    HANDLE thread3 = (HANDLE)_beginthreadex(0,0,&thread_fun2,0,0,0); //thread 3
    
    WaitForSingleObject(thread1,INFINITE);
    WaitForSingleObject(thread2,INFINITE);
    WaitForSingleObject(thread3,INFINITE);
    
    
return 0;
}




1.局部变量局部用是安全?br />Z?因ؓ每个thread 都有自己的运行堆栈,而局部变量是生存在堆栈中,大家不干扰?br />所以代?
int local1;
++local1;
是安全的

2.全局原生变量多线E读写是不安全的
全局变量是在?heap)?br />long global1 = 0;
++global2;
++q个操作其实分ؓ两部Q一个是读,另外一个是?br /> mov         ecx,global
 add         ecx,1
 mov         global,ecx
所以代?处是不安全的

3.函数静态变量多U程d也是不安全的
道理?
所以代?处也是不安全?br />
4.volatile能保证全局整Ş变量是多U程安全的么
不能?br />volatile仅仅是告诫compiler不要对这个变量作优化Q每ơ都要从memory取数|而不是从register
所以代?也不是安?br />
5.InterlockedIncrement保证整型变量自增的原子?/strong>
所以代?是安全的

6.function static object的初始化是多U程安全的么
不是?br />著名的Meyer Singleton其实不是U程安全?br />Object & getInstance()

     static Object o;
     return o;
}
可能会造成多次初始化对?br />所以代?处是不安全的

7.?2机器上,4字节整Ş一ơassign是原子的
比如
i =10; //thread1
i=4; //thread2
不会Di的值处于未知状?要么?0要么?


写好多线E安全的法宝是装Q数据有保护的被访问到
安全性:
局部变?gt;成员变量>全局变量

]]>
内存寚whttp://www.shnenglu.com/ivenher/articles/15782.html爱饭?/dc:creator>爱饭?/author>Wed, 29 Nov 2006 07:36:00 GMThttp://www.shnenglu.com/ivenher/articles/15782.htmlhttp://www.shnenglu.com/ivenher/comments/15782.htmlhttp://www.shnenglu.com/ivenher/articles/15782.html#Feedback0http://www.shnenglu.com/ivenher/comments/commentRss/15782.htmlhttp://www.shnenglu.com/ivenher/services/trackbacks/15782.html在我们的E序中,数据l构q有变量{等都需要占有内存,在很多系l中Q它都要求内存分配的时候要寚wQ这样做的好处就是可以提高访问内存的速度?br />

 我们q是先来看一D늮单的E序Q?br />

                                E序一
 1 #include <iostream>
 2 using namespace std;
 3 
 4 struct X1
 5 {
 6   int i;//4个字?/span>
 7   char c1;//1个字?/span>
 8   char c2;//1个字?/span>
 9 };
10 
11 struct X2
12 {
13   char c1;//1个字?/span>
14   int i;//4个字?/span>
15   char c2;//1个字?/span>
16 };
17 
18 struct X3
19 {
20   char c1;//1个字?/span>
21   char c2;//1个字?/span>
22   int i;//4个字?/span>
23 };
24 int main()
25 {   
26     cout<<"long "<<sizeof(long)<<"\n";
27     cout<<"float "<<sizeof(float)<<"\n";
28     cout<<"int "<<sizeof(int)<<"\n";
29     cout<<"char "<<sizeof(char)<<"\n";
30 
31     X1 x1;
32     X2 x2;
33     X3 x3;
34     cout<<"x1 的大?/span>"<<sizeof(x1)<<"\n";
35     cout<<"x2 的大?/span>"<<sizeof(x2)<<"\n";
36     cout<<"x3 的大?/span>"<<sizeof(x3)<<"\n";
37     return 0;
38 }

      
      q段E序的功能很单,是定义了三个结构X1,X2,X3,q三个结构的主要区别是内存数据摆放的顺序,其他都是一LQ另外程序输入了几种基本cd所占用的字节数Q以及我们这里的三个l构所占用的字节数?br />
q段E序的运行结果ؓQ?br />

1 long 4
2 float 4
3 int 4
4 char 1
5 x1 的大?/span>8
6 x2 的大?/span>12
7 x3 的大?/span>8


     l果的前面四行没有什么问题,但是我们在最后三行就可以看到三个l构占用的空间大不一P造成q个原因是内部数据的摆N序,怎么会这样呢Q?br />
    下面是我们需要讲的内存对齐了?br />
    内存是一个连l的块,我们可以用下面的图来表示,  它是?个字节对一个对齐单位的Q?br />
                                                    图一

mem1.jpg

   让我们看看三个结构在内存中的布局Q?br />
   首先?X1Q如下图所C?br />

mem2.jpg


    X1 中第一个是 IntcdQ它占有4字节Q所以前?格就是满了,然后W二个是charcdQ这中类型只占一个字节,所以它占有了第二个4字节l块中的W一|W三个也是charcdQ所以它也占用一个字节,它就排在了第二个l块的第二格Q因为它们加在一起大也不超q一个块Q所以他们三个变量在内存中的l构是q样的,因ؓ有内存分块对齐,所以最后出来的l果?Q而不?Q因为后面两个格子其实也是被用了?br />
    再次看看X2Q如图所C?br />

mem4.jpg

    X2中第一个类型是CharcdQ它占用一个字节,所以它首先排在W一l块的第一个格子里面,W二个是IntcdQ它占用4个字节,W一l块已经用掉一|q剩3|肯定是无法放下第二Intcd的,因ؓ要考虑到对齐,所以不得不把它攑ֈW二个组块,W三个类型是CharcdQ跟W一个类伹{所因ؓ有内存分块对齐,我们的内存就不是8个格子了Q而是12个了?br />

再看看X3Q如下图所C:



mem3.jpg

   关于X3的说明其实跟X1是类似的Q只不过它把两个1个字节的攑ֈ了前面,怿看了前面两种情况的说明这里也是很Ҏ理解的?br />



]]>
Ʒþþþù3d| һɫþ88Ʒۺ | AVݺɫۺϾþ | Ůͬþ| þþþһƷ| ˾þ91| þùƷӰԺ| ɫۺϾþþĻ| ŮþþŮ| ˾Ʒþþþ7777| ٸۺϾþĻ | ٸ88þĻ| ޾Ʒþþþϼ | avԾþþþa鶹 | þþ| þþþòҰ¸߳| þۺɫHEZYO| þþƷձҰ| þþþAVרJN| þþƷþһ| ޹Ʒ˾þ| þɧ| պƷھþ| 99þۺϹƷ| þۺϾɫۺŷȥ | þþþþƷAV| ٸþĻһ | Ʒݾþþþø99| þù˾Ʒ| þþþֻоƷ | 99þùѸ| þþþþùaѹۿ| ŷһþþƷ| þһ| Ʒþۺ| þ°Ҳȥ| þþ޾Ʒ| þþƷҹɫA| ޹Ʒþ| þþù| ޾ƷŮþ777777|