另外一份杂记

时间:2022-09-01 22:52:08


可以edit的JComboBox,将输入的值添加到JComboBox中:
// assume you have a JComboBox named "cb"
cb.setEditable(true);

ComboBoxEditor editor = cb.getEditor();
Component component = editor.getEditorComponent();
component.addKeyListener(new KeyAdapter() {
 public void keyPressed(KeyEvent e) {
  if ( e.getKeyCode == KeyEvent.VK_F5 ) {
   ComboBoxEditor editor = cb.getEditor();
   cb.addItem(editor.getItem());
   cb.editor.setItem(null);
  }
 }
});

弹出窗口引用弹出它的窗口:var vArray = window.opener.oldData.length;
CTR + J --->自动加入addActionListener()等代码!!!跟ctr + shift + c很像

启动sessionserver,要配置security:
 使用的是哪个jdk是由path环境变量来决定的,而不是java-home,比如:
 PATH=C:/j2sdk1.4.2_04/jre/bin;D:/oracle/ora92/bin;D:/Program Files/Oracle/jre/1.
  3.1/bin;D:/Program Files/Oracle/jre/1.1.8/bin;D:/WINNT/system32;D:/WINNT;D:/WINN
  T/System32/Wbem;"E:/Program Files/Symantec/Norton Ghost 2003/";C:/j2sdk1.4.2_04/
  bin;D:/WINNT/system32;D:/WINNT;D:/WINNT/System32/Wbem;D:/Program Files/UltraEdit
  此时使用的是C:/j2sdk1.4.2_04/jre/bin(注意:不是C:/j2sdk1.4.2_04/,暂不太清楚这两者有何区别。) 。
  对于设置security,这个是很重要的。
启动tomcat:
 可以不用startup.bat命令,而用catalina run 或catalina startup

要拷贝:C:/j2sdk1.4.2_04
  E:/essp
  E:/Tomcat
  
改oracle的端口:
 那个大侠可以帮帮我呢,我想让一台计算机同时作web服务器和数据库服务器,但是oracle占用了80端口,web就用不了,请各位帮我解决一下,拜托了
  这是由于oracle内置Apache造成的,可以更改Apache的应用端口,方法如下:
  请修改目录oracle/ora81/Apache/Apache/conf中的两个文件:httpd.conf、httpd.conf.default,将文件中的端口由80改为8080即可将Apache的应用端口改为8080端口,重新启动Apache,Web就能使用80端口了,此时Apache使用的是8080端口。
  若你不知道Apache如何重启,就重新启动你的计算机,重启后,问题应当解决。
试验发现,如果不在init文件中设参数的话,Oracle仍然会要求一个随机端口和1521端口来共同通讯,只是这个随机端口,并不随客户端会话和登录的变化而变化,在没有重启服务器时,是固定的。
 (试验发现,在专用模式下,每次连接,oracle服务器会按+1方式,提供一个非1521的端口。)
 所以,还需要在init.ora文件的最后加上一条参数:
 mts_dispatchers="(address=(protocol=tcp)(host=myoradb)(port=1521))(dispatchers=1)"
随机端口有很多解决办法,一般是在WINDOWS下要开启SHARED SOCKET功能,于是在注册表HKEY_LOCAL_MACHINE/Software/Oracle/HOME0下设了USE_SHARED_SOCKET=TRUE,小心地试了一把竟然就成功了,原来还以为都讲的是ORACLE8,没想到ORACLE9上也适用,很不错啦。
 
 MTS(多线程服务器)在 INIT.ORA 文件中进行配置,INIT.ORA 样本的参数设置
 如下所示:
 mts_dispatchers="ipc,1"
 mts_dispatchers="tcp,1"
 mts_max_dispatchers=10
 mts_servers=1
 mts_max_servers=10
 mts_service=TEST
 mts_listener_address="(ADDRESS=(PROTOCOL=ipc)(KEY=TEST))"
 mts_listener_address="(ADDRESS=(PROTOCOL=tcp)(HOST=10.74.72.42)(PORT=1526))"

REGEDIT命令编辑注册表。

http 500,503错误为servlet程序错误,400,403可能是找不到servlet。
如果applet jar包没有进行认证,会出现security异常。
教训:如果一个属性的设置没有作用,那么可以试着在程序运行的最后设置该属性,因为太靠前设置的话,可能没效,被后面的设置覆盖了。
prm_tr = eval("tr"+i); 可以由字符串得到对象,对象的id为该字符串。
教训:在老的essp中,页面F006_top_list.jsp中提交修改时出现“MII未定义”错误,其中MII为公司代码。
 原因是:在方法wait()中,setTimeout()的参数为compid,有下面两种方式:
  setTimeout("wait('" +iCompid+ "', " +trid+ ")",50);     --》 正确:给icompid加上单引号
  setTimeout("wait(" +iCompid+ ", " +trid+ ")",50);     --》 错误:该表达式可能为wait(MII,12),而MII是未定义的对象。
怎么在启动tomcat前为log4就设 system property -- log4j.configuration? 
-- 设置环境变量CATALINA_OPTS 为 set TOMCAT_OPTS=-Dlog4j.configuration=foobar.lcf -Dlog4j.configuratorClass=com.foo.BarConfigurator
 or set TOMCAT_OPTS=-Dlog4j.configuration=file:/c:/foobar.lcf
1.牢记:在url中路径用 ..//logs//debug.log,不然单斜线会被ingore
2.作applet - servlet通讯用的类及其成员要serailizable。
3.如果一个类总是reload不了,可以考虑重起tomcat,清空workdir,在jbuilder中rebuild web。
4.In the java world, use "/" replace of "/" which is used in window.
5.net use
//10.5.2.222/IPC$ /del
 type C:/bat/a.txt  在控制台显示文件a.txt的内容。
 cls 清屏
6.在文件中搜索字符串。
 FIND [/V] [/C] [/N] [/I] "string" [[drive:][path]filename[ ...]]
 
   /V        显示所有未包含指定字符串的行。
   /C        仅显示包含字符串的行数。
   /N        显示行号。
   /I        搜索字符串时忽略大小写。
   "string"  指定要搜索的文字串,
   [drive:][path]filename
             指定要搜索的文件。
 
 如果没有指定路径,FIND 将搜索键入的或者由另一命令产生的文字。
7 start cmd /k
 新开一个窗口运行命令cmd。
Soft-ice无疑是动态调试领域最重要的工具 
8。rononce -p ----15秒关机
9。系统的缺省库的路径/lib /usr/lib /usr/local/lib 在这三个路径下面的库,我们可以不指定路径.
10。 有时候我们使用了某个函数,但是我们不知道库的名字,这个时候怎么办呢?
 很抱歉,对于这个问题我也不知道答案,我只有一个傻办法.首先,我到标准库路径下面去找看看有没有和我用的函数相关的库,我就这样找到了线程(thread)函数的库文件(libpthread.a).
 当然,如果找不到,只有一个笨方法.比如我要找sin这个函数所在的库. 就只 好用 nm -o /lib/*.so|grep sin>~/sin 命令,然后看~/sin文件,到那里面去找了.
 在sin文件当中,我会找到这样的一行libm-2.1.2.so:00009fa0 W sin 这样我就知道了sin在 libm-2.1.2.so库里面,我用 -lm选项就可以了(去掉前面的lib和后面的版本标志,就剩下m了所以是 -lm).
11。头文件和系统求助

  有时候我们只知道一个函数的大概形式,不记得确切的表达式,或者是不记得着函数在那个头文件进行了说明.这个时候我们可以求助系统.

  比如说我们想知道fread这个函数的确切形式,我们只要执行 man fread 系统就会输出着函数的详细解释的.和这个函数所在的头文件说明了. 如果我们要write这个函数的说明,当我们执行man write时,输出的结果却不是我们所需要的. 因为我们要的是write这个函数的说明,可是出来的却是write这个命令的说明.为了得到write的函数说明我们要用 man 2 write. 2表示我们用的write这个函数是系统调用函数,还有一个我们常用的是3表示函数是C的库函数.

  记住不管什么时候,man都是我们的最好助手.

 

13.当连接器运行时,它首先会扫描输入文件,找出每个段的大小,收集所有符号的定义和引用。连接器会建立一个段表记录输入文件中所有的段,一个符号表记录所有导入或导入的符号。
利用第一遍扫面的得到的数据,连接器为每个符号分配数字地址,确定输出文件中段的大小和位置,计算出各个部分需要出现在输出文件的什么位置。
第二遍扫描利用在第一遍扫描中收集的信息来控制实际的连接过程。连接器读入并重载目标代码,把符号引用换成数字地址,调整代码和数据中的内存地址以反映重载后的段地址,将重载后的代码写入输出文件中。最后将输出文件连同头部信息,重载的段和符号表信息写入磁盘. 
14。每个全局符号都由一个下划线开始,原因在第5章中说明
15. 任何N字节的数据的地址必须有至少log2(N)个低位的零.
 没有对齐的数据会造成性能的降低,在一些系统 (多数RISC芯片系统) 中还会造成程序错误。 
 很多处理器对程序指令都有对齐的要求,多数RISC芯片要求指令必须对齐到4字节边界。
16.从一个连接器的角度来看,连接器需要调整的地址和偏移量域都对齐到字节边界,所以连接器无需考虑指令编码。
17.直到60年代,可寻址的内存变大,如果使用可以保存整个地址空间得指令集会占掉过多的仍然十分宝贵的内存空间。
 为了解决这个问题,计算机设计师在一些或全部指令中取消了直接寻址方法,而使用索引和基寄存器来提供寻址中使用的位数中的部分或全部。指令可以变得更短,但造成了更加复杂的编程。 
18.如果一次大的改动后,编译和run都成问题,那么可以全部checkout一次。
 如果tomcat出现莫名其妙的问题,可以:
 1)编译整个工程
 2)clean web模块,build  web模块
 3)更换tomcat
 4)如果1、2、3都不管用,那么可能是源程序或包有问题,极有可能是有程序或包没有出出来。
  从cvs中checkout整个工程。
 5)如果是run essp,那么记得启动session server。
19.log4j.properties中下面行:
 log4j.rootCategory=info, stdout
   要有,它使所有Log都有一个appender——stdout.如果没有的话,那么没有在log4j.properties中定义的log将会找不到appender。
   比如Category log = Category.getInstance( MyTest.class.getName() );  就在log4j.properties中没有定义。
20.在strust中如果
  <strust:form action="myAction">
 中的myAction在strustConfig.xml中找不到的话,会出错:画面出不来,也没有提示信息。
 
 实际上,如果下面的依赖关系不满足的话,就会出错:画面出不来,也没有提示信息,入下:
 
 1) <html:text  styleId = "qualityActivity"  fieldtype = "text"  name = "qualityActivity"  beanName = "QTActvForm" />
 
  a)styleId在.css文件中有定义,如果没有,该控件就按flowlayout去放置,不会出现什么错误。
  b)beanName = "QTActvForm" 在struts_config.xml中定义的:
  
    <form-bean name="QTActvForm" type="server.essp.qc.qtActv.form.FQC01020_QTActvForm" />
   
   在action中引用这个form:
   
    <action name="QTActvForm" path="/QTActv" scope="request" type="server.essp.qc.qtActv.action.FQC01020_QTActvAction" validate="true">
        <forward name="QTActv" path="/qc/qtActv/FQC01020_QTActv.jsp" />
       </action>
     
      在FQC01020_QTActvAction中为该form设值:
     
       request.setAttribute("QTActvForm", rtnActionForm);
 
  在这四个位置中:beanName(jsp中)、name(struts-config.xml的form-bean标签)、name(struts-config.xml的action标签)、key(Action类中request.setAttribut())
  如果1、2、3个名字不同的话,jsp中控件的值就不能传到Action中;
  如果1、2、4个名字不同的话,action中的设到request中的值就不能自动设到jsp中去。
  
  这四个位置的名字不同不会引起异常或错误,画面会显示。
  c)name="qualityActivity"指定form —— QTActvForm的一个属性。
   注意:区分大小写。
   典型地:在server.essp.qc.qtActv.form.FQC01020_QTActvForm.java中:
    private String qualityActivity;
    
   如果qualityActivity不是form —— QTActvForm中的一个属性,那么会出错:画面一片空白。
 
 2)<html:form action="/QTActv" >
 
  这里指定接受表单提交的action的url,它要在struts-config.xml中定义:
  
   <action name="QTActvForm" path="/QTActv" scope="request" type="server.essp.qc.qtActv.action.FQC01020_QTActvAction" validate="true">
       <forward name="QTActv" path="/qc/qtActv/FQC01020_QTActv.jsp" />
      </action>
  
  是action标签中的path="/QTActv".
  
  如果在struts-config.xml中找不到匹配"/QTActv"url的action,那么会出错:画面一片空白或者出现下面的错误信息:
   org.apache.jasper.JasperException: Cannot retrieve mapping for action /QTActv
  。
  
 3)<forward name="QTActv" path="/qc/qtActv/FQC01020_QTActv.jsp" />
 
  这个标签在struts-config.xml中定义。表示一个转向的url。
  在action中引用这个forward,进入转向的页面:
   
    return mapping.findForward("QTActv");
   
  如果"QTActv"在struts-config.xml找不到的话,那么转向的页面就一片空白。
  
21.如果formbean中的一个属性的值为null,那么该属性同名的控件会显示默认的值(即在jsp中写的value="xxx")。
 如果null表示“没有值”,而不是“默认值”,那么这种情况要避免。比如当这个值为null时,将其设为""。
22?message 如何显示?
 怎么自动验证数据?
 提交表单后,在action中forward的页面总是在新窗口中打开,怎么样不打开新窗口。
 表格的css样式没有定义(如何只关注数据,不关心显示)
 如何使html中的表格像applet中一样显示:title固定不变,数据行很多时自动出现滚动条。
 如何捕获表格的行点击、双击操作。
 当修改、新增、删除一条数据后如何使table同步显示?用刷新吗?
 当有控制变量时,是将它放在formbean中,还是不放在formabean中(action中用request.getParameter()取)?
 
 servlet端的出错信息如何显示?
 
 框架结构能否写成模版。
22. md21的用法:
  1)E:/BAK/0706/md21/samples/config/database 中配置数据库,md21即是根据此配置来生成数据库的所有表的xml和java文件。
  2)E:/BAK/0706/md21/samples/build.xml中有一行是指定数据库配置文件:
   <!ENTITY database SYSTEM "file:./config/database/mysql.xml">
  3)启动数据库(比如mysql数据库)
  4)运行命令:ant -f E:/BAK/0706/md21/samples/build.xml
   在生成的图形界面中为所需表的每个字段指定正确的java数据类型。
   点击generate按钮,将在E:/BAK/0706/md21/samples/build/gen-src/essp/tables文件夹下生成xml文件。
  5)运行命令:ant -f E:/BAK/0706/md21/samples/build.xml hbm2java
   将在E:/BAK/0706/md21/samples/build/gen-src/essp/tables文件夹下生成java文件。
   这一步实际上是根据xml文件生成java文件。
23.rtexprvalue:是否支持运行时表达式取值,即值是否可以用<%=abc%> 来指定。
 比如:<input type=text value=<%=age%> /> 其中type属性的rtexprvalue=false, value属性的rtexprvalue=true。(我猜想type是不能运行时指定值的的)
24.请求的范围:
 session-scoped内的对象是在整个会话过程中可用。
 page-scoped内的对象是在特定jsp页面中可用。可以认为是jsp对应的java类的局部变量
 request-scoped内的对象是在当前请求/应答循环生命期内可用。它看上去和page-session很像,但是(例如)当jsp页面使用重定向(<jsp:forward page="other.jsp" />)
  将浏览器送往另一个页面时,对象依然可用。
 application-scoped内的对象在web应用内任何请求中都可用。
25.在jsp中写的java代码叫scriptlet,比如:<%=request.getParameter("name")%>
 scriptlet的一种注释方式:<%-- This is a comment.
         --%>
26.pageDesign的问题: 
 没法改变formbean,既使指定了formbean,也没用。
 如果指定require的话,生成jsp时总报“请刷新页面信息”
 如何指定前一个控件,后一个控件。
27.Attribute type invalid according to the specified TLD 该错误是因为:tld文件中这个tag没有定义属性type.
28.在sql server中的查询分析器中的语句:
 insert into [UPLOAD_LOG_TEMP] select * from [FA].[dbo].[UPLOAD_LOG] where modifydate='2004-05-04 00:16:07.000'

 有时候要指定表(fa)和角色(dbo)         
29.jsp编译异常:quote symbol expected
,原因是:tag的属性的值必须要用引号扩起来。比如<html:form action="xp.do" >
30.奇怪的jsp编译、运行错误:
 org.apache.jasper.JasperException
 
 at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:254) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241) ............................................
 
 [ERROR]org.apache.struts.taglib.tiles.InsertTag$InsertHandler.doEndTag(InsertTag.java:922) - ServletException in '/qc/qtActv/FQC01020QualityActivityListContent2.jsp': null org.apache.jasper.JasperException ............................................
 
 ApplicationDispatcher[/crm]: Servlet.service() for servlet debugjsp threw exception org.apache.jasper.JasperException: ServletException in '/qc/qtActv/FQC01020QualityActivityListContent2.jsp': null ...........................................
 
 上面的是摘要的。
 错误的原因是一个强制类型转换出错了:( (FQC01020QualityActivityForm)oneBean ).getRid()
 应该是( (FQC01020QualityActivityVBean)oneBean ).getRid()
 谁能从这个现象看得出原因呢?
31.jsp生成java文件时,为什么有的tag对应一个函数调用,有的tag对应一段代码?比如<logic:equal>tag就是对应一段代码。<bean:write>就是对应一个函数调用。
32.如果form的method为get,那么提交后的页面的地址会看到问号连接的参数,形如:
http://localhost:8080/crm/qc/qtActv/qualityActivityInsertAction.do?focus_name=production&list_start_index=-1&subsessionid=&change_flag=&cancel_flag=&forward_path=&querystring=&back_path=&context_path=%2Fcrm&url_suffix=.do&text_length_evaluation_mode=byte&rid=&qualityActivityType=5&qualityActivity=&production=&productionUnit=&method=&criterion=&remark=&productionSizePlan=0&densityPlan=0.00&defectRatePlan=0.00&productionSizeAct=0&densityAct=0.00&defectRateAct=0.00&caseAct=0&defectAct=0&btnOk=btnOk
33.tiles标签的page属性:<tiles:insert page="/layout/tabbedLayout.jsp" flush="true"/> 其中的uri是相对应用的根目录。比如应用为crm,则完整路径为/crm/layout/tabbedLayout.jsp。
 千万不要再多余地加/crm,不然就成了/crm/crm/layout/tabbedLayout.jsp。
 更bt地是,找不到文件不会报错。
 
 如果page指定的页面没有对应的java文件生成,那么多半是因为指定的文件找不到。
34.象下面的不明不白的jsp异常:
 ApplicationDispatcher[/crm]: Servlet.service() for servlet debugjsp threw exception org.apache.jasper.JasperException at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:254) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241) 
 多半是因为出现异常,比如空指针。

35.在strust-config.xml中定义action 时如果没有指定form属性,会出现下面的异常:
 unretrieve form null on action ......
 
 如果这个action不出现在jsp中(即为form的action属性的值),好像不会出现上面的异常。
36.看看下面的异常是什么原因:
 
 org.apache.jasper.JasperException: /qc/qtActv/defect/FQC01021DefectUpdate.jsp(42,33) equal symbol expected
 
 at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:94) at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:428) 
 原因是有一个非法字符:
     <html:optionsCollection  name? = "webVo"  property="injectedPhaseList" />
 在属性name的后面有一个非法字符。     
37.在一个文件中的开始加上:
 <%@ page contentType="text/html; charset=GBK" %>
 不然汉字可能会有乱码。
38.
 1:table的列对不齐
 2:如何调整css样式,比如label的背景为什么颜色?整体风格要想日本人的那样吗? --no
 !!!我还是认为用绝对定位会使代码清晰很多!
 不然,如果增加一个控件,那么多个程序要增加这个控件,并且每个程序要增加布局代码。
 如果用绝对定位的话,只需改变css文件,然后在每个文件中增加这个控件。 
 
39.
 下面的异常:
 org.apache.jasper.JasperException: No getter method for property  of bean webVo
 
 原因是bean中没有一个属性。
41.
 native2java将汉字转成utf-8时会出现下面的问题:
  "请先选择要删除的质量目标。" -->"/u7487/u5cf0/u539b/u95ab/u590b/u5ae8/u7455/u4f78/u57b9/u95c4/u3087/u6b91/u7490/u3129/u567a/u9429/ue1bd/u7223/u9286/ufffd
 
 最后一个引号弄掉了。
 解决办法是在最后多加一个或多个空格。  

42. <bean:parameter id="rid" name="rid"  value=""/>
 上面的value属性很重要,它是默认值。如果request.getParameter("rid")为null, 那么它的值就为value指定的值,如果没有指定,则为null.
 如果没有parameter rid,又没有指定value,那么会出异常。
 很奇怪,这个异常没有在tamcat中报出来。————〉查源码很辛苦啊。
 
 今天又出现同样的问题,但没找出原因。因为不能调试进struts的parameterTag类。郁闷
43.在用ant编译struts时遇到很奇怪的问题,如果编译的classpath中包含了struts.jar,那么编译有错;将它删除后就好了。
 用ant编译时会有jar包的版本问题,比如commons-logging-api.jar和commons-logging.jar,后面一个新一些。最好用最新的。
44.卡号:2781436590。
   订单号:3818804

//--------------------------------------------好网址---------------------
http://www.linuxforum.net/forum/postlist.php?Cat=&Board=program&page=&view=&sb=&o=
 
 
//--------------learning bat 文件 -----------------------
0. 如果命令太长,可以换行,换行符为 '^',这样就像写在一行是一样.
    注意在为环境变量设置时要小心空格:"set a = 1 ",这表示环境变量'a '的值为' 1 ',是不是很奇怪!!
    而且windows对路径敏感,一般环境变量的值为一个路径时,不要以'/'结尾。以为windows认为C:/temp//a.txt总是不存在地。
1. 将输出到控制台的字符输出到文件:> 和 >>
 命令: net use >a.txt 将输出结果写到文件a.txt中(输出结果就是准备打印到控制台的字符)。
  net use >>a.txt 将输出结果追加到文件a.txt中。
2、@ 
 @echo off -  @的作用就是让脚本在执行时不显示@后面的echo off部分,如果没有@则会在控制台打印出echo off字符
3、::
 这个命令的作用很简单,它是注释命令,在批处理脚本中和rem命令等效
5、:和goto
 goto是个跳转命令,:是一个标签,如下:
 echo begin
 goto end ::跳转到标签end去
 echo skip this line
 :end ::定义一个标签,和c语言的“end:”一样
 echo end
 end是一个标签,如果没有定义end,则会报错“系统找不道指定标签 - end”,但之前的语句会执行。
 标签后面的字符会被忽略:如: end echo end的echo end被忽略。
6、%
 这个百分号是批处理中的参数
 文件qq.bat中:
  echo %1 %2
 执行qq first second
  输出 first second
 参数依次叫"%1","%2","%3",作纯文本替换:在执行前做替换:
 改文件qq.bat为:
  echo %1ch%2
  %1ch%2 %1ch%2
 执行qq e o
 作文本替换后为:
  echo echo
  echo echo
 输出当然就为:echo
      echo 了。
 非常奇怪的是:参数%10无效,被认为是%1外加个0。这有个好处:不存在%1和%10的混淆,因为没有第10个参数。
7. %variable%     
 引用环境变量variable:如echo %java_home% 会打印出C:/j2sdk1.4.2_04
 与参数一样,这里也为纯文本替换,再执行。
    
 参数%和环境变量%%会混淆吗?不会:
  如果一个%后跟数字,则%2和%2%都是引用参数2
  如果一个%后跟字母,则一定是引用环境变量,要用%%括起。
  %2%2则是两个参数引用
  %java_home%c 是一个环境变量的引用和字符c的连接。
8。 &
 在同一行连接多个命令,比如(echo a)&(echo b).这些命令依次被执行
 &&
 在同一行连接多个命令,比如(echo a)&&(echo b).这些命令依次被执行,不过,一旦一个程序执行出错,就不再执行后面的程序。
 比较(del abx )&&(echo bbbb)与(del abx )&(echo bbbb)
 
10. |
 管道命令:就是让前一命令的输出当做后一命令的输入
 比如 help命令会列出所有的dos命令, more命令会将字符串或文件显示出来,如果太多,会翻屏显示。
 help | more 会把help的输出传给more,这样会一屏一屏地显示dos命令。
  ||
  这个命令的用法和&&几乎一样,但作用刚好和它相反:利用这种方法在执行多条命令时,当遇到一个执行正确的命令就退出此命令组合,不再继续执行下面的命令

11. <、>&、<&
 这三个命令也是管道命令,但它们一般不常用,你只需要知道一下就ok了,当然如果想仔细研究的话,可以自己查一下资料。
 
 <,输入重定向命令,从文件中读入命令输入,而不是从键盘中读入。
 >&,将一个句柄的输出写入到另一个句柄的输入中。
 <&,刚好和>&相反,从一个句柄读取输入并将其写入到另一个句柄输出中。
 
12 三个筛选器:
  more 命令每次显示一屏文件内容或命令输出。
  find 命令在文件和命令输出中搜索指定字符。
  sort 命令按字母顺序排列文件和命令输出。
  
  要将输入从文件发送到筛选器命令,请使用小于符号 (<)。比如:  
   sort < a.txt >b.txt
   将对文件a.txt的内容排序,每一行为一个元素,按元素从小到大的顺序排列。结果再写到文件b.txt中去。(很奇怪,如果是
   sort < a.txt >a.txt, 则文件a.txt为空;而 sort < a.txt >>a.txt,则是正常的。 )
 
 这三个命令都可以使用管道命令 | ,将上一个命令的输出作为自己的输入:
  dir | find ".LOG"
  dir命令列出当前文件夹的所有文件,find在其中找.log,输出含.log的行。(区分大小写)

8. if
 IF [NOT] ERRORLEVEL number command ::errorlevel为上一个程序的执行结果(可看作是main的返回参数,一般成功为0,失败为1),errrorlevel也是一个环境变量
 IF [NOT] string1==string2 command ::字串的比较,字串不须用引号括起。除非含空格
 IF [/I] string1 compare-op string2 command ::字符串的比较,compare-op可为:equ, neq, lss, leq, grt, geq
              ::选项/I表示比较时忽略大小写。
 IF [NOT] EXIST filename command  ::判断文件名是否存在
 IF [NOT] defined variable command ::判断环境变量variable是否定义
 比较字符串时,如果有一边的字符没有,则会报错。
  if - else
 
 ELSE 命令必须与 IF 命令的尾端在同一行上。
 1。命令: if exist C:/bat/a.txt. del C:/bat/a.txt. else echo C:/bat/a.txt is missing. 没有效。
   del命令的下一条命令必须转行,else命令必须转行。
 2。命令: if exist C:/bat/a.txt. del C:/bat/a.txt.
     else echo C:/bat/a.txt is missing. 没有效。
     因为ELSE 命令必须与 IF 命令的尾端在同一行上。 
 3。命令: IF EXIST C:/bat/a.txt. (
           del C:/bat/a.txt.
       ) ELSE (
           echo C:/bat/a.txt is missing.
       )
  正确。这里用括号将命令括起,则if 的尾端为右括号)。
 3。命令: IF EXIST C:/bat/a.txt. (del C:/bat/a.txt. ) ELSE ( echo C:/bat/a.txt is missing. )
  正确。命令可以用括号括起。
 
9. for

 (下面中的“文件”字眼多指“set”的一个元素,即并不仅指文件,还可以为字符)
 对一组文件中的每一个文件执行某个特定命令。
 
 FOR %variable IN (set) DO command [command-parameters]
 (注意:IN (set), in与左括号间有空格。)
 
   %variable  指定可替换的参数。
   (set)      指定一个或一组文件。可以使用通配符。
   command    指定对每个文件执行的命令。
   command-parameters
              对特定命令所指定的参数。
             
 (这里非常单纯,对set中的每个元素遍历。set中的元素用逗号隔开。)
 
 在批处理文件中使用 FOR 命令时, 指定变量请使用 %%variable
 而不要用 %variable。变量名称是区分大小写的,所以 %i 不同于 %I.
 
 (不知道“指定变量请使用 %%variable”是什么意思? —— 在控制台执行for命令,可以用% 或 %%形式; 在批处理文件中则只能用%%形式。
  实验发现:指定%I,或者%%I都可以,不过后续的变量也要对应地带%或%%。
  实验发现:如果set为*,则是遍历当前目录的所有文件,就好象指定了 /d 一样。
 )
 
 如果命令扩展名被启用,下列额外的 FOR 命令格式会受到
 支持:
 
 FOR /D %variable IN (set) DO command [command-parameters]
 
     如果集中包含通配符,则指定与目录名匹配,而不与文件
     名匹配。
 (举个例子 C:/bat>for /d %i in (C:/bat/*) do @echo %i
  输出: C:/bat/d
   C:/bat/复件 d
 这里的星号*表示合符条件的文件夹,从输出可以看出只列出文件夹,不管文件夹下的文件。)
 
 FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
 
     检查以 [drive:]path 为根的目录树,指向每个目录中的
     FOR 语句。如果在 /R 后没有指定目录,则使用当前
     目录。如果集仅为一个单点(.)字符,则枚举该目录树。
 (举个例子 C:/bat>for /r E:/tomcat/essp %k in (*) do @echo %k
  输出: E:/tomcat/essp/Shutdown.bat
   E:/tomcat/essp/Startup.bat
   E:/tomcat/essp/runsvr.bat.bak
   E:/tomcat/essp/runsvr.bat
 这里的星号*表示合符条件的文件
 如果集仅为一个单点(.)字符,则枚举当前目录的目录树,“枚举目录树”的意思是列出该文件夹及它的所有晚辈文件夹,但不含文件。 )
 
 FOR /L %variable IN (start,step,end) DO command [command-parameters]
 
     该集表示以增量形式从开始到结束的一个数字序列。
     因此,(1,1,5) 将产生序列 1 2 3 4 5,(5,-1,1) 将产生
     序列 (5 4 3 2 1)。
 (这里也很单纯,行如for( int i=start; i<=end; i+=step){} )
 
 FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
 FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
 FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
 
     或者,如果有 usebackq 选项:
 
 FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
 FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
 FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
 
     filenameset 为一个或多个文件名。继续到 filenameset 中的
    下一个文件之前,每份文件都已被打开、读取并经过处理。
     处理包括读取文件,将其分成一行行的文字,然后将每行
     解析成零或更多的符号。然后用已找到的符号字符串变量值
     调用 For 循环。以默认方式,/F 通过每个文件的每一行中分开
     的第一个空白符号。跳过空白行。您可通过指定可选 "options"
     参数替代默认解析操作。这个带引号的字符串包括一个或多个
     指定不同解析选项的关键字。这些关键字为:
 
         eol=c           - 指一个行注释字符的结尾(就一个)
         skip=n          - 指在文件开始时忽略的行数。
         delims=xxx      - 指分隔符集。这个替换了空格和跳格键的
                           默认分隔符集。
         tokens=x,y,m-n  - 指每行的哪一个符号被传递到每个迭代
                           的 for 本身。这会导致额外变量名称的分配。m-n
                           格式为一个范围。通过 nth 符号指定 mth。如果
                           符号字符串中的最后一个字符星号,
                           那么额外的变量将在最后一个符号解析之后
                           分配并接受行的保留文本。
         usebackq        - 指定新语法已在下类情况中使用:                   
                           在作为命令执行一个后引号的字符串并且一个单
                           引号字符为文字字符串命令并允许在 filenameset
                           中使用双引号扩起文件名称。
                           (
             表达的不是很清楚,重新整理如下:
              不指定userbackq时:set的元素若用双引号括起,则该原素看作字符串;若用单引号括起,则看作命令,该命令将先于for语句被执行(执行的输出当作set)。
     指定userbackq时,set的元素若用双引号括起,则该原素看作文件名,如果文件名中含空格,那么指定usebackq然后用双引号括起是
       有必要的。;如果用单引号括起,则看作字符串。 )
     
 
     某些范例可能有助:
 
 FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k
 
     会分析 myfile.txt 中的每一行,忽略以分号打头的那些行,将
     每行中的第二个和第三个符号传递给 for 程序体;用逗号和/或
     空格定界符号。请注意,这个 for 程序体的语句引用 %i 来
     取得第二个符号,引用 %j 来取得第三个符号,引用 %k
     来取得第三个符号后的所有剩余符号。对于带有空格的文件
     名,您需要用双引号将文件名括起来。为了用这种方式来使
     用双引号,您还需要使用 usebackq 选项,否则,双引号会
     被理解成是用作定义某个要分析的字符串的。
 
     %i 专门在 for 语句中得到说明,%j 和 %k 是通过
     tokens= 选项专门得到说明的。您可以通过 tokens= 一行
     指定最多 26 个符号,只要不试图说明一个高于字母 'z' 或
     'Z' 的变量。请记住,FOR 变量名分大小写,是通用的;而且,
     同时不能有 52 个以上都在使用中。
 
     您还可以在相邻字符串上使用 FOR /F 分析逻辑;方法是,
     用单引号将括号之间的 filenameset 括起来。这样,该字符
     串会被当作一个文件中的一个单一输入行。
 
     最后,您可以用 FOR /F 命令来分析命令的输出。方法是,将
     括号之间的 filenameset 变成一个反括字符串。该字符串会
     被当作命令行,传递到一个子 CMD.EXE,其输出会被抓进
     内存,并被当作文件分析。因此,以下例子:
 
       FOR /F "usebackq delims==" %i IN (`set`) DO @echo %i
 
     会枚举当前环境中的环境变量名称。
 
 (无疑,上面对FOR /F的讲解和清楚,下面再强调几点:
 0. 被分析的对象为文件的每一行、字符串、命令的输出
  如果一个文件有10行,那么for将循环10次
 1. 参数eol实际上就是指定注释符号,以注释符号开头的行将被忽略。
 2. 参数delims指定分隔符号,比如“delims=a/ [”就指定四个分割符号,每行将被这些分割符号分成一个一个的单词
 3. 文件的内容经过分析后为一个一个的单词,依次排序为1,2,3,4,...
    参数tokens指定哪些单词为输出,将要输出的单词的序号列出;引用这些单词时,从i开始,依次为%i,%j,%k直到,%z
        。也可以指定从哪个字母开始,如%a IN ('set'), 那么输出的单词的引用依次为%a, %b, %c
        可以指定星号*,表示所有剩余的单词 
 )
 
 另外,FOR 变量参照的替换已被增强。您现在可以使用下列
 选项语法:
 
      ~I         - 删除任何引号("),扩充 %I
      %~fI        - 将 %I 扩充到一个完全合格的路径名
      %~dI        - 仅将 %I 扩充到一个驱动器号
      %~pI        - 仅将 %I 扩充到一个路径
      %~nI        - 仅将 %I 扩充到一个文件名
      %~xI        - 仅将 %I 扩充到一个文件扩展名
      %~sI        - 扩充的路径只含有短名
      %~aI        - 将 %I 扩充到文件的文件属性
      %~tI        - 将 %I 扩充到文件的日期/时间
      %~zI        - 将 %I 扩充到文件的大小
      %~$PATH:I   - 查找列在路径环境变量的目录,并将 %I 扩充
                    到找到的第一个完全合格的名称。如果环境变量名
                    未被定义,或者没有找到文件,此组合键会扩充到
                    空字符串
 
 可以组合修饰符来得到多重结果:
 
      %~dpI       - 仅将 %I 扩充到一个驱动器号和路径
      %~nxI       - 仅将 %I 扩充到一个文件名和扩展名
      %~fsI       - 仅将 %I 扩充到一个带有短名的完整路径名
      %~dp$PATH:i - 查找列在路径环境变量的目录,并将 %I 扩充
                    到找到的第一个驱动器号和路径。
      %~ftzaI     - 将 %I 扩充到类似输出线路的 DIR
 
 在以上例子中,%I 和 PATH 可用其他有效数值代替。%~ 语法
 用一个有效的 FOR 变量名终止。选取类似 %I 的大写变量名
 比较易读,而且避免与不分大小写的组合键混淆。
 显示、设置或删除 cmd.exe 环境变量。
 (没有真正的实验过,上面的命令总体是将一些前缀加到输出的单词前。输出的单词在上面为I,也可指定其他的。)
 
10 . set

 显示、设置或删除 cmd.exe 环境变量。
 
 SET [variable=[string]]
 
   variable  指定环境变量名称。
   string    指定要指派给变量的一系列字符。
 
 仅键入 SET 而不加参数,可以显示当前的环境变量。
 
 如果命令扩展名被启用,SET 会如下改变:
 
 可仅用一个变量激活 SET 命令,等号或值不显示所有前缀匹配
 SET 命令已使用的名称的所有变量的值。例如:
 
     SET P
 
 会显示所有以字母 P 打头的变量
 
 如果在当前环境中找不到该变量名称, SET 命令将把 ERRORLEVEL
 设置成 1。
 
 SET 命令不允许变量名含有等号。
 
 (在下面,可以看出环境变量被当作普通的变量参与计算,可被赋值,与常数运算等,这使得bat有
 如java、c等语言的计算功能。记住参数/a, 和 /p
 
 不管你相不相信,set命令区分空格:
  1. set list=abc
  2. set list= abc
  3. set list =abc
 上面三个语句互不相同:
  1. 定义变量(list),值为(abc)
  2. 定义变量(list),值为(abc )
  3. 定义变量(list ),值为(abc)
 并且,set将等号右边的所有字符都认为是值,等号左边的都是变量名,不过连接符号除外如&, &&等。
 结论:不要在等号的左右留空格。 
 )
 
 在 SET  命令中添加了两个新替换:
 
     SET /A expression
     SET /P variable=[promptString]
 
 /A 命令选项指定等号右边的字符串为被评估的数字表达式。该表达式
 评估器很简单并以递减的优先权顺序支持下列操作:
 
     ()                  - 分组
     * / %               - 算数运算符
     + -                 - 算数运算符
     << >>               - 逻辑移位
                        - 按位“与”
     ^                   - 按位“异”
     |                   - 按位“或”
     = *= /= %= += -=    - 赋值
       &= ^= |= <<= >>=
     ,                   - 表达式分隔符
 
 如果您使用任何逻辑或取余操作符, 您需要将表达式字符串用
 引号扩起来。在表达式中的任何非数字字符串键作为环境变量
 名称,这些环境变量名称的值已在使用前转换成数字。如果指定
 了一个环境变量名称,但未在当前环境中定义,那么值将被定为
 零。这使您可以使用环境变量值做计算而不用键入那些 % 符号
 来得到它们的值。如果 SET /A 在命令脚本外的命令行执行的,
 那么它显示该表达式的最后值。该分配的操作符在分配的操作符
 左边需要一个环境变量名称。除十六进制有 0x 前缀, 八进制
 有 0 前缀的,数字值为十进位数字。因此, 0x12 与 18 和 022
 相同。请注意八进制公式可能很容易搞混: 08 和 09 是无效的数字,
 因为 8 和 9 不是有效的八进制位数。
 
 /P 命令选项允许将变量数值设成用户输入的一行输入。读取输入
 行之前,显示指定的 promptString。promptString 可以是空的。
 
 环境变量替换已如下增强:
 
     %PATH:str1=str2%
 
 会扩展 PATH 环境变量,用 "str2" 代替扩展结果中的每个 "str1"。
 要有效地从扩展结果中删除所有的 "str1","str2" 可以是空的。
 "str1" 可以以星号打头;在这种情况下,"str1" 会从扩展结果的
 开始到 str1 剩余部分第一次出现的地方,都一直保持相配。
 
 (用str2替换掉%path%中的子串str1,但并不改变环境变量path)
 
 也可以为扩展名指定子字符串。
 
     %PATH:~10,5%
 
 会扩展 PATH 环境变量,然后只使用在扩展结果中从第 11 个(偏
 移量 10)字符开始的五个字符。如果没有指定长度,则采用默认
 值,即变量数值的余数。如果两个数字(偏移量和长度)都是负数,
 使用的数字则是环境变量数值长度加上指定的偏移量或长度。
 
     %PATH:~-10%
 
 会抽取 PATH 变量的最后十个字符。
 
     %PATH:~0,-2%
 
 会抽取 PATH 变量的所有字符,除了最后两个。
 (总结:%path:~offset,len%
 1. 结果是%path%[offset+1, offset+len]子串
 2. offset为负数时,那么offset=总长度+offset。直观地,可看作是从后面往前面的第offset位。
    len为负数时,那么len将不再是长度,而看作结束位,即结果为%path%[offset+1,总长度+len]
  如果总长度+len < offset+1,那么结果为空。  
 3. offset没有指定时,值默认为0
    len没有指定时,值默认为最大,即总长度
   (注意,不指定len时,不要写offset与len之间的间隔号——逗号,不然结果总为空)
 )
 
 
 终于添加了延迟环境变量扩充的支持。该支持总是按默认值被
 停用,但也可以通过 CMD.EXE 的 /V 命令行命令选项而被启用/停用。
 请参阅 CMD /?
 
 考虑到读取一行文本时所遇到的目前扩充的限制时,延迟环境
 变量扩充是很有用的,而不是执行的时候。以下例子说明直接
 变量扩充的问题:
 
     set VAR=before
     if "%VAR%" == "before" (
         set VAR=after;
         if "%VAR%" == "after" @echo If you see this, it worked
     )
 
 不会显示消息,因为在读到第一个 IF 语句时,BOTH IF 语句中
 的 %VAR% 会被代替;原因是: 它包含 IF 的文体,IF 是一个
 复合语句。所以,复合语句中的 IF 实际上是在比较 "before" 和
 "after",这两者永远不会相等。同样。以下这个例子也不会达到
 预期效果:
 
     set LIST=
     for %i in (*) do set LIST=%LIST% %i
     echo %LIST%
 
 原因是,它不会在目前的目录中建立一个文件列表,而只是将
 LIST 变量设成找到的最后一个文件。这也是因为 %LIST% 在
 FOR 语句被读取时,只被扩充了一次;而且,那时的 LIST 变量
 是空的。因此,我们真正执行的 FOR 循环是:
 
     for %i in (*) do set LIST= %i
 
 这个循环继续将 LIST 设成找到的最后一个文件。
 
 延迟环境变量扩充允许您使用一个不同的字符(惊叹号)在执行
 时间扩充环境变量。如果延迟的变量扩充被启用,可以将上面
 例子写成以下所示,以达到预期效果:
 
     set VAR=before
     if "%VAR%" == "before" (
         set VAR=after
         if "!VAR!" == "after" @echo If you see this, it worked
     )
 
     set LIST=
     for %i in (*) do set LIST=!LIST! %i
     echo %LIST%
 
 如果命令扩展名被启用,有几个动态环境变量可以被扩展,但
 不会出现在 SET 显示的变量列表中。每次变量数值被扩展时,
 这些变量数值都会被动态计算。如果用户用这些名称中任何
 一个定义变量,那个定义会替代下面描述的动态定义:
 
 %CD% - 扩展到当前目录字符串。
 
 %DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。
 
 %TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。
 
 %RANDOM% - 扩展到 0 和 32767 之间的任意十进制数字。
 
 %ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。
 
 %CMDEXTVERSION% - 扩展到当前命令处理器扩展名版本号。
 
 %CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。
 
 (
 总结:
 1. set命令定义变量,行如set 变量名=值
 2. 在任何语句被执行前,会先识别 %变量名% ,将变量替换为它的值,如果没有该变量,则认作是普通字符串;
   比如:
    set list=a
    set list=%list% b
    第二句作替换后为:set list=a b,执行结果为:list的值为a b。
  替换只做一次,替换后不再识别 %变量名%,即不作第二次替换。 比如:
    set list=a
    set tlist=list
    set list=%%tlist%% b
  则第三句作一次替换后为 set list=%list% b, 执行结果:list的值为%list b。
  “一条语句”指:
     一行语句 ——可以用 &, &&, |连接
     if - else 语句 —— 从if开始,到else的结尾都认为是一条语句
     for
  对if - else , for复合语句要特别注意:
   set list=a
   set tlist=b
   if list==a (
    set tlist=list
    set %tlist%=aa )    
  执行时,第三句先作一次替换为:
   if list== a (
    set tlist=list
    set b=aa )
  结果是list的值为a
 3. 第2点是默认情况 
  执行命令C:/bat>cmd /v:on ,将“延迟变量扩充”开关打开(默认是关闭的),这样与第二点不同:
  “一条语句”被执行前先替换 %变量名%
  “一条短语”被执行前先替换 !变量名!
  这样用&, &&, |, if - else, for是一条语句,由多条短语组成。
  对上面的例子:
   set list=a
    set tlist=b
    if list==a (
     set tlist=list
     set !tlist!=aa )    
   执行时,短语set !tlist!=aa作替换后为:set list=aa
   结果是list的值为aa 
  
  试一下:
   cmd /v:on
   set list=a
   set tlist=list
   for %i in (*) do set list=!%tlist%! %i  
  
 )
 
 
 
//--------------learning makefile 文件 -----------------------
1.一个简单的makefile
 ### makefile 开始 ###
 myprog : foo.o bar.o
  gcc foo.o bar.o -o myprog
 
 foo.o : foo.c foo.h bar.h
  gcc -c foo.c -o foo.o
 
 bar.o : bar.c bar.h
  gcc -c bar.c -o bar.o
 ### makefile 结束 ###
 
 一个简单的Makefile文件包含一系列的“规则”,其样式如下:
 
  目标(target)…: 依赖(prerequiries)… 
  <tab>命令(command)
  
  或者
  目标(target)…: 依赖(prerequiries)… ;命令(command)
  <tab>命令(command)
  

 比如上例中第一个规则,目标为myprog,它依赖foo.o 和 bar.o。
 命令为gcc,它前面有一个tab符。如果跟在依赖后面,则不需要tab符。
 目标的依赖也是一个目标,比如foo.c,foo.h,bar.h
 
2. 一定要牢记:Make的全部工作是当目标(确切地说是最终目标)需要更新时,按照您制定的具体规则执行命令。Make并不知道命令是如何工作的。

 最终目标(target)是make最终努力更新的目标。其它更新的目标是因为它们作为最终目标的依赖,或依赖的依赖,等等以此类推。如果一些规则和最终目标无任何关联则这些规则不会被执行。
 
 缺省的最终目标是第一个规则的第一个目标。例外:以句点(‘.’)开始的目标不是缺省最终目标
 可以在make命令中指定最终目标 —— make foo.o

3. 执行makefile文件
 1.缺省情况下,当make寻找makefile文件时,它试图搜寻具有如下的名字的文件,按顺序:‘GNUmakefile’、‘makefile’和‘Makefile’。
 2.用参数指定makefile文件:make -f file1 file2 file3
  可以指定多个文件,将按次序一个一个执行。

4. include :包含其他makefile文件
 include filename1 filename2 filename3
 include不是一个命令,不能以tab键开头。
 include把其他文件包含进来。
 也可以用参数指定包含哪些文件:make -include

 如果makefile文件名不以‘/’开头,并且在当前目录下也不能找到,则需搜寻另外的目录。
 首先,搜寻以‘-|’或‘--include-dir’参数指定的目录,然后依次搜寻下面的目录(如果它们存在的话):‘prefix/include' (通常为 ‘/usr/local/include') ‘/usr/gnu/include', ‘/usr/local/include', ‘/usr/include'。

5. $$ —— 为美圆符
 * 为通配符, /* 为星号,显然 / 将特殊符号恢复本义。
 在定义变量时,通配符为本义,比如:
  objs = *.o 定义objs为名字为*的.o文件,而不是所有的.o文件。
  objs = ${wildcard *.o} 定义objs为所有的.o文件。
 在规则中通配符会扩展,但如果扩展时,找不到匹配的文件,则通配符恢复本义,比如:
  myprog : *.o
  如果没有一个.o文件,则myprog会依赖文件*.o文件。 
6. 在目录中搜寻依赖
 VPATH变量
  如果一个作为目标或依赖的文件在当前目录中不存在,make就会在VPATH指定的目录中搜寻该文件。
  如果在这些目录中找到要寻找的文件,则就象这些文件在当前目录下存在一样,规则把这些文件指定为依赖。
  在VPATH变量定义中,目录的名字由冒号或空格分开。
 vpath指令
  vpath pattern directories
   对一定格式类型的文件名指定一个搜寻路径。搜寻的路径由一列要搜寻的目录构成,目录由冒号(在MS-DOS、MS-WINDOWS系统中用分号)或空格隔开,和VPATH变量定义要搜寻的路径格式一样。
  
  vpath pattern   
   清除和一定类型格式相联系的搜寻路径。
  
  vpath   
   清除所有前面由vapth指令指定的搜寻路径。
   
  当对同一个pattern定义多个dir时,会顺序搜索这些dir,比如
   vpath %.c foo
   vpath %   blish
   vpath %.c bar
   表示搜寻`.c'文件先搜寻目录`foo'、然后`blish',最后`bar';如果是如下代码:
   
   vpath %.c foo:bar
   vpath %   blish
   表示搜寻`.c'文件先搜寻目录‘foo'、然后‘bar',最后‘blish'。

 目录搜寻过程
     当通过目录搜寻找到一个文件,该文件有可能不是您在依赖列表中所列出的依赖;有时通过目录搜寻找到的路径也可能被废弃。Make决定对通过目录搜寻找到的路径保存或废弃所依据的算法如下:
  
  1、如果一个目标文件在makefile文件所在的目录下不存在,则将会执行目录搜寻。
  
  2、如果目录搜寻成功,则路径和所得到的文件暂时作为目标文件储存。
  
  3、所有该目标的依赖用相同的方法考察。
  
  4、把依赖处理完成后,该目标可能需要或不需要重新创建:
  
   1、如果该目标不需要重建,目录搜寻时所得到的文件的路径用作该目标所有依赖的路径,同时包含该目标文件。简而言之,如果make不必重建目标,则您使用通过目录搜寻得到的路径。(?不懂!)
   
   2、如果该目标需要重建,目录搜寻时所得到的文件的路径将废弃,目标文件在makefile文件所在的目录下重建。简而言之,如果make要重建目标,是在makefile文件所在的目录下重建目标,而不是在目录搜寻时所得到的文件的路径下。(?really?)
  
  该算法似乎比较复杂,但它却可十分精确的解释实际您所要的东西。
  
  其它版本的make使用一种比较简单的算法:如果目标文件在当前目录下不存在,而它通过目录搜寻得到,不论该目标是否需要重建,始终使用通过目录搜寻得到的路径。
 
 建议:如果目标不与makefile同目录,则应该指定它的路径(?好建议?)
 
 连接库的搜寻目录 
  当一个依赖的名字是‘-|name’的形式时,make特别地在当前目录下、与vpath匹配的目录下、VPATH指定的目录下以及‘/lib’, ‘/usr/lib', 和 ‘prefix/lib'(正常情况为`/usr/local/lib',但是MS-DOS、MS-Windows版本的make的行为好像是prefix定义为DJGPP安装树的根目录的情况)目录下搜寻名字为‘libname.so'的文件然后再处理它。
  如果没有搜寻到‘libname.so'文件,那么在前述的目录下搜寻‘libname.a'文件。

  例如,如果在您的系统中有‘/usr/lib/libcurses.a'的库文件,则:
  
  foo : foo.c -lcurses
          cc $^ -o $@
  如果‘foo’比‘foo.c’更旧,将导致命令‘cc foo.c /usr/lib/libcurses.a -o foo'执行。
  
  实际上,从'-|name'到'libname.so'或'libname.a'的转换是由 .LIBPATTERNS变量支持的。
  .LIBPATTERNS变量的缺省值是"‘lib%.so lib%.a'",可以重定义该变量,比如为空值。

3. 隐含规则:如果一个目标没有对应的规则(即在规则中,它是目标而不是目标的依赖),或者规则中没有命令, 就会启动隐含规则。
 如果隐含规则在最终目标的依赖链中,那么它总被执行。
 依后缀名的隐含规则:
  Compiling C programs(编译C程序)
   'n.o' 自动由'n.c' 使用命令 '$(CC) -c $(CPPFLAGS) $(CFLAGS)'生成 。 #即如果目标名符合“n.o”,那么此隐含规则就适用
  Compiling C++ programs (编译C++程序)
   'n.o'自动由'n.cc' 或'n.C'使用命令'$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)'生成。 我们鼓励您对C++源文件使用后缀'.cc' 代替后缀'.C'。
  Assembling and preprocessing assembler programs (汇编以及预处理汇编程序)
   'n.o'自'n.S'运行C编译器,cpp,生成。命令为:'$(CPP) $(CPPFLAGS)'。
  Linking a single object file (连接一个简单的OBJ文件)
   'n' 自动由'n.o' 运行C编译器中的连接程序 linker (通常称为 ld)生成。命令为: '$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'
   也可以连接多个obj文件,但要求目标与一个依赖目标同名,不过后缀可不同,通常省略同名的依赖目标:如
    x: y.o z.o
   此时:1.省略了一个依赖目标:x.o, 还原后为:x: x.o, y.o, z.o. ?如果x.o不存在,将不会适用该隐含规则吗?
      2.隐含规则为$(CC) $(LDFLAGS) x.o y.o z.o $(LOADLIBES) $(LDLIBS) -o x
  Yacc for C programs (由Yacc生成C程序)
   'n.c'自动由'n.y'使用命令'$(YACC) $(YFLAGS)'运行 Yacc生成。
  Lex for C programs (由Lex生成C程序)
   'n.c'自动由'n.l' 运行 Lex生成。命令为:'$(LEX) $(LFLAGS)'。
 隐含规则中使用的变量,包括命令名变量和命令使用的参数变量。下面是命令名变量:
  CC
   C语言编译程序;缺省为:'cc'.
  CXX
   C++编译程序;缺省为:'g++'.   
  CPP
   带有标准输出的C语言预处理程序;缺省为:'$(CC) -E'.   
  YACC
   将 Yacc语言转变为 C程序的程序;缺省为:'yacc'.   
  MAKEINFO
   将Texinfo 源文件转换为信息文件的程序;缺省为:'makeinfo'.
  RM
   删除文件的命令;缺省为:'rm -f'.
   
 这里是值为上述命令的附加参数的变量列表。在没有注明的情况下,所有变量的值缺省为空值。  
  CFLAGS
   用于C编译器的额外标志。
  CXXFLAGS
   用于C++编译器的额外标志。   
  CPPFLAGS
   用于C预处理以及使用它的程序的额外标志 (C和 Fortran 编译器)。   
  YFLAGS
  用于Yacc的额外标志。Yacc。
  
  隐含规则链:启动隐含规则时,如果隐含规则的依赖目标(可能是个文件)不存在,则会启动一个新的隐含规则。依次类推,会形成一个隐含规则链。
   比如:从文件myprog.y到文件myprog.o,要首先运行隐含规则Yacc,其次运行隐含规则cc。
  注意:运行隐含规则链时会生成中间文件(但是,如果其中有文件在makefile中被提及,则它不是中间文件),如果这些中间文件存在,则会更新这些文件,如果不存在,会在更新最终目标后删除这些中间文件。
     
  .SECONDARY : 中间文件列表
   .SECONDARY 目标告诉make不要删除列出的中间文件
  .INTERMEDIATE : 中间文件列表
   .INTERMEDIATE 目标告诉make列出的是中间文件,即使这些文件可能在makefile中提及。
   
   没有一条隐含规则可以在隐含规则链中出现两次以上(含两次)。这可以强制make在搜寻一个隐含规则链时阻止无限循环。
   可以把隐含规则链看作是一个隐含规则。
   对同一个后缀可能会有多个隐含规则适用。则这些规则会按优先顺序执行其中一条。比如:
    从文件myprog.c到执行文件myprog,可以有规则链编译——连接,也可以直接用命令cc同时编译和连接。后一条规则优先。
    

2.依靠dependent
 myprog : foo.o bar.o
   表示目标myprog依靠foo.o和bar.o两个目标(target).“依靠”的意思是说:文件myprog的时间戳应该比文件foo.o或文件bar.o新,如果比它们旧的话,就需要运行
  目标myprog,即允许gcc foo.o bar.o -o myprog.
   依靠是有连锁反应的,目标foo.o又依靠foo.c ,foo.h, bar.h, 如果这三个文件中有一个比foo.o新,就允许目标foo.o
 一般,要保证目标文件和源程序(.c和所有包含的.h)同步。
  
 (使用 gcc 的时候,用 -M 开关,它会为每一个你给它的C文件输出一个规则,把目标文件 做为目的,而这个C文件和所有应该被 #include 的 header 文 件将做为依靠文件。注意这个规则会加入所有 header 文件,包 括被角括号(`<', `>')和双引号(`"')所包围的文件。其实我们可以 相当肯定系统 header 档(比如 stdio.h, stdlib.h 等等)不会 被我们更改,如果你用 -MM 来代替 -M 传递给 gcc,那些用角括 号包围的 header 档将不会被包括。(这会节省一些编译时间))

5。假象目标(Phony Targets)
 1、一个目标就是一个文件,一个目标“依靠”另外几个目标,就是保证这个文件比依靠的文件要新,如果旧的话,就执行该目标下的命令。
 2、如果一个目标myprog依靠另一个目标foo.o,目标foo.o又依靠目标foo.c, 那么依次序foo.c —— foo.o——myprog执行。
 3、如果一个目标(实际上是文件名)不存在,那么它总是最旧的。比如:
   all : foo.o bar.o
    gcc foo.o bar.o -o myprog
  由于文件“all”总不存在,所以命令gcc ...一旦在最终目标的依赖链中就会被执行。
  
  再比如,
   cleanall :
    rm *.o
    rm myprog
  cleanall并不存在,但它没有依赖,所以它也总是最旧的,一旦在最终目标的依赖链中就会被执行。
  cleanall会删除所有.o和myprog文件。
  
  如果一个依靠目标不存在,那么是不是和这种情况一样?
   
 4、如果一个目标没有依赖,那么它总是最新的。(当然,如果目标自己也不存在,根据第⒊条,它总是最旧的。)
  比如:
   foo.o:
    gcc -o foo.o foo.c
  foo.o存在,所以gcc命令总不会被执行。
 
  再比如:在上例中,文件cleanall存在,那么命令make cleanall 也不会运行规则的命令,因为目标已经是最新的。
  显然,这种情况要避免。解决办法是:    
   使用目标不存在、且没有命令和依赖的规则:
    clean: FORCE
           rm $(objects)
    FORCE:
   make会认为FORCE规则总要被执行,执行结果是FORCE是最新的,目标clean将比它旧,所以clean会被执行。
   简单地说:空依赖是最旧的,FORCE依赖是最新的。这两点可以利用。
  另一种解决办法是使用.PHONY目标,见下面第5.条。
   
 5、内建的假象目标“.PHONY”: 系统知道它是一个不存在的文件,所以根本不去检查磁盘或查找隐含规则。
  一个.PHONY目标依赖的目标也将是假象目标。
  比如:
   .PHONY : cleanall
  即使cleanall文件存在,目标cleanall也是个假象目标。实际上,make根本不去检查cleanall存不存在。
  
 一般,一个假想目标不应该是一个实际目标文件的依赖。
6. /
 一行命令写在两行时,用“/”连接
 如:
  rm edit main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o

 多行注释也可以用/
 如:# line1 /
  line2
3.Makefile 变量
 例子:
  ### makefile 开始 ###
  OBJS = foo.o bar.o
  CC = gcc
  CFLAGS = -Wall -O -g
  
  myprog : $(OBJS)
  $(CC) $(OBJS) -o myprog
  
  foo.o : foo.c foo.h bar.h
  $(CC) $(CFLAGS) -c foo.c -o foo.o
  
  bar.o : bar.c bar.h
  $(CC) $(CFLAGS) -c bar.c -o bar.o
  ### makefile 结束 ###
 
  = 比如CC = gcc, 要设定一个变量,你只要在一行的开始写下这个变量的名字,后面跟一个 = 号,后面跟你要设定的这个变量的值。
  := 比如CC := gcc,“:=”表示立即赋值, 一般情况下与“=”是一样的。下面情况会有区别:
   CC = gcc
   CC2 = ${CC}
   CC = cc
   这三句执行后,变量CC2的值是cc, 而不是gcc. 就好象CC2与表达式${CC}绑定,在需要它时,就计算
  再看:
   CC = gcc
   CC2 := ${CC}
   CC = cc
   这三句执行后,变量CC2的值是gcc, 而不是cc. 这里CC2的值是立即计算,并不随变量CC的改变而改变。
   
 以后你要引用 这个变量,写一个 $ 符号,后面是围在括号里的变量名。
  三个比较有用的build_in变量是 $@, $< 和 $^ (这些变量不需要括号括住)。
   $@ 扩展成当前规则的目的文件名(即当前的target),
   $< 扩展成依靠列表中的第一个依靠文件,
    $^ 扩展成整个依靠的列表(属于当前target的整个依靠列表,除掉了里面所有重复的文件名)。
  利用$@, $< , $^,重写上面的例子:
 
   ### makefile 开始 ###
   OBJS = foo.o bar.o
   CC = gcc
   CFLAGS = -Wall -O -g
   
   myprog : $(OBJS)
   $(CC) $^ -o $@
   
   foo.o : foo.c foo.h bar.h
   $(CC) $(CFLAGS) -c $< -o $@
   
   bar.o : bar.c bar.h
   $(CC) $(CFLAGS) -c $< -o $@
   ### makefile 结束 ###
 
  解释:
   目标myprog中,$^ = $(OBJS) = foo.o bar.o
        $@ = myprog
   目标foo.o中, $< = foo.c
        $@ = foo.o
   目标bar.o中, $< = bar.c
        $@ = bar.o
  显然,使用内建变量$@, @<, @^可以减少修改的位置。
4。 自动变量是内建变量,其名字为“变量符$ + 名字”,比如$@
 自动变量列表:
  $@
   规则的目标文件名。如果目标是一个档案成员,则变量
'$@' 档案文件的文件名。对于有多个目标的格式规则(参阅格式规则简介),变量'$@'是那个导致规则命令运行的目标文件名。
  $%
   当目标是档案成员时,该变量是目标成员名,参阅使用make更新档案文件。例如,如果目标是'foo.a(bar.o)',则'$%'的值是'bar.o',
'$@'的值是'foo.a'。如果目标不是档案成员,则'$%'是空值。
  $<
   第一个依赖的文件名。如果目标更新命令来源于隐含规则,该变量的值是隐含规则添加的第一个依赖。参阅使用隐含规则。
  $?
   所有比目标'新'的依赖名,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make更新档案文件。
  $^
   所有依赖的名字,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make更新档案文件。对同一个目标来说,一个文件只能作为一个依赖,不管该文件的文件名在依赖列表中出现多少次。所以,如果在依赖列表中,同一个文件名出现多次,变量'$^'的值仍然仅包含该文件名一次。
  $+
   该变量象'$^',但是,超过一次列出的依赖将按照它们在makefile文件中出现的次序复制。这主要的用途是对于在按照特定顺序重复库文件名很有意义的地方使用连接命令。
  $*
   和隐含规则匹配的stem(径),参阅格式匹配。如果一个目标为'dir/a.foo.b',目标格式规则为:'a.%.b' ,则stem为'dir/foo'。在构建相关文件名时stem 十分有用。
   在静态格式规则中,stem是匹配目标格式中字符'%'的文件名中那一部分。在一个没有stem具体规则中;变量'$*' 不能以该方法设置。
   如果目标名以一种推荐的后缀结尾(参阅过时的后缀规则),变量'$*'设置为目标去掉该后缀后的部分。例如,如果目标名是'foo.c',则变量'$*' 设置为'foo', 因为'.c' 是一个后缀。GNU make 处理这样奇怪的事情是为了和其它版本的make兼容。
   在隐含规则和静态格式规则以外,您应该尽量避免使用变量'$*'。在具体规则中如果目标名不以推荐的后缀结尾,则变量'$*'在该规则中设置为空值。
   当您希望仅仅操作那些改变的依赖,变量'$?' 即使在具体的规则中也很有用。例如,假设名为'lib'的档案文件包含几个OBJ文件的拷贝,则下面的规则仅将发生变化的OBJ文件拷贝到档案文件:
    lib: foo.o bar.o lose.o win.o
           ar r lib $?
   在上面列举的变量中,有四个变量的值是单个文件名。三个变量的值是文件名列表。这七个变量都有仅仅存放文件的路径名或仅仅存放目录下文件名的变体。
   变量的变体名是由变量名追加字母'D'或'F'构成。这些变体在GNU make中处于半废状态,原因是使用函数T dir和notdir 能够得到相同的结果。
   参阅文件名函数。注意,'F'变体省略所有在dir函数中总是输出的结尾斜杠这里是这些变体的列表:
  `$(@D)'
   目标文件名中的路径部分,结尾斜杠已经移走。如果变量
`$@'的值是`dir/foo.o',变体 `$(@D)'的值是`dir'。 如果变量`$@'的值不包含斜杠,则变体的值是`.'。
  `$(@F)'
   目标文件名中的真正文件名部分。如果变量
`$@'的值是`dir/foo.o',变体  `$(@F)'的值是` foo.o '。`$(@F)' 等同于 `$(notdir $@)'
  `$(*D)'
  `$(*F)'
   stem(径)中的路径名和文件名;在这个例子中它们的值分别为:`dir' 和 `foo' 。
  `$(%D)'
  `$(%F)'
   档案成员名中的路径名和文件名;这仅对采用'archive(member)'形式的档案成员目标有意义,并且当成员包含路径名时才有用。参阅档案成员目标。
  `$(<D)'
  `$(<F)'
   第一个依赖名中的路径名和文件名。
  `$(^D)'
  `$(^F)'
   所有依赖名中的路径名和文件名列表。
  `$(?D)'
  `$(?F)'
   所有比目标'新'的依赖名中的路径名和文件名列表。
  注意,在我们讨论自动变量时,我们使用了特殊格式的惯例;我们写"the value of'$<'", 而不是"the variable <" ;和我们写普通变量,例如变量 objects 和 CFLAGS一样。我们认为这种惯例在这种情况下看起来更加自然。这并没有其它意义,变量'$<'的变量名为 < 和变量'$(CFLAGS)' 实际变量名为CFLAGS一样。您也可以使用'$(<)'代替'$<'。

5. 隐含规则搜寻算法
  这里是make为一个目标't'搜寻隐含规则的过程。这个过程用于任何没有命令的双冒号规则,用于任何不含命令的普通规则的目标,以及用于任何不是其它规则目标的依赖。这个过程也能用于来自隐含规则的依赖递归调用该过程搜寻规则链。
  在本算法中不提及任何后缀规则,因为后缀规则在makefile文件读入时转化为了格式规则。
  对于个是'archive(member)'的档案成员目标,下述算法重复两次,第一次使用整个目标名't',如果第一次运行没有发现规则,则第二次使用'(member)'作为目标't'。
   
   1、在't'中分离出路径部分,称为'd',剩下部分称为'n'。例如如果't'是'src/foo.o',那么'd'是'src/';'n'是'foo.o'。
   
   2、建立所有目标名匹配't'和'n'的格式规则列表。如果目标格式中含有斜杠,则匹配't',否则,匹配'n'。
   
   3、如果列表中有一个规则不是万用规则,则从列表中删除所有非最终万用规则。
   
   4、将没有命令的规则也从列表中移走。
   
   5、对每个列表中的格式规则:
    1、寻找stem's',也就是和目标格式中%匹配的't'或'n'部分。
    2、使用stem's'计算依赖名。如果目标格式不包含斜杠,则将'd'添加在每个依赖的前面。
    3、测试所有的依赖是否存在或能够创建。(如果任何文件在makefile中作为目标或依赖被提及,则我们说它应该存在。)如果所有依赖存在或能够创建,或没有依赖,则可使用该规则。
   
   6、如果到现在还没有发现能使用的规则,进一步试。对每一个列表中的规则:
    1、  如果规则是最终规则,则忽略它,继续下一条规则。
    2、  象上述一样计算依赖名。
    3、  测试所有的依赖是否存在或能够创建。
    4、  对于不存在的依赖,按照该算法递归调用查找是否能够采用隐含规则创建。
    5、  如果所有依赖存在或能使用隐含规则创建,则应用该规则。
    7、  如果没有隐含规则,则如有用于目标'.DEFAULT'规则,则应用该规则。在这种情况下,将目标'.DEFAULT'的命令给与't'。
  一旦找到可以应用的规则,对每一个匹配的目标格式(无论是't'或'n')使用stem's'替换%,将得到的文件名储存起来直到执行命令更新目标文件't'。在这些命令执行以后,把每一个储存的文件名放入数据库,并且标志已经更新,其时间戳和目标文件't'一样。
  如果格式规则的命令为创建't'执行,自动变量将设置为相应的目标和依赖(参阅自动变量)。

4。隐含规则 (Implicit Rules)
 当一个目标下没有命令时,会调用隐含命令。
 比如foo.o目标下没有命令gcc foo.c foo.h bar.h -o foo.o时会调用隐含命令:
  $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
 翻译后为:
  gcc $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c foo.c -o foo.o
 变量$(CFLAGS) ,$(CPPFLAGS) ,$(TARGET_ARCH)需自己定义,用来控制编译过程。
 
 ?使用哪一种隐含规则由什么决定。

6.函数 (Functions)  
 不会在makefile中定义一个函数,而只会引用一个函数: ${函数名 空格 参数1,参数2,参数三,...}。
 引用一个函数,可以将其运行结果赋给一个变量,比如:
  SOURCES = $(wildcard *.c)
 函数wildcard将所有匹配“*.c”的文件的文件名列出,结果赋给变量SOURCES
 再比如:
  OBJS = $(patsubst %.c,%.o,$(SOURCES))
 函数patsubst在变量${SOURCES}中匹配“%.c”字符串,将字符串“%.c”替换成“%.o”。简单地说,就是将${SOURCES}中的“c”替换为“o”
 
 通配符%表示一个或多个字符;
 通配符*表示零个或多个字符;
7.规则(rule)
 target: components
 TAB rule
 
 每个rule的前面要有一个tab符
 
7.一个复杂的例子:
 (注意:在一行的最后并不能跟注释,下面这样写只是为了方便讲解,实际用时要删除这些注释)
 ### makefile 开始 ###

 ######################################
 #
 # Generic makefile
 #
 # by George Foot
 # email:
george.foot@merton.ox.ac.uk
 ######################################
 
 ### Customising
 # 用户设定
 #
 # Adjust the following if necessary; EXECUTABLE is the target
 # executable's filename, and LIBS is a list of libraries to link in
 # (e.g. alleg, stdcx, iostr, etc). You can override these on make's
 # command line of course, if you prefer to do it that way.
 #
 # 如果需要,调整下面的东西。 EXECUTABLE 是目标的可执行文件名, LIBS
 # 是一个需要连接的程序包列表(例如 alleg, stdcx, iostr 等等)。当然你
 # 可以在 make 的命令行覆盖它们,你愿意就没问题。
 #
 
 EXECUTABLE := mushroom.exe
 LIBS := alleg
 
 # Now alter any implicit rules' variables if you like, e.g.:
 #
 # 现在来改变任何你想改动的隐含规则中的变量,例如
 
 CFLAGS := -g -Wall -O3 -m486  #隐含规则会用到这些变量
 CXXFLAGS := $(CFLAGS)
 
 # The next bit checks to see whether rm is in your djgpp bin
 # directory; if not it uses del instead, but this can cause (harmless)
 # `File not found' error messages. If you are not using DOS at all,
 # set the variable to something which will unquestioningly remove
 # files.
 #
 # 下面先检查你的 djgpp 命令目录下有没有 rm 命令,如果没有,我们使用
 # del 命令来代替,但有可能给我们 'File not found' 这个错误信息,这没
 # 什么大碍。如果你不是用 DOS ,把它设定成一个删文件而不废话的命令。
 # (其实这一步在 UNIX 类的系统上是多余的,只是方便 DOS 用户。 UNIX
 # 用户可以删除这5行命令。)
 
 ifneq ($(wildcard $(DJDIR)/bin/rm.exe),)  #查找${DJDIR)/bin/rm.exe文件,(这里通过与空串比较看是否找到)
  RM-F := rm -f #定义变量RM-F 为 rm -f
 else
  RM-F := del
 endif
 
 # You shouldn't need to change anything below this point.
 #
 # 从这里开始,你应该不需要改动任何东西。(我是不太相信,太NB了!)
 
 SOURCE := $(wildcard *.c) $(wildcard *.cc)   #查找所有.c 和 .cc的源文件列表
 OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCE)))   #生成目标文件列表,注意:相同名字的.c和.cc文件将生成重复的.o文件
 DEPS := $(patsubst %.o,%.d,$(OBJS))  #生成.d 结尾的DEPS文件列表
 MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))  #分两步:1.wildcard ${DEPS} 找出所有已存在的.d文件 ;
                #   2.filter-out将找出的.d文件从DEPS文件列表中删除,剩余是不存在的.d文件列表
                #不存在的DEPS文件列表放在变量MISSING_DEPS中。
 MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.c,$(MISSING_DEPS)) /  #分两步:1.patsubst %.d, %.c, ${MISSING_DEPS}列出所有.d文件对应的.c源文件,后面的一个patsubst也一样
            $(patsubst %.d,%.cc,$(MISSING_DEPS))) #   2.wildcard 源文件列表c 源文件列表cc 找出源文件列表c和源文件列表cc存在的源文件
                    #为什么用patsubst后还要用wildcard呢?因为一个.d文件可能对应一个.c文件,也可能对应一个.cc文件,所以这里查找以找到实际的.c或.cc文件
 
 CPPFLAGS += -MD #?+= 与自赋值运算符很像
 
 .PHONY : everything deps objs clean veryclean rebuild
 
 everything : $(EXECUTABLE)
 
 deps : $(DEPS)  #目标deps依靠DEPS文件列表
  #会触发隐含的命令吗?
 
 objs : $(OBJS)  #目标objs依靠OBJS文件列表
  #会触发隐含的命令吗?
 
 clean :  #一个假像目标,没有依靠文件,不会自动运行
  @$(RM-F) *.o  #删除所有.o文件
  @$(RM-F) *.d  #删除所有.d文件
 
 veryclean: clean  #一个假象目标,依靠假象目标clean
  @$(RM-F) $(EXECUTABLE)  #删除生成的可执行文件
 
 rebuild: veryclean everything  #一个假象目标,依靠veryclean和everything
 
 ifneq ($(MISSING_DEPS),)  #如果有不存在的DEPS文件(即.d文件)
 $(MISSING_DEPS) :    #目标是所有不存在的DEPS文件,没有依靠的文件
  @$(RM-F) $(patsubst %.d,%.o,$@) 
 endif
 
 -include $(DEPS)  #将DEPS文件包含到makefile中,与c语言的#include很像,为纯文本替换。
 
 $(EXECUTABLE) : $(OBJS)  #可执行文件,依靠所有.o文件
  gcc -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))  #分两步:1.addprefix -l,${LIBS}  将${LIBS}中的每一项加上前缀“-l”(不是数字1)
               #   2.命令gcc,根据.o文件和库文件生成可执行文件
 
 ### makefile 结束 ###


append:
 
Administrator@XTY-FE540439EF0 /cygdrive/d/cygwin/xty/src
 $
1. $ gcc a.c -o a.o
  生成a.o
 $ gcc a.c -o a
  生成a.exe
 $ gcc a.c
  生成a.exe
 $ gcc a.o
  a.o(.text+0x0):libgcc2.c: multiple definition of `mainCRTStartup'
  /usr/lib/crt0.o(.text+0x0): first defined here
  a.o(.data+0x0):/cygnus/netrel/src/gcc-2.95.3-5/gcc/libgcc2.c: multip
  n of `__cygwin_crt0_bp'
  /usr/lib/crt0.o(.data+0x0): first defined here
  collect2: ld returned 1 exit status
 $ gcc a.o -nostartfiles
  生成a.exe
  注:当用gcc编译源程序为“.o”文件的时候,需要加一个“-nostartfiles”选项。这个选项使得C编译器不链接系统的启动函数库里面的启动函数。否则,就会得到一个“multiple-definition”的错误。
 $ gcc a.c -o a.x
  生成a.x
 $ gcc a.x -nostartfiles
  生成a.exe
  注:生成的exe运行后不打印“hello world”。(是不是目标文件的后缀.x造成的?)
  
//------------------------------------essp-----------------------------
1.如果系统变大,那么编译和打包整个project会很费时间.
  考虑将系统分成common, 子系统, 交叉package, 这样每个人都只要关心common,他自己的系统,他和别人的交叉的package.其他的文件可以不用打包.
2.Parameter的名值对,其中名字应该全部大写比如param.put( "NAME","xty" );

4.用全局的comform来记住当前的applet是谁,而不是去引用那个applet。减少偶合。
5.事件处理函数要统一的有完整的参数,就和原形一样。
6.注释掉代码用"//", 注释或说明用"/* */"
7.除了共同的方法(即每个程序都要有的方法)以外,其他方法属于自己写的私有方法,最好:1.为private;2.不直接引用成员变量,若要引用的话,应以参数形式传入。
8.用javadoc生成代码的文档
9.如何隐藏自己的类(即自己写的,别人不会用到的。)?一个目录下大堆的类分不清主次。
10.命名规则为(前缀 + 有意义的名字),比如ID_PWP, NAME_PWP, actionPerformed_BTN_SAVE, 常用量(对象)的名字全部大写
11.对jtable,为每种类型的数据写一个描绘器,如number,date,combobox,lable,button。
12.设计不做好,编码累死人。
   我不知道劲往哪位置使。
13.设计一种出错状态,一旦出现异常,比如网络异常或其它等,就锁住整个画面。写一个统一的异常处理函数。
14.是项目是account还是project?这是个问题。
15.跟最好的人,学最好的技术。不然,鲜有进展。
16.函数使用排行榜:包括入选类/类之函数,新增类/类之函数, 这四个的排行榜
17.jdispnumber的默认最大长度应该为最大。现在是: 要是不设它的话就显示不出来。
18.红色的字和红色的背景,看不到字。
19.   VWJTextArea.java  -- 160
      ///textarea是容许输入转行符(enter键)的
20.      VWJTable.java ---10
      ///建议VWJTable也实现IVWComponent接口,特别是validateValue方法
21.   VWUtil.java -- 86
      ///modify:
      } else if (NOT_SET_FLAG.equals(flag)) { ///add
22.   PwWprev.java -- 27 private Integer wprevTime;
///须为BigDeciaml, 有可能为小数
23.   HBComAccess.java  -- 49
      ///既能新增又能修改?好像不能新增。
25.把事情做的漂亮点!
26.对表格中的component作setErrorField没用。how to do.