`
xitonga
  • 浏览: 583702 次
文章分类
社区版块
存档分类
最新评论

教你如何使用Makefile编译工程代码

 
阅读更多

一、前言概述

《跟我一起学Makefile》是一篇全面学习编写Makefile基本规则的很好的文章,初学者应该好好理解里面的知识要点。但是很多人学完之后,并不能站在一个系统的高度通过Makefile来组织整个工程的编译。麻雀虽小,五脏俱全 ——此篇的目的就是想通过简单的实例,来说明如何使用Makefile组织大型工程项目。

二、工程框架


图1 工程框架

假设现有一个如图1所示的工程:其各自代码如下:

// add.h
#if !defined(__ADD_H__)
#define __ADD_H__
#if defined(__ADD__)
extern int add(int a, int b);
#endif /*__ADD__*/
#endif /*__ADD_H__*/
// add.c
#include<stdio.h>
#include<stdlib.h>

#if defined(__ADD__)
int add(int a, int b)
{
    return a+b;
}
#endif /*__ADD__*/
// sub.h
#if !defined(__SUB_H__)
#define __SUB_H__

#if defined(__SUB__)
extern int sub(int a, int b);
#endif /*__SUB__*/
#endif /*__SUB_H__*/
// sub.c
#include<stdio.h>
#include<stdlib.h>

#if defined(__SUB__)
int sub(int a, int b)
{
    return a-b;
}
#endif /*__SUB__*/
// test.c
#include 
#include 

#if defined(__ADD__)
#include "add.h"
#endif /*__ADD__*/
#if defined(__SUB__)
#include "sub.h"
#endif /*__SUB__*/

int main(int argc, const char *argv[])
{
    int a = 10, b = 20;

#if defined(__ADD__)
    printf("%d+%d = %d\n", a, b, add(a, b));
#endif /*__ADD__*/
#if defined(__SUB__)
    printf("%d-%d = %d\n", a, b, sub(a, b));
#endif /*__SUB__*/

    return 0;
}

三、编写Makefile

在project目录下新建make目录,所有makefile文件都放在此目录下。则Makefile文件包含:

①、宏开关模块

宏开关模块:是通过一个开关(switch)来控制某个宏的开启和关闭,以此达到控制软件平台某个功能的开启和关闭。

// switch.mak
CFG_ADD_SUPPORT = TRUE # FALSE # 加法开关
CFG_SUB_SUPPORT = FALSE # TRUE # 减法开关

②、宏加载模块

宏加载模块:根据宏开关模块的设置,将宏加入编译选项

// option.mak
ifeq(TRUE, $(strip $(CFG_ADD_SUPPORT)))
    OPTIONS += __ADD__
endif

ifeq(TRUE, $(strip $(CFG_SUB_SUPPORT)))
    OPTIONS += __SUB__
endif
③、路径设置模块
// paths.mak
# 设置头文件路径(相对路径)
INCLUDED := -I../add \
            -I../sub

# 设置源文件路径
ADD_PATH = ../add        # 加法源文件路径(相对路径)
SUB_PATH = ../sub        # 减法源文件路径(相对路径)
SRC_PATH = ../src         # 测试源文件路径(相对路径)

# 加载源文件
SRC_LIST := $(SRC_PATH)/test.c   # 加载测试源文件
#ifeq(TRUE, $(strip $(CFG_ADD_SUPPORT)))
SRC_LIST += $(ADD_PATH)/add.c    # 加载加法源文件
#endif /*CFG_ADD_SUPPORT*/
#ifeq(TRUE, $(strip $(CFG_SUB_SUPPORT)))
SRC_LIST += $(SUB_PATH)/sub.c    # 加载减法源文件
#endif /*CFG_SUB_SUPPORT*/

④、编译模块

// Makefile
# 引入makefile文件
include switch.mak
include options.mak
include paths.mak

CC := gcc

CFLAGS := -O2 $(INCLUDED)
CFLAGS += $(patsubst %, -D%, $(OPTIONS))  # patsubst起拼接作用

OBJS := $(subst .c, .o, $(SRC_LIST))      # subst起替换作用
TARGET := $(SRC_PATH)/test.elf

.PHONY: all clean clean_all

all: $(TARGET)
$(TARGET): $(OBJS)
    $(CC) $(CFLAGS) -o $(TARGET) $(OBJS)

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

clean:
    rm -fr $(OBJS) 

⑤、编译和执行

#cd project/make
#make
#cd ../test

⑥、运行结果

1. 如果CFG_ADD_SUPPORT = TRUE ,并且CFG_SUB_SUPPORT = FALSE,则运行结果为:

10+20 = 30

2. 如果CFG_ADD_SUPPORT = TRUE ,并且CFG_SUB_SUPPORT = TURE,则运行结果为:

10+20 = 30

10-20 = -10

3. 如果CFG_ADD_SUPPORT =FALSE ,并且CFG_SUB_SUPPORT = TRUE,则运行结果为:

10-20 = -10

四、最终框架


图2 最终框架

作者:邹祁峰

2012年11月23日

分享到:
评论

相关推荐

    Makefile万能通用版(C++和C混合编译也适用)

    通用版,Makefile C++和c混合编译

    GNU libiconv-1.15和libintl-0.19.8.1,VS2015工程和 Makefile 命令行编译文件

    VS的工程为VS2015的工程文件,使用VC140工具集,如果没有2015,也可以用Makefile.mak文件来编译。 nmake /f Makefile.mak [DLL] [DEBUG] 指定 DLL=1 编译dll版本,默认是lib版本,libiconv.lib , libintl.lib。 ...

    scons控制编译工程例子

    linux一般通过makefile控制编译。linux代码目录结构是 ...全编译工程: cd scons_project_root scons 总结,每个目录都可以单独编译,对于某工程师只负责某部门lib,提高编译效率。这个是非常方便的。

    Makefile工程实战.pdf

    实现通过makefile来管理编译代码,包括生成静态库和动态库,多目录管理文件等等一系列架构组织,完成一个通用的Makefile模板。包括: 1. 构建工程 2. 自动添加目标对头文件的依赖 3. 目录管理源文件 4. 目录管理目标...

    使用autoconf生成Makefile并编译工程的步骤

    这里我会用一个工程来说明怎么做,有一些步骤不是必须的,但是如果你看不出来哪些步骤不是必须的,最好跟着一步步走,因为某些步骤省略了,代码也需要做出相应修改(如修改路径等)。 步骤 首先安装autoconf sudo ...

    libcurl 静态编译 加载 测试工程

    1, 下载libcurl http://curl.haxx.se/dlwiz/?type=source 选择"platform independent", 下载, 在winbuid目录下, 执行...2, 在builds 中找到 libcurl_debug.lib, 加载到 vs工程中, 执行测试工程代码, 下载baidu页面内容

    linux makefile 工程目录下,所有c文件

    linux 工程编译 makefile 工程目录下所有的C文件,工程目录下可以有子目录

    Linux的makefile语法规则

    特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、...

    GNU libiconv-1.15和libintl-0.19.8.1,VS2017工程和 Makefile.mak 命令行编译文件

    VS的工程为VS2017的工程文件,使用VC141工具集,SDK10.0.17134.12,如果没有2017,也可以用Makefile.mak文件来编译。 或者你自己降低版本,我最初使用的最低版本是VC140_xp,SDK7.1A,也就是VS2015默认安装的兼容xp...

    makefile-nginx案例.zip

    一份关于makefile编写的代码案例,仔细看看注释,多多了解一下make。 老师,要带着大家,从无到有产生这套 通讯架构源代码【项目/工程】 项目 肯定会有多个源文件,头文件,会分别存放到多个目录;我们要规划项目...

    跟我一起写makefile

    特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、...

    makefile详细规则

    工程中根据源文件的修改情况来进行代码的编译正是使用了make的这个特征。make执行时,根据Makefile的规则检查文件的修改情况,决定是否执行定义的动作(那些修改过的文件将会被重新编译)。这是GNU make的执行依据。

    GLOG源码 使用CMAKE之后生成了win32和win64的工程sln文件 在VS2019下编译成功,生成的库文件

    来自google的开源日志类源码,在window下编译通过,亲测。而且使用这些动态库、静态库和头文件编写了对应的Demo,源码也已上传,请自行查找。

    Linux-生成动态库工程代码

    qt工程代码 也有Makefile 直接使用make编译也可

    makefile脚本

    一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 ...

    openldap2.4.39 修正版,可用nmake编译

    该包只限用于WINDOWS下编译PHP缺少LDAP相关依赖包时使用。...请注意,libldap的dll,采用的liblber的静态库,因为你必须首先编译lib版本。使用如下命令: nmake /f makefile.mak nmake /f makefile.mak dll=1

    GCC开发STM32程序源码(附makefile_makefilestm32_gccstm32_stm32Makefile_st

    /20200318/4271ace044c760b540134ec23141f91b.rar

    一个带类似IDE目录树的makefile实例

    对于大型工程源代码最好分目录存放便于管理,但是编写makefile就相对麻烦点。 这里是我写的一个makefile demo,它的关键之处在编译前导入config_xxx_file_list.mk,这个文件可以看成是IDE环境的代码目录树。具体...

    cbp2make-stl-rev135.tar.gz

    常见开源项目采用makefile来组织源代码的编译。cbp2make可以很好的将CB的工程文件转换为makefile 文件。 1、下载cbp2make的源代码; 2、解压后打开工程文件cbp2make.cbp,然后在CB中建造工程。 3、为长期使用方便...

    LINUX下编译与调试

    2. makefile使用 2 2.1. 基本过程处理 2 2.2. 特殊处理与伪目标 3 2.3. 变量、函数与规则 5 3. 程序调试 8 3.1. gdb常用命令 8 3.2. gdb 应用举例 9 3.3. assert断言宏 12 3.4. 错误处理函数和进程退出函数 13 3.5. ...

Global site tag (gtag.js) - Google Analytics