精华内容
下载资源
问答
  • 做个类似java,安卓手册的程序(安卓程序)该怎么做,数据是本地的,如何实现,需要用到数据库吗
  • 都说MSDN 上面的最好的手册C++开发怎么在MSDN 上面找东西,,大家不要喷呀, MSDN 上面搜索出来的东西太多了,我是新手, 如果我只想查找 C++ 的函数库要怎么查??
  • 前言 MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。MyBatis 去掉了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。...这样的好处是将SQL与程序代码分离,做到可以

    前言

    MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。MyBatis 去掉了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解进行配置和原始映射,以将接口和Java的POJO (Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。

    MyBatis作为持久层框架,其主要思想是将程序中的大量SQL语句剥离出来,配置在配置文件中,以实现SQL的灵活配置。这样做的好处是将SQL与程序代码分离,做到可以在不修改程序代码的情况下,直接在配置文件中修改SQL。

    在这里分享一份 [mybatis从入门到精通] 的强力教程,定能够助你一臂之力。

    面试准备

    不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。 运筹帷幄之后,决胜千里之外!不打毫无准备的仗,我觉得大家可以先从下面几个方面来准备面试:

    1. 自我介绍。(介绍自己的项目经历以及一些特长而不是简单自我介绍喜好等)

    2. 自己面试中可能涉及哪些知识点、那些知识点是重点。

    3. 面试中哪些问题会被经常问到、面试中自己该如何回答。

    4. 自己的简历该如何写。

    “80%的offer掌握在20%的人手中” 这句话也不是不无道理的。决定你面试能否成功的因素中实力固然占有很大一部 分比例,但是如果你的心态或者说运气不好的话,依然无法拿到满意的 offer。运气暂且不谈,就拿心态来说,千万 不要因为面试失败而气馁或者说怀疑自己的能力,面试失败之后多总结一下失败的原因,后面你就会发现自己会越来 越强大。

    另外,大家要明确的很重要的几点是:

    1. 写在简历上的东西一定要慎重,这可能是面试官大量提问的地方;

    2. 将自己的项目经历完美的展示出来非常重要。

    常见面试问题及范围如下

    Java基础

    1. 重载和重写的区别

    2. String 和 StringBuffer、StringBuilder 的区别是什么?String 为什么是不可变的?

    3. 自动装箱与拆箱

    4. == 与 equals

    5. final 关键字

    6. Object类的常见方法

    7. Java 中的异常处理

    8. 获取用键盘输入常用的的两种方法

    9. 接口和抽象类的区别是什么

    集合框架

    1. Arraylist 与 LinkedList 异同

    2. ArrayList 与 Vector 区别

    3. HashMap的底层实现

    4. HashMap 和 Hashtable 的区别

    5. HashMap 的长度为什么是2的幂次方

    6. HashMap 多线程操作导致死循环问题

    7. HashSet 和 HashMap 区别

    8. ConcurrentHashMap 和 Hashtable 的区别

    9. ConcurrentHashMap线程安全的具体实现方式/底层具体实现

    多线程与并发

    1. AQS 原理

    2. AQS 对资源的共享方式

    3. AQS底层使用了模板方法模式

    4. 说一说自己对于 synchronized 关键字的了解

    5. 说说自己是怎么使用 synchronized 关键字,在项目中用到了吗

    6. 讲一下 synchronized 关键字的底层原理

    7. 说说 JDK1.6 之后的synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗

    8. 谈谈 synchronized和ReenTrantLock 的区别

    9. 说说 synchronized 关键字和 volatile 关键字的区别

    10. 为什么要用线程池?

    11. 实现Runnable接口和Callable接口的区别

    12. 执行execute()方法和submit()方法的区别是什么呢?

    13. 如何创建线程池

    14. 介绍一下Atomic 原子类

    15. JUC 包中的原子类是哪4类?

    16. 讲讲 AtomicInteger 的使用

    17. 能不能给我简单介绍一下 AtomicInteger 类的原理

    JVM

    1. Java 中会存在内存泄漏吗,简述一下?

    2. 描述一下 JVM 加载 Class 文件的原理机制?

    3. 什么是tomcat类加载机制?

    4. 类加载器双亲委派模型机制?

    5. 垃圾回收常见问题

    6. 什么是GC? 为什么要有 GC?

    7. 简述一下Java 垃圾回收机制?

    8. 如何判断一个对象是否存活?

    9. 垃圾回收的优点和原理,并考虑 2 种回收机制?

    10. Java 中垃圾收集的方法有哪些?

    11. 讲讲你理解的性能评价及测试指标?

    12. 常用的性能优化方式有哪些?

    网络编程与操作系统

    1. TCP、UDP 协议的区别

    2. 在浏览器中输入url地址 ->> 显示主页的过程

    3. 各种协议与HTTP协议之间的关系

    4. HTTP长连接、短连接

    5. TCP 三次握手和四次挥手(面试常客)

    6. 简单介绍一下 Linux 文件系统?

    7. 一些常见的 Linux 命令了解吗?

    MySQL

    1. 说说自己对于 MySQL 常见的两种存储引擎:MyISAM与InnoDB的理解?

    2. 数据库索引了解吗?

    3. 为什么索引能提高查询速度?

    4. Mysql如何为表字段添加索引?

    5. 对于大表的常见优化手段说一下?

    Spring

    1. Spring Bean 的作用域

    2. Spring 事务中的隔离级别

    3. Spring 事务中的事务传播行为

    4. AOP是什么?

    5. IOC是什么?

    分布式

    1. 为什么要用 redis缓存?

    2. 为什么要用 redis 而不用 map/guava 做缓存?

    3. redis 和 memcached 的区别?

    4. redis 常见数据结构以及使用场景分析?(String,Hash,List,Set,Sorted Set)

    5. redis 设置过期时间

    6. redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)

    7. redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)?

    8. redis 事务

    9. 缓存雪崩和缓存穿透问题解决方案

    10. 如何解决 Redis 的并发竞争 Key 问题

    11. 如何保证缓存与数据库双写时的数据一致性?

    12. 什么是消息队列?为什么要用消息队列?

    13. 通过异步处理提高系统性能(削峰、减少响应所需时间)

    14. 降低系统耦合性

    15. 使用消息队列带来的一些问题

    16. JMS两种消息模型

    17. JMS 五种不同的消息正文格式

    18. 常见的消息队列对比

    19. 什么是 Dubbo?为什么要用 Dubbo?

    20. 什么是 RPC?RPC原理是什么?

    21. Dubbo 工作原理?

    22. 解释一下什么是负载均衡?

    23. 看看 Dubbo 提供的负载均衡策略?

    24. zookeeper宕机与dubbo直连的情况?

    线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

    一线互联网P7面试集锦+各种大厂面试集锦

    资料领取方式:戳这里

    学习笔记以及面试真题解析

    数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

    [外链图片转存中…(img-FIF7aiy7-1623294968641)]

    一线互联网P7面试集锦+各种大厂面试集锦

    [外链图片转存中…(img-nGpnLobz-1623294968644)]

    资料领取方式:戳这里

    学习笔记以及面试真题解析

    展开全文
  • Spring入门学习手册 2:怎么用注解来DI/IOC 目录 一、如果使用注解的话,在配置文件中应该什么? 在beans标签后加上一个 <context:annotation-config/> 复制代码 标签来声明将要使用注解就...

    Spring入门学习手册 2:怎么用注解来DI/IOC

    目录

    一、如果使用注解的话,在配置文件中应该做什么?

    在beans标签后加上一个

    <context:annotation-config/>
    复制代码

    标签来声明将要使用注解就可以了。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        
        <!--在此处加上此标签-->
        <context:annotation-config/>
        <bean name="c" class="com.learn.springDemo.Category">
            <property name="name" value="Eather"></property>
            <property name="id" value="12345"></property>
        </bean>
        <bean name="p" class="com.learn.springDemo.Product">
            <property name="name" value="a product"></property>
            <property name="id" value="1008611"></property>
    
            <!--将下面这行注释掉,因为代码中将使用自动装配来将categroy实例注入product-->
            <!--<property name="category" ref="c"></property>-->
    
        </bean>
    
    </beans>
    复制代码

    二、注解应该怎么用?

    如果是使用@Autowired注解的话,可以加在两个地方前面。

    属性前面 以及 setter方法前面。

    如下代码:

    package com.learn.springDemo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    public class Product {
        private int id;
        private String name;
    
        //加在这个地方
        @Autowired
        private Category category;
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        //加在这个地方
        @Autowired
        public void setCategory(Category category) {
            this.category = category;
        }
    
        public int getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        public Category getCategory() {
            return this.category;
        }
    }
    
    复制代码

    在这里必须要import org.springframework.beans.factory.annotation.Autowired;

    运行结果:

    a product's id is 1008611 and its category name is Eather
    复制代码

    三、注入同一个类的不同实例应该怎么办?

    上一篇笔记 里提到了 xml里面可以写多个相同的bean吗 这个问题,也就是注入同一个类的不同实例应该怎么办?在使用xml配置时很简单,改一下name就行。

    此时就可以使用@Resource注解

    先改一下xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--在此处加上此标签-->
        <context:annotation-config/>
        <bean name="c" class="com.learn.springDemo.Category">
            <property name="name" value="Eather"></property>
            <property name="id" value="12345"></property>
        </bean>
        <bean name="cc" class="com.learn.springDemo.Category">
            <property name="name" value="David"></property>
            <property name="id" value="10086"></property>
        </bean>
        <bean name="p" class="com.learn.springDemo.Product">
            <property name="name" value="a product"></property>
            <property name="id" value="1008611"></property>
    
            <!--将下面这行注释掉-->
            <!--<property name="category" ref="c"></property>-->
    
        </bean>
    
    </beans>
    复制代码

    注解应该加在属性的前面

    package com.learn.springDemo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import javax.annotation.Resource;
    
    public class Product {
        private int id;
        private String name;
    
        @Resource(name = "c")
        private Category category;
    
        @Resource(name = "cc")
        private Category category1;
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setCategory(Category category) {
            this.category = category;
        }
    
        public void setCategory1(Category category1) {
            this.category1 = category1;
        }
    
        public int getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        public Category getCategory() {
            return this.category;
        }
    
        public Category getCategory1() {
            return category1;
        }
    }
    复制代码

    测试代码:

    package com.learn.springTest;
    
    import com.learn.springDemo.Product;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        public static void main(String args[]) {
            ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
    
    
            Product p = (Product) ac.getBean("p");
    
            System.out.println(p.getName() + "'s id is " + p.getId() + " and its category name is "  + p.getCategory().getName() + " and " + p.getCategory1().getName());
    
        }
    
    }
    复制代码

    运行结果:

    a product's id is 1008611 and its category name is Eather and David
    复制代码

    四、xml配置文件里可不可以 bean 也不写?

    上述例子都是对 注入对象行为 的注解,对于bean对象本身的使用可不可以也用注解的方式进行,而不写到配置文件中呢?

    答案当然是可以,修改一下配置文件,去掉所有beansbean标签,加上

    <context:component-scan base-package="com.learn.springDemo"/>
    复制代码

    base-package 用来指定要扫描的包。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--在此处加上此标签-->
        <context:component-scan base-package="com.learn.springDemo" />
    
    </beans>
    复制代码

    类定义代码是:

    package com.learn.springDemo;
    
    import org.springframework.stereotype.Component;
    
    @Component("c")
    public class Category {
        private int id;
        private String name = "我是一个Category";
    
        public int getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    
    package com.learn.springDemo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    
    @Component("p")
    public class Product {
        private int id;
        private String name = "我是一个product";
    
        @Autowired
        private Category category;
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setCategory(Category category) {
            this.category = category;
        }
    
    
        public int getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        public Category getCategory() {
            return this.category;
        }
    }
    复制代码

    测试代码是:

    package com.learn.springTest;
    
    import com.learn.springDemo.Product;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        public static void main(String args[]) {
            ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
    
    
            Product p = (Product) ac.getBean("p");
    
            System.out.println("product 名字是 " + p.getName() + " category 名字是 "  + p.getCategory().getName());
    
        }
    
    }
    复制代码

    运行结果是:

    product 名字是 我是一个product category 名字是 我是一个Category
    复制代码

    至于前面的第三个问题应该怎么解决,暂时我也不知道,可能这个问题没有太大的意义吧!

    展开全文
  • 小编为什么强烈的案例uBlock ... Origin怎么用并不熟悉。所以今天我们chrome插件网精心整理了这篇uBlock Origin中文使用手册,希望能够帮助到大家。 关于 uBlock Origin 有人曾经过对比:

            小编为什么强烈的案例uBlock Origin这款广告过滤插件呢?因为真心觉得使用起来非常的方便。但是仍然有很多人习惯了使用ABP(AdBlock Plus),对于uBlock Origin怎么用并不熟悉。所以今天我们chrome插件网精心整理了这篇uBlock Origin中文使用手册,希望能够帮助到大家


    关于 uBlock Origin

    有人曾经做过对比:uBlock Origin对比ABP有性能上的优势,其最为突然的性能优势就是其占用极低的内存和 CPU。有分析说adp主要靠的是屏蔽,而ublock Origin主要靠的是阻断,ABP的工作需要在所有网页插入屏蔽脚本和css,而uBlock Origin直接阻止需要屏蔽的内容进入当前网页。一般的拦截请求的规则大家都差不多,关键的是元素隐藏规则,uBlock 把它叫做修饰规则 cosmetic filters,ABP 不管是什么网页都会插入 14000 多条元素隐藏规则,所以占用内存很大,uBlock 插入的很少,因为他是在网页开始加载以后才判断需要用到哪些元素隐藏规则。所以才在性能上面要更加优越。

    大约在2016年10月份,著名浏览器Mozilla 把获取附加组件里广告过滤的推荐由 Adblock Plus 改成了 uBlock Origin,这次改动直接导致 ABP的日下载量少了将近 5 万(30%)而 uBlock Origin日下载量增加了几乎 5 万次(200%+)。由此可以uBlock Origin越来越被大家接受。


    uBlcok Origin的最新版本1.13.2。更新于2017.6.21。最新版下载地址:http://chromecj.com/productivity/2017-06/770.html

    uBlock Origin界面功能介绍

    当我们在chrome浏览器中安装好uBlock Origin插件后,我们点击其按钮标记可以看到如下图所示的基础信息。

    其中包含以下几个图标:

    (1)巨大的电源按钮:用于打开和关闭uBlock Origin按钮,蓝色开启/灰色关闭 。
    点击巨大的电源按钮可以针对当前站点关闭 uBlock Origin,也就是将当前站点添加为 白名单,在你下次访问时仍会保留此状态。相对地,按住 Ctrl 并点击按钮只针对当前页面关闭 uBlock Origin在 Mac下是按住command ⌘ 点击
     
    (2)闪电图标去除当前页面的元素。点击闪电图标可以进入元素去除器模式,在此你可以交互式地移除当前页面的一个或多个元素。不过这里移除元素始终是临时性的,也就是说页面重新载入后所移除的元素又将重新显示出来。
     
    (3)元素吸管图标:点击滴管图标可以进入元素选择器模式,在这里你可以交互地从页面选择元素并创建过滤规则来永久移除该元素。屏蔽元素按钮(用过ABP的都知道) 
     
    (4)列表图标网络请求日志(个人理解:网络请求记录监控中心):可以按照网络资源查看/屏蔽的控制系统 。网络请求日志与开发工具的网络 不同之处在于,不单单可以查看网络资源,还可以屏蔽不想要的脚本等等之流 。你可以在浏览器里实时查看网络通信情况。提示:点击图标的同时按住 Shift 键可以切换选择是在新窗口还是新标签页中打开记录台。uBO 会在你未按 Shift 键打开记录台时记住你的选择。
     
    (5)禁止网页弹窗按钮,开启后,该网页永久无法弹窗 。默认情况下弹出窗口是允许显示的,除非有相应的过滤规则屏蔽。但如果开启该选项,不管规则如何,当前站点的所有弹出窗口都会被屏蔽:
    ublock origin禁止弹窗
    能否屏蔽弹出窗口取决于所选过滤规则列表是否包含相应的规则,所以这项功能特别适合第三方规则列表没有相应规则对付网站弹出窗口的情况。
    **基于 Chromium 的浏览器请注意:**由于 Chromium API 的限制,uBlock Origin无法始终辨别出新建的标签页是弹出窗口还是来自用户正常的链接点击。所以一旦使用了这个开关禁止弹出窗口,你 可能 无法通过右键菜单在新标签页里打开链接。
     
    (6)严格屏蔽大的媒体元素按钮,开启后,将不再对当前网页本身进行屏蔽,比如可以用于网络运营商的网络劫持,规则(uBlock设置->自定义规则列表)。该功能主要目的是节省网络带宽,其次是提高可能的网页载入速度。默认情况下此选项处于禁用状态。你可以到控制面板的 设置 版块打开默认全局启用的开关。
     
    对媒体元素超过特定大小后是否屏蔽的这个门限值是可以配置的,它是一个全局屏蔽的值。你可以将值设置为 0,这表示屏蔽所有媒体元素。在本文档里我们将超过该大小值的媒体元素(图像、视频、音频)称为 “大型媒体元素 ”。你可以基于站点启用和禁用这项功能,即针对当前站点点击弹出界面里的对应开关。
    (7)禁止修饰生效按钮,开启,隐藏元素规则失效 。该特性生效时,图标旁边的数字表示被 uBO 修饰规则隐藏的元素数量。如果网页有被隐藏的元素,那么一旦你禁用修饰规则,这些元素就会立即显示,一旦启用立即隐藏。
     
    (8)禁止第三方字体:三种颜色:红(block)、灰(noop)、绿(allow) 出于安全和隐私方面考虑,许多人希望默认能屏蔽所有网页字体。你只需在控制面板的 "自定义规则 " 版块直接添加下面这条规则:
    no-remote-fonts: * true
    这样 uBlock 就会默认屏蔽任何地方的网页字体,而你又可以根据不同的站点点击这个开关来允许使用网页字体。
    基于 Chromium 的浏览器请注意:Chromium 的 webRequest API 无法准确报出 font 类的请求,所以字体会被归为 other 类型。uBlock 是根据一条 URL 路径的"扩展名"来判断一条请求是否属于字体资源,但一条 URL 的请求类型可以千变万化,所以对于基于 Chromium 的浏览器,uBlock 也许得在请求产生以后才能屏蔽字体,也就是从远端服务器接收到响应标头以后,毕竟从响应标头可以确认资源属于哪种类型。

    uBlock Origin如何添加白名单

    许多用户的反馈希望增加能将网站加为白名单的功能,也就是在特定的网站禁用 uBlock。其实这项功能已经有了,就是那个巨大的电源按钮。点击这个按钮你可以将当前网站加入白名单,在你下次访问该网站时仍会记住你的选择。如下图所示:

    常见的uBlock Origin规则推荐

    初始默认加载和执行下列过滤规则列表:
     
    - EasyList
    - Peter Lowe’s Ad server list
    - EasyPrivacy
    - Malware domains
     
    这里还有更多的规则列表供你选择:
     
    - Fanboy’s Enhanced Tracking List
    - Dan Pollock’s hosts file
    - hpHosts’s Ad and tracking servers
    - MVPS HOSTS
    - Spam404
    - 等等
     
    当然,启用越多的过滤规则就会产生越高的内存占用。 然而,即使再添加 Fanboy 额外的两个规则列表,如 hpHosts’s Ad 和 tracking servers,uBlock₀ 的内存占用依然比其他常见的过滤工具要低的多。

    uBlock Origin小结

    ABP的过滤规则建立或许比较直观方便,但对于不想详细研究直接用其他人维护的列表且对性能要求较高的人来说,uBlock Origin也许更适合(说的就是我~~)。

    展开全文
  • 生产计划的人来说非常不错,看看别的公司的计划是怎么样的,可以好好学习下
  • makefile总结 (可做手册使用)

    千次阅读 2016-07-14 22:02:28
    引言:楼主超棒。 千里之行,始于足下 ...makefile:是一个文本形式的脚本文件,包含一些规则,具体告诉make编译哪些文件,怎么编译。 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是

    引言:楼主超棒。 千里之行,始于足下


    Makefile使用总结


    1. Makefile 简介

    自己补充两个概念:
    make:一种控制编译或者重复编译软件的工具
    makefile:是一个文本形式的脚本文件,包含一些规则,具体告诉make编译哪些文件,怎么编译。


    Makefile 是和 make 命令一起配合使用的.
    很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之间的依赖关系不知会多复杂.


    Makefile的组织流程的能力如此之强, 不仅可以用来编译项目, 还可以用来组织我们平时的一些日常操作. 这个需要大家发挥自己的想象力.

    Makefile 是和 make 命令一起配合使用的.

    很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之间的依赖关系不知会多复杂.

    Makefile的组织流程的能力如此之强, 不仅可以用来编译项目, 还可以用来组织我们平时的一些日常操作. 这个需要大家发挥自己的想象力.

     

    本篇博客是基于 {精华} 跟我一起写 Makefile 而整理的, 有些删减, 追加了一些示例.

    非常感谢 gunguymadman_cu 提供如此详尽的Makefile介绍, 这正是我一直寻找的Makefile中文文档.

     

    1.1 Makefile 主要的 5个部分 (显示规则, 隐晦规则, 变量定义, 文件指示, 注释)

    Makefile基本格式如下:

    target ... : prerequisites ...
        command
        ...
        ...

    其中,

    • target        - 目标文件, 可以是 Object File, 也可以是可执行文件
    • prerequisites - 生成 target 所需要的文件或者目标
    • command       - make需要执行的命令 (任意的shell命令), Makefile中的命令必须以 [tab] 开头

     

    1. 显示规则 :: 说明如何生成一个或多个目标文件(包括 生成的文件, 文件的依赖文件, 生成的命令)
    2. 隐晦规则 :: make的自动推导功能所执行的规则
    3. 变量定义 :: Makefile中定义的变量
    4. 文件指示 :: Makefile中引用其他Makefile; 指定Makefile中有效部分; 定义一个多行命令
    5. 注释     :: Makefile只有行注释 "#", 如果要使用或者输出"#"字符, 需要进行转义, "\#"

     

    1.2 GNU make 的工作方式

    1. 读入主Makefile (主Makefile中可以引用其他Makefile)
    2. 读入被include的其他Makefile
    3. 初始化文件中的变量
    4. 推导隐晦规则, 并分析所有规则
    5. 为所有的目标文件创建依赖关系链
    6. 根据依赖关系, 决定哪些目标要重新生成
    7. 执行生成命令

     

    2. Makefile 初级语法

    2.1 Makefile 规则

    2.1.1 规则语法

    规则主要有2部分: 依赖关系 和 生成目标的方法.

    语法有以下2种:

    target ... : prerequisites ...
        command
        ...

    或者

    target ... : prerequisites ; command
        command
        ...

    *注* command太长, 可以用 "\" 作为换行符

     

    2.1.2 规则中的通配符

    • *     :: 表示任意一个或多个字符
    • ?     :: 表示任意一个字符
    • [...] :: ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字
    • ~     :: 表示用户的home目录

     

    2.1.3 路径搜索

    当一个Makefile中涉及到大量源文件时(这些源文件和Makefile极有可能不在同一个目录中),

    这时, 最好将源文件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量VPATH 就是完成这个功能的.

    指定了 VPATH 之后, 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到VPATH 指定的路径中再去查找..

    VPATH 使用方法:

    • vpath <directories>            :: 当前目录中找不到文件时, 就从<directories>中搜索
    • vpath <pattern> <directories>  :: 符合<pattern>格式的文件, 就从<directories>中搜索
    • vpath <pattern>                :: 清除符合<pattern>格式的文件搜索路径
    • vpath                          :: 清除所有已经设置好的文件路径

     

    复制代码
    # 示例1 - 当前目录中找不到文件时, 按顺序从 src目录 ../parent-dir目录中查找文件
    VPATH src:../parent-dir   
    
    # 示例2 - .h结尾的文件都从 ./header 目录中查找
    VPATH %.h ./header
    
    # 示例3 - 清除示例2中设置的规则
    VPATH %.h
    
    # 示例4 - 清除所有VPATH的设置
    VPATH
    复制代码

     

    2.2 Makefile 中的变量

    2.2.1 变量定义 ( = or := )

    OBJS = programA.o programB.o
    OBJS-ADD = $(OBJS) programC.o
    # 或者
    OBJS := programA.o programB.o
    OBJS-ADD := $(OBJS) programC.o

    其中 = 和 := 的区别在于, := 只能使用前面定义好的变量, = 可以使用后面定义的变量

    测试 =

    复制代码
    # Makefile内容
    OBJS2 = $(OBJS1) programC.o
    OBJS1 = programA.o programB.o
    
    all:
        @echo $(OBJS2)
    
    # bash中执行 make, 可以看出虽然 OBJS1 是在 OBJS2 之后定义的, 但在 OBJS2中可以提前使用
    $ make
    programA.o programB.o programC.o
    复制代码

     

    测试 :=

    复制代码
    # Makefile内容
    OBJS2 := $(OBJS1) programC.o
    OBJS1 := programA.o programB.o
    
    all:
        @echo $(OBJS2)
    
    # bash中执行 make, 可以看出 OBJS2 中的 $(OBJS1) 为空
    $ make
    programC.o
    复制代码

     

    2.2.2 变量替换

    复制代码
    # Makefile内容
    SRCS := programA.c programB.c programC.c
    OBJS := $(SRCS:%.c=%.o)
    
    all:
        @echo "SRCS: " $(SRCS)
        @echo "OBJS: " $(OBJS)
    
    # bash中运行make
    $ make
    SRCS:  programA.c programB.c programC.c
    OBJS:  programA.o programB.o programC.o
    复制代码

     

    2.2.3 变量追加值 +=

    复制代码
    # Makefile内容
    SRCS := programA.c programB.c programC.c
    SRCS += programD.c
    
    all:
        @echo "SRCS: " $(SRCS)
    
    # bash中运行make
    $ make
    SRCS:  programA.c programB.c programC.c programD.c
    复制代码

     

    2.2.4 变量覆盖 override

    作用是使 Makefile中定义的变量能够覆盖 make 命令参数中指定的变量

    语法:

    • override <variable> = <value>
    • override <variable> := <value>
    • override <variable> += <value>

     

    下面通过一个例子体会 override 的作用:

    复制代码
    # Makefile内容 (没有用override)
    SRCS := programA.c programB.c programC.c
    
    all:
        @echo "SRCS: " $(SRCS)
    
    # bash中运行make
    $ make SRCS=nothing
    SRCS:  nothing
    
    #################################################
    
    # Makefile内容 (用override)
    override SRCS := programA.c programB.c programC.c
    
    all:
        @echo "SRCS: " $(SRCS)
    
    # bash中运行make
    $ make SRCS=nothing
    SRCS:  programA.c programB.c programC.c
    复制代码

     

    2.2.5 目标变量

    作用是使变量的作用域仅限于这个目标(target), 而不像之前例子中定义的变量, 对整个Makefile都有效.

    语法:

    • <target ...> :: <variable-assignment>
    • <target ...> :: override <variable-assignment> (override作用参见 变量覆盖的介绍)

     

    示例:

    复制代码
    # Makefile 内容
    SRCS := programA.c programB.c programC.c
    
    target1: TARGET1-SRCS := programD.c
    target1:
        @echo "SRCS: " $(SRCS)
        @echo "SRCS: " $(TARGET1-SRCS)
    
    target2:
        @echo "SRCS: " $(SRCS)
        @echo "SRCS: " $(TARGET1-SRCS)
    
    # bash中执行make
    $ make target1
    SRCS:  programA.c programB.c programC.c
    SRCS:  programD.c
    
    $ make target2     <-- target2中显示不了 $(TARGET1-SRCS)
    SRCS:  programA.c programB.c programC.c
    SRCS:
    复制代码

     

    2.3 Makefile 命令前缀

    Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不用前缀.

    3种格式的shell命令区别如下:

    • 不用前缀 :: 输出执行的命令以及命令执行的结果, 出错的话停止执行
    • 前缀 @   :: 只输出命令执行的结果, 出错的话停止执行
    • 前缀 -   :: 命令执行有错的话, 忽略错误, 继续执行

     

    示例:

    复制代码
    # Makefile 内容 (不用前缀)
    all:
        echo "没有前缀"
        cat this_file_not_exist
        echo "错误之后的命令"       <-- 这条命令不会被执行
    
    # bash中执行 make
    $ make
    echo "没有前缀"             <-- 命令本身显示出来
    没有前缀                    <-- 命令执行结果显示出来
    cat this_file_not_exist
    cat: this_file_not_exist: No such file or directory
    make: *** [all] Error 1
    
    ###########################################################
    
    # Makefile 内容 (前缀 @)
    all:
        @echo "没有前缀"
        @cat this_file_not_exist
        @echo "错误之后的命令"       <-- 这条命令不会被执行
    
    # bash中执行 make
    $ make
    没有前缀                         <-- 只有命令执行的结果, 不显示命令本身
    cat: this_file_not_exist: No such file or directory
    make: *** [all] Error 1
    
    ###########################################################
    
    # Makefile 内容 (前缀 -)
    all:
        -echo "没有前缀"
        -cat this_file_not_exist
        -echo "错误之后的命令"       <-- 这条命令会被执行
    
    # bash中执行 make
    $ make
    echo "没有前缀"             <-- 命令本身显示出来
    没有前缀                    <-- 命令执行结果显示出来
    cat this_file_not_exist
    cat: this_file_not_exist: No such file or directory
    make: [all] Error 1 (ignored)
    echo "错误之后的命令"       <-- 出错之后的命令也会显示
    错误之后的命令              <-- 出错之后的命令也会执行
    复制代码

     

    2.4 伪目标

    伪目标并不是一个"目标(target)", 不像真正的目标那样会生成一个目标文件.

    典型的伪目标是 Makefile 中用来清理编译过程中中间文件的 clean 伪目标, 一般格式如下:

    .PHONY: clean   <-- 这句没有也行, 但是最好加上
    clean:
        -rm -f *.o

     

    2.5 引用其他的 Makefile

    语法: include <filename>  (filename 可以包含通配符和路径)

    示例:

    复制代码
    # Makefile 内容
    all:
        @echo "主 Makefile begin"
        @make other-all
        @echo "主 Makefile end"
    
    include ./other/Makefile
    
    # ./other/Makefile 内容
    other-all:
        @echo "other makefile begin"
        @echo "other makefile end"
    
    # bash中执行 make
    $ ll
    total 20K
    -rw-r--r-- 1 wangyubin wangyubin  125 Sep 23 16:13 Makefile
    -rw-r--r-- 1 wangyubin wangyubin  11K Sep 23 16:15 makefile.org   <-- 这个文件不用管
    drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 23 16:11 other
    $ ll other/
    total 4.0K
    -rw-r--r-- 1 wangyubin wangyubin 71 Sep 23 16:11 Makefile
    
    $ make
    主 Makefile begin
    make[1]: Entering directory `/path/to/test/makefile'
    other makefile begin
    other makefile end
    make[1]: Leaving directory `/path/to/test/makefile'
    主 Makefile end
    复制代码

     

    2.6 查看C文件的依赖关系

    写 Makefile 的时候, 需要确定每个目标的依赖关系.

    GNU提供一个机制可以查看C代码文件依赖那些文件, 这样我们在写 Makefile 目标的时候就不用打开C源码来看其依赖那些文件了.

    比如, 下面命令显示内核源码中 virt/kvm/kvm_main.c 中的依赖关系

    $ cd virt/kvm/
    $ gcc -MM kvm_main.c 
    kvm_main.o: kvm_main.c iodev.h coalesced_mmio.h async_pf.h   <-- 这句就可以加到 Makefile 中作为编译 kvm_main.o 的依赖关系

     

    2.7 make 退出码

    Makefile的退出码有以下3种:

    • 0 :: 表示成功执行
    • 1 :: 表示make命令出现了错误
    • 2 :: 使用了 "-q" 选项, 并且make使得一些目标不需要更新

     

    2.8 指定 Makefile, 指定特定目标

    默认执行 make 命令时, GNU make在当前目录下依次搜索下面3个文件 "GNUmakefile", "makefile", "Makefile",

    找到对应文件之后, 就开始执行此文件中的第一个目标(target). 如果找不到这3个文件就报错.

     

    非默认情况下, 可以在 make 命令中指定特定的 Makefile 和特定的 目标.

    示例:

    复制代码
    # Makefile文件名改为 MyMake, 内容
    target1:
        @echo "target [1]  begin"
        @echo "target [1]  end"
    
    target2:
        @echo "target [2]  begin"
        @echo "target [2]  end"
    
    # bash 中执行 make
    $ ls
    Makefile
    $ mv Makefile MyMake
    $ ls
    MyMake
    $ make                     <-- 找不到默认的 Makefile
    make: *** No targets specified and no makefile found.  Stop.
    $ make -f MyMake           <-- 指定特定的Makefile
    target [1]  begin
    target [1]  end
    $ make -f MyMake target2   <-- 指定特定的目标(target)
    target [2]  begin
    target [2]  end
    复制代码

     

    2.9 make 参数介绍

    make 的参数有很多, 可以通过 make -h 去查看, 下面只介绍几个我认为比较有用的.

    参数

    含义

    --debug[=<options>] 输出make的调试信息, options 可以是 a, b, v
    -j --jobs 同时运行的命令的个数, 也就是多线程执行 Makefile
    -r --no-builtin-rules 禁止使用任何隐含规则
    -R --no-builtin-variabes 禁止使用任何作用于变量上的隐含规则
    -B --always-make 假设所有目标都有更新, 即强制重编译

     

    2.10 Makefile 隐含规则

    这里只列一个和编译C相关的.

    编译C时,<n>.o 的目标会自动推导为 <n>.c

    复制代码
    # Makefile 中
    main : main.o
        gcc -o main main.o
    
    #会自动变为:
    main : main.o
        gcc -o main main.o
    
    main.o: main.c    <-- main.o 这个目标是隐含生成的
        gcc -c main.c
    复制代码

     

    2.11 隐含规则中的 命令变量 和 命令参数变量

    2.11.1 命令变量, 书写Makefile可以直接写 shell时用这些变量.

    下面只列出一些C相关的

    变量名

    含义

    RM rm -f
    AR ar
    CC cc
    CXX g++

    示例:

    复制代码
    # Makefile 内容
    all:
        @echo $(RM)
        @echo $(AR)
        @echo $(CC)
        @echo $(CXX)
    
    # bash 中执行make, 显示各个变量的值
    $ make
    rm -f
    ar
    cc
    g++
    复制代码

     

    2.11.2 命令参数变量

    变量名

    含义

    ARFLAGS AR命令的参数
    CFLAGS C语言编译器的参数
    CXXFLAGS C++语言编译器的参数

     

    示例: 下面以 CFLAGS 为例演示

    复制代码
    # test.c 内容
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        printf ("Hello Makefile\n");
        return 0;
    }
    
    # Makefile 内容
    test: test.o
        $(CC) -o test test.o
    
    # bash 中用 make 来测试
    $ ll
    total 24K
    -rw-r--r-- 1 wangyubin wangyubin  69 Sep 23 17:31 Makefile
    -rw-r--r-- 1 wangyubin wangyubin 14K Sep 23 19:51 makefile.org   <-- 请忽略这个文件
    -rw-r--r-- 1 wangyubin wangyubin 392 Sep 23 17:31 test.c
    
    $ make
    cc    -c -o test.o test.c
    cc -o test test.o               <-- 这个是自动推导的
    
    $ rm -f test test.o
    
    $ make CFLAGS=-Wall             <-- 命令中加的编译器参数自动追加入下面的编译中了
    cc -Wall   -c -o test.o test.c
    cc -o test test.o
    复制代码

     

    2.12 自动变量

    Makefile 中很多时候通过自动变量来简化书写, 各个自动变量的含义如下:

    自动变量

    含义

    $@ 目标集合
    $% 当目标是函数库文件时, 表示其中的目标文件名
    $< 第一个依赖目标. 如果依赖目标是多个, 逐个表示依赖目标
    $? 比目标新的依赖目标的集合
    $^ 所有依赖目标的集合, 会去除重复的依赖目标
    $+ 所有依赖目标的集合, 不会去除重复的依赖目标
    $* 这个是GNU make特有的, 其它的make不一定支持

     

    3. Makefile 高级语法

    3.1 嵌套Makefile

    在 Makefile 初级语法中已经提到过引用其它 Makefile的方法. 这里有另一种写法, 并且可以向引用的其它 Makefile 传递参数.

    示例: (不传递参数, 只是调用子文件夹 other 中的Makefile)

    复制代码
    # Makefile 内容
    all:
        @echo "主 Makefile begin"
        @cd ./other && make
        @echo "主 Makefile end"
    
    
    # ./other/Makefile 内容
    other-all:
        @echo "other makefile begin"
        @echo "other makefile end"
    
    # bash中执行 make
    $ ll
    total 28K
    -rw-r--r-- 1 wangyubin wangyubin  104 Sep 23 20:43 Makefile
    -rw-r--r-- 1 wangyubin wangyubin  17K Sep 23 20:44 makefile.org   <-- 这个文件不用管
    drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 23 20:42 other
    $ ll other/
    total 4.0K
    -rw-r--r-- 1 wangyubin wangyubin 71 Sep 23 16:11 Makefile
    
    $ make
    主 Makefile begin
    make[1]: Entering directory `/path/to/test/makefile/other'
    other makefile begin
    other makefile end
    make[1]: Leaving directory `/path/to/test/makefile/other'
    主 Makefile end
    复制代码

     

    示例: (用export传递参数)

    复制代码
    # Makefile 内容
    export VALUE1 := export.c    <-- 用了 export, 此变量能够传递到 ./other/Makefile 中
    VALUE2 := no-export.c        <-- 此变量不能传递到 ./other/Makefile 中
    
    all:
        @echo "主 Makefile begin"
        @cd ./other && make
        @echo "主 Makefile end"
    
    
    # ./other/Makefile 内容
    other-all:
        @echo "other makefile begin"
        @echo "VALUE1: " $(VALUE1)
        @echo "VALUE2: " $(VALUE2)
        @echo "other makefile end"
    
    # bash中执行 make
    $ make
    主 Makefile begin
    make[1]: Entering directory `/path/to/test/makefile/other'
    other makefile begin
    VALUE1:  export.c        <-- VALUE1 传递成功
    VALUE2:                  <-- VALUE2 传递失败
    other makefile end
    make[1]: Leaving directory `/path/to/test/makefile/other'
    主 Makefile end
    复制代码

     

    *补充* export 语法格式如下:

    • export variable = value
    • export variable := value
    • export variable += value

     

    3.2 定义命令包

    命令包有点像是个函数, 将连续的相同的命令合成一条, 减少 Makefile 中的代码量, 便于以后维护.

    语法:

    define <command-name>
    command
    ...
    endef

     

    示例:

    复制代码
    # Makefile 内容
    define run-hello-makefile
    @echo -n "Hello"
    @echo " Makefile!"
    @echo "这里可以执行多条 Shell 命令!"
    endef
    
    all:
        $(run-hello-makefile)
    
    
    # bash 中运行make
    $ make
    Hello Makefile!
    这里可以执行多条 Shell 命令!
    复制代码

     

    3.3 条件判断

    条件判断的关键字主要有 ifeq ifneq ifdef ifndef

    语法:

    复制代码
    <conditional-directive>
    <text-if-true>
    endif
    
    # 或者
    <conditional-directive>
    <text-if-true>
    else
    <text-if-false>
    endif
    复制代码

     

    示例: ifeq的例子, ifneq和ifeq的使用方法类似, 就是取反

    复制代码
    # Makefile 内容
    all:
    ifeq ("aa", "bb")
        @echo "equal"
    else
        @echo "not equal"
    endif
    
    # bash 中执行 make
    $ make
    not equal
    复制代码

     

    示例: ifdef的例子, ifndef和ifdef的使用方法类似, 就是取反

    复制代码
    # Makefile 内容
    SRCS := program.c
    
    all:
    ifdef SRCS
        @echo $(SRCS)
    else
        @echo "no SRCS"
    endif
    
    # bash 中执行 make
    $ make
    program.c
    复制代码

     

    3.4 Makefile 中的函数

    Makefile 中自带了一些函数, 利用这些函数可以简化 Makefile 的编写.

    函数调用语法如下:

    $(<function> <arguments>)
    # 或者
    ${<function> <arguments>}
    • <function> 是函数名
    • <arguments> 是函数参数

     

    3.4.1 字符串函数

    字符串替换函数: $(subst <from>,<to>,<text>)

    功能: 把字符串<text> 中的 <from> 替换为 <to>

    返回: 替换过的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(subst t,e,maktfilt)  <-- 将t替换为e
    
    # bash 中执行 make
    $ make
    makefile
    复制代码

     

    模式字符串替换函数: $(patsubst <pattern>,<replacement>,<text>)

    功能: 查找<text>中的单词(单词以"空格", "tab", "换行"来分割) 是否符合 <pattern>, 符合的话, 用 <replacement> 替代.

    返回: 替换过的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(patsubst %.c,%.o,programA.c programB.c)
    
    # bash 中执行 make
    $ make
    programA.o programB.o
    复制代码

     

    去空格函数: $(strip <string>)

    功能: 去掉 <string> 字符串中开头和结尾的空字符

    返回: 被去掉空格的字符串值

    复制代码
    # Makefile 内容
    VAL := "       aa  bb  cc "
    
    all:
        @echo "去除空格前: " $(VAL)
        @echo "去除空格后: " $(strip $(VAL))
    
    # bash 中执行 make
    $ make
    去除空格前:         aa  bb  cc 
    去除空格后:   aa bb cc
    复制代码

     

    查找字符串函数: $(findstring <find>,<in>)

    功能: 在字符串 <in> 中查找 <find> 字符串

    返回: 如果找到, 返回 <find> 字符串,  否则返回空字符串

    复制代码
    # Makefile 内容
    VAL := "       aa  bb  cc "
    
    all:
        @echo $(findstring aa,$(VAL))
        @echo $(findstring ab,$(VAL))
    
    # bash 中执行 make
    $ make
    aa
    复制代码

     

    过滤函数: $(filter <pattern...>,<text>)

    功能: 以 <pattern> 模式过滤字符串 <text>, *保留* 符合模式 <pattern> 的单词, 可以有多个模式

    返回: 符合模式 <pattern> 的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(filter %.o %.a,program.c program.o program.a)
    
    
    # bash 中执行 make
    $ make
    program.o program.a
    复制代码

     

    反过滤函数: $(filter-out <pattern...>,<text>)

    功能: 以 <pattern> 模式过滤字符串 <text>, *去除* 符合模式 <pattern> 的单词, 可以有多个模式

    返回: 不符合模式 <pattern> 的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(filter-out %.o %.a,program.c program.o program.a)
    
    # bash 中执行 make
    $ make
    program.c
    复制代码

     

    排序函数: $(sort <list>)

    功能: 给字符串 <list> 中的单词排序 (升序)

    返回: 排序后的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(sort bac abc acb cab)
    
    # bash 中执行 make
    $ make
    abc acb bac cab
    复制代码

     

    取单词函数: $(word <n>,<text>)

    功能: 取字符串 <text> 中的 第<n>个单词 (n从1开始)

    返回: <text> 中的第<n>个单词, 如果<n> 比 <text> 中单词个数要大, 则返回空字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(word 1,aa bb cc dd)
        @echo $(word 5,aa bb cc dd)
        @echo $(word 4,aa bb cc dd)
    
    # bash 中执行 make
    $ make
    aa
    
    dd
    复制代码

     

    取单词串函数: $(wordlist <s>,<e>,<text>)

    功能: 从字符串<text>中取从<s>开始到<e>的单词串. <s>和<e>是一个数字.

    返回: 从<s>到<e>的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(wordlist 1,3,aa bb cc dd)
        @echo $(word 5,6,aa bb cc dd)
        @echo $(word 2,5,aa bb cc dd)
    
    
    # bash 中执行 make
    $ make
    aa bb cc
    
    bb
    复制代码

     

    单词个数统计函数: $(words <text>)

    功能: 统计字符串 <text> 中单词的个数

    返回: 单词个数

    复制代码
    # Makefile 内容
    
    all:
        @echo $(words aa bb cc dd)
        @echo $(words aabbccdd)
        @echo $(words )
    
    # bash 中执行 make
    $ make
    4
    1
    0
    复制代码

     

    首单词函数: $(firstword <text>)

    功能: 取字符串 <text> 中的第一个单词

    返回: 字符串 <text> 中的第一个单词

    复制代码
    # Makefile 内容
    all:
        @echo $(firstword aa bb cc dd)
        @echo $(firstword aabbccdd)
        @echo $(firstword )
    
    # bash 中执行 make
    $ make
    aa
    aabbccdd
    复制代码

     

    3.4.2 文件名函数

    取目录函数: $(dir <names...>)

    功能: 从文件名序列 <names> 中取出目录部分

    返回: 文件名序列 <names> 中的目录部分

    复制代码
    # Makefile 内容
    all:
        @echo $(dir /home/a.c ./bb.c ../c.c d.c)
    
    
    # bash 中执行 make
    $ make
    /home/ ./ ../ ./
    复制代码

     

    取文件函数: $(notdir <names...>)

    功能: 从文件名序列 <names> 中取出非目录部分

    返回: 文件名序列 <names> 中的非目录部分

    复制代码
    # Makefile 内容
    all:
        @echo $(notdir /home/a.c ./bb.c ../c.c d.c)
    
    # bash 中执行 make
    $ make
    a.c bb.c c.c d.c
    复制代码

     

    取后缀函数: $(suffix <names...>)

    功能: 从文件名序列 <names> 中取出各个文件名的后缀

    返回: 文件名序列 <names> 中各个文件名的后缀, 没有后缀则返回空字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(suffix /home/a.c ./b.o ../c.a d)
    
    # bash 中执行 make
    $ make
    .c .o .a
    复制代码

     

    取前缀函数: $(basename <names...>)

    功能: 从文件名序列 <names> 中取出各个文件名的前缀

    返回: 文件名序列 <names> 中各个文件名的前缀, 没有前缀则返回空字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(basename /home/a.c ./b.o ../c.a /home/.d .e)
    
    
    # bash 中执行 make
    $ make
    /home/a ./b ../c /home/
    复制代码

     

    加后缀函数: $(addsuffix <suffix>,<names...>)

    功能: 把后缀 <suffix> 加到 <names> 中的每个单词后面

    返回: 加过后缀的文件名序列

    复制代码
    # Makefile 内容
    all:
        @echo $(addsuffix .c,/home/a b ./c.o ../d.c)
    
    
    # bash 中执行 make
    $ make
    /home/a.c b.c ./c.o.c ../d.c.c
    复制代码

     

    加前缀函数: $(addprefix <prefix>,<names...>)

    功能: 把前缀 <prefix> 加到 <names> 中的每个单词前面

    返回: 加过前缀的文件名序列

    复制代码
    # Makefile 内容
    all:
        @echo $(addprefix test_,/home/a.c b.c ./d.c)
    
    # bash 中执行 make
    $ make
    test_/home/a.c test_b.c test_./d.c
    复制代码

     

    连接函数: $(join <list1>,<list2>)

    功能: <list2> 中对应的单词加到 <list1> 后面

    返回: 连接后的字符串

    复制代码
    # Makefile 内容
    all:
        @echo $(join a b c d,1 2 3 4)
        @echo $(join a b c d,1 2 3 4 5)
        @echo $(join a b c d e,1 2 3 4)
    
    # bash 中执行 make
    $ make
    a1 b2 c3 d4
    a1 b2 c3 d4 5
    a1 b2 c3 d4 e
    复制代码

     

    3.4.3 foreach

    语法:

    $(foreach <var>,<list>,<text>)

     

    示例:

    复制代码
    # Makefile 内容
    targets := a b c d
    objects := $(foreach i,$(targets),$(i).o)
    
    all:
        @echo $(targets)
        @echo $(objects)
    
    # bash 中执行 make
    $ make
    a b c d
    a.o b.o c.o d.o
    复制代码

     

    3.4.4 if

    这里的if是个函数, 和前面的条件判断不一样, 前面的条件判断属于Makefile的关键字

    语法:

    $(if <condition>,<then-part>)

    $(if <condition>,<then-part>,<else-part>)

     

    示例:

    复制代码
    # Makefile 内容
    val := a
    objects := $(if $(val),$(val).o,nothing)
    no-objects := $(if $(no-val),$(val).o,nothing)
    
    all:
        @echo $(objects)
        @echo $(no-objects)
    
    # bash 中执行 make
    $ make
    a.o
    nothing
    复制代码

     

    3.4.5 call - 创建新的参数化函数

    语法:

    $(call <expression>,<parm1>,<parm2>,<parm3>...)

     

    示例:

    复制代码
    # Makefile 内容
    log = "====debug====" $(1) "====end===="
    
    all:
        @echo $(call log,"正在 Make")
    
    # bash 中执行 make
    $ make
    ====debug==== 正在 Make ====end====
    复制代码

     

    3.4.6 origin - 判断变量的来源

    语法:

    $(origin <variable>)

    返回值有如下类型:

    类型

    含义

    undefined <variable> 没有定义过
    default <variable> 是个默认的定义, 比如 CC 变量
    environment <variable> 是个环境变量, 并且 make时没有使用 -e 参数
    file <variable> 定义在Makefile中
    command line <variable> 定义在命令行中
    override <variable> 被 override 重新定义过
    automatic <variable> 是自动化变量

     

    示例:

    复制代码
    # Makefile 内容
    val-in-file := test-file
    override val-override := test-override
    
    all:
        @echo $(origin not-define)    # not-define 没有定义
        @echo $(origin CC)            # CC 是Makefile默认定义的变量
        @echo $(origin PATH)         # PATH 是 bash 环境变量
        @echo $(origin val-in-file)    # 此Makefile中定义的变量
        @echo $(origin val-in-cmd)    # 这个变量会加在 make 的参数中
        @echo $(origin val-override) # 此Makefile中定义的override变量
        @echo $(origin @)             # 自动变量, 具体前面的介绍
    
    # bash 中执行 make
    $ make val-in-cmd=val-cmd
    undefined
    default
    environment
    file
    command line
    override
    automatic
    复制代码

     

    3.4.7 shell

    语法:

    $(shell <shell command>)

    它的作用就是执行一个shell命令, 并将shell命令的结果作为函数的返回.

    作用和 `<shell command>` 一样, 是反引号

     

    3.4.8 make 控制函数

    产生一个致命错误: $(error <text ...>)

    功能: 输出错误信息, 停止Makefile的运行

    复制代码
    # Makefile 内容
    all:
        $(error there is an error!)
        @echo "这里不会执行!"
    
    # bash 中执行 make
    $ make
    Makefile:2: *** there is an error!.  Stop.
    复制代码

     

    输出警告: $(warning <text ...>)

    功能: 输出警告信息, Makefile继续运行

    复制代码
    # Makefile 内容
    all:
        $(warning there is an warning!)
        @echo "这里会执行!"
    
    # bash 中执行 make
    $ make
    Makefile:2: there is an warning!
    这里会执行!
    复制代码

     

    3.5 Makefile中一些GNU约定俗成的伪目标

    如果有过在Linux上, 从源码安装软件的经历的话, 就会对 make clean, make install 比较熟悉.

    像 clean, install 这些伪目标, 广为人知, 不用解释就大家知道是什么意思了.

    下面列举一些常用的伪目标, 如果在自己项目的Makefile合理使用这些伪目标的话, 可以让我们自己的Makefile看起来更专业, 呵呵 :)

    伪目标

    含义

    all 所有目标的目标,其功能一般是编译所有的目标
    clean 删除所有被make创建的文件
    install 安装已编译好的程序,其实就是把目标可执行文件拷贝到指定的目录中去
    print 列出改变过的源文件
    tar 把源程序打包备份. 也就是一个tar文件
    dist 创建一个压缩文件, 一般是把tar文件压成Z文件. 或是gz文件
    TAGS 更新所有的目标, 以备完整地重编译使用
    check 或 test 一般用来测试makefile的流程

    make编译大概模板
    .SUFFIXES:.c .o     //.c和.o建立关联
    
    CC=gcc
    SRCS=hello.c\
            add.c      //同时编译两个.c文件
    
    OBJS=$(SRCS:.c=.o)    //ORJS=hello.o add.o
    EXEC=hello
    
    
    start: $(OBJS)                 //依赖hello.o add.o
            $(CC) -o $(EXEC) $(OBJS)
            @echo '----------------ok------------'
    
    .c.o:
            $(CC) -o $@ -c $<  //自动根据$(OBJS) 中.o的数量循环编译, 直到编译完所有的.c文件
    	//如果需要调试, $(CC) -g -o $@ -c $<   
    
    clean:
            rm -f $(OBJS)
    展开全文
  • 如果您正在 XML 应用程序中使用 XPath,但是却需要对 Web 应用程序使用 jQuery,那会怎么样呢?如果您知道 jQuery,却需要在应用程序中使用 XPath,又会如何呢?使用这个方便的集锦手册(phrase book),从知道的...
  • SEO实操指南手册

    2019-07-22 12:44:52
    提纲1、前言2、SEO工作原理1)SE工作原理2)名词解释3、SEO实操1)、SEO框架STEP 1:网站内部优化STEP 2:网站内部优化STEP 3:关键字选择2)、SEO实施案例a、SEO大师是怎么做SEO的b、网上商城怎么做SEOc、极端SEO3...
  • 怎么做一个开源项目

    2013-01-05 16:54:00
    包括如下内容:选择哪个license怎么组织代码写文档,包括用户手册,开发指南使用邮件列表来和使用者开发者沟通使用版本号,这样便于跟踪bug。在代码中加tag,写版本更新记录。其它开发者如何贡献代码 转载于:...
  • MeterSphere平台新增数据库查询校验使用手册 MeterSphere手册目录...MeterSphere接口自动化测试是一件非常愉快的事情,提供的功能也是非常强大,下面我们就来说说怎么在MeterSphere平台中使用数据库业务测试吧。
  • 企业百度百科怎么做是有技巧的,百度百科的手册里也写到,创建词条时候不能卖广告,要写的比较又影响力的。很多人喜欢在创建词条的时候把自己公司网站的连接放进去,往往这个词条就没有重见天日的时候了,所以千万...
  • 使使用用Python的的Turtle库库绘绘制制森森林林的的实实例例 今天小编就为大家...下下面面是是官官方方手手册册 Turtle官方手册 1.配配置置编程程环境境 由于现在的笔记本是临时借的编程环境不是熟悉的环境又由于种种
  • JVM指令手册

    2020-05-22 12:33:34
    最近在学习JVM字节码指令,通过 jclasslib 工具 可以显示出来命令,但是不知道是怎么在操作数栈和局部变量表怎么移动的,通过查寻指令手册才能看明白。列在这希望也能帮助学习JVM的你。 0x00 nop 什么都不。 0x01...
  • Dell存储成功案例手册

    2017-07-12 09:46:13
    Dell存储成功案例手册,看看别人是怎么的,可帮助你了解更多DELL存储部署知识。
  • 1.明确目标,认真、仔细的阅读大纲 2.看真题,频率较高的要重点复习,不偏题和怪题。...掌握:不但要知道,而且还要知道是如何推导的,有什么用途,怎么使用,熟练的用他解决问题 会用 :会用就行,不用知道定理
  • C++在线参考手册

    2021-01-20 13:35:34
    比如字符串的find()函数怎么用的? 关于作者 博客:https://blog.csdn.net/xmcy001122 我的Golang项目自荐: IM开源项目。包含Flutter客户端和纯Go实现的服务的,目前支持单聊...
  • 芯片型号是16c950,芯片手册上指名有三条地址线可以用来配置芯片寄存器,但是具体该怎么配置阿?有没有人来指点一下。芯片手册上没有说明啊![图片]...
  • bugzilla使用手册

    2009-06-11 16:47:10
    budzilla 使用手册,方便使用 流程规范,便于软件测试人员和学习人员;微软Windows Word的第一版的开发项目曾被认为是“死亡之旅”项目。好象永远也不完,永远超时。所有人疯狂地工作,可怎么也完成不了任务。整个...
  • php中文手册

    2011-09-09 19:13:24
    很详细的介绍了PHP语言,以及怎么去用好这门语言,适合于初学者以及在编程过程中辅助查询手册 PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言...
  • 施耐德ATV71_CANopen手册

    2015-01-24 16:15:59
    施耐德ATV71_CANopen手册,可以看下大公司的产品是怎么做的,一起学习
  • Kettle这个ETL工具集,它允许你管理来自不同数据库的数据,通过提供一个图形化的用户环境来描述你想做什么,而不是你想怎么做。 此手册帮助大家更好的学习此款软件
  • 详细讲解ORACLE9I数据库怎么样使用RMAN增量备份应用操作手册
  • GLUI用户手册

    2011-11-01 15:37:27
    A GLUT-Based User Interface Library by Paul Rademacher 怎么样用OpenGL界面
  • Bootstrap用户手册

    2014-10-08 18:03:10
    这本书会告诉你怎么做。 熟悉Bootstrap的文件结构、网格系统和容器布局; 学习HTML中用于排版、代码、表格、表单、按钮、图片以及图标的元素; 设计界面及其他网页元素,比如导航、面包屑,以及自定义模态窗口等; ...
  • 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体原因,本文就来深入分析一下该规定背后的思考。 一、foreach循环 foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常...
  • npgsql指南手册

    2012-10-08 09:03:51
    从第三页开始往后,有关于怎么连接数据库,查询数据库等实例,希望下载的人看完实例,模仿着

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 866
精华内容 346
关键字:

手册怎么做