搜档网
当前位置:搜档网 › Makefile'l详解

Makefile'l详解

Makefile'l详解
Makefile'l详解

=== 1 概述

=== 2 角色分工

=== 3 内核编译文档

--- 3.1 目标定义

--- 3.2 内嵌对象- obj-y

--- 3.3 可加载模块- obj-m

--- 3.4 导出符号

--- 3.5 库文档- lib-y

--- 3.6 目录递归

--- 3.7 编译标记

--- 3.8 命令依赖

--- 3.9 依赖关系

--- 3.10 特别规则

=== 4 辅助程式

--- 4.1 简单辅助程式

--- 4.2 组合辅助程式

--- 4.3 定义共享库

--- 4.4 C++语言使用方法

--- 4.5 辅助程式编译控制选项

--- 4.6 何时建立辅助程式

--- 4.7 使用hostprogs-$(CONFIG_FOO)

=== 5 编译清除机制

=== 6 体系Makefile文档

--- 6.1 变量配置

--- 6.2 增加预配置项

--- 6.3 目录表

--- 6.4 引导映像

--- 6.5 编译非内核目标

--- 6.6 编译引导映像命令

--- 6.7 定制编译命令

--- 6.8 预处理连接脚本

--- 6.9 $(CC)支持功能

=== 7 Kbuild变量

=== 8 Makefile语言

=== 9 Credits

=== 10 TODO

=== 1 概述

Makefile包括五部分:

Makefile 顶层Makefile文档

.config 内核配置文档

arch/$(ARCH)/Makefile 机器体系Makefile文档

scripts/Makefile.* 任何内核Makefiles共用规则

kbuild Makefiles 其他makefile文档

通过内核配置操作产生.config文档,顶层Makefile文档读取该文档的配置。顶层Makefile文档负责产生两个主要的程式:vmlinux (内核image)和模块。顶层Makefile文档根据内核配置,通过递归编译内核代码树子目录建立这两个文档。顶层Makefile文档文本一个名为

arch/$(ARCH)/Makefile的机器体系makefile文档。机器体系Makefile文档为顶层makefile

文档提供和机器相关的信息。每一个子目录有一个makefile文档,子目录makefile文档根据上级目录makefile文档命令启动编译。这些makefile使用.config文档配置数据构建各种文档列表,并使用这些文档列表编译内嵌或模块目标文档。scripts/Makefile.*包含了任何的定义和规则,和makefile文档一起编译出内核程式。

=== 2 角色分工

人们和内核makefile存在四种不同的关系:

*用户* 用户使用"make menuconfig"或"make"命令编译内核。他们通常不读或编辑内核makefile文档或其他源文档。

*普通研发者* 普通研发者维护设备驱动程式、文档系统和网络协议代码,他们维护相关子系统的makefile文档,因此他们需要内核makefile文档整体性的一般知识和关于kbuild公共接口的周详知识。

*体系研发者* 体系研发者关注一个整体的体系架构,比如sparc或ia64。体系研发者既需要掌控关于体系的makefile文档,也要熟悉内核makefile文档。

*内核研发者* 内核研发者关注内核编译系统本身。他们需要清楚内核makefile文档的任何方面。本文档的读者对象是普通研发者和系统研发者。

=== 3 内核编译文档

内核中大多数makefile文档是使用kbuild基础架构的makefile文档。本章介绍kbuild的makefile中的语法。

3.1节“目标定义”是个快速导引,后面各章有周详介绍和实例。

--- 3.1 目标定义

目标定义是makefile文档的主要部分(核心)。这些目标定义行定义了如何编译文档,特别的兼容选项和递归子目录。

最简单的makefile文档只包含一行:

Example: obj-y += foo.o

这行告诉kbuild在该目录下名为foo.o的目标文档(object),foo.o通过编译foo.c或foo.S 而得到。

假如foo.o编译成一个模块,则使用obj-m变量,因此常见写法如下:

Example: obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO)能够代表y(built-in对象)或m(module对象)。

假如CONFIG_FOO不是y或m,那么这个文档不会被编译和链接。

--- 3.2 内嵌对象- obj-y

makefile文档将为编译vmlinux的目标文档放在$(obj-y)列表中,这些列表依赖于内核配置。

Kbuild编译任何的$(obj-y)文档,然后调用"$(LD) -r"合并这些文档到一个built-in.o文档中。built-in.o经过父makefile文档链接到vmlinux。$(obj-y)中的文档顺序很重要。列表中文档允许重复,文档第一次出现将被链接到built-in.o,后续出现该文档将被忽略。

链接顺序之所以重要是因为一些函数在内核引导时将按照他们出现的顺序被调用,如函数(module_init() / __initcall)。所以要牢记改变链接顺序意味着也要改变SCSI控制器的检测顺序和重数磁盘。

例如:#drivers/isdn/i4l/Makefile

# 内核ISDN子系统和设备驱动程式Makefile

# 每个配置项是个文档列表

obj-$(CONFIG_ISDN) += isdn.o

obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

--- 3.3 可加载模块- obj-m

$(obj-m)表示对象文档(object files)编译成可加载的内核模块。

一个模块能够通过一个源文档或几个源文档编译而成。makefile只需简单地他们加到$(obj-m)。

例如:#drivers/isdn/i4l/Makefile

obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

注意:在这个例子中$(CONFIG_ISDN_PPP_BSDCOMP)含义是'm'。

假如内核模块通过几个源文档编译而成,使用以上同样的方法。

Kbuild需要知道通过哪些文档编译模块,因此需要配置一个$(-objs)变量。

例如:#drivers/isdn/i4l/Makefile

obj-$(CONFIG_ISDN) += isdn.o

isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

在这个例子中,模块名isdn.o. Kbuild首先编译$(isdn-objs)中的object文档,然后运行"$(LD) -r"将列表中文档生成isdn.o.

Kbuild使用后缀-objs、-y识别对象文档。这种方法允许makefile使用CONFIG_符号值确定一个object文档是否是另外一个object的组成部分。

例如:#fs/ext2/Makefile

obj-$(CONFIG_EXT2_FS) += ext2.o

ext2-y := balloc.o bitmap.o

ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o

在这个例子中,假如$(CONFIG_EXT2_FS_XATTR)表示'y',则ext2.o只有xattr.o组成部分。

注意:当然,当您将对象文档编译到内核时,以上语法同样有效。因此,假如

CONFIG_EXT2_FS=y,Kbuild将先编译ext2.o文档,然后链接到built-in.o。

--- 3.4 导出符号目标

在makefile文档中没有特别导出符号的标记。

--- 3.5 库文档- lib-y

obj-*中的object文档用于模块或built-in.o编译。object文档也可能编译到库文档中--lib.a。

任何罗列在lib-y中的object文档都将编译到该目录下的一个单一的库文档中。

包含在0bj-y中的object文档假如也列举在lib-y中将不会包含到库文档中,因为他们不能被访问。但lib-m中的object文档将被编译进lib.a库文档。

注意在相同的makefile中能够列举文档到buit-in内核中也能够作为库文档的一个组成部分。因此在同一个目录下既能够有built-in.o也能够有lib.a文档。

例如:#arch/i386/lib/Makefile

lib-y := checksum.o delay.o

这样将基于checksum.o、delay.o创建一个lib.a文档。

对于内核编译来说,lib.a文档被包含在libs-y中。将“6.3 目录表”。

lib-y通常被限制使用在lib/和arch/*/lib目录中。

--- 3.6 目录递归

makefile文档负责编译当前目录下的目标文档,子目录中的文档由子目录中的makefile文档

负责编译。编译系统将使用obj-y和obj-m自动递归编译各个子目录中文档。

假如ext2是个子目录,fs目录下的makefile将使用以下赋值语句是编译系统编译ext2子目录。

例如: #fs/Makefile

obj-$(CONFIG_EXT2_FS) += ext2/

假如CONFIG_EXT2_FS配置成'y(built-in)或'm'(modular),则对应的obj-变量也要配置,内核编译系统将进入ext2目录编译文档。

内核编译系统只使用这些信息来决定是否需要编译这个目录,子目录中makefile文档规定那些文档编译为模块那些是内核内嵌对象。

当指定目录名时使用CONFIG_变量是一种良好的做法。假如CONFIG_选项不为'y'或'm',内核编译系统就会跳过这个目录。

--- 3.7 编译标记

EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS

任何的EXTRA_变量只能使用在定义该变量后的makefile文档中。EXTRA_变量被makefile 文档任何的执行命令语句所使用。

$(EXTRA_CFLAGS)是使用$(CC)编译C文档的选项。

例如: # drivers/sound/emu10k1/Makefile

EXTRA_CFLAGS += -I$(obj)

ifdef

DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG

endif

定义这个变量是必须的,因为顶层makefile定义了$(CFLAGS)变量并使用该变量编译整个

代码树。

$(EXTRA_AFLAGS)是每个目录编译汇编语言源文档的选项。

例如: #arch/x86_64/kernel/Makefile

EXTRA_AFLAGS := -traditional

$(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)用于每个目录的$(LD)和$(AR)选项。

例如: #arch/m68k/fpsp040/Makefile

EXTRA_LDFLAGS := -x

CFLAGS_$@, AFLAGS_$@

CFLAGS_$@和AFLAGS_$@只使用到当前makefile文档的命令中。

$(CFLAGS_$@)定义了使用$(CC)的每个文档的选项。$@部分代表该文档。

例如: # drivers/scsi/Makefile

CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF

CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY

-DSEAGATE_USE_ASM

这三行定义了aha152x.o、gdth.o和seagate.o文档的编译选项。

$(AFLAGS_$@)使用在汇编语言代码文档中,具备同上相同的含义。

例如: # arch/arm/kernel/Makefile

AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional

AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional

--- 3.9 依赖关系

内核编译记录如下依赖关系:

1) 任何的前提文档(both *.c and *.h)

2) CONFIG_ 选项影响到的任何文档

3) 编译目标文档使用的命令行

因此,假如改变$(CC)的一个选项,任何相关的文档都要重新编译。

--- 3.10 特别规则

特别规则使用在内核编译需要规则定义而没有相应定义的时候。典型的例子如编译时头文档的产生规则。其他例子有体系makefile编译引导映像的特别规则。特别规则写法同普通的Make 规则。

Kbuild(应该是编译程式)在makefile所在的目录不能被执行,因此任何的特别规则需要提供前提文档和目标文档的相对路径。

定义特别规则时将使用到两个变量:

$(src):$(src)是对于makefile文档目录的相对路径,当使用代码树中的文档时使用该变量$(src)。

$(obj):$(obj)是目标文档目录的相对路径。生成文档使用$(obj)变量。

例如: #drivers/scsi/Makefile

$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl

$(CPP) -DCHIP=810 - -objs)包含了任何的用于链接最终可执行程式的对象。

例如: #scripts/lxdialog/Makefile

hostprogs-y := lxdialog

lxdialog-objs := checklist.o lxdialog.o

扩展名.o文档都编译自对应的.c文档。在上面的例子中checklist.c编译成checklist.o,lxdialog.c编译为lxdialog.o。最后两个.o文档链接成可执行文档lxdialog。

注意:语法-y不能用于定义主机程式。

--- 4.3 定义共享库

扩展名为.so的对象是共享库文档,并且是位置无关的object文档。内核编译系统提供共享库使用支持,但使用方法有限制。在下面例子中libkconfig.so库文档被链接到可执行文档conf 中。

例如: #scripts/kconfig/Makefile

hostprogs-y := conf

conf-objs := conf.o libkconfig.so

libkconfig-objs := expr.o type.o

共享库文档需要对应的-objs定义, 在上面例子中库libkconfig由两个对象组成:expr.o和type.o。expr.o和type.o将被编译为位置无关代码并被链接如libkconfig.so。共享库不支持C++语言。

--- 4.4 C++语言使用方法

内核编译系统提供了对C++主机程式的支持以用于内核配置,但不主张其他方面使用这种方法。

例如: #scripts/kconfig/Makefile

hostprogs-y := qconf

qconf-cxxobjs := qconf.o

在上面例子中可执行文档由C++文档https://www.sodocs.net/doc/8014213040.html,组成- 通过$(qconf-cxxobjs)标识。

假如qconf由.c和.cc文档混合组成,附加行表示这种情况。

例如: #scripts/kconfig/Makefile

hostprogs-y := qconf

qconf-cxxobjs := qconf.o

qconf-objs := check.o

--- 4.5 辅助程式编译控制选项

当编译主机程式时仍然能够使用$(HOSTCFLAGS)配置编译选项传递给$(HOSTCC)。这些选项将影响任何使用变量HOST_EXTRACFLAG的makefile创建的主机程式。

例如: #scripts/lxdialog/Makefile

HOST_EXTRACFLAGS += -I/usr/include/ncurses

为单个文档配置选项使用下面方式:

例如: #arch/ppc64/boot/Makefile

HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)

也能够使用附加链接选项:

例如: #scripts/kconfig/Makefile

HOSTLOADLIBES_qconf := -L$(QTDIR)/lib

当链接qconf时将使用外部选项"-L$(QTDIR)/lib"。

--- 4.6 何时建立辅助程式

只有当需要时内核编译系统才会编译主机程式。有两种方式:

(1) 在特别规则中作为隐式的前提需求

例如: #drivers/pci/Makefile

hostprogs-y := gen-devlist

$(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist

( cd $(obj); ./gen-devlist ) 产生 .config文档

2) 保存内核版本到include/linux/version.h文档中

3) 符号链接include/asm to include/asm-$(ARCH)

4) 更新任何目标对象的其他前提文档

- 附加前提文档定义在arch/$(ARCH)/Makefile文档中

5) 递归进入init-* core* drivers-* net-* libs-*中的任何子目录和编译任何的目标对象

- 上面变量值都引用到arch/$(ARCH)/Makefile文档。

6) 链接任何的object文档生成vmlinux文档,vmlinux文档放在代码树根目录下。

最开始链接的几个object文档列举在arch/$(ARCH)/Makefile文档的head-y变量中。

7) 最后体系makefile文档定义编译后期处理规则和建立最终的引导映像bootimage。 - 包括创建引导记录

- 准备initrd映像和相关处理

--- 6.1 变量配置

LDFLAGS $(LD)一般选项

选项使用于链接器的任何调用中。通常定义emulation就能够了。

例如: #arch/s390/Makefile

LDFLAGS := -m elf_s390

注意: EXTRA_LDFLAGS和LDFLAGS_$@能够进一步订制使用选项,将第7章。 LDFLAGS_MODULE $(LD)链接模块的选项

LDFLAGS_MODULE通常配置$(LD)链接模块的.ko选项。

默认为"-r"即可重定位输出文档。

LDFLAGS_vmlinux $(LD)链接vmlinux选项

LDFLAGS_vmlinux定义链接最终vmlinux时链接器的选项。

LDFLAGS_vmlinux支持使用LDFLAGS_$@。

例如: #arch/i386/Makefile

LDFLAGS_vmlinux := -e stext

OBJCOPYFLAGS objcopy选项

当使用$(call if_changed,objcopy)转化a .o文档时,OBJCOPYFLAGS中的选项将被使用。 $(call if_changed,objcopy)经常被用作为vmlinux产生原始的二进制文档。

例如: #arch/s390/Makefile

OBJCOPYFLAGS := -O binary

#arch/s390/boot/Makefile

$(obj)/image: vmlinux FORCE $(call if_changed,objcopy)

在上面例子中$(obj)/image是vmlinux的二进制版本文档。$(call if_changed,xxx)

的使用方法见后。

AFLAGS $(AS)汇编选项

默认值见顶层Makefile文档

针对每个体系需要另外添加和修改他。

例如: #arch/sparc64/Makefile

AFLAGS += -m64 -mcpu=ultrasparc

CFLAGS $(CC)编译器选项

默认值见顶层Makefile文档

针对每个体系需要另外添加和修改他。

通常CFLAGS变量值取决于内核配置。

例如: #arch/i386/Makefile

cflags-$(CONFIG_M386) += -march=i386

CFLAGS += $(cflags-y)

许多体系Makefiles文档动态启动市场目标机器上的C编译器检测支持的选项: #arch/i386/Makefile

...

cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,\

-march=pentium2,-march=i686) ...

# Disable unit-at-a-time mode ...

CFLAGS += $(call cc-option,-fno-unit-at-a-time)

...

第一个例子当config选项是'y'时将被选中。

CFLAGS_KERNEL $(CC)编译built-in对象的选项

$(CFLAGS_KERNEL)包含外部C编译器选项编译本地内核代码。

CFLAGS_MODULE $(CC)编译模块选项

$(CFLAGS_MODULE)包含外部C编译器选项编译可加载内核代码。

--- 6.2 增加预配置项

prepare: 这个规则用于列举开始进入子目录编译前需要的前提文档。通常是些包含汇编常量的头文档。

例如:

#arch/s390/Makefile

prepare: include/asm-$(ARCH)/offsets.h

在这个例子中include/asm-$(ARCH)/offsets.h将在进入子目录前编译。

详见XXX-TODO文档描述了kbuild如何产生offset头文档。

--- 6.3 目录表

体系makefile文档和顶层makefile文档一起定义了如何建立vmlinux文档的变量。注意没有体系相关的模块对象定义部分:任何的模块对象都是体系无关的。

head-y, init-y, core-y, libs-y, drivers-y, net-y

$(head-y) 列举首先链接到vmlinux的对象文档。

$(libs-y) 列举了能够找到lib.a文档的目录。

其余的变量列举了能够找到内嵌对象文档的目录。

$(init-y) 列举的对象位于$(head-y)对象之后。

然后是如下位置秩序:

$(core-y), $(libs-y), $(drivers-y) 和$(net-y)。

顶层makefile定义了任何同用目录,arch/$(ARCH)/Makefile文档只需增加体系相关的目录。

例如: #arch/sparc64/Makefile

core-y += arch/sparc64/kernel/

libs-y += arch/sparc64/prom/ arch/sparc64/lib/

drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/

--- 6.4 引导映像

体系makefile文档定义了编译vmlinux文档的目标对象,将他们压缩和封装成引导代码,并复制到合适的位置。这包括各种安装命令。如何定义实际的目标对象无法为任何的体系结构提供标准化的方法。

附加处理过程常位于arch/$(ARCH)/下的boot/目录。

内核编译系统无法在boot/目录下提供一种便捷的方法创建目标系统文档。因此

arch/$(ARCH)/Makefile要调用make命令在boot/目录下建立目标系统文档。建议使用的方法

是在arch/$(ARCH)/Makefile中配置调用,并且使用完整路径引用

arch/$(ARCH)/boot/Makefile。

例如: #arch/i386/Makefile

boot := arch/i386/boot

bzImage: vmlinux

$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

建议使用"$(Q)$(MAKE) $(build)="方式在子目录中调用make命令。

没有定义体系目标系统文档的规则,但执行"make help"命令要列出任何目标系统文档,因此必须定义$(archhelp)变量。

例如: #arch/i386/Makefile

define

archhelp echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)'

endef

当执行不带参数的make命令时,将首先编译第一个目标对象。在顶层makefile中第一个目标对象是all:。

一个体系结构需要定义一个默认的可引导映像。

"make help"命令的默认目标是以*开头的对象。

增加新的前提文档给all目标能够配置不同于vmlinux的默认目标对象。

例如: #arch/i386/Makefile

all: bzImage

当执行不带参数的"make"命令时,bzImage文档将被编译。

--- 6.5 编译非内核目标

extra-y

extra-y定义了在当前目录下创建没有在obj-*定义的附加的目标文档。

在extra-y中列举目标是处于两个目的:

1) 是内核编译系统在命令行中检查变动情况

- 当使用$(call if_changed,xxx)时

2) 内核编译系统知道执行"make clean"命令时删除哪些文档

例如: #arch/i386/kernel/Makefile

extra-y := head.o init_task.o

上面例子extra-y中的对象文档将被编译但不会练接到built-in.o中。

--- 6.6 编译引导映像命令

Kbuild提供了一些编译引导映像有用的宏。

if_changed

if_changed是后面命令使用的基础。

用法:

target: source(s)

FORCE $(call if_changed,ld/objcopy/gzip)

当这条规则被使用时他将检查哪些文档需要更新,或命令行被改变。后面这种情况将迫使重新编译编译选项被改变的执行文档。使用if_changed的目标对象必须列举在$(targets)中,否则命令行检查将失败,目标一直会编译。

赋值给$(targets)的对象没有$(obj)/前缀。

if_changed也能够和定制命令配合使用,见6.7"kbuild定制命令"。

注意: 一个常见错误是忘记了FORCE前导词。

ld

链接目标。常使用LDFLAGS_$@作为ld的选项。

objcopy

复制二进制文档。常用于arch/$(ARCH)/Makefile中和使用OBJCOPYFLAGS作为选项。

也能够用OBJCOPYFLAGS_$@配置附加选项。

gzip

压缩目标文档。使用最大压缩算法压缩目标文档。

例如: #arch/i386/boot/Makefile

LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary

LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext

targets += setup setup.o bootsect bootsect.o

$(obj)/setup $(obj)/bootsect: %: %.o FORCE

$(call if_changed,ld)

在上面例子中有两个可能的目标对象,分别需要不同的链接选项。使用LDFLAGS_$@语法为每个目标对象配置不同的链接选项。

$(targets)包含任何的目标对象,因此内核编译系统知道任何的目标对象并且将:

1) 检查命令行的改变情况

2) 执行make clean命令时删除目标对象

": %: %.o"是简写方法,减写setup.o和bootsect.o文档。

注意: 常犯错误是忘记"target :="语句,导致没有明显的原因目标文档被重新编译。

--- 6.7 定制编译命令

当执行带KBUILD_VERBOSE=0参数的编译命令时命令的简短信息会被显示。要让定制命

令具备这种功能需要配置两个变量:

quiet_cmd_ - 将被显示的内容

cmd_ - 被执行的命令

例如: #

quiet_cmd_image = BUILD $@

cmd_image = $(obj)/tools/build $(BUILDFLAGS) \

$(obj)/vmlinux.bin > $@

targets += bzImage

$(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE

$(call if_changed,image)

@echo 'Kernel: $@ is ready'

执行"make KBUILD_VERBOSE=0"命令编译$(obj)/bzImage目标时将显示:

BUILD arch/i386/boot/bzImage

--- 6.8 预处理连接脚本

当编译vmlinux映像时将使用arch/$(ARCH)/kernel/vmlinux.lds链接脚本。

相同目录下的vmlinux.lds.S文档是这个脚本的预处理的变体。内核编译系统知晓.lds文档并使用规则*lds.S -> *lds。

例如: #arch/i386/kernel/Makefile

always := vmlinux.lds

#Makefile

export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)

$(always)赋值语句告诉编译系统编译目标是vmlinux.lds。$(CPPFLAGS_vmlinux.lds)赋

值语句告诉编译系统编译vmlinux.lds目标的编译选项。

编译*.lds时将使用到下面这些变量:

CPPFLAGS : 定义在顶层Makefile

EXTRA_CPPFLAGS : 能够配置在编译的makefile文档中

CPPFLAGS_$(@F) : 目标编译选项。注意要使用文档全名。

--- 6.9 $(CC)支持功能

内核可能会用不同版本的$(CC)进行编译,每个版本有不同的性能和选项,内核编译系统提供基本的支持用于验证$(CC)选项。$(CC)通常是gcc编译器,但其他编译器也是能够。

cc-option cc-option 用于检测$(CC)是否支持给定的选项,假如不支持就使用第二个可选项。

例如: #arch/i386/Makefile

cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) 在上面例子中假如$(CC)支持-march=pentium-mmx则cflags-y等于该值,否则等于

-march-i586。假如没有第二个可选项且第一项不支持则cflags-y没有被赋值。

cc-option-yn cc-option-yn用于检测gcc是否支持给定的选项,支持返回'y'否则'n'。

例如: #arch/ppc/Makefile

biarch := $(call cc-option-yn, -m32)

aflags-$(biarch) += -a32

cflags-$(biarch) += -m32

在上面例子中假如$(CC)支持-m32选项则$(biarch)配置为y。当$(biarch)等于y时,变量$(aflags-y)和$(cflags-y)将分别等于-a32和-m32。

cc-option-align gcc版本>= 3.0用于定义functions、loops等边界对齐选项。

gcc = 3.00

LAMMPS手册-中文版讲解之欧阳家百创编

LAMMPS手册-中文解析 一、 欧阳家百(2021.03.07) 二、简介 本部分大至介绍了LAMMPS的一些功能和缺陷。 1.什么是LAMMPS? LAMMPS是一个经典的分子动力学代码,他可以模拟液体中的粒子,固体和汽体的系综。他可以采用不同的力场和边界条件来模拟全原子,聚合物,生物,金属,粒状和粗料化体系。LAMMPS可以计算的体系小至几个粒子,大到上百万甚至是上亿个粒子。 LAMMPS可以在单个处理器的台式机和笔记本本上运行且有较高的计算效率,但是它是专门为并行计算机设计的。他可以在任何一个按装了C++编译器和MPI的平台上运算,这其中当然包括分布式和共享式并行机和Beowulf型的集群机。 LAMMPS是一可以修改和扩展的计算程序,比如,可以加上一些新的力场,原子模型,边界条件和诊断功能等。 通常意义上来讲,LAMMPS是根据不同的边界条件和初始条件对通过短程和长程力相互作用的分子,原子和宏观粒子集合对它们的牛顿运动方程进行积分。高效率计算的LAMMPS通过采用相邻清单来跟踪他们邻近的粒子。这些清单是根据粒子间的短程互拆力的大小进行优化过的,目的是防止局部粒子密度过高。在

并行机上,LAMMPS采用的是空间分解技术来分配模拟的区域,把整个模拟空间分成较小的三维小空间,其中每一个小空间可以分配在一个处理器上。各个处理器之间相互通信并且存储每一个小空间边界上的”ghost”原子的信息。LAMMPS(并行情况)在模拟3维矩行盒子并且具有近均一密度的体系时效率最高。 2.LAMMPS的功能 总体功能: 可以串行和并行计算 分布式MPI策略 模拟空间的分解并行机制 开源 高移植性C++语言编写 MPI和单处理器串行FFT的可选性(自定义) 可以方便的为之扩展上新特征和功能 只需一个输入脚本就可运行 有定义和使用变量和方程完备语法规则 在运行过程中循环的控制都有严格的规则 只要一个输入脚本试就可以同时实现一个或多个模拟任务 粒子和模拟的类型: (atom style命令) 原子 粗粒化粒子 全原子聚合物,有机分子,蛋白质,DNA

linux驱动的Makefile分析

第6行,判断KERNELRELEASE是否为空,该变量是描述内核版本的字符串。只有执行make命令的当前目录为内核源代码目录时,该变量才不为空字符。 第7、8行定义了KERNELDIR和PWD变量。KERNELDIR是内核路径变量,PWD是由执行pwd命令得到的当前模块路径。 第11行make的语法是”Make –C 内核路径M=模块路径modules”,该语法会执行内核模块的编译 第13行是将模块安装到对应的路径中,当在命令执行make modules_install时,执行该命令,其他时候不执行 第24行,意思是将hello.o编译成hello.ko模块。如果要编译其他模块时,只要将hello.o中的hello改成模块的文件名就可以了 Makefile的执行过程: 执行make命令后,将进入Makefile文件。此时KERNELRELEASE变量为空,此时是第一次进入Makefile文件。当执行完变量赋值代码后,会根据make参数执行不同的逻辑。 如下: make modules_install 命令,将执行13、15行将模块安装到操作系统中。 make clean命令,会删除目录中的所有临时文件。 make命令,会执行10、11行编译模块。首先$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 中的-C $(KERNELDIR)选项,会使编译器进入内核源码目录/home/zzc/linux-2.6.31,读取Makefile文件,从中得到一些信息,例如变量KERNELRELEASE将在这里赋值。当内核源码目录中的Makefile文件读取完成后,编译器会根据选项M=$(PWD)第二次进入模块所在的目录,并再一次执行Makefie文件。当第二次执行Makefile文件时,变量KERNELRELEASE

手动建立makefile简单实例解析

手动建立makefile简单实例解析 假设我们有一个程序由5个文件组成,源代码如下:/*main.c*/ #include "mytool1.h" #include "mytool2.h" int main() { mytool1_print("hello mytool1!"); mytool2_print("hello mytool2!"); return 0; } /*mytool1.c*/ #include "mytool1.h" #include void mytool1_print(char *print_str) { printf("This is mytool1 print : %s ",print_str); } /*mytool1.h*/ #ifndef _MYTOOL_1_H #define _MYTOOL_1_H void mytool1_print(char *print_str); #endif /*mytool2.c*/ #include "mytool2.h" #include void mytool2_print(char *print_str) { printf("This is mytool2 print : %s ",print_str); }

/*mytool2.h*/ #ifndef _MYTOOL_2_H #define _MYTOOL_2_H void mytool2_print(char *print_str); #endif 首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat 9.0的make版本为GNU Make version 3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。 在一个Makefile中通常包含下面内容: 1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。 2、要创建的目标体所依赖的文件(dependency_file)。 3、创建每个目标体时需要运行的命令(command)。 格式如下: target:dependency_files command target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。 dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。 command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。 在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则

Makefile下编写Helloworld的例子

什么是makefile?或许很多Windows的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得 要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专 业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile, 从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中, makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复 杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大的提高了软件 开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如: Delphi的make,VisualC++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 更新版本 hello.c程序 #include int main(){printf("Hello,World!\n");

return 0;}=== makefile开始=== Helloworld: hello.o gcc hello.o–o Helloworld Hello.o: hello.c hello.h gcc–MM hello.c gcc–c hello.c–o hello.o .PHONY: clean Clean: rm–rf*.o hellworld === makefile结束===

LINUX编程 Makefile中的变量详解应用

第六章:Makefile中的变量 -------------------------------------------------------------------------------- 在Makefile中,变量就是一个名字(像是C语言中的宏),代表一个文本字符串(变量的值)。在Makefile的目标、依赖、命令中引用一个变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”)。在Makefile中变量的特征有以下几点: 1. Makefile中变量和函数的展开(除规则的命令行以外),是在make读取makefile文件时进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的。 2. 变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。 3. 变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说不能作为环境变量使用。 4. 变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile 传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。 5. 另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“$<”、“$@”、“$?”、“$*”等。 6.1 变量的引用 当我们定义了一个变量之后,就可以在Makefile的很多地方使用这个变量。变量的引用方式是:使用“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”来引用一个变量的定义。例如:“$(foo) ”或者“${foo}”就是取变量“foo”的值。美元符号“$”在Makefile中有特殊的含义,所有在命令或者文件名中使用“$”时需要用两个美元符号“$$”来表示。对一个变量的引用可以在Makefile的任何上下文中,目标、依赖、命令、绝大多数指示符和新变量的赋值中。这里有一个例子,其中变量保存了所有.o文件的列表: objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects)

MakeFile

MAKE 的使用 当编译单个文件时,使用GCC已经绰绰有余,但对于有几十个甚至上百个源文件的大工程来讲,单纯用GCC命令进行编译肯定就不行了,那样编译一次太麻烦,这就要求有一种自动化的方法,于是在Linux系统中Make工具就诞生了。 1、什么是Make makefile shell 什么是Make,可以将Make理解为一种脚本,这种脚本主要是用于多文件编译,在传统的命令行式编译方式中,如果修改了工程中的某一个头文件,有时候不需要重新编译整个工程,而只需要编译与这个头文件相关联的源文件即可,但如何以手动的方式从一个大工程里将这些文件找出,并手动编译,是件很麻烦的事情。 为了解决这一问题,设计了Make,make程序可以维护具有相互依赖性的源文件,当某些文件发生改变时,它能自动识别出,并只对相应文件进行自动编译。 虽然make工具有很多智能识别机制,但它无法自动了解他所面对的工程源文件的组成以及依赖规则,这些都需要开发人员编写makefile脚本,告诉make工具。MakeFile编写好以后,就可以在每次修改源文件之后,执行make命令就好了。Makefile make 什么又是makefile了,很多windows的程序开发人员都不知道这个东西,因为那些Windows的IDE都为你做了这些工作,但我觉得要作为一个好的和专业的程序员,makefile还是要懂得,这就好像在有这么多的HTML的编辑器,但如果你想成为一个专业人士,就必须了解HTML的标识的含义。特别在Linux下的软件编译,你就必须自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成某个大型大工程的能力。 2、makefile的组成 一个完整的makefile文件通常由五个部分组成: ◆显示规则 显示规则是指主动编写描述规则,用于指示在何种状态下更新哪些目标文件,即编写makefile时需要明确指出各目标文件所依赖的源文件的集合,以及编 译本目标文件所需的命令。 ◆隐含规则 指用make中默认的编译方式进行编译,即make工具可以根据目标文件的类型自动推导出的规则(由于我们的make有自动推导的功能,所以隐晦的规则可以 让我们比较粗糙地简略书写Makefile ,这是由make所支持的) abc.o abc.c cc -o abc.o -c abc.c ◆变量定义 为提升语句的灵活性,在make脚本中可以使用变量,来代表一个字符串,一组编译命令或一组文件名。(在makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点类似于C语言中的宏,当makefile 被执行时,其中的变量都会被扩展到相应的引用位置上) ◆makefile指示符 指示符告诉make工具,当程序在读取makefile文件时要执行的动作。 (文件指示包括三部分,一个是在一个makefile中引用另外一个makefile,就像C语言中的include一样,另一个是指根据某些情况制定MakeFile中的有效部分,就像C 语言中的预编译#if一样,还有就是定义一个多行的命令,)

make_Makefile 结构分析

Makefile结构分析 -----uClinux (2.6.x内核)系统映像过程 刘江欧阳昭暐吕熙隆 1、源代码文件及目录构成 解压缩uClinux-dist-20070130.tar.gz压缩文件,在uClinux-dist原始子目录下主要有:config、Bin、linux-2.4.x、linux-2.6.x 、lib、tools、Include、user和vendors,以及文件Makefile。另外,在编译后生成子目录images和romfs,以及文件autoconfig.h、config.in和两个隐含文件:.config和.depend。 config子目录包含文件及下一级子目录,如 config.in、configure.help、Fixconfig、Makefile、 Mkconfig、Setconfig所有这些文件及子目录 Scripts均与系统配置有关; linux-2.6.x子目录是嵌入式操作系统 uClinux-2.6.x的核心目录,包括下一级子目录 arch、include、init、drivers、fs、ipc、kernel、 lib、Mm、scripts和关键文件Makefile、 rules.make,编译后还要生成新文件romfs.o、linux 和system.map;lib子目录为嵌入式操作系统提供 压缩和改进了的函数库支持;tools子目录包含 romfs-inst.sh文件,通过调用此文件,可以把目录 或文件加入到romfs子目录中;user子目录包含各 种驱动程序文件目录,根据用户的配置情况,不同的 驱动程序会被编译进最后形成的操作系统中; vendors子目录包括与特定硬件平台相关的分类目录 组。目录结构如图1所示。 Makefile的详细介绍情况在 uClinux-dist\linux-2.6.x\Documentation\kbuil d中,如图2所示。图1、目录结构即Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:

通用Makefile模板及实例

1 通用Makefile——1 实现的功能: ?make——编译和连接程序 ?make objs——编译程序,生成目标文件 ?make clean——清除编译产生的目标文件(*.o)和依赖文件(*.d) ?make cleanall——清除目标文件(*.o)、依赖文件(*.d)和可执行文件(*.exe)?make rebuild——重新编译连接程序,相当于make clean && make Usage: Makefile源代码 # Gneric C/C++ Makefile #################################################### PROGRAM := SRCDIRS := SRCEXTS := CPPFLAGS := CFLAGS := CFLAGS += CXXFLAGS := CXXFLAGS += LDFLAGS := LDFLAGS += SHELL = /bin/sh SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS)))) OBJS = $(foreach x,$(SRCEXTS),\ $(patsubst %$(x),%.o,$(filter %$(x),$(SOURCES)))) DEPS = $(patsubst %.o,%.d,$(OBJS)) .PHONY: all objs clean cleanall rebuild all : $(PROGRAM) %.d : %.c @$(CC) -MM -MD $(CFLAGS) {1}lt; %.d : %.C @$(CC) -MM -MD $(CXXFLAGS) {1}lt; objs : $(OBJS) %.o : %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) {1}lt; %.o : %.cpp $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) {1}lt; $(PROGRAM) : $(OBJS) ifeq ($(strip $(SRCEXTS)),.c) $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS)

跟我一起写Makefile(可以注释版)

跟我一起写 Makefile 作者:陈皓 整理:祝冬华

第一部分、概述 (6) 第二部分、关于程序的编译和链接 (6) 第三部分、Makefile 介绍 (7) 一、Makefile的规则 (7) 二、一个示例 (8) 三、make是如何工作的 (9) 四、makefile中使用变量 (10) 五、让make自动推导 (11) 六、另类风格的makefile (12) 七、清空目标文件的规则 (13) 第四部分、Makefile 总述 (13) 一、Makefile里有什么? (13) 1、显式规则。 (14) 2、隐晦规则。 (14) 3、变量的定义。 (14) 4、文件指示。 (14) 5、注释。 (14) 二、Makefile的文件名 (15) 三、引用其它的Makefile (15) 四、环境变量 MAKEFILES (16) 五、make的工作方式 (16) 第五部分、书写规则 (17) 一、规则举例 (17) 二、规则的语法 (17) 三、在规则中使用通配符 (18) 四、文件搜寻 (19) 五、伪目标 (20) 六、多目标 (22) 七、静态模式 (22) 八、自动生成依赖性 (24) 第六部分书写命令 (25) 一、显示命令 (26) 二、命令执行 (26) 三、命令出错 (27) 四、嵌套执行make (28) 五、定义命令包 (30) 第七部分使用变量 (30) 一、变量的基础 (31) 二、变量中的变量 (32) 三、变量高级用法 (34) 四、追加变量值 (37) 五、override 指示符 (37) 六、多行变量 (38)

八、目标变量 (39) 九、模式变量 (40) 第八部分使用条件判断 (40) 一、示例 (40) 二、语法 (42) 第九部分使用函数 (43) 一、函数的调用语法 (44) 二、字符串处理函数 (44) 1、subst (44) 2、patsubst (45) 3、strip (45) 4、findstring (46) 5、filter (46) 6、filter-out (46) 7、sort (47) 8、word (47) 9、wordlist (47) 10、words (47) 11、firstword (48) 12、字符串函数实例 (48) 三、文件名操作函数 (48) 1、dir (48) 2、notdir (48) 3、suffix (49) 4、basename (49) 5、addsuffix (49) 6、addprefix (49) 7、join (50) 四、foreach 函数 (50) 五、if 函数 (50) 六、call函数 (51) 七、origin函数 (51) “undefined” (52) “default” (52) “file” (52) “command line” (52) “override” (52) “automatic” (52) 八、shell函数 (53) 九、控制make的函数 (53) 1、error (53) 2、warning (54) 第十部分 make 的运行 (54)

Makefile 语法分析

Makefile 语法分析第一部分 VERSION = 2 # 给变量VERSION赋值 PATCHLEVEL = 6 # 给变量PATCHLEVEL赋值 SUBLEVEL = 22 # 给变量SUBLEVEL赋值 EXTRAVERSION = .6 # 给变量EXTRAVERSION赋值 NAME = Holy Dancing Manatees, Batman! # 给变量NAME赋值 # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can be located in ./README # Comments in this file are targeted only to the developer, do not # expect to learn how to build the kernel reading this file. # Do not: # o use make's built-in rules and variables # (this increases performance and avoid hard-to-debug behavour); # o print "Entering directory ..."; MAKEFLAGS += -rR --no-print-directory # 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。 # 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”; # 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符;# 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符 # 在执行make时的命令行选项参数被通过变量“MAKEFLAGS”传递给子目录下的make程序。# 对于这个变量除非使用指示符“unexport”对它们进行声明,它们在整个make的执行过程中始终被自动的传递给所有的子make。 # 还有个特殊变量SHELL与MAKEFLAGS一样,默认情况(没有用“unexport”声明)下在整个make的执行过程中被自动的传递给所有的子make。 # # -rR --no-print-directory # -r disable the built-in impilict rules. # -R disable the built-in variable setttings. # --no-print-directory。 # We are using a recursive build, so we need to do a little thinking # to get the ordering right. # # Most importantly: sub-Makefiles should only ever modify files in # their own directory. If in some directory we have a dependency on # a file in another dir (which doesn't happen often, but it's often # unavoidable when linking the built-in.o targets which finally # turn into vmlinux), we will call a sub make in that other dir, and

makefile 中 $@ $^ % 使用

makefile 中$@ $^ %< 使用 https://www.sodocs.net/doc/8014213040.html,/kesaihao862/article/details/7332528 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识。在这篇文章当中,我们将会学到以下内容:源程序编译Makefile的编写程序库的链接程序的调试头文件和系统求助1.源程序的编译在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器。下面我们以一个实例来说明如何使用gcc编译器。假设我们有下面一个非常简单的源程序(hello.c):int main(int argc,char **argv){printf("Hello Linux\n");}要编译这个程序,我们只要在命令行下执行:gcc -o hello hello.cgcc 编译器就会为我们生成一个hello的可执行文件。执行./hello就可以看到程序的输出结果了。命令行中gcc表示我们是用gcc来编译我们的源程序,-o 选项表示我们要求编译器给我们输出的可执行文件名为hello 而hello.c是我们的源程序文件。gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了。-o 选项我们已经知道了,表示我们要求输出的可执行文件名。-c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件。-g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息。知道了这三个选项,我

们就可以编译我们自己所写的简单的源程序了,如果你想要知道更多的选项,可以查看gcc的帮助文档,那里有着许多对其它选项的详细说明。2.Makefile的编写假设我们有下面这样的一个程序,源代码如下:/* main.c */#include "mytool1.h"#include "mytool2.h" int main(int argc,char **argv){mytool1_print("hello");mytool2_print("hello");}/* mytool1.h */ #ifndef _MYTOOL_1_H#define _MYTOOL_1_Hvoid mytool1_print(char *print_str);#endif/* mytool1.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_Hvoid 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.cgcc -c mytool1.cgcc -c mytool2.cgcc -o main main.o mytool1.o mytool2.o这样的话我们也可以产生main程序,而且也不时很麻烦。但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)那么我们难道还要重新输入上面的命令?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了。是的对于这个程序来说,是可

Makefile超强经典教程

Makefile经典教程 0 Makefile概述 (2) 0.1关于程序的编译和链接 (2) 1 Makefile介绍 (3) 1.1 Makefile的规则 (4) 1.2一个示例 (4) 1.3 make是如何工作的 (6) 1.4 makefile中使用变量 (7) 1.5让make自动推导 (8) 1.6另类风格的makefile (9) 1.7清空目标文件的规则 (10) 2 Makefile总述 (11) 2.1 Makefile里有什么? (11) 2.2Makefile的文件名 (12) 2.3引用其它的Makefile (12) 2.4环境变量MAKEFILES (13) 2.5 make的工作方式 (13) 3 Makefile书写规则 (14) 3.1规则举例 (14) 3.2规则的语法 (14) 3.3在规则中使用通配符 (15) 3.4文件搜寻 (16) 3.5伪目标 (17) 3.6多目标 (19) 3.7静态模式 (20) 3.8自动生成依赖性 (22) 4 Makefile书写命令 (24) 4.1显示命令 (24) 4.2命令执行 (25) 4.3命令出错 (25) 4.4嵌套执行make (26) 4.5定义命令包 (29) 1

0 Makefile概述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。 在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。 0.1关于程序的编译和链接 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是.obj 文件,UNIX

自动生成Makefile详解

autoconf 和automake生成Makefile文件 本文介绍了在linux 系统中,通过Gnu autoconf 和automake 生成Makefile 的方法。主要探讨了生成Makefile 的来龙去脉及其机理,接着详细介绍了配置Configure.in 的方法及其规则。 引子 无论是在Linux还是在Unix环境中,make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件,我们都经常要用到make或make install。利用make工具,我们可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的应用程序,使用make和makefile工具就可以轻而易举的理顺各个源文件之间纷繁复杂的相互关系。 但是如果通过查阅make的帮助文档来手工编写Makefile,对任何程序员都是一场挑战。幸而有GNU 提供的Autoconf及Automake这两套工具使得编写makefile不再是一个难题。 本文将介绍如何利用GNU Autoconf 及Automake 这两套工具来协助我们自动产生Makefile文件,并且让开发出来的软件可以像大多数源码包那样,只需"./configure", "make","make install" 就可以把程序安装到系统中。 模拟需求 假设源文件按如下目录存放,如图1所示,运用autoconf和automake生成makefile文件。图1文件目录结构 假设src是我们源文件目录,include目录存放其他库的头文件,lib目录存放用到的库文件,然后开始按模块存放,每个模块都有一个对应的目录,模块下再分子模块,如apple、orange。每个子目录下又分core,include,shell三个目录,其中core和shell目录存放.c文件,include的存放.h文件,其他类似。 样例程序功能:基于多线程的数据读写保护(联系作者获取整个autoconf和automake

实例—使用make及Makefile文件

2.3 实例—使用make及Makefile文件 一个工程有3个头文件(head1.h、head2.h、exam2.h)和8个C文件(main.c、exam1.c、exam2.c、exam3.c、exam4.c、exam5.c、exam6.c、exam7.c),建立一个Makefile文件(文件名为makefile),内容如下。注意,上述12个文件位于同一个目录中。 example : main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o gcc -o example main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o main.o : main.c head1.h gcc -c main.c exam1.o : exam1.c head1.h exam2.h gcc -c exam1.c exam2.o : exam2.c head1.h exam2.h gcc -c exam2.c exam3.o : exam3.c head1.h head2.h gcc -c exam3.c exam4.o : exam4.c head1.h head2.h gcc -c exam4.c exam5.o : exam5.c head1.h head2.h gcc -c exam5.c exam6.o : exam6.c head1.h head2.h exam2.h gcc -c exam6.c exam7.o : exam7.c head1.h gcc -c exam7.c clean : rm example main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o makefile文件告诉make命令如何编译和链接这几个文件。在当前路径下执行make命令,就可以生成可执行文件example。如果要删除可执行文件和所有的中间目标文件,只需执行make clean命令即可。 Makefile文件的操作规则是: ①如果该工程没有编译过,所有C文件都要编译并被链接。 ②如果该工程的某几个C文件被修改,只需编译被修改的C文件,并链接目标程序。 ③如果该工程的头文件被改变,需要编译包含这些头文件的C文件,并链接目标程序。 在这个Makefile文件中,目标文件(target)有:执行文件example和中间目标文件(*.o);依赖文件(prerequisites)有:冒号后面的.c文件和.h文件。 每一个.o文件都有一组依赖文件,而这些.o文件又是执行文件example的依赖文件。依赖关系是指目标文件由哪些文件生成。在定义好依赖关系后,规则命令定义了如何生成目标文件,其一定要以一个Tab键打头。 make会比较targets文件和prerequisites文件的时间戳,如果prerequisites文件的日期比targets文件的日期要新,或者target不存在,make就会执行相应的规则命令。 默认方式下,执行make命令时,make会在当前目录下找Makefile,如果找到,make 会找文件中的第一个目标文件(target),上面的例子是example文件,并把这个文件作为最终的目标文件。如果example文件不存在,或example所依赖的.o文件的修改时间比example 文件新,make就会执行相应的规则命令生成example文件。如果example所依赖的.o文件不存在,make会在当前目录中找目标为.o文件的依赖文件(C文件和H文件),如果找到,则根据规则生成.o文件,然后再用.o文件生成make的最终结果,也就是可执行文件example。 有上可知,make会一层一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在寻找的过程中,如果出现错误(比如被依赖的文件找不到)make就会直接退出,并报错。 clean不是一个文件,只是一个动作名字,类似于C语言中的lable,冒号后什么也没有,这样make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的规则命令。要执行其后的命令,就要在make命令后显式的指出这个lable的名字,例如执行make clean命令。

openwrt顶层Makefile分析

openwrt 这里主要介绍openwrt的主Makefile,并未对各个目录下的Makefile和相关文件进行介绍。 在Makefile里是两个主要的分支,由if语句根据OPENWRT_BUILD的值进行不同的处理。第一个部分主要是执行编译前的准备,第二个部分是执行编译。 打开Makefile文件,可以看到默认的make目标world,这个目标没有依赖文件和执行命令。 执行make的时候,首先进入第一个部分,此时OPENWRT_BUILD的值为0,然后将OPENWRT_BUILD的值赋为1,在这里用到了override指示符,override指示符的作用的忽略make命令行的参数的赋值,可以对该变量进行赋值。 载入include下的相关文件,在toplevel.mk可以看到 %:: @+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq @+$(SUBMAKE) -r $@ 默认的目标就会执行这里。 在toplevel.mk的顶部定义了PREP_MK= OPENWRT_BUILD= QUIET=0,将OPENWRT_BUILD的值赋为0。 在执行@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq命令的时候,在make命令行里有$(PREP_MK)变量,而由于OPENWRT_BUILD的值为0,在verbose.mk文件里NO_TRACE_MAKE := $(MAKE) V=99,所以会执行顶层 目录的Makefile第一个分支部分的目标prereq,即toplevel.mk文件中的目标prereq: prereq:: prepare-tmpinfo .config @+$(MAKE) -r -s tmp/.prereq-build $(PREP_MK) @+$(NO_TRACE_MAKE) -r -s $@ 这里会进行一些编译前的准备工作,然后执行@+$(NO_TRACE_MAKE) -r -s $@,再次去执行顶层Makefile,此时,并没有$(PREP_MK)变量,所以会执行顶层Makefile的第一个部分,载入include下的相关文件,和一些必要的Makefile文件,在顶层Makefile去寻找prereq目标, prereq: $(target/stamp-prereq) tmp/.prereq_packages 处理它的依赖文件。 然后再接着执行toplevel.mk %:: @+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq @+$(SUBMAKE) -r $@ 在@+$(SUBMAKE) -r $@命令中也没有$(PREP_MK)变量,所以在顶层Makefile的第二个部分,寻找Makefile的默认目标,即world。 world: prepare $(target/stamp-compile) $(package/stamp-cleanup) $(package/stamp-compile) $(package/stamp-install) $(package/stamp-rootfs-prepare) $(target/stamp-install) FORCE $(_SINGLE)$(SUBMAKE) -r package/index 根据各个依赖文件进行相应的编译,最终完成编译。 在顶层Makefile里比较麻烦的是,将Makefile分为了两个主要分支,在每个分支里通过include载入相应的文件,在这些文件里包含相应的目标执行命令,在命令中多次用make + 目标+ 参数的方式,则会再次执行Makefile文件,就形成了Makefile的嵌套执行。

相关主题