小型C/C++项目的makefile编写

【前言】在我所接触到的Linux嵌入式开发中,大多使用的是C语言,采用makefile文件对源文件进行编译后生成可执行文件。本文即从个人经历上介绍小型的C项目如何编写makefile文档。

一、gcc命令

从目的上看,gcc命令和makefile的功能是一样,即是把源文件编译后生成可执行文件或.o二进制文件。gcc命令中有许多的额外的参数,本文仅介绍以下几种最简单和常用的方法:

有helloworld.c文件如下:

#include <stdio.h>
int main()
{
        printf("helloworld!\n");
        return 0;
}

使用如下gcc命令,将在同一文件目录下生成a.out可执行文件,在terminal中运行该文件即可在屏幕中打印出helloworld!:

$  gcc helloworld.c

使用如下gcc命令,将在同一文件目录下生成helloworld.o二进制文件,它可以被用来连接文件:

$    gcc -c helloworld.c

如果要生成特定名称的可执行文件,可以使用如下gcc命令,它将生成helloworld可执行文件,区别于a.out可执行文件,在termianl执行它可以打印出helloworld!:

$    gcc helloworld.c -o helloworld

以上三种gcc命令,主要区别是参数不同,-c和-o的区别在于,-c只编译不连接,故只生成.o的二进制文件,-o即指定名称输出可执行文件。对于单个或者几个的源文件,使用gcc命令即可,但是一旦文件具有依赖关系,gcc命令的执行顺序是需要规定的,否则无法顺序编译项目,这是gcc命令的缺点,而makefile区别于gcc命令的地方正在于它能规定好文件间的依赖关系,以及加入依赖的库文件和头文件。

如果要引用其它目录下的头文件,其gcc命令如下,采用-I的参数:

$    gcc -I /ycl/include/ helloworld.c -o helloworld

如果要引用其它的目录下的库文件,如libmlib.so,其gcc命令如下,采用-L的参数:

$    gcc -L /ycl/lib –lmlib helloworld.c -o helloworld

二、makefile简要语法

makefile的用处是告诉编辑器,本项目以怎样的规则进行编译和链接,运行make命令需要makfile文件作为支撑。

要弄明白makefile,其关键是理解它的核心语法(源自博文http://blog.csdn.net/liang13664759/article/details/1771246 ):

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

target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

prerequisites就是,要生成那个target所需要的文件或是目标。

command也就是make需要执行的命令。(任意的Shell命令)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

示例代码如下:

CXX = g++

CXXFLAGS =    -O2 -g -Wall -fmessage-length=0
CFLAGS = `pkg-config --cflags lcm`
LDFLAGS=`pkg-config --libs lcm`        -lpthread

OBJS =        DSRC_module.o                LCMHandler.o                UDPHandler.o

TARGET =    DSRC_module
$(TARGET):    $(OBJS)
    $(CXX) -o [email protected] $^ $(LDFLAGS)

 DSRC_module.o: DSRC_module.cpp
    $(CXX) $(CFLAGS) -I. -o [email protected] -c $<

LCMHandler.o: LCMHandler.cpp
    $(CXX) $(CFLAGS) -I. -o [email protected] -c $<

UDPHandler.o: UDPHandler.cpp
    $(CXX) $(CFLAGS) -I. -o [email protected] -c $<

all: $(TARGET)

clean:
    rm -f $(OBJS) $(TARGET)

示例代码中出现了变量,makefile中变量采用$(变量)的方法使用,如$(TARGET)即表示DSRC_module。该makefile的目的是生成名为DSRC_ module的可执行文件,即$(TARGET),它的依赖文件是$(OBJS)所代表的DSRC_module.o、LCMHandler.o、UDPHandler.o三个文件。由于这三个文件都未生成,故针对每一个文件都需要进行编译生成,所以有三个.o文件为目标的makefile语句。

文中特殊字符说明如下:[email protected]目标文件,$^--所有的依赖文件,$<--第一个依赖文件。比如在如下的代码中,[email protected]代表DSRC_module.cpp,$<代表第一个依赖文件,也就是DSRC_module.cpp。

DSRC_module.o: DSRC_module.cpp
    $(CXX) $(CFLAGS) -I. -o [email protected] -c $<

三、makefile编写

使用装用CDT插件的eclipse可以直接生成helloworld项目的makefile项目,makefile内容如下:

CXXFLAGS =    -O2 -g -Wall -fmessage-length=0

OBJS =        example.o

LIBS =

TARGET =    example

$(TARGET):    $(OBJS)
    $(CXX) -o $(TARGET) $(OBJS) $(LIBS)

all:    $(TARGET)

clean:
    rm -f $(OBJS) $(TARGET)

其中CXXFLAGS是编译参数变量,CXX是makefile内置变量,CXX默认表示g++(C++编译器)。这个makefile的有两个功能:①编译代码,将example.c编译成example.o并链接成example可执行文件;②清除项目,当项目需要重新编译或整理时,使用make clean命令即可清除生的OBJS和TARGET变量中的名称。

在上述代码中,之所以依赖文件没有.c文件,这是因为此处使用了makefile的自动推导功能,只要依赖关系中有.o文件,它会自动添加同名称的.c文件作为依赖文件,并由$(CXX) -o example.o可以自动推导出$(CXX) -o example.c。

$(TARGET):    $(OBJS)
    $(CXX) -o $(TARGET) $(OBJS) $(LIBS)

基于上述的makefile文件,如果此时需要添加新的.c和.h文件,则改变OBJS的内容即可,比如填加test.c文件,则代码如下(注意test.o前的不能加空格,需用tab键):

CXXFLAGS =    -O2 -g -Wall -fmessage-length=0

OBJS =        example.o                   test.o

LIBS =

TARGET =    example

$(TARGET):    $(OBJS)
    $(CXX) -o $(TARGET) $(OBJS) $(LIBS)

all:    $(TARGET)

clean:
    rm -f $(OBJS) $(TARGET)    

如果需要添加头文件,则只需添加和修改如下代码:

HEADER_DIR = /home/duser/dot3
$(TARGET):    $(OBJS)
    $(CXX) -o $(TARGET) $(OBJS) $(LIBS) -I $(HEADER_DIR)

如果需要添加库文件,需要两个变量,LDFLAGS---相当于库所在路径,LIBS---要链接的库文件。则只需添加和修改如下代码:

LDFLAGS += -L/lib
LIB += -ltest
$(TARGET):    $(OBJS)
    $(CXX) -o $(TARGET) $(OBJS) -I $(HEADER_DIR) $(LDFLGS)$(LIBS)
时间: 2024-08-09 11:48:27

小型C/C++项目的makefile编写的相关文章

一个项目的Makefile编写及调试

在src目录下包含很多文件夹,那么需要遍历所有的目录执行Makefile,那么给一个在src目录下的Makefile. # 需要排除的目录 exclude_dirs := include bin # 取得当前子目录深度为1的所有目录名称 DIRS := $(shell find . -maxdepth 1 -type d) DIRS := $(basename $(patsubst ./%,%,$(DIRS))) DIRS := $(filter-out $(exclude_dirs),$(DI

自动生成项目的Makefile文件

自动生成项目的Makefile文件 理论基础 跟我一起写 Makefile:   http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=408225 例解 autoconf 和 automake 生成 Makefile 文件:   http://www.ibm.com/developerworks/cn/linux/l-makefile/index.html 步骤 写好Makefile.am 运行 autoscan , 自动创建两个文件: a

makefile编写--引用

1. Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之间的依赖关系不知会多复杂. Makefile的组织流程的能力如此之强, 不仅可以用来编译项目, 还可以用来组织我们平时的一些日常操作. 这个需要大家发挥自己的想象力. 本篇博客是基于 {精华} 跟我一起写 Makefile 而整理的, 有些删减, 追加了一些示例. 非常感谢 gunguymadman

09_Android中ContentProvider和Sqllite混合操作,一个项目调用另外一个项目的ContentProvider

1.  编写ContentPrivider提供者的Android应用 清单文件 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itheima28.sqlitedemo" android:versionCode=&qu

单目录下多文件 makefile编写

makefile很久就接触过了,但是一直没怎么深入的去学习和总结:在项目中我也只是看看makefile或者修改部分语句,全部自己动手写的话还真没有:知识在于沉淀,这句说的非常好,所以现在把自己理解的东西,记录下来,以便后面查阅: 这篇blog要分享的是在单目录下多文件的makefile编写,首先说明当前目录下有多少文件:fun.h   fun.c  main.c  makefile:其中*.c 文件都要依赖 *.h文件: 首先常规编译: 预处理期:gcc  -E  -o fun.i  fun.c

Cocos2d-x项目的MVC框架

Cocos2d-x项目的MVC框架 本篇所用的Cocos2d-x版本为:Cocos2d-x 3.2 当我们已经开始搭建好项目,着手开始写代码的时候,我想同学们肯定会遇到这样的一个问题: 某些UI类在加载到父级上之后,经常毫无原由的造成崩溃现象.或者代码写了好几千行,难以进行维护及其他人帮助处理等.这是为什么呢? 其实,就是因为2点: 你对Cocos2d-x还是不够了解 你没有框架的概念 其实,这种问题往往是因为,你子级元素在父级addchild之前,就开始调用到了父级元素.或者说你就一直埋头去写

linux下makefile编写及automake整理

makefile编写规则 在一个makefile中通常包含如下内容: 1 需要由make工具创建的目标体(target),通常是目标文件或可执行文件 2 要创建的目标体所依赖的文件(dependency_file) 3 创建每个目标体时需要运行的命令(command),这一行必须以制表符(tab键)开头 格式: target: dependency_files command /* 该行必须以tab键开头*/ 例如,有两个文件分别为hello.c和hello.h,创建的目标体为hello.o,执

Web高效管理多个项目的SVN仓库

转至:https://www.jianshu.com/p/a0af00642585 采用方案 Linux+Apache+Subversion+MySQL+JDK+Tomcat+Svnadmin 目录 0.安装准备 0.1 升级系统软件包 0.2 关闭SELinux 0.3 安装wget 1.部署Apache 1.1 安装apache 1.2 修改配置文件 1.3 启动apache服务 1.4 调整防火墙,允许80端口访问 1.5 浏览器访问测试 2.部署Subversion 2.1 安装SVN

跨过Nginx上基于uWSGI部署Django项目的坑

先说说他们的关系,Nginx和uWSGI都是Web服务器,Nginx负责静态内容,uWSGI负责Python这样的动态内容,二者配合共同提供Web服务以实现提高效率和负载均衡等目的.uWSGI实现了多个协议,如WSGI,HTTP协议,还有它自己的uwsgi协议,想了解更多关于uWSGI和uwsgi协议内容可以查阅这里.这样和fastcgi类似,请求和响应的流程如下: Request > Nginx > uWSGI > Django > uWSGI > Nginx > R