-
2021-05-16 09:21:30
【转载,非常不错的一篇博文,循序渐进,简单易懂】
假设我们有下面这样的一个程序,源代码如下:
/* main.c */
#include
#include
int main(int argc,char **argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/* mytool1.h */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/* mytool1.c */
#include
void mytool1_print(char *print_str)
{
printf("This is mytool1 print %s\n",print_str);
}
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
/* mytool2.c */
#include
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s\n",print_str);
}
当然由于这个程序是很短的我们可以这样来编译
gcc -c main.c -I.
gcc -c mytool1.c -I.
gcc -c mytool2.c -I.
gcc -o main main.o mytool1.o mytool2.o
因为我们在程序中使用了我们自己的2个头文件,而在包含这2个头文件的时候,我们使用的是<> 这样编译器在编译的时候会去系统默认的头文件路径找我们的2个头文件,由于我们的2个头文件不在系统能够的缺省路径下面,所以我们自己扩展系统的缺省路径,为此我们使用了-I.选项,表示将系统缺省的头文件路径扩展到当前路径.
这样的话我们也可以产生main程序,而且也不是很麻烦.但是考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)那么我们难道还要重新输入上面的命令?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了.是的对于这个程序来说,是可以起到作用的.但是当我们把事情想的更复杂一点,如果我们的程序有几百个源程序的时候,难道也要编译器重新一个一个的去编译?
为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make.我们只要执行一下make,就可以把上面的问题解决掉.在我们执行make之前,我们要先编写一个非常重要的文件.--Makefile.对于上面的那个程序来说,可能的一个Makefile的文件是:
# 这是上面那个程序的Makefile文件
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c -I.
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c -I.
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c -I.
有了这个Makefile文件,不管我们什么时候修改了源程序当中的什么文件,我们只要执行make命令,我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件她连理都不想去理的.
下面我们学习Makefile是如何编写的.
在Makefile中也#开始的行都是注释行.Makefile中最重要的是描述文件的依赖关系的说明.一般的格式是:
target: components
TAB rule
第一行表示的是依赖关系.第二行是规则.
main:main.o mytool1.o mytool2.o
表示我们的目标(target)main的依赖对象(components)是main.o mytool1.o mytool2.o 当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令.就象我们的上面那个Makefile第三行所说的一样要执行 gcc -o main main.o mytool1.o mytool2.o 注意规则一行中的TAB表示那里是一个TAB键
Makefile有三个非常有用的变量.分别是$@,$^,$
$@--目标文件,$^--所有的依赖文件,$
如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:
# 这是简化后的Makefile
# 记得我们的优化和警告选项吗?
main:main.o mytool1.o mytool2.o
gcc -O2 -o $@ $^
main.o:main.c mytool1.h mytool2.h
gcc -O2 -Wall -c $< -I.
mytool1.o:mytool1.c mytool1.h
gcc -O2 -Wall -c $< -I.
mytool2.o:mytool2.c mytool2.h
gcc -O2 -Wall -c $< -I.
经过简化后我们的Makefile是简单了一点,不过人们有时候还想简单一点(唉,看来程序员都是大懒鬼哦 ^_^). 为此make又有了一些缺省的规则
这里我们学习一个Makefile的缺省规则
.c.o:
gcc -c $<
这个规则表示所有的 .o文件都是依赖与其相应的.c文件的.例如mytool.o依赖于mytool.c这样Makefile还可以变为:
# 这是再一次简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
.c.o:
gcc -c $< -I.
如果你还是嫌这样太麻烦的话,我们还可以进行一些简化工作.为此我们来学习一下Makefile的一些缺省的宏定义 Makefile一般有很多很多的宏,我们这里只是学习几个常用的宏.
CC 表示我们的编译器名称,缺省值为cc.
CFLAGS 表示我们想给编译器的编译选项
LDLIBS 表示我们的在编译的时候编译器的连接库选项.(我们的这个程序中还用不到这个选项)
使用了上面的宏后我们的Makefile可以是
CC=gcc
CFLAGS=-g -Wall -O2 -I.
main:main.o mytool1.o mytool2.o
.c.o:
CC CFLAGS $<
好了,我们的Makefile 也差不多了,可以输入make -f Makefile来运行Makefile文件。如果想知道更多的关于Makefile规则可以查看相应的文档. 使用(man make 或者是info make)
其实,对于小的工程可以自己建立 MAKEFILE ,要是大的工程的话,最好使用AUTOMAKE 等工具,相当方便。
更多相关内容 -
Makefile编写实例
2020-04-25 13:58:111.实例所需文件 1.1 head.hadd.cpp sub.cppmain.cpp在同一目录下 head.h 1 int add(int a, int b); 2 int sub(int a, int b); add.cpp 1 #include "head.h" 2 3 int add(int a, int b) 4 { ...-
1.实例所需文件
1.1 head.h add.cpp sub.cpp main.cpp 在同一目录下
head.h
1 int add(int a, int b); 2 int sub(int a, int b);
add.cpp
1 #include "head.h" 2 3 int add(int a, int b) 4 { 5 return a + b; 6 }
sub.cpp
1 #include "head.h" 2 3 int sub(int a, int b) 4 { 5 return a - b; 6 }
main.cpp
1 #include "head.h" 2 #include <stdio.h> 3 4 int main() 5 { 6 printf("2 + 1 = %d \n", add(2, 1)); 7 printf("2 - 1 = %d \n", sub(2, 1)); 8 return 0; 9 }
1.2 不使用Makefile
gcc -c add.cpp && gcc -c sub.cpp 生成 add.o sub.o
gcc main.cpp -o main.out add.o sub.o 生成main.out
1.3 运行main.out
2 加入src include bin obj目录来管理源文件级生成文件
2.1 改变下目录结构,将head.h放入include 将add.cpp sub.cpp main.cpp 放入src 空的obj用于保存稍后生成的目标文件 空的bin目录用于保存之后生成的可执行文件
2.2 在obj目录生成 add.o sub.o
gcc -c src/add.cpp -o obj/add.o -I include && gcc -c src/sub.cpp -o obj/sub.o -I include
2.3 在bin目录生成main.out
gcc src/main.cpp obj/add.o obj/sub.o -I include/ -o bin/main.out
3 采用Makefile
3.1 清除上面obj bin下生成文件,编写Makefile
3.2 make 执行结果
4 改进Makefile
4.1 编辑Makefile
1 OBJDIR=obj 2 BINDIR=bin 3 INCLUDEDIR=include 4 SRCDIR=src 5 TARGET=$(BINDIR)/main.out 6 7 # 将src/sub.cpp 替换成 obj/sub.o 方法1 较繁琐 8 # $(shell ls $(SRCDIR)/*.cpp) 获取src下所有cpp文件但带有src/ notdir去掉文件名前的路径 9 #CPPFILES=$(notdir $(shell ls $(SRCDIR)/*.cpp)) 10 #BASE=$(basename $(CPPFILES)) 11 #将.cpp 替换成 .o 12 #OBJS=$(addsuffix .o, $(addprefix $(OBJDIR)/, $(BASE))) 13 14 # 将src/sub.cpp 替换成 obj/sub.o 方法2 较简单 15 OBJS=$(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(wildcard $(SRCDIR)/*.cpp)) 16 $(warning "log objs: $(OBJS)") 17 $(TARGET):$(OBJS) 18 rm -rf $@ 19 gcc -o $(TARGET) $(OBJS) -I $(INCLUDEDIR) 20 $(OBJDIR)/%.o:$(SRCDIR)/%.cpp 21 gcc -c $< -o $@ -I $(INCLUDEDIR) 22 clean: 23 rm -rf $(OBJDIR)/* $(BINDIR)/*
4.2 相关指令解释
$(shell ls $(SRCDIR)/*.cpp) 执行shell命令 等价于 ls src/*.cpp
$(notdir $(shell ls $(SRCDIR)/*.cpp)) 去掉src/add.cpp 等 前面 src/
$(basename $(CPPFILES)) 获取add.cpp等 没有后缀.cpp的文件名
$(addprefix $(OBJDIR)/, $(BASE)) 给add等添加obj/前缀
$(addsuffix .o, $(addprefix $(OBJDIR)/, $(BASE))) 给obj/add等添加.o后缀
$(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(wildcard $(SRCDIR)/*.cpp)) 将src/add.cpp等替换为bin/add.o
$@ 目标文件即$(TARGET)
$< 依赖文件即$(OBJS)
$(warning "log objs: $(OBJS)") Makefile的打印 也可用@echo
4.3 make 及main.out运行结果
-
-
Makefile 编写实例
2016-06-12 20:35:08近几天因工作需要编写Makefile,于是在网上搜索相关资料学写Makefile 时间比较仓促 但总还算达到了软件代码自动化编译的目的,参考主要资料来源于网上一位大神《跟我学写Makefile》博客,现主要记录自己在编写过程...近几天因工作需要编写Makefile,于是在网上搜索相关资料学写Makefile 时间比较仓促 但总还算达到了软件代码自动化编译的目的,参考主要资料来源于网上一位大神《跟我学写Makefile》博客,现主要记录自己在编写过程体会及注意要点:
对Makefile 理解:始于起点也终于起点,即从目标文件、依赖文件、依赖规则这里开始,也在这儿结束。整个Makefile围绕目标文件:依赖文件展开的,进行一系列变量替换与推导,直到所有显式内容全都替换出来 先编译生成所需要的*.o中间文件,最后将所需的*.o文件链接起来生成最终可执行的目标文件。
在编写Makefile过程用到的函数:
addprefix 增加前缀函数 主要用在搜索.h文件路径
addsuffix 增加后缀函数 主要用于将源文件集合到一块与wildcard函数搭配使用
widcard 通配符扩展函数
patsubst 通配符替换 主要用于源文件到中间目标文件替换
notdir 去路径
vpath 制定查找路径 用于.c、.cpp .o 等路径搜索查找
下面给出我的简单Makefile代码:
TARGET_NAME = test
DIR_ALL := .
DIR_ALL += ./main
DIR_ALL += ./namespace
DIR_ALL += ./type
DIR_C := $(DIR_ALL)
DIR_CPP := $(DIR_ALL)
DIR_BIN := ./release
DIR_OBJ := $(DIR_BIN)/obj
DIR_DEP := $(DIR_BIN)/dep
TARGET = $(DIR_BIN)/$(TARGET_NAME)
INC_ALL := $(DIR_ALL)
CC = gcc
CPP = g++
INCFLAGS = $(addprefix -I,$(INC_ALL))
CFLAGS = -Wall $(INCFLAGS) -g -std=gnu99
CPPFLAGS = -Wall $(INCFLAGS) -g
LDFLAGS = -lpthread -lrt
SOURCES_C := $(wildcard $(addsuffix /*.c, $(DIR_C)))
SOURCES_CPP := $(wildcard $(addsuffix /*.cpp, $(DIR_CPP)))
OBJS := $(patsubst %.c,%.o,$(notdir $(SOURCES_C))) $(patsubst %.cpp,%.o,$(notdir $(SOURCES_CPP)))
DEPS := $(patsubst %.cpp,%.d,$(notdir $(SOURCES_CPP))) $(patsubst %.c,%.d,$(notdir $(SOURCES_C)))
VPATH_H := $(subst .,:.,$(INC_ALL))
VPATH_C := $(subst .,:.,$(DIR_C))
VPATH_CPP := $(subst .,:.,$(DIR_CPP))
vpath %.h $(VPATH_H)
vpath %.c $(VPATH_C)
vpath %.cpp $(VPATH_CPP)
vpath %.o $(DIR_OBJ)
vpath %.d $(DIR_DEP)
all:$(TARGET)
$(TARGET):$(OBJS)
$(CPP) $(addprefix $(DIR_OBJ)/, $(OBJS)) -o $@ $(LDFLAGS)
%.o:%.c %.d
$(CC) $(CFLAGS) -c $< -o $(DIR_OBJ)/$@
%.o:%.cpp %.d
$(CPP) $(CPPFLAGS) -c $< -o $(DIR_OBJ)/$@
%.d:%.c
@set -e
rm -rf $(DIR_DEP)/*.d
$(CC) $< $(INCFLAGS) -MM -o $(DIR_DEP)/$@
%.d:%.cpp
@set -e
$(CPP) $< $(INCFLAGS) -MM -o $(DIR_DEP)/$@
-include $(addprefix $(DIR_DEP)/,$(DEPS))
.PHONY:clean
clean:
rm -rf $(DIR_OBJ)/*.o
rm -rf $(DIR_DEP)/*.d
rm -rf $(TARGET)
执行make命令后信息如下:
g++ change.cpp -I. -I./main -I./namespace -I./type -MM -o ./release/dep/change.d
g++ -Wall -I. -I./main -I./namespace -I./type -g -c change.cpp -o ./release/obj/change.o
g++ ./main/main.cpp -I. -I./main -I./namespace -I./type -MM -o ./release/dep/main.d
g++ -Wall -I. -I./main -I./namespace -I./type -g -c ./main/main.cpp -o ./release/obj/main.o
g++ ./namespace/namespace.cpp -I. -I./main -I./namespace -I./type -MM -o ./release/dep/namespace.d
g++ -Wall -I. -I./main -I./namespace -I./type -g -c ./namespace/namespace.cpp -o ./release/obj/namespace.o
g++ ./release/obj/change.o ./release/obj/main.o ./release/obj/namespace.o -o release/test -lpthread -lrt
一点点体会:在调试Makefile过程中可能会碰到路径变量写错导致无法编译问题,我通常用@echo命令将可能出错的变量打印出来,好查找问题 一步一步修改。
例如
@echo $(DIR_CPP) 就可以将所以包含.cpp文件路径打印出来 如果路径变量不对的话 编译过程肯定会出错
-
makefile简单示例
2021-05-11 12:15:23makefile简单示例 -
linux C++中makefile使用实例
2015-10-14 16:30:56makefile的使用实例 主要功能是对两个数求平方根; 包含的文件为: main.cpp makefile my_multi.cpp my_multi.h my_sqrt.cpp my_sqrt.h -
makefile编写实例
2015-10-10 09:36:01本文记述了一个简单的makefile编写测试实例,第一步很重要,有了这个原始的例子,我们可以走得更远,也是本人在学完>之后的一个实践,受启发于MTK的系统编译组织方法... 文件清单如下: created by sf.kaka 090329 ...本文记述了一个简单的makefile编写测试实例,第一步很重要,有了这个原始的例子,我们可以走得更远,也是本人在学完<<makefile中文教程>>之后的一个实践,受启发于MTK的系统编译组织方法...
文件清单如下:
created by sf.kaka 090329
main.c:
#include "func1.h"
#include "func2.h"int main()
{
func1_print("hello func1!");
func2_print("hello func2!");
return 0;
}func1.c:
void func1_print(char *print_str)
{
print_str = "func2";
}func1.h
#ifndef __FUNC1_H_H__
#define __FUNC1_H_H__void func1_print(char *print_str);
#endif //__FUNC1_H_H__
func2.c
void func2_print(char *print_str)
{
// printf("This is func2 print : %s ",print_str);
print_str = "func2";
}func2.h
#ifndef __FUNC2_H_H__
#define __FUNC2_H_H__void func2_print(char *print_str);
#endif //__FUNC2_H_H__
makefile文件:test.mak
main:main.o func1.o func2.o
armcc -o main main.o func1.o func2.o
main.o:main.c func1.h func2.h
armcc -c main.c
func1.o:func1.c
armcc -c func1.c
func2.o:func2.c
armcc -c func2.c
clean:
rm -f *.o main执行命令: **\make.exe -f test.mak即可
执行条件:gnu的make工具,armcc编译器
-
makefile编写及实例
2011-11-09 11:15:13makefile 编写及简化代码实例.doc makefile 编写 精华.doc -
Go项目的示例Makefile-Golang开发
2021-05-26 16:29:08go-makefile-example在Go好的Makefile博客文章中介绍了Makefile的示例项目。 安装程序运行以下命令进行尝试:git clone https://github.com/azer/go-makefile-example.git cd go-mak go-makefile-example Go好的... -
Makefile文件编写例子
2021-09-15 14:20:03Makefile文件编写如下: 格式1: main: main.o oled.o pcf8574.o gcc -o main main.o oled.o pcf8574.o -lpthread mian.o: mian.c oled.h pcf8574.h gcc -c main.c oled.o: oled.c oled.h gcc -c oled.c pc -
Linux C : Makefile 的编写和示例
2021-05-03 22:31:34make工具是Unix/Linux 的一个编译工具,它按照顺序读取 Makefile 或 makefile ,进行自动地有选择地执行编译链接,只对影响到的修改的文件进行重新编译,不需要对整个工程进行重新编译。而Makefile中些内容的就是它... -
linux——makefile编写
2021-06-17 00:12:53文章目录一、为啥要编写makefile二、makefile的一些规则2.1 基本格式2.2 编写方式2.3一些规则三、makefile编写 一、为啥要编写makefile 目的很简单,减少我们的工作量啊。 在linux环境下,我们可以编译一个程序,... -
Makefile 简单实例
2020-09-10 17:53:32文章目录makefile 命令规则忽略命令出错自动化变量指定伪目标简单示例 makefile 命令规则 target… : prerequisites … command … … --------------------------------------------------------------------------... -
Linux中Makefile的编写(详细示例以及截图)
2021-07-15 21:17:49Makefile的编写 在实现Makefile的编写之前呢,我们先来了解一下程序的编译和链接 使用C、C++编写可执行程序,首先要把源文件编译成中间代码文件,Linux下是 .o 文件,即 Object File,这个动作叫做编译(compile)... -
Makefile编写实例(生成so文件)
2016-12-15 18:29:01CC = gcc XX = g++ CFLAGS = -Wall -O -g #TARGET = ./msgsql_client PROTOBUF_INC=/usr/local/shipu/mdpserver/libs/protobuf-2.5.0/output/include BOOST_INC=/usr/local/shipu/mdpserver/libs/boost_1_61_0 -
makefile文件编写简单入门示例
2020-12-16 15:55:25学会了makefile文件的编写,就能很轻松的解决这个问题了。 现在我们来看一个简单的程序,一共包含三个文件: 1. print.h #include<stdio.h> void print_Hello(); 2. print.c #include"print.h" ... -
Makefile完整例子
2012-08-06 17:02:59详细介绍了Makefile编写规范,配合项目给出了详细的例子。 例子 给出了大型软件编写Makefile的模板,可以借鉴。 其中程序用Source Insight 3打开查看。内涵Source Insight 3 的VC6.0风格文件,对熟悉VC 开发环境的... -
Makefile简单编写实例
2019-10-04 04:35:24介绍一下Makefile的简单编写例子。 编写Makefile的规则就是: 目标文件:依赖文件 (tab)编译规则 现在我有一个文件目录结构为: 解释一下这几个文件。首先我创建makefile目录,底下有一个include目录和src目录。... -
一个通用Makefile例子的详解
2021-05-16 09:21:56我们在Linux环境下开发程序,少不了要自己编写Makefile,一个稍微大一些的工程下面都会包含很多.c的源文 件。如果我们用gcc去一个一个编译每一个源文件的话,效率会低很多,但是如果我们可以写一个Makefile,那么只... -
Makefile编写实例(生成可执行文件)
2016-12-15 18:21:15CC = gcc XX = g++ CFLAGS = -Wall -O -g TARGET = ./msgsql_rpc_server PROTOBUF_INC=/usr/local/shipu/mdpserver/libs/protobuf-2.5.0/output/include BOOST_INC=/usr/local/shipu/mdpserver/libs/boost_1_61 -
Linux中make和makefile简单讲解(实例)
2021-05-06 20:38:32make和makedile简单讲解make的作用make的使用makefile文件 make的作用 make的使用 makefile文件 -
C语言 makefile学习及实现实例
2020-08-31 00:23:25主要介绍了C语言 makefile学习及实现实例的相关资料,需要的朋友可以参考下 -
Linux 如何编写makefile详解
2020-11-21 20:06:04Linux c/c++ 开发少不了编写 makefile 文件,一次编写,终身受益,哈哈!另外,gcc编译基础知识可参考我这篇博客:Linux C gcc编译基础知识详解 一、makefile三要素 目标: 依赖: 规则命令: 二、写法 目标:依赖 ... -
Makefile文件的使用和编写(进阶)
2021-05-16 21:16:34上文通过一个简单的介绍了Makefile文件的编写使用,本篇文章通过一个比较复杂的例子来加深对makefile的理解。 Makefile文件编写的优势就是不需要重复的写大量的命令行,减少工作量同时减低错误率。所以就用多文件... -
linux下makefile的编写
2019-07-17 09:38:19默认的编译器是linux下的GCC和CC make编译的步骤: 源文件首先会生成中间目标文件(一般为.o文件),再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、...1、Makefile的规则 target... : ... -
Makefile编写例子
2018-01-07 00:44:46大致整理了一下,可以贴出来的Makefile。 直接贴了,加油。 WORKROOT=../../../ LIBPATH=$(WORKROOT)/lib2-64/ LIBPATH2=$(WORKROOT)/public/ INCDIR = -I ./ \ -I$(LIBPATH2)/configure/output/include/ \ -
linux 驱动之Kconfig文件和Makefile文件实例
2021-01-10 00:57:46linux 驱动之Kconfig文件和Makefile文件实例 在Linux编写驱动的过程中,有两个文件是我们必须要了解和知晓的。这其中,一个是Kconfig文件,另外一个是Makefile文件。如果大家比较熟悉的话,那么肯定对内核编译需要的... -
Makefile 编写 简易教程 (实例)
2016-07-08 08:48:03MakeFile 编译文件 MakeFile: all: myapp # Which compiler CC = gcc # Where to install INSTDIR = /usr/local/bin # Where are include files kept INCLUDE = . # Options for development CFLAGS = -g -... -
Makefile编写
2018-09-17 22:12:04编写Makefile,以下是一则实例 文件结构 简单的一个C语言工程 Makefile实例 VERSION = 1.0.0 # 源文件目录 输出执行文件目录 头文件目录 SRC_PATH = ./src OUT_PATH = ./output INCLUDE = -I./include # 在./src... -
5.Makefile简单使用实例
2018-12-23 11:45:59目录 ...4.Makefile实例 5.Makefile简单语法 6.Makefile 函数 6.1.foreach 函数 6.2.过滤函数 -filter 6.3.获取匹配模式文件名函数— wildcard 6.4.模式替换函数— patsubst ...