百度
360搜索
搜狗搜索

makefile编写入门教程,Linux平台Makefile文件的编写基础篇详细介绍

本文目录一览: Linux平台Makefile文件的编写基础篇

目的: 基本掌握了 make 的用法,能在Linux系统上编程。 环境: Linux系统,或者有一台Linux服务器,通过终端连接。一句话:有Linux编译环境。 准备: 准备三个文件:file1.c, file2.c, file2.h file1.c: #include #include "file2.h" int main() { printf("print file1$$$$$$$$$$$$ "); File2Print(); return 0; }
file2.h:
#ifndef FILE2_H_ #define FILE2_H_
#ifdef __cplusplus
extern "C" {
#endif
void File2Print();
#ifdef __cplusplus
}
#endif
#endif

file2.c: #include "file2.h" void File2Print() { printf("Print file2********************** "); }
基础: 先来个例子: 有这么个Makefile文件。(文件和Makefile在同一目录) === makefile 开始 === helloworld:file1.o file2.o gcc file1.o file2.o -o helloworld file1.o:file1.c file2.h gcc -c file1.c -o file1.o
file2.o:file2.c file2.h
gcc -c file2.c -o file2.o

clean:
rm -rf *.o helloworld
=== makefile 结束 ===
一个 makefile 主要含有一系列的规则,如下: A: B (tab) (tab)
每个命令行前都必须有tab符号。

上面的makefile文件目的就是要编译一个helloworld的可执行文件。让我们一句一句来解释:
helloworld : file1.o file2.o: helloworld依赖file1.o file2.o两个目标文件。
gcc File1.o File2.o -o helloworld: 编译出helloworld可执行文件。-o表示你指定 的目标文件名。

file1.o : file1.c: file1.o依赖file1.c文件。
gcc -c file1.c -o file1.o: 编译出file1.o文件。-c表示gcc 只把给它的文件编译成目标文件, 用源码文件的文件名命名但把其后缀由“.c”或“.cc”变成“.o”。在这句中,可以省略-o file1.o,编译器默认生成file1.o文件,这就是-c的作用。

file2.o : file2.c file2.h gcc -c file2.c -o file2.o
这两句和上两句相同。

clean:
rm -rf *.o helloworld
当用户键入make clean命令时,会删除*.o 和helloworld文件。

如果要编译cpp文件,只要把gcc改成g++就行了。
写好Makefile文件,在命令行中直接键入make命令,就会执行Makefile中的内容了。

到这步我想你能编一个Helloworld程序了。

上一层楼:使用变量
上面提到一句,如果要编译cpp文件,只要把gcc改成g++就行了。但如果Makefile中有很多gcc,那不就很麻烦了。
第二个例子:
=== makefile 开始 === OBJS = file1.o file2.o CC = gcc CFLAGS = -Wall -O -g helloworld : $(OBJS) $(CC) $(OBJS) -o helloworld file1.o : file1.c file2.h $(CC) $(CFLAGS) -c file1.c -o file1.o file2.o : file2.c file2.h $(CC) $(CFLAGS) -c file2.c -o file2.o

clean:
rm -rf *.o helloworld === makefile 结束 ===

这里我们应用到了变量。要设定一个变量,你只要在一行的开始写下这个变量的名字,后 面跟一个 = 号,后面跟你要设定的这个变量的值。以后你要引用 这个变量,写一个 $ 符号,后面是围在括号里的变量名。

CFLAGS = -Wall -O –g,解释一下。这是配置编译器设置,并把它赋值给CFFLAGS变量。
-Wall: 输出所有的警告信息。
-O: 在编译时进行优化。
-g: 表示编译debug版本。

这样写的Makefile文件比较简单,但很容易就会发现缺点,那就是要列出所有的c文件。如果你添加一个c文件,那就需要修改Makefile文件,这在项目开发中还是比较麻烦的。

再上一层楼:使用函数
学到这里,你也许会说,这就好像编程序吗?有变量,也有函数。其实这就是编程序,只不过用的语言不同而已。
第三个例子:
=== makefile 开始 === CC = gcc
XX = g++ CFLAGS = -Wall -O –g
TARGET = ./helloworld
%.o: %.c
$(CC) $(CFLAGS) -c lt; -o [email?protected]
%.o:%.cpp
$(XX) $(CFLAGS) -c lt; -o [email?protected]

SOURCES = $(wildcard *.c *.cpp) OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))
$(TARGET) : $(OBJS) $(XX) $(OBJS) -o $(TARGET)
chmod a+x $(TARGET)
clean:
rm -rf *.o helloworld === makefile 结束 ===
函数1:wildcard
产生一个所有以 '.c' 结尾的文件的列表。
SOURCES = $(wildcard *.c *.cpp)表示产生一个所有以 .c,.cpp结尾的文件的列表,然后存入变量 SOURCES 里。

函数2:patsubst
匹配替换,有三个参数。第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的列表。
OBJS = $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCES)))表示把文件列表中所有的.c,.cpp字符变成.o,形成一个新的文件列表,然后存入OBJS变量中。

%.o: %.c
$(CC) $(CFLAGS) -c lt; -o [email?protected]
%.o:%.cpp
$(XX) $(CFLAGS) -c lt; -o [email?protected]
这几句命令表示把所有的.c,.cpp编译成.o文件。
这里有三个比较有用的内部变量。 [email?protected] 扩展成当前规则的目的文件名, lt; 扩展成依靠 列表中的第一个依靠文件,而 $^ 扩展成整个依靠的列表(除掉了里面所有重 复的文件名)。

chmod a+x $(TARGET)表示把helloworld强制变成可执行文件。

编写一个简单的 makefile 文件

obj=main.o iodata.o run.o io.s
example: $(obj)
cc -o example $(obj)
#下面的可有可无
main.o:main.c
cc -c main.o
iodata.0:iodata.c
cc -c iodata.c
run.o:run.c
cc -c run.c
#io.s 我不敢确定啊
  makefile文件里面主要有三种内容:
  
  1.变量声明:
  变量声明就是一种基本的严格字符替换的操作。
  比如在前面声明了:objects=program.o foo.o utils.o
  那么在后面出现的所有$(objects)或者${objects}都会被自动替换成上面的那个字符序列,而且是严格替换,即不带空格的。
  
  2.映射法则
  
  3.命令:
  映射法则和命令通常都是联合起来组成这样的结构形式:
  target... : prerequisites..
  command
  
  可以简单地理解为通过prerequisites,也就是先决的依赖文件,采取后面描述的相应的命令(这里的命令都是linux里的shell命令)command之后(一般是)生成了文件target。命令的前面都要按以下tab建留一段空白来表示它是命令。
  有的target后面并没有先决条件,也就是后面的命令是无条件执行的。
makefile 文件c语言程序:
#include

#include

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)

{

printk(KERN_ALERT "Hello, world\n");

return 0;

}

static void hello_exit(void)

{

printk(KERN_ALERT "Goodbye, cruel world\n");

}

module_init(hello_init);

module_exit(hello_exit);

makefile:

# If KERNELRELEASE is defined, we've been invoked from the

# kernel build system and can use its language.

ifneq ($(KERNELRELEASE),)

obj-m := hello.o

# Otherwise we were called directly from the command

# line; invoke the kernel build system.

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

makefile教程

基于 Make 命令教程 - 阮一峰的网络日志 (ruanyifeng.com) 总结,可以将make看作一个自顶向下的构建工具
在makefile相同目录下执行 make 可查看效果
makefile文件名默认 Makefile 或 makefile .也可以指定文件: make -f rules.txt 或者 make --file=rules.txt
如果 前置条件 满足,执行 命令 构建 目标
目标可以是文件,也可以是某个操作的名字
运行 make clean 可以执行这个操作:
如果make检测到当前目录中存在clean文件,就不会执行clean操作,因此最好标明clean是个操作
前置条件通常是一组文件名,用空格分割,指定了目标是否重新构建的标准:只要有一个前置文件不存在,或者有过更新(前置文件的修改时间晚于目标文件),目标就需要重新构建
如果当前目录没有source.txt,make会首到makefile的下面去寻找有没有生成source.txt的目标
命令行首默认必须是一个tab键!!!,如果测试过程有报错记得检查下 ,如果想替换,可用.RECIPEPREFIX替换(对整个文件生效 (The .RECIPEPREFIX is only supported since 3.82
每条命令都在单独的shell中执行,这些shell没有关联,也没有继承关系
解决办法就是通过写成一行
或者用反斜杠转义
最后一个办法是加上 .ONESHELL: 命令 (同上
# 表示注释
正常情况下,make会打印每条命令,即使注释也会打印,在命令前面加@可以关闭打印
通配符
用来指定一组符合条件的文件名,与bash类似 * ? [...]
允许对文件名进行模式匹配,匹配符是%
下面的命令将 file1.c 编译为file1.o
允许使用 = 自定义变量
调用shell变量,需要两个$$,因为make命令会使$转义
变量支持引用
为了区分生效时间,分成四类 gnu make - What is the difference between the GNU Makefile variable assignments =, ?=, := and +=? - Stack Overflow
内置变量
$(CC)指向当前编译器
$(MAKE)指向当前make工具
详细如表 https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
自动变量
https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
判断和循环 与bash相同
函数格式
内置函数
https://www.gnu.org/software/make/manual/html_node/Functions.html

如何编写makefile

makefile其实就是shell基本,把我们在编译一个程序中所有的步骤(命令)都写进去,然后执行make命令时系统自动运行makefile文件内的指令,接着就是自动编译了,其实和手工编译原理相同,只是makefile实现了自动化编译而已。至于怎么写?不同类型的程序有各自的编译器和编译指令,不是很复杂的编译过程不用makefile最好,gtk+编程最喜欢使用makefile了,你去看看gtk+编程例子里的makefile吧,QT自动创建的makefile非常恐怖,内容相当复杂
如果你想写
Makefile
的话,那么你只要用一个不将制表符过滤掉的文本编辑器就可以了,用
vi/vim
可以,用
emacs
可以,用其它的
geditor
也是可以的,只要是文本编辑器就可以了。你在
win
下也可以用记事本写
Makefile
,当然要确保你的系统已经安装了
make
了(最好了
GNU
make)。Makefile
是不需要后缀的,也就是说
Makefile
的文件名就是
Makefile。
下面我给出一个我写的一个简单的
Makefile
给你参考一下吧:
#
Makefile
for
'kmp'
CC=gcc
CFLAGS=-g
1 # To build modules outside of the kernel tree, we run "make"
2 # in the kernel source tree; the Makefile these then includes this
3 # Makefile once again.
4 # This conditional selects whether we are being included from the
5 # kernel Makefile or not.
6 ifeq ($(KERNELRELEASE),)
7
8 # Assume the source tree is where the running kernel was built
9 # You should set KERNELDIR in the environment if it's elsewhere
10 KERNELDIR ?= /lib/modules/$(shell uname -r)/build
11 # The current directory is passed to sub-makes as argument
12 PWD := $(shell pwd)
13
14 modules:
15 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
16
17 modules_install:
18 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
19
20 clean:
21 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
22
23 .PHONY: modules modules_install clean
24
25 else
26 # called from kernel build system: just declare what our modules are
27 obj-m := hello.o
28 endif
在lwn上可以找到这个例子,你可以把以上两个文件放在你的某个目录下,然后执行make,也许你不一定能成功,因为linux kernel 2.6要求你编译模块之前,必须先在内核源代码目录下执行make,换言之,你必须先配置过内核,执行过make,然后才能make你自己的模块.原因我就不细说了,你按着她要求的这么去做就行了.
另外注意命令前面必须是tab
什么是命令?
类似于这种
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
http://wiki.netbsd.se/index.php/Basic_Unix_programming#Using_BSD_Make
去看看,也许有帮助
你先用gcc把它给编译出来。然后再想用makefile
gcc最一般的用法就是:
gcc -o 要生成的可执行文件名 源代码文件名
如:gcc -o hello.x hello.c
如果一些头文件要指明的话,可以这样:
gcc -o hello.x -I头文件所在的文件夹 -l一些库名 hello.c
最通常,我们用到一些数学库。gcc -o hello.x -lm hello.c
makefile的话,你可以基于上述的语句进行修改:建议你看点资料,或一些典型的例子。但是注意的是规则那一行,得用Tab键打头。
hello.x : hello.o
gcc -o hello.x hello.o (这一行,得用Tab打头)
hello.o : hello.c 头文件
gcc -c hello.o hello.c -I头文件所在目录 -lm (这一行,得用Tab打头)

阅读更多 >>>  linux国产操作系统好用吗

[Linux]编写一个简单的C语言程序,编写Makefile文件。

c语言程序:
#include

#include

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)

{

printk(KERN_ALERT "Hello, world\n");

return 0;

}

static void hello_exit(void)

{

printk(KERN_ALERT "Goodbye, cruel world\n");

}

module_init(hello_init);

module_exit(hello_exit);

makefile:

# If KERNELRELEASE is defined, we've been invoked from the

# kernel build system and can use its language.

ifneq ($(KERNELRELEASE),)

obj-m := hello.o

# Otherwise we were called directly from the command

# line; invoke the kernel build system.

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

这个已经通过调试了!

//calculate.h

#ifndef DEFCALCULATE_H

#define DEFCALCULATE_H

#include

#include

#include

#include

using namespace std;

// =========================================================================

// = 一些标志,如数字、+-*/()

enum Token_value

{

NAME,

NUMBER,

END,

PLUS='+',

MINUS='-',

MUL='*',

DIV='/',

PRINT=';',

ASSIGN='=',

LP='(',

RP=')'

};

//#############################################################################

//#############################################################################

double term(bool); //乘法

double prim(bool); //处理初等项

double error(const string&); //错误函数

Token_value get_token(); //输入

double expr(bool get); //加和减

//#############################################################################

//#############################################################################

extern double number_value; //

extern string string_value; //

extern Token_value curr_tok; //当前操作标志

extern map

table;//

extern int no_of_errors; //

#endif

//winconsole.cpp

#include "calculate.h"

#include

istream* input;

int main()

{

//switch(argc)

//{

//case 1:

input=&cin;

// break;

//case 2:

// input=new istringstream(argv[1]);

// break;

//default:

// error("too many arguments");

// return 1;

//}

table["pi"]=3.14159;

table["e"]=2.718182;

while (*input)

{

get_token();

if (curr_tok==END)

{

break;

}

if (curr_tok==PRINT)

{

continue;

}

cout<
<expr(false)<<endl;
}

if (input!=&cin)

{

delete input;

}

return 0;

}

//error.cpp

#include "calculate.h"

int no_of_errors;

double error(const string& s)

{

no_of_errors++;

cerr<<"error:"<
<s<<'\n';
return 1;

}

//expr.cpp

#include "calculate.h"

Token_value curr_tok=PRINT;

double expr(bool get)//加和减

{

double left=term(get);

for (;;)

{

switch(curr_tok)

{

case PLUS:

left+=term(true);

break;

case MINUS:

left-=term(true);

break;

default:

return left;

}

}

}

//get_token.cpp

#include "calculate.h"

extern Token_value curr_tok;

Token_value get_token()

{

char ch=0;

cin>>ch;

switch(ch)

{

case 0:

return curr_tok=END;

case ';':

case '*':

case '/':

case '+':

case '-':

case '(':

case ')':

case '=':

return curr_tok=Token_value(ch);

case '0':case '1':case '2':case '3':case '4':

case '5':case '6':case '7':case '8':case '9':

case '.':

cin.putback(ch);

cin>>number_value;

return curr_tok=NUMBER;

default:

if (isalpha(ch))

{

cin.putback(ch);

cin>>string_value;

return curr_tok=NAME;

}

error("bad token");

return curr_tok=PRINT;

}

}

//prim.cpp

#include "calculate.h"

double number_value;

string string_value;

map

table;

double prim(bool get)

{

if (get)

{

get_token();

}

switch(curr_tok)

{

case NUMBER:

{

double v=number_value;

get_token();

return v;

}

case NAME:

{

double& v=table[string_value];

if (get_token()==ASSIGN)

{

v=expr(true);

}

return v;

}

case MINUS:

{

return -prim(true);

}

case LP:

{

double e=expr(true);

if (curr_tok!=RP)

{

return error(")expected");

}

get_token();

return e;

}

default:

return error("primary expected");

}

}

//term.cpp

#include "calculate.h"

double term(bool get)

{

double left=prim(get);

for (;;)

{

switch(curr_tok)

{

case MUL:

left*=prim(true);

break;

case DIV:

if (double d=prim(true))

{

left/=d;

break;

}

return error("divide by 0");

default:

return left;

}

}

}

//makefile

objects = error.o expr.o get_token.o prim.o term.o winconsole.o

calculate:$(objects)

g++ -Wall -g -o calculate $(objects)

$(objects) : %.o : %.cpp

g++ -c $(CXXFLAGS) $< -o $@

//这是一个在linux下实现的简单的计算器程序,实现带括号的+-*/运算的,由于复制进来代码格式有点出入,你自己把代码格式规范下,尤其是makefile文件里的命令前面一定要以一个tab开始

八 环境变量

8.1 查看环境变量

$ env ? 显示所有的环境变量设置

$ echo $ENV_VARIABLE ? 显示指定环境变量的设置

例:

$ echo $PATH

/bin:/etc:/usr/bin:/tcb/bin

8.2 设定环境变量

$ ENV_VARIABLE=XXX;export ENV_VARIABLE

例:

$ PATH=$PATH:$INFORMIXDIR/bin;export PATH ? 将环境变量PATH设定为原PATH值+$INFORMIXDIR/bin

8.3 取消环境变量设置

$ unset $ENV_VARIABLE

例:

$ set GZJ=gzj;export GZJ ? 设置环境变量GZJ

$ echo $GZJ

gzj ? 显示环境变量值

$ unset $GZJ ? 取消环境变量GZJ的设置

$ echo $GZJ

? 已取消

一 makefile规则

makefile是一个make的规则描述脚本文件,包括四种类型行:目标行、命令行、宏定义行和make伪指令行(如“include”)。makefile文件中注释以“#”开头。当一行写不下时,可以用续行符“\”转入下一行。

1.1 目标行

目标行告诉make建立什么。它由一个目标名表后面跟冒号“:”,再跟一个依赖性表组成。

例:

example: depfile deptarget

该目标行指出目标example与depfile和deptarget有依赖关系,如果depfile或deptarget有修改,则重新生成目标。

example1 example2 example3: deptarget1 deptarget2 depfile

该目标行指出目标名表中的example1、example2、example3这三个各自独立的目标是用相同的依赖列表和规则生成的。

clean:

空的依赖列表说明目标clean没有其他依赖关系。

目标行后续的以Tab 开始的行是指出目标的生成规则,该Tab字符不能以空格代替。例如:

example.o:example.c example.h

cc –c example.c

该例子指出目标example.o依赖于example.c和example.h。如果example.c或example.h其中之一改变了,就需要执行命令cc –c example.c重新生成目标example.o。

可以用文件名模式匹配来自动为目标生成依赖表,如:

prog: *.c

以下是一个简单的makefile的例子:

图 1 最简单的makefile例

make使用makefile文件时,从第一个目标开始扫描。上例中的第一个目标为all,所以目标clean不会自动被执行,可以通过命令make clean来生成目标。

1.2 命令行

命令行用来定义生成目标的动作。

在目标行中分号“;”后面的文件都认为是一个命令,或者一行以Tab制表符开始的也是命令。

如在上面的makefile例中,第三行以Tab字符开始的cc命令即是一个命令行,说明要生成hello应执行的命令。也可以写成:hello:hello.o;cc –c hello –L…

一般情况下,命令行的命令会在标准输出中回显出来,如对上面的makefile执行make时,标准输出如下:

cc -c hello.c

cc -o hello -L/usr/X11R6/lib -L/usr/lib -lXm -lXt -lX11 hello.o

cc -c hello1.c

cc -o hello1 -L/usr/X11R6/lib -L/usr/lib -lXm -lXt -lX11 hello1.o

如果不希望命令本身回显,可在命令前加@字符,如在上例中不希望回显cc –c hello.c和cc –c hello1.c,可修改makefile文件如下:

图 2 抑制回显的makefile例

对该makefile文件执行make时,标准输出如下:

cc -o hello -L/usr/X11R6/lib -L/usr/lib -lXm -lXt -lX11 hello.o

cc -o hello1 -L/usr/X11R6/lib -L/usr/lib -lXm -lXt -lX11 hello1.o

可以看出,命令行前有@字符的不回显。

1.3 宏定义行

在makefile中,可以使用宏定义减少用户的输入,例如上例中对hello和hello1的编译选项均为“-L/usr/X11R6/lib -L/usr/lib -lXm -lXt -lX11”,此时可以用宏来代替,如:

图 3 使用宏定义的makefile例

宏定义的基本语法是:

name=value

在定义宏时,次序不重要。宏不需要在使用前定义。如果一个宏定义多次,则使用最后一次的定义值。

可以使用“$”字符和“()”或“{}”来引用宏,例如:

cc –o hello.o $(CCFLAGS) hello.o

也可以将一个宏赋值给另一个宏,但这样的定义不能循环嵌套,如:

A=value1

B=value2

C=$(A) $(B)等价于C=value1 value2

1.4 伪指令

makefile大部分由宏定义行、命令行和目标行组成。第四种类型是make伪指令行。make伪指令没有标准化,不同的make可能支持不同的伪指令集,使得makefile有一定的不兼容性。如果要考虑移植性问题,则要避免使用make伪指令。但有一些伪指令,如include,由于使用比较多,很多不同make都提供该伪指令。

1.4.1 伪指令include

该伪指令类似C语言中的#include,它允许一次编写常用的定义并包括它。include伪指令必须在一行中,第一个元素必须是include,并且跟一个要包含的文件名,如:

include default.mk

1.4.2 伪指令“#”

“#”字符也是make的伪指令,它指出“#”后面的文件是注释,如:

PROGNAME=test # define macro

#don't modify this

二 后缀规则

2.1 双后缀规则

在前面的makefile例中有许多重复内容,例如,生成hello和hello1的命令类似,生成hello.o和hello1.o的命令也类似,除了编译或链接的文件不一样外,其它均相同,这时,我们就可以使用后缀规则。首先看一个双后缀的例子:

图 4 使用双后缀规则的makefile例

后缀规则使用特殊的目标名“.SUFFIXES”。

第一行中.SUFFIXES的依赖表为空,用来清除原有的后缀规则,因为.SUFFIXES可以在makefile中多次使用,每一次都将新的后缀规则加入以前的后缀规则中。

第二行中指定后缀规则为“.c .o”,即表示将所有的.c文件转换为.o文件。

第三行指定将.c文件转换成.o文件的方法。$(CC)为make的预定义宏,其默认值为cc,$
<为特殊的宏,代替当前的源文件,即所有要编译的.c文件。
第六行指定目标hello和hello1的生成方法。$@为特殊的宏,代替当前的目标名,即hello和hello1,$@.o即为hello.o和hello1.o。

上例介绍的是双后缀规则,即它包含两个后缀,如.c.o,用来把一个C源文件编译为目标文件。双后缀规则描述如何由第一个后缀类型的文件生成第二个后缀类型的文件,例如:.c.o规则描述如何由.c文件生成.o文件。

2.2 单后缀规则

单后缀规则描述了怎样由指定后缀的文件生成由它基名为名字的文件。例如使用单后缀规则.c,可以由hello.c和hello1.c生成hello和hello1文件。例如将前面的makefile改为:

图 5 使用单后缀规则的makefile例

由于.c后缀规则为make标准后缀规则,make为其指定了相应的命令行,所以在makefile中可以不用再指定其目标生成的具体命令行。

下表是make提供的标准后缀规则。

表 1 make标准后缀规则

后缀规则 命令行

.c $(LINK.c) –o $@ $< $(LDLIBS)

.c.ln $(LINK.c) $(POUTPUT OPTPUT OPTION) –i $<

.c.o $(COMPILE.c) $(OUTPUT OPTION) $<

.c.a $(COMPILE.c) –o $% $<

$(AR) $(ARFLAGS) $@ $%

$(RM) $%

三 特殊目标

在后缀规则中使用了特殊目标.SUFFIXES,用来指定新增的后缀规则。make还提供了几个特殊目标来设置make的行为,下面为一些特殊的目标:

? .IGNORE

make在执行命令行时,如果返回的是错误码,make的缺省动作是停止并退出。增加该目标后,make将忽略命令行返回的错误码,并继续执行后续的操作。

? .SILENT

前面已经介绍过,make在执行命令行时会回显命令行内容,在命令行前增加“@”字符将抑制该命令行的回显。

如果增加该目标,所有的命令行不再回显,相当于在每个命令行前均增加了“@”字符。

? .PRECIOUS

当收到一个信号或从shell命令返回非零的错误码时,make删除它所有已建立的文件。但有些文件即使出了错误,用户也不想让make删除,这些文件可以作为.PRECIOUS目标的参数。它可以在一个makefile中出现多次,每一次都累积文件列表。

? .SUFFIXES

它为makefile指定新的后缀规则,新的后缀规则作为.SUFFIXES的依赖表给出。.SUFFIXES可以在一个makefile中多次使用,每一次都将新的后缀规则加入以前的后缀规则中,如果.SUFFIXES的依赖表为空,则设置后缀规则表为空。

四 特殊的宏

为简单使用规则,make提供了几个特殊的宏:

? $@

整个当前目标名的值可以由宏“$@”来代替。

? $<

当前的源文件由“$<”来代替。例如,在前面的例子中用到了$(CC) –c $<,其中的“$<”是所有要编译的.c文件。宏“$<”仅在后缀规则或.DEFAULT中有效。

? $*

当前目标的基名由宏“$*”来代替。例如目标的名字是hello.o,则基名就是除去了后缀.o的hello。

以上介绍的特殊宏使用了make自身的规则,用户不可以改变。下表介绍了C中预定义的宏。

用途 宏 默认值

库文档汇编命令 AR ar

ARFLAGS rv

AS as

ASFLAGS

COMPILE.s $(AS) $(ASFLAGS) $(TARGET ARCH)

C编译器命令 CC cc

CFLAGS

CPPFLAGS

COMPILE.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET ARCH) –c

LINK.c $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET ARCH)

链接编辑器命令 LD ld

LDFLAGS

rm命令 RM rm

后缀列表 SUFFIXES .o .c .c~ .s .s~ .S .S~ .ln .f .f~ .F .F~ .l .mod .mod~ .sym

.def .def~ .p .p~ .r .r~ .y .y~ .h .h~ .sh .sh~ .cps .cps~

五 makefile的应用

当调用make时,它在当前目录下搜索文件名是“makefile”或“Makefile”的文件,并执行。

如果不想使用上述缺省文件,可以使用命令行中的“-f”来指定文件,如将编写的makefile命名为mklib,则指定为“make –f mklib”。

阅读更多 >>>  linux怎么进程状态转换

</s<<'\n';
</expr(false)<<endl;

如何自己编写Makefile

 相信很多朋友都有过这样的经历,看着开源项目中好几页的makefile文件,不知所云。在日常学习和工作中,也有意无意的去回避makefile,能改就不写,能用ide就用ide。其实makefile并没有想象的那么难写,只要你明白了其中的原理,自己实践几次。你也可以自己写makefile,让别人对你头来羡慕的目光。
  下面本人介绍一下自己的学习成果,初学阶段,欢迎大家多多指正。
  简单的说,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至可以在makefile中执行shell脚本。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  关于程序的编译和链接
  一般来说,无论是C还是C++,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o
文件,即 Object File,这个动作叫做编译(compile),一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。然后再把大量的Object
File合成执行文件,这个动作叫作链接(link)。
  编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。
  链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object
File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library
File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
  下面我们开始看看如何自己写出makefile。
  Makefile的规则
  目标 :
需要的条件 (注意冒号两边有空格)
    命令  (注意前面用tab键开头)
  解释一下:
  1
目标可以是一个或多个,可以是Object File,也可以是执行文件,甚至可以是一个标签。
  2
需要的条件就是生成目标所需要的文件或目标
  3
命令就是生成目标所需要执行的脚本
  总结一下,就是说一条makefile规则规定了编译的依赖关系,也就是目标文件依赖于条件,生成规则用命令来描述。在编译时,如果需要的条件的文件比目标更新的话,就会执行生成命令来更新目标。
  下面举个简单的例子说明。如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。
  edit : main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
cc -o edit
main.o kbd.o command.o display.o /
insert.o search.o
files.o utils.o
main.o : main.c
defs.h
cc -c main.c
kbd.o : kbd.c defs.h
command.h
cc -c kbd.c
command.o : command.c defs.h
command.h
cc -c command.c
display.o : display.c defs.h
buffer.h
cc -c display.c
insert.o : insert.c defs.h
buffer.h
cc -c insert.c
search.o : search.c defs.h
buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h
command.h
cc -c files.c
utils.o : utils.c
defs.h
cc -c utils.c
clean :
rm edit main.o
kbd.o command.o display.o /
insert.o search.o files.o
utils.o
  将上面的内容写入到Makefile文件中,然后执行make就可以进行编译,执行make
clean就可以删除所有目标文件。解释一下,也就是说生成最终的目标文件edit,依赖于一系列的.o目标文件,而这些.o文件又是需要用源文件来编译生成的。
  需要注意的是,clean后面没有条件,而clean本身也不是文件,它只不过是一个动作名字,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。
  make是如何工作的
  在默认的方式下,也就是我们只输入make命令。那么,

1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。

2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。

3、如果edit文件不存在,或是edit所依赖的后面的 .o
文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。

4、如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)

5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o
文件生命make的终极任务,也就是执行文件edit了。
  makefile中使用变量
  前面的知识已经足以让你自己完成一个简单的makefile了,不过makefile的精妙之处远不止如此,下面来看看如何在makefile中使用变量吧。
  在上面的例子中,先让我们看看edit的规则:
edit : main.o kbd.o command.o
display.o /
insert.o search.o files.o
utils.o
cc -o edit main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
  我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文件,那么我们需要在两个地方加(应该是三个地方,还有一个地方在clean中)。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果
makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们可以使用变量。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。
  于是,我们使用变量objects
  objects = main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
  这样一来,原来的makefile变成如下的样子:
  objects = main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
edit : $(objects)

cc -o edit $(objects)
main.o : main.c defs.h
cc -c
main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c

command.o : command.c defs.h command.h
cc -c command.c

display.o : display.c defs.h buffer.h
cc -c display.c

insert.o : insert.c defs.h buffer.h
cc -c insert.c

search.o : search.c defs.h buffer.h
cc -c search.c
files.o
: files.c defs.h buffer.h command.h
cc -c files.c
utils.o
: utils.c defs.h
cc -c utils.c
clean :
rm
edit $(objects)
  这样看起来方便多了吧,也更加省事了。如果有新的.o文件怎么办?当然是在objects里面添加了,这样只需要一处改变,很方便吧。
  让make自动推导
  GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。
  只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且
cc -c whatever.c
也会被推导出来,于是,我们的makefile再也不用写得这么复杂。我们的是新的makefile又出炉了。
  objects = main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
edit : $(objects)

阅读更多 >>>  怎么在win下装linux

cc -o edit $(objects)
main.o : defs.h
kbd.o :
defs.h command.h
command.o : defs.h command.h
display.o : defs.h
buffer.h
insert.o : defs.h buffer.h
search.o : defs.h
buffer.h
files.o : defs.h buffer.h command.h
utils.o :
defs.h
  clean :
rm edit
$(objects)
  当然,如果你觉得那么多[.o]和[.h]的依赖有点不爽的话,好吧,没有问题,这个对于make来说很容易,谁叫它提供了自动推导命令和文件的功能呢?来看看最新风格的makefile吧。
  objects = main.o kbd.o command.o display.o
/
insert.o search.o files.o utils.o
edit : $(objects)

cc -o edit $(objects)
$(objects) : defs.h
kbd.o
command.o files.o : command.h
display.o insert.o search.o files.o :
buffer.h
clean :
rm edit $(objects)

怎么编写Makefile生成静态库

编写Makefile生成静态库的方法:
方法一
//////////////////////////////////////////////////////////////////
divFIX=/usr
LIBDIR=$(divFIX)/lib
INCLUDEDIR=$(divFIX)/include
#$(DESTDIR) is usally empty. rpmbuild needs it.
DESTDIR=
CC=gcc
CFLAGS=
LIBS=
INCLUDES=
AR=ar
all: hello.a
hello.a: file1.o file2.o
$(AR) -r $@ $^
file1.o: file1.c
$(CC) $(CFLAGS) -c $^ -o $@ $(LIBS) $(INCLUDES)
file2.o: file2.c
$(CC) $(CFLAGS) -c $^ -o $@ $(LIBS) $(INCLUDES)
install:
@echo Copying library files to $(DESTDIR)/$(LIBDIR):
@cp -rp libthreadpool.a $(DESTDIR)/$(LIBDIR)/
@echo Copying head files to $(DESTDIR)/$(DATADIR):
@cp -rp src/thread-pool.h $(DESTDIR)/$(INCLUDEDIR)/
clean:
rm -rf *.o \
*.a
uninstall:
rm -rf $(LIBDIR)/hello.a\
$(INCLUDEDIR)/hello.h
//////////////////////////////////////////////////////////////////////////
方法二
gcc -o hellofile.a file1.o file2.o -lc -lm -shared
动态库
gcc -o hellofile.so file1.o file2.o -lc -lm -shared
# -lpthread 线程
# -shared 共享库
# -lm 表示连接名为“libm.a”的数学函数库
# -lc 代表链接器将连接GCC的标准C库
# -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
# -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
# .a为后缀的文件,是由目标文件构成的档案库文件;
# .so 为动态库。

linux中用C语言编写完模块后怎么编写makefile文件?用到什么命令?以什么格式编写?

1、先写Makefile编译出***.ko文件
模板如下,保存到命名为Makefile文件里,放到你代码的同级目录下
TARGET=my_proc.ko
LINUXDIR=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)
obj-m :=
obj-m += my_proc.o
all: $(TARGET)
$(TARGET): $(OBJS)
make -C $(LINUXDIR) SUBDIRS=$(PWD) modules
clean:
rm -f modules.order Module.symvers $(TARGET) *.mod.c *.o
rm -rf .tmp_versions .mod* Module.markers
2、make
3、root权限下用命令插入模块
insmod my_proc.ko
4、可以用你写的应用程序打开、操作模块了
5、查看模块命令
lsmod
cat /proc/modules
modinfo my_proc.ko
6、root下卸载模块
rmmod
光在这说有点困难,我有个ppt里比较详细的讲解怎么进行,如果有需要的话,把你的邮箱留给我~~
看来你对makefile还不了解,先认真看看make使用手册吧,以下是make中文手册阅读地址http://www.linuxsir.org/main/doc/gnumake/GNUmake_v3.80-zh_CN_html/index.html
vi Makefile #打开vi编辑器
在编辑器里输入以下内容:
#当只有一个文件需要编译的时候
finame:filename.c #冒号前面是要编译成的目标文件(可以任意命名),后面是你编写的C文件
gcc -o filename filename.c #gcc前面是按Tab制表符
#filename:filename.c 是指filename文件的生成要依赖filename.c文件
#然后换行后按Tab键,然后编写编译规则
#make命令一般是同时编译多个文件时才使用,以下是同时编写多个独立的C文件
#filename1和filename2……没有依赖关系
filename1:filename1.c
gcc -o filename1 filename1.c
filename2:filename2.c
gcc -o filename2 filename2.c
#makefile编译多个需要依赖(互相调用的文件)
main:main.o file1.o file2.o #main是最终要生成的目标文件,后面.o就是需要调用的文件的对象文件
main.o:main.c
gcc -c main.c #生成main.o对象文件,main.c里面是有主函数的
file1.o:file1.c
gcc -c file1.c
file2.o:file2.c
gcc -c file2.c
#以上差不多就可以用了
#一下是我找的例子
#include "mytool1.h"
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 "mytool2.h"
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s\n",print_str);
}
当然由于这个程序是很短的我们可以这样来编译
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
这样的话我们也可以产生main 程序,而且也不时很麻烦.
# 这是上面那个程序的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
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
有了这个Makefile 文件,不过我们什么时候修改了源程序当中的什么文件,我们只要执行
make 命令,我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件她连理
都不想去理的。
下面我们学习Makefile 是如何编写的。
在Makefile 中也#开始的行都是注释行.Makefile 中最重要的是描述文件的依赖关系的说
明.一般的格式是:
target: components
TAB rule
第一行表示的是依赖关系.第二行是规则.
比如说我们上面的那个Makefile 文件的第二行
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 键

如何在linux下写makefile

Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。
make命令的选项与参数
语法
makefile文件由一组依赖关系和规则组成。每个依赖关系由一个目标(即将要创建的文件)和一组该目标所依赖的源文件组成。
依赖关系
依赖关系定义了最终应用程序里的每个文件与源文件之间的关系。
上面两行就是依赖关系:目标a.out:依赖于main.o,目标main.o依赖于main.c和main.h。所以,如果main.c和main.h发生更改,则需要重新编译整个程序。
如果需要一次创建多个目标文件,则使用为目标all:
注意:如果未指定一个all目标,则make命令只创建makefile文件的第一个目标。
规则
规则定义了目标的创建方式。
注意:规则所在行必须以制表符tab开头。
下面就是一个简单的例子:
make命令会自行判断文件的正确顺序,并使用给出的规则创建相应的文件,并在屏幕显示出来。如果多次编译,则make命令会读取makefile文件来确定重建目标的最少命令,而不会重复编译。
注释
makefile文件的注释以#开头,到一行的结束。

makefile文件中也可以定义宏,也可以用make命令时在命令行定义,如果需要使用文件外部定义,最好不要用空格。
然后就完了。

网站数据信息

"makefile编写入门教程,Linux平台Makefile文件的编写基础篇"浏览人数已经达到22次,如你需要查询该站的相关权重信息,可以点击进入"Chinaz数据" 查询。更多网站价值评估因素如:makefile编写入门教程,Linux平台Makefile文件的编写基础篇的访问速度、搜索引擎收录以及索引量、用户体验等。 要评估一个站的价值,最主要还是需要根据您自身的需求,如网站IP、PV、跳出率等!