文档库 最新最全的文档下载
当前位置:文档库 › makefile文件编写介绍

makefile文件编写介绍

makefile文件编写介绍
makefile文件编写介绍

文档简要整理Android的make脚本的内容。以供备忘和参考。

1. Build Layers

Build Layers描述的是产品的硬件配置情况,据此make时选择不同的配置和模块。按照从上到下的顺序,Build Layer分成4层。

Layer sample Note

Arch arm, x86 处理器的种类

Board -板子类型的代号

Device - device配置的类型代号

Product -具体产品的代号

2. 添加应用

2.1 一个例子

以calculator为例,app代码可以放到packages/apps/目录下边,一个app对应一个目录,此例,pakcages/apps/Calculator/。创建Android.mk,已去除多余的注释行。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_JAVA_LIBRARIES := libarity

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_SDK_VERSION := current

LOCAL_PACKAGE_NAME := Calculator

include $(BUILD_PACKAGE)

include $(CLEAR_VARS)

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := libarity:arity-2.1.2.jar

include $(BUILD_MULTI_PREBUILT)

# Use the folloing include to make our test apk.

include $(call all-makefiles-under,$(LOCAL_PATH))

至少有一个子目录,src下放源码。

Android.mk中需要赋值的几个LOCAL_XXX变量,

LOCAL_PATH,调用my-dir(在defination.mk中定义),得到当前路径,即,/ pakcages/apps/Calculator/。

LOCAL_MODULE_TAGS,,取值范围debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要预装,则应定义core.mk。

LOCAL_SRC_FILES,app的所有源码,可以调用all-java-files-under得到,如果是java源码的话。

LOCAL_PACKAGE_NAME,package的名字,这个名字在脚本中将标识这个app或package。$(CLEAR_VARS)指的是clear_vars.mk,脚本会清空所有LOCAL_xxx的变量,不影响后面这些变量的使用。

$(BUILD_PACKAGE)指的是package.mk

最后一句all-makefiles-under将会包含当前目录下所有的mk脚本文件。

2.2 LOCAL_XXX的列表

说明:

必须定义, 在app或package的Android.mk中必须给定值。

可选定义,在app或package的Android.mk中可以也可以不给定值。

不用定义,在app或package的Android.mk中不要给定值,脚本自动指定值。

LOCAL_PATH,当前路径,必须定义。

LOCAL_PACKAGE_NAME,必须定义,package的名字,这个名字在脚本中将标识app或package。

LOCAL_MODULE_SUFFIX,不用定义,module的后缀,=.apk。

LOCAL_MODULE,不用定义,=$(LOCAL_PACKAGE_NAME)。

LOCAL_JAVA_RESOURCE_DIRS,不用定义。

LOCAL_JAVA_RESOURCE_FILES,不用定义。

LOCAL_MODULE_CLASS,不用定义。

LOCAL_MODULE_TAGS,可选定义。默认optional。取值范围user debug eng tests optional samples shell_ash shell_mksh。

LOCAL_ASSET_DIR,可选定义,推荐不定义。默认$(LOCAL_PATH)/assets

LOCAL_RESOURCE_DIR,可选定义,推荐不定义。默认product package和device package 相应的res路径和$(LOCAL_PATH)/res。

LOCAL_PROGUARD_ENABLED,可选定义,默认为full,如果是user或userdebug。取值full, disabled, custom。

full_android_manifest,不用定义,=$(LOCAL_PATH)/AndroidManifest.xml。LOCAL_EXPORT_PACKAGE_RESOURCES,可选定义,默认null。如果允许app的资源被其它模块使用,则设置true。

LOCAL_CERTIFICATE,可选定义,默认为testkey。最终

private_key := $(LOCAL_CERTIFICATE).pk8

certificate := $(LOCAL_CERTIFICATE).x509.pem

2.3 mm创建apk时的package.mk中变量分析

以Calculator为例,

由LOCAL_PATH,LOCAL_PACKAGE_NAME导出变量LOCAL_MODULE,all_assets,all_assets,all_resources。

设置LOCAL_MODULE_CLASS=APPS,此值local-intermediates-dir会用到。

设置中间生成目录路径,中间路径将放置R.stamp文件。

package_expected_intermediates_COMMON := $(call local-intermediates-dir,COMMON) 这里COMMON是null,而LOCAL_MODULE_CLASS=APPS,所以

package_expected_intermediates_COMMON=out/target/common/obj/$(LOCAL_MODULE_CLASS )/$(LOCAL_MODULE)_intermediates

package_expected_intermediates_COMMON=out/target/common/obj/APPS/Calculator_inte

rmediates

设置

LOCAL_BUILT_MODULE_STEM := package.apk

LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM) @base_rules.mk

built_module_path := $(intermediates) @base_rules.mk

intermediates := $(call local-intermediates-dir) @java.mk

最终

LOCAL_BUILT_MODULE=out/target/product//obj/$(LOCAL_MODULE_CLASS)/$(LOCA

L_MODULE)_intermediates/$(LOCAL_BUILT_MODULE_STEM)

LOCAL_BUILT_MODULE=out/target/product/generic/obj/APPS/Calculator_intermediates/ package.apk

由LOCAL_CERTIFICATE导出

private_key := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).pk8 certificate := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).x509.pem LOCAL_CERTIFICATE默认为testkey。

2.4 package.mk中定义的几个PACKAGE.xxx变量

PACKAGES.$(LOCAL_PACKAGE_NAME).PRIVATE_KEY := $(private_key)

PACKAGES.$(LOCAL_PACKAGE_NAME).CERTIFICATE := $(certificate)

PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES)) PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES := $(all_resources)

PACKAGES := $(PACKAGES) $(LOCAL_PACKAGE_NAME)

全编译时,PACKAGES变量将会记录遍历到的packages。

Android Make脚本的简记(2)

内容提要

文档简要整理Android的make脚本的内容。以供备忘和参考。

1. java.mk分析

选取APPS场景,以Calculator为例说明。

LOCAL_JAVA_LIBRARIES=true时,Android.mk中不能定义LOCAL_SDK_VERSION。

当LOCAL_SDK_VERSION=current时,LOCAL_JAVA_LIBRARIES=android_stubs_current。

package.mk中定义LOCAL_BUILT_MODULE_STEM=package.apk。

两个中间目录的路径,即对应的obj目录下APPS/_intermediates/。intermediates=out/target/product/generic/obj/APPS/Calculator_intermediates https://www.wendangku.net/doc/972267082.html,MON=out/target/common/obj/APPS/Calculator_intermediates

LOCAL_INTERMEDIATE_TARGETS先前package.mk中已经定义了R.stamp,java.mk有增添了7

个。

LOCAL_INTERMEDIATE_TARGETS += /

$(full_classes_jar) /

$(full_classes_compiled_jar) /

$(full_classes_emma_jar) /

$(full_classes_full_names_jar) /

$(full_classes_stubs_jar) /

$(full_classes_jarjar_jar) /

$(built_dex)

此例中,具体值是

LOCAL_INTERMEDIATE_TARGETS=

out/target/common/obj/APPS/Calculator_intermediates/src/R.stamp

@defined in package.mk

out/target/common/obj/APPS/Calculator_intermediates/classes.jar

@full_classes_jar

out/target/common/obj/APPS/Calculator_intermediates/classes-full-debug.jar @full_classes_compiled_jar

out/target/common/obj/APPS/Calculator_intermediates/emma_out/lib/classes-full-de

bug.jar @full_classes_emma_jar

out/target/common/obj/APPS/Calculator_intermediates/classes-full-names.jar

@full_classes_full_names_jar

out/target/common/obj/APPS/Calculator_intermediates/stubs.jar

@full_classes_stubs_jar

out/target/common/obj/APPS/Calculator_intermediates/classes-jarjar.jar

@full_classes_jarjar_jar

out/target/common/obj/APPS/Calculator_intermediates/classes.dex

@built_dex

java.mk随后include base_rules.mk

后面处理了EMMA,PROGUARD在enable/disable情况下的动作

最后定义的target, $(LOCAL_MODULE)-findbugs因为prebuilt/common下还没有findbugs,

目前不可用。

java.mk还定义了几个特别的变量,

ALL_MODULES.$(LOCAL_MODULE).PROGUARD_ENABLED:=$(LOCAL_PROGUARD_ENABLED)

ALL_MODULES.$(LOCAL_MODULE).CHECKED := $(full_classes_compiled_jar)

ALL_MODULES.$(LOCAL_MODULE).STUBS := $(full_classes_stubs_jar)

2. base_rules.mk的分析

续1的场景。

提取变量my_prefix:=TARGET_

LOCAL_MODULE_TAGS在Android.mk或package.mk中已经设定,默认是optional。

确认LOCAL_MODULE_PATH,默认$($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),此例中是out/target/product/generic/system/app

设定module_id := MODULE.$(TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE),此例MODULE.TARGET.APPS.Calculator。

设定中间目录路径intermediates,https://www.wendangku.net/doc/972267082.html,MON,参见1.

设定LOCAL_MODULE_STEM=$(LOCAL_MODULE),此例,Calculator。LOCAL_INSTALLED_MODULE_STEM=Calculator.apk。

LOCAL_INTERMEDIATE_TARGETS追加上package.apk,参见1.

处理aidl,转为java,放在https://www.wendangku.net/doc/972267082.html,MON下的目录中。

处理logtag,转为java,放在https://www.wendangku.net/doc/972267082.html,MON下的目录中。

确定java_sources,这包括android.mk中包含的,aidl和logtag生成的。

处理java_resource_files

处理了java lib相关

定义clean-$(LOCAL_MODULE) target, 可以删除app/package的生成文件,包括$(PRIVATE_CLEAN_FILES),$(LOCAL_BUILT_MODULE),$(LOCAL_INSTALLED_MODULE),$(intermediates),$(https://www.wendangku.net/doc/972267082.html,MON)

还定义了$(LOCAL_MODULE) target, 几个变量的值

LOCAL_MODULE=Calculator

LOCAL_BUILT_MODULE=out/target/product/generic/obj/APPS/Calculator_intermediates/ package.apk

LOCAL_INSTALLED_MODULE=out/target/product/generic/system/app/Calculator.apk

最后定义了几个ALL_MODULES变量。

ALL_MODULES.$(LOCAL_MODULE).CLASS

ALL_MODULES.$(LOCAL_MODULE).PATH

ALL_MODULES.$(LOCAL_MODULE).TAGS

ALL_MODULES.$(LOCAL_MODULE).CHECKED

ALL_MODULES.$(LOCAL_MODULE).BUILT

ALL_MODULES.$(LOCAL_MODULE).INSTALLED

ALL_MODULES.$(LOCAL_MODULE).REQUIRED

ALL_MODULES.$(LOCAL_MODULE).EVENT_LOG_TAGS

3. multi_prebuilt.mk的分析

续1的场景。

mulit_prebuilt.mk顾名思义就是多次调用prebuilt.mk,对几种明确的prebuilt library 完成需要的copy操作。

multi_prebuilt.mk定义了命令auto-prebuilt-boilerplate。入口有6个参数

# $(1): file list, ":"

# $(2): IS_HOST_MODULE

# $(3): MODULE_CLASS

# $(4): OVERRIDE_BUILT_MODULE_PATH

# $(5): UNINSTALLABLE_MODULE

# $(6): BUILT_MODULE_STEM

根据这6个参数,命令确定

LOCAL_IS_HOST_MODULE

LOCAL_MODULE_CLASS

OVERRIDE_BUILT_MODULE_PATH

LOCAL_UNINSTALLABLE_MODULE

LOCAL_MODULE

LOCAL_SRC_FILES

LOCAL_BUILT_MODULE_STEM

LOCAL_MODULE_SUFFIX

并调用prebuilt.mk

multi_prebuilt.mk中分别对下面5中lib调用了auto-prebuilt-boilerplate。

prebuilt_static_libs := $(filter %.a,$(LOCAL_PREBUILT_LIBS))

prebuilt_shared_libs := $(filter-out %.a,$(LOCAL_PREBUILT_LIBS))

prebuilt_executables := $(LOCAL_PREBUILT_EXECUTABLES)

prebuilt_java_libraries := $(LOCAL_PREBUILT_JAVA_LIBRARIES)

prebuilt_static_java_libraries := $(LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES)

4. prebuilt.mk的分析

续1的场景。

首先,include base_rules.mk

定义

PACKAGES.$(LOCAL_MODULE).OVERRIDES

第二步,如果是APPS类型,则zipalign,并拷贝到中间路径$(intermediates)。不是APPS,则不做zipalign。

本例是JAVA_LIBRARY类型,目的路径out/target/common/obj/JAVA_LIBRARIES/libarity_intermediates/javalib.jar,注意其中的libarity和javalib.jar。

最后检查 signed情况。

Android101110: Android Make脚本的简记(3)

内容提要

文档简要整理Android的make脚本的内容。以供备忘和参考。

1. findleaves.py的分析

main.mk中调用了findleaves.py,得到所有子目录下Android.mk文件的路径。

subdir_makefiles := /

$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)

$(subdirs)一般编译中取值$(TOP)。

使用方法,

Usage: %(progName)s []

Options:

--mindepth=

Both behave in the same way as their find(1) equivalents.

--prune=

Avoids returning results from inside any directory called

(e.g., "*/out/*"). May be used multiple times.

程序首先依次选取dirlist中的目录,然后遍历所有子目录查找Android.mk文件,如果有,则加入到返回列表中。

2. pathmap.mk的分析

pathmap.mk 中定义了一个列表pathmap_INCL,列表中每项是"短名:路径"对。命令

include-path-for使用这个pathmap_INCL列表,输入短名,得到路径。你可以在这个列表中添加自己的对。使用$(call include-path-for, <短名>)就可以得到路径。

另外,定义了FRAMEWORKS_BASE_JAVA_SRC_DIRS,含有frameworks/base目录下含java文件的所有目录。

3. config.mk的分析

首先,包含pathmap.mk,其次,定义了一些变量,例如通用的编译参数,package的后缀名等。

随后包含buildspec.mk。

接着包含envsetup.mk。

然后包含$(board_config_mk)。$(board_config_mk)是位于build/target/board /$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor/*/$(TARGET_DEVICE) /目录下的BoardConfig.mk文件。

-------TODO

4. buildspec.mk的分析

buildspec.mk是用户应当配置的脚本文件,模板可以使用buildspec.mk.default,放到$(TOP)下。

在buildspec.mk中,用户应该配置好主要的参数,例如TARGET_PRODUCT,TARGET_BUILD_VARIANT, CUSTOM_MODULES, TARGET_SIMULATOR, TARGET_BUILD_TYPE,CUSTOM_LOCALES,和BUILD_ENV_SEQUENCE_NUMBER等。

如果不使用buildspec.mk配置参数,也可以使用环境变量的形式。若不配置参数,那么android会使用默认的参数。

5. envsetup.mk的分析

首先包含进version_defaults.mk,定义好一些版本相关的变量。参见version_defaults.mk。

定义CORRECT_BUILD_ENV_SEQUENCE_NUMBER,这个数字用于buildspec.mk更新时的提醒,应该同buildspec.mk中的或环境变量中的BUILD_ENV_SEQUENCE_NUMBER相等。一般不用关注。

随后检查TARGET_PRODUCT,若为空,则置generic。TARGET_PRODUCT应当在buildspec.mk 或环境变量中已经定义好。

再检查TARGET_BUILD_VARIANT,若为空,则置eng。TARGET_BUILD_VARIANT应当在buildspec.mk或环境变量中已经定义好。

然后包含进product_config.mk。

接着,检查$(TARGET_BUILD_VARIANT),取值范围是eng user userdebug tests。

随后判定HOST_OS(linux),HOST_ARCH(x86)

接着,确定TARGET_ARCH和TARGET_OS,若没有定义,则取默认值。

TARGET_ARCH := arm

TARGET_OS := linux

接着,确定TARGET_BUILD_TYPE,若没有定义,则取默认值。

TARGET_BUILD_TYPE := release

接着,确定OUT_DIR。OUT_DIR是存放中间文件和最终结果的地方。若没有定义,则取默认值。OUT_DIR := $(TOPDIR)out

随后,定义了一些列的路径变量

DEBUG_OUT_DIR,TARGET_OUT_ROOT_release,TARGET_OUT_ROOT_debug,TARGET_OUT_ROOT,BUILD_OUT,PRODUCT_OUT,TARGET_COMMON_OUT_ROOT,等等。

6. version_defaults.mk的分析

version_defaults.mk是检查一些跟版本相关的变量是否定义,如果未定义,则使用默认值。这些变量包括

PLATFORM_VERSION,默认AOSP

PLATFORM_SDK_VERSION,默认8

PLATFORM_VERSION_CODENAME,默认AOSP

DEFAULT_APP_TARGET_SDK,默认AOSP

BUILD_ID,默认UNKNOWN

BUILD_NUMBER,默认eng.$(USER).$(shell date +%Y%m%d.%H%M%S)的形式。

version_defaults.mk首先包含进build_id.mk。用户应当配置build_id.mk,而不应该改动version_defaults.mk文件。

然后检查上述变量,如未定义则赋值默认值。

7. build_id.mk的分析

用户可以在build_id.mk中定义这样几个参数,

PLATFORM_VERSION

PLATFORM_SDK_VERSION

PLATFORM_VERSION_CODENAME

DEFAULT_APP_TARGET_SDK

BUILD_ID

BUILD_NUMBER

这些参数最终将出现build.prop中。

Froyo的build_id.mk中定义了2个变量,

BUILD_ID,通常用于说明分支branch的,默认的是OPENMASTER,用户应该配置这个参数。DISPLAY_BUILD_NUMBER,在TARGET_BUILD_VARIANT=user的版本中,build.prop中是ro.build.id是显示成$(BUILD_ID).$(BUILD_NUMBER),还是显示成$(BUILD_ID)形式。设成true,则显示前者。

8. product_config.mk的分析

make PRODUCT--

如果使用上述形式的make命令,那么将等同于

TARGET_PRODUCT:=

TARGET_BUILD_VARIANT:=

goal_name:=PRODUCT--

MAKECMDGOALS:=droid

.PHONY: $(goal_name)

$(goal_name): $(MAKECMDGOALS)

endif

注意,goal的取值范围是user userdebug eng tests,如果不属于上述范围,则将算入MAKECMDGOALS中,此时, TARGET_BUILD_VARIANT := eng。例如

make PRODUCT-dream-installclean

等同于

TARGET_PRODUCT=dream make installclean

使用make PRODUCT--这种形式,可以方便的指定TARGET_PRODUCT,和TARGET_BUILD_VARIANT。

make APP-

如果使用上述形式的make命令,那么将等同于

TARGET_BUILD_APPS:=

unbundled_goals:=APP-

MAKECMDGOALS:=droid

.PHONY: $(unbundled_goals)

$(unbundled_goals): $(MAKECMDGOALS)

使用make APP-这种形式,可以方便的指定TARGET_BUILD_APPS。

注意,PRODUCT--和APP-可以一块使用。

处理完PRODUCT--和APP-,product_config.mk会包含下面3个文件

node_fns.mk

product.mk

device.mk

上面的3个mk文件定义了一些命令,用于搜寻product, device对应的目录,生成相应的PRODUCT.XXX,和DEVICE.XXX变量。

接着,使用$(call import-products, $(get-all-product-makefiles))遍历Prodcut相关的AndroidProducts.mk文件,读入PRODCUTS.xxx变量。可以去掉文件中下面两句话的注释符,查看。

#$(dump-products)

#$(error done)

随后,使用PRODCUT.xxx和TARGET_PRODUCT,得到INTERNAL_PRODUCT信息,即指定product 的路径。

再由INTERNAL_PRODUCT得到TARGET_DEVICE,PRODUCT_LOCALES,PRODUCT_BRAND,PRODUCT_MODEL,PRODUCT_MANUFACTURER,PRODUCT_DEFAULT_WIFI_CHANNELS,PRODUCT_POLICY,PRODUCT_COPY_FILES,PRODUCT_PROPERTY_OVERRIDES,PRODUCT_PACKAGE_OVERLAYS,DEVICE_PACKAGE_OVERLAYS,PRODUCT_TAGS,PRODUCT_OTA_PUBLIC_KEYS。

由PRODUCT_LOCALES导出PRODUCT_AAPT_CONFIG。

ADDITIONAL_BUILD_PROPERTIES中追加PRODUCT_PROPERTY_OVERRIDES中的值。

上面所说的这些值,实际上都是在product的mk文件中定义。

9. node_fns.mk的分析

定义了一些命令。这些命令在product.mk,device.mk,和product_config.mk中会使用。这里重点说明import-nodes。

import-nodes需要3个入口参数:

$(1)是一个字串,是输出变量的主干名。例如”PRODUCTS"和”DEVICES“。

$(2)是一个makefile文件列表,这些文件中应该含有对$(3)中变量的定义。

$(3)是一个变量列表。

import- nodes会创建这样形式的变量,以$(1)="PRODUCTS", $(2)中含有"build/target/product/core.mk", $(3)中含有"PRODUCT_NAME", 而且core.mk中定义了PRODUCT_NAME:=core为例,

PRODUCT.build/target/product/core.mk.PRODUCT_NAME:=core

import- nodes中还考虑了inherit的问题,如果某个PRODUCTS.XXX变量的值中有‘@inherit:’标识后面跟着 mk文件名的字串,则会把那个mk文件中相应的变量的属性添加到PRODUCTS.XXX中。'@inherit:'是 inherit-product命令添加的。参见product.mk。

在product_config.mk中会说明$(2)中的mk文件列表是AndroidProducts.mk中的PRODUCT_MAKEFILES定义的。

node_fns.mk的代码真的很杀伤脑细胞...

10. product.mk的分析

product.mk构造了一些命令,供product_config.mk中使用。

_find-android-products-files这个命令会得到device/和vendor/, 包括子目录,以及build/target/product/下的AndroidProducts.mk文件列表。

get-all-product-makefiles这个命令会得到所有$(_find-android-products-files)的AndroidProducts.mk文件中PRODUCT_MAKEFILES变量定义的mk文件。

_product_var_list对应的是import-nodes命令的$(3), 定义了会生成那些PRODUCT属性名的变量。这些变量实际也是在product的mk文件中要考虑定义的。

_product_var_list := /

PRODUCT_NAME /

PRODUCT_MODEL /

PRODUCT_LOCALES /

PRODUCT_PACKAGES /

PRODUCT_DEVICE /

PRODUCT_MANUFACTURER /

PRODUCT_BRAND /

PRODUCT_PROPERTY_OVERRIDES /

PRODUCT_COPY_FILES /

PRODUCT_OTA_PUBLIC_KEYS /

PRODUCT_POLICY /

PRODUCT_PACKAGE_OVERLAYS /

DEVICE_PACKAGE_OVERLAYS /

PRODUCT_CONTRIBUTORS_FILE /

PRODUCT_TAGS /

PRODUCT_SDK_ADDON_NAME /

PRODUCT_SDK_ADDON_COPY_FILES /

PRODUCT_SDK_ADDON_COPY_MODULES /

PRODUCT_SDK_ADDON_DOC_MODULE /

PRODUCT_DEFAULT_WIFI_CHANNELS

import-products会调用import-nodes。product_config.mk中用到。

define import-products

$(call import-nodes,PRODUCTS,$(1),$(_product_var_list))

endef

inherit-product命令则将在所有的PRODUCT.xxx变量值中后缀上'@inherit:',当import-nodes处理时,会替换成继承的属性。

check-all-products命令借助$(PRODUCTS)诸变量,会对product进行唯一性检查和PRODUCT_NAME,PRODUCT_BRAND,PRODCUT_COPY_FILES的简单检查。

resolve-short-product-name命令,给定Product的短名,返回对应mk的路径。

11. device.mk的分析

同product.mk类似,device.mk构造了一些命令。有resolve-short-device-name,和import-devices。

Android Make脚本的简记(4)

内容提要

文档简要整理Android的make脚本的内容。以供备忘和参考。

1. config.mk的分析

首先,包含pathmap.mk,其次,定义了一些变量,例如通用的编译参数,package的后缀名等。

随后包含buildspec.mk。

接着包含envsetup.mk。envsetup.mk中会遍历所有product相关的路径,载入所有支持的product的信息到变量集 PRODUCT..中,一个product对应一个。最后根据TARGET_PRODUCT的值,定义各种跟product相关的变量,包括 TARGET_DEVICE变量。

然后包含$(board_config_mk)。$(board_config_mk)是位于build/target/board/$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor /*/$(TARGET_DEVICE)/目录下的BoardConfig.mk文件。$(TARGET_DEVICE)已经在product_config.mk中定义了。在包含$(board_config_mk)之前,会做检查,多个$(board_config_mk)存在则报错。

定义TARGET_DEVICE_DIR,TARGET_BOOTLOADER_BOARD_NAME,TARGET_CPU_ABI等跟board相关的变量。

接着,依次以HOST_和TARGET_条件包含select.mk。这里说明TARGET_的select.mk。先定义combo_os_arch,通常是linux-arm,然后定义各种跟编译链接相关的一些变量,最后再包含进build/core/combo/TARGET_linux- arm.mk。

再包含javac.mk,定义javac的命令和通用参数。

随后,定义一些变量,指向通用工具,其中一些是os提供的,例如YACC;一些是froyo编译生成,放在out/host/linux-x86/bin/下,一些是预定义的脚本和工具,例如MKTARBALL。

最后定义了一些编译链接变量,这里专门列出,

HOST_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)

HOST_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)

HOST_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)

HOST_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)

TARGET_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)

TARGET_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)

TARGET_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)

TARGET_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)

HOST_GLOBAL_LD_DIRS += -L$(HOST_OUT_INTERMEDIATE_LIBRARIES)

TARGET_GLOBAL_LD_DIRS += -L$(TARGET_OUT_INTERMEDIATE_LIBRARIES)

HOST_PROJECT_INCLUDES:= $(SRC_HEADERS) $(SRC_HOST_HEADERS) $(HOST_OUT_HEADERS) TARGET_PROJECT_INCLUDES:= $(SRC_HEADERS) $(TARGET_OUT_HEADERS)

ifneq ($(TARGET_SIMULATOR),true)

TARGET_GLOBAL_CFLAGS += $(TARGET_ERROR_FLAGS)

TARGET_GLOBAL_CPPFLAGS += $(TARGET_ERROR_FLAGS)

endif

HOST_GLOBAL_CFLAGS += $(HOST_RELEASE_CFLAGS)

HOST_GLOBAL_CPPFLAGS += $(HOST_RELEASE_CPPFLAGS)

TARGET_GLOBAL_CFLAGS += $(TARGET_RELEASE_CFLAGS)

TARGET_GLOBAL_CPPFLAGS += $(TARGET_RELEASE_CPPFLAGS)

其中的TARGET_PROJECT_INCLUDES包含了SRC_HEADERS,添加头文件路径的话,可以改动SRC_HEADERS。

最后包含进dumpvar.mk

2. javac.mk的分析

javac.mk中会定义javac的编译命令和通用参数。

CUSTOM_JAVA_COMPILER做为javac.mk的入口参数,可以考虑openjdk,eclipse。不定义时则使用默认的javac。另外定义为openjdk时,因为prebuilt/对应目录下没有相应的工具,所以还不可用。

依次一般忽略定义CUSTOM_JAVA_COMPILER,只要直接配置自己编译环境的path,指向使用的javac就可以了。

javac在linux平台的定义是

javac -J-Xmx512M -target 1.5 -Xmaxerrs 9999999

-J-Xmx512M,传递给vm launcher参数-Xmx512M,告知起始空间设定为512M。

-target 1.5,编译的结果适用1.5版本。

-Xmaxerrs 9999999,最大输出的错误数是9999999。

3. dumpvar.mk的分析

dumpvar.mk 支持两种target: dumpvar-,和dumpvar-abs-。envsetup.sh 中的 get_build_var和get_abs_build_var就使用了这些target。

使用方法:假设位于$(TOPDIR)路径,

CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f build/core/config.mk dumpvar-

CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f build/core/config.mk dumpvar-abs-

第一种形式,返回varName的值。第二种形式,返回varName的值,前缀上路径。考虑到android 脚本中广泛使用':=’的变量定义方法,因此,基本上只能显示dumpvar.mk之前定义的变量值。LOCAL_xxxx的变量也不适用。

4. cleanbuild.mk的分析

main.mk在包含了config.mk后,会包含进cleanbuild.mk。

定义了add-clean-step命令。有一个入口参数

$(1),执行删除操作的具体shell命令。

一般add-clean-step应当在%/cleanspec.mk脚本中使用,命令会为$(1)定义一个变量保存,变量的名字是 INTERNAL_STEP.$(_acs_id),所有的$(_acs_id)保存在INTERNAL_STEPS中。$(_acs_id)的值分成3 个部分构造

第一部分是有cleanspec.mk的路径转化而来,用'_'替代'/','-'替代'.',后缀_acs。第二部分是$(INTERNAL_CLEAN_BUILD_VERSION),默认是4,第三部分是有'@'组成,cleanspec.mk 中的第几个add- clean-step就用几个@。

例如,packages/apps/Camera/cleanspec.mk中定义了两个删除动作

$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/Camera*)

$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Camera*)

那么,对应的有

INTERNAL_STEP.packages_apps_Camera_CleanSpec-mk_acs4@ := rm -rf $(PRODUCT_OUT)/obj/APPS/Camera*

INTERNAL_STEP.packages_apps_Camera_CleanSpec-mk_acs4@@ := rm -rf $(OUT_DIR)/target/common/obj/APPS/Camera*

接着,包扩进cleanspec.mk

包含进$(PRODUCT_OUT)/clean_steps.mk,

接下来,检查CURRENT_CLEAN_BUILD_VERSION是否与INTERNAL_CLEAN_BUILD_VERSION相同,默认是4

如果相同,

执行所有在INTERNAL_STEPS中登记的删除操作。

否则,

删除 $(OUT_DIR)

然后,重新生成$(PRODUCT_OUT)/clean_steps.mk,写入"CURRENT_CLEAN_BUILD_VERSION := $(INTERNAL_CLEAN_BUILD_VERSION)"和"CURRENT_CLEAN_STEPS := $(INTERNAL_CLEAN_STEPS)"。

随后,读入$(PRODUCT_OUT)/previous_build_config.mk,看是否与当前的编译选项一致,不一致则标明上次的中间文件不可用,则删除相应的中间目录,或提示用户。接着重新将当前的信息写入$(PRODUCT_OUT)/previous_build_config.mk,格式是,

current_build_config := /

$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)$(building_sdk)-{$(locale_list)}

echo "PREVIOUS_BUILD_CONFIG := $(current_build_config)" > /

$(previous_build_config_file)

最后,定义了两个target, installclean和dataclean。

dataclean删除的主要是./$(PRODUCT_OUT)/data/*,

installclean的删除包括dataclean。installclean的本意是用于不同build_type编译时删除前次的中间文件。

总结cleanbuild.mk的内容,就3件事,一是载入所有的CleanSpec.mk,二是检查更新clean_steps.mk和 previous_build_config.mk,避免不同编译间的互相干扰。最后是,定义installclean和dataclean。

5. cleanspec.mk的分析

首先定义

INTERNAL_CLEAN_BUILD_VERSION := 4

接着使用findleaves.py遍历所有子目录,找到CleanSpec.mk,并包含进。用户可以在CleanSpec.mk中定义自己需要的删除操作。实际上还可以包含不仅仅是删除的操作。

至此,INTERNAL_STEP.XXXX包含了所有CleanSpec.mk定义的clean动作。

6. version_checked.mk的分析

main.mk 在cleanbuild.mk后,会借助$(OUT_DIR)/version_checked.mk检查版本,如果版本不一致,则重新检查系统文件系统大小写敏感问题,路径上是否含有空格,java和javac 的版本,没有问题,则更新version_checked.mk。

version_checked.mk中就定义了

VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)

7. showcommands和checkbuild的说明

checkbuild貌似并未使用。

showcommands必须同其它target一同使用,showcommands会详细打印出执行的具体命令内容。

8. definations.mk的说明

definations.mk中定义了大量的命令,其它的mk文件将使用。这其中包括执行编译链接的命令,通常是transform-XXX-to-XXX的形式,例如,transform-cpp-to-o。

其中的inherit-package命令有待研究...

Android101112: Android Make脚本的简记(5)

内容提要

文档简要整理Android的make脚本的内容。以供备忘和参考。

声明

仅限学习交流,禁止商业用途。转载需注明出处。

1. Makefile的分析

首先定义target,用于生成$(OUT_DOCS)/index.html

再定义target,用于生成$(TARGET_ROOT_OUT)/default.prop

再定义target,用于生成$(TARGET_OUT)/build.prop。build.prop文件记录了一系列属性值。它的内容分成两部分,第一部分是一些关于 product,device,build的一般性属性值,第二部分的属性值源自ADDITIONAL_BUILD_PROPERTIES。 product配置mk文件中定义的PRODUCT_PROPERTY_OVERRIDES会加入到 ADDITIONAL_BUILD_PROPERTIES,建议增加property 时,直接修改 PRODUCT_PROPERTY_OVERRIDES。

再定义target,用于生成$(PRODUCT_OUT)/sdk/sdk-build.prop

再定义target,package-stats,用于生成$(PRODUCT_OUT)/package-stats.txt,这个文件包含了.jar,.apk后缀文件的信息。

再定义target,apkcerts-list,用于生成$(name)-apkcerts-$(FILE_NAME_TAG),描述各module的certificate和private_key文件信息。

接着,如果定义了CREATE_MODULE_INFO_FILE,则生成$(PRODUCT_OUT)/module-info.txt,其中包含了描述所有module的信息。

再定义target,event-log-tags。

接着,处理ramdisk.img

再处理boot.img,如果TARGET_NO_KERNEL不是true,则将kernel和ramdisk.img组装成boot.img。

接着,定影命令combine-notice-files,用于生成target,notice_files。notice_files

会抽取生成相应的声明文件。

随后,建立target,otacert,用于将.x509.pem后缀的认证文件打包存放到$(TARGET_OUT_ETC)/security/otacerts.zip。

接着,建立target,recoveryimage,处理recovery img

还有下面的target,

systemimage-nodeps, snod

systemtarball-nodeps,stnod

boottarball-nodeps,btnod

userdataimage-nodeps

userdatatarball-nodeps

otatools

target-files-package

otapackage

installed-file-list

tests-zip-package

dalvikfiles

updatepackage

最后包含进 build/core/task/下的mk文件。

Android Make脚本的简记(3)

2011-07-19 19:59

Email: zcatt@https://www.wendangku.net/doc/972267082.html,

Blog https://www.wendangku.net/doc/972267082.html,

内容提要

文档简要整理Android的make脚本的内容。以供备忘和参考。

声明

仅限学习交流,禁止商业用途。转载需注明出处。

版本记录

Date Ver Note

2010-11-10 0.1 Draft. zcatt@Beijing

2010-11-11 0.2 add inherit-product

1. findleaves.py的分析

main.mk中调用了findleaves.py,得到所有子目录下Android.mk文件的路径。

subdir_makefiles := \

$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)

$(subdirs)一般编译中取值$(TOP)。

使用方法,

Usage: %(progName)s []

Options:

--mindepth=

Both behave in the same way as their find(1) equivalents.

--prune=

Avoids returning results from inside any directory called

(e.g., "*/out/*"). May be used multiple times.

程序首先依次选取dirlist中的目录,然后遍历所有子目录查找Android.mk文件,如果有,则加入到返回列表中。

2. pathmap.mk的分析

pathmap.mk中定义了一个列表pathmap_INCL,列表中每项是"短名:路径"对。命令include-path-for使用这个 pathmap_INCL列表,输入短名,得到路径。你可以在这个列表中添加自己的对。使用$(call include-path-for, <短名>)就可以得到路径。

另外,定义了FRAMEWORKS_BASE_JAVA_SRC_DIRS,含有frameworks/base目录下含java文件的所有目录。

3. config.mk的分析

首先,包含pathmap.mk,其次,定义了一些变量,例如通用的编译参数,package的后缀名等。

随后包含buildspec.mk。

接着包含envsetup.mk。

然后包含$(board_config_mk)。$(board_config_mk)是位于build/target/board /$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor/*/$(TARGET_DEVICE) /目录下的BoardConfig.mk文件。

-------TODO

跟我一起写Makefile

跟我一起写Makefile 陈皓 1 概述 什么是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。 2 关于程序的编译和链接 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是.obj 文件,UNIX下是.o 文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ 文件)。 链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是.lib 文件,在UNIX下,是Archive File,也就是.a 文件。 总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错

手动建立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文件

Linux如何写makefile文件 关于程序的编译和链接 —————————— 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在 C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文 件)。 链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件, 只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给 中间目标文件打个包,在Windows 下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。 总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明, 编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File. 好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。 Makefile 介绍 ——————— make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。 首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有 8

跟我一起写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 中$@ $^ %< 使用 https://www.wendangku.net/doc/972267082.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脚本,让她帮我去完成不就可以了。是的对于这个程序来说,是可

C++项目的Makefile编写

一个C++项目的Makefile编写-Tony与Alex的对话系列- - Tony : Hey Alex, How are you doing? Alex : 不怎么样。(显得很消沉的样子) Tony : Oh , Really ? What is the matter? Alex : 事情是这样的。最近有一个Unix下的C++项目要求我独自完成,以前都是跟着别人做,现在让自己独立完成,还真是不知道该怎么办,就连一个最简单的项目的Makefile都搞不定。昨晚看了一晚上资料也没有什么头绪。唉!! Tony : 别急,我曾经有一段时间研究过一些关于Makefile的东西,也许能帮得上忙,来,我们一起来设计这个项目的Makefile。 Alex : So it is a deal。(一言为定) Tony : 我们现在就开始吧,给我拿把椅子过来。 (Tony坐在Alex电脑的旁边) Tony : 把你的项目情况大概给我讲讲吧。 Alex : No Problem ! 这是一个“半成品”项目,也就是说我将提供一个开发框架供应用开发人员使用,一个类似MFC的东西。 Tony : 继续。 Alex : 我现在头脑中的项目目录结构是这样的: APL (Alex's Programming Library) -Make.properties -Makefile(1) -include //存放头文件 -Module1_1.h -Module1_2.h -Module2_1.h -Module2_2.h -src //存放源文件 -Makefile(2) -module1 -Module1_1.cpp -Module1_2.cpp -Makefile(3) -module2 -Module2_1.cpp -Module2_2.cpp -Makefile(3) -... -lib //存放该Project依赖的库文件,型如libxxx.a -dist //存放该Project编译连接后的库文件libapl.a -examples //存放使用该“半成品”搭建的例子应用的源程序 Makefile(4)

怎样使用Makefile

Mak k e f ile 跟我一 我一起起写Ma 陈皓 (CSDN) 概 述 什么是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。 关于程序的编译和链接 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File 合成执行文件,这个动作叫作链接(link)。

如何编写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。 关于程序的编译和链接 —————————— 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。

Makefile两个实验教案

Makefile工程管理器 14.1 编写包含多文件的Makefile 【实验内容】 编写一个包含多文件的Makefile。 【实验目的】 通过对包含多文件的Makefile的编写,熟悉各种形式的Makefile,并且进一步加深对Makefile中用户自定义变量、自动变量及预定义变量的理解。 【实验平台】 PC机、CentOS 5 操作系统、gcc等工具。 【实验步骤】 1.用vi在同一目录下编辑两个简单的Hello程序,如下所示: #hello.c #include "hello.h" int main() { printf("Hello everyone!\n"); } #hello.h #include 2.仍在同一目录下用vim编辑Makefile,不使用变量替换,用一个目标体实现(即直接将 hello.c和hello.h编译成hello目标体)。并用make验证所编写的Makefile是否正确。 3.将上述Makefile使用变量替换实现。同样用make验证所编写的Makefile是否正确 4.用编辑另一Makefile,取名为Makefile1,不使用变量替换,但用两个目标体实现(也 就是首先将hello.c和hello.h编译为hello.o,再将hello.o编译为hello),再用make的‘-f’选项验证这个Makefile1的正确性。 5.将上述Makefile1使用变量替换实现 【详细步骤】 1.用vi打开上述两个代码文件‘hello.c’和‘hello.h’ 2.在shell命令行中用gcc尝试编译,使用命令:‘gcc hello.c -o hello’,并运行hello可执 行文件查看结果。 3.删除此次编译的可执行文件:rm –rf hello 4.用vim编辑Makefile,如下所示: hello:hello.c hello.h gcc hello.c -o hello 5.退出保存,在shell中键入:make查看结果 6.再次用vim打开Makefile,用变量进行替换,如下所示: OBJS :=hello.o CC :=gcc hello:$(OBJS) $(CC) $^ -o $@

MakeFile编写规则

MakeFile编写规则 什么是makefile (3) 关于程序的编译和链接 (3) Makefile 介绍 (4) 一、Makefile的规则 (4) 二、一个示例 (4) 三、make是如何工作的 (6) 四、makefile中使用变量 (6) 五、让make自动推导 (7) 六、另类风格的makefile (8) 七、清空目标文件的规则 (8) Makefile 总述 (9) 一、Makefile里有什么 (9) 二、Makefile的文件名 (9) 三、引用其它的Makefile (9) 四、环境变量MAKEFILES (10) 五、make的工作方式 (10) 实例说明 (11) 一、简单例子 (11) 二、规则的语法 (11) 三、在规则中使用通配符 (12) 四、文件搜寻 (12) 五、伪目标 (13) 六、多目标 (14) 七、静态模式 (15) 八、自动生成依赖性 (16) 书写命令 (17) 一、显示命令 (17) 二、命令执行 (18) 三、命令出错 (18) 四、嵌套执行make (19) 五、定义命令包 (20) 使用变量 (21) 一、变量的基础 (21) 二、变量的赋值 (21) 第一种方式 (22) 第二种方式 (22) 三、变量高级用法 (23) 一种是变量值的替换 (23) 第二种高级用法——“把变量的值再当成变量” (24) 四、追加变量值 (25) 五、override 指示符 (26) 六、多行变量 (26)

七、环境变量 (26) 八、目标变量 (27) 九、模式变量 (27) 十、自动化变量 (28) 使用条件判断 (30) makefile的编写规则--语法及函数 (31) 条件表达式 (31) 函数 (32) 一、函数的调用语法 (32) 二、字符串处理函数 (33) $(subst ,, ) (33) $(patsubst ,, ) (33) $(strip ) (34) $(findstring , ) (34) $(filter , ) (34) $(filter-out , ) (34) $(sort ) (35) $(word , ) (35) $(wordlist ,, ) (35) $(words ) (35) $(firstword ) (36) 三、文件名操作函数 (36) $(dir ) . (36) $(notdir ) .. (36) $(suffix ) .. (37) $(basename ) .. (37) $(addsuffix , ) (37) $(addprefix , ) .. (37) 其他函数 (37) $(join , ) (37) foreach 函数 (38) if 函数 (38) call函数 (38) origin函数 (39) shell函数 (40) 控制make的函数 (40) $(error ) . (40) $(warning ) . (40) make 的运行 (41) 一、make的退出码 (41) 二、指定Makefile (41) 三、指定目标 (41) 四、检查规则 (42)

实验三 Makefile的编写及应用

闽江学院电子系 实验报告 学生姓名:3142731班级:学号:课程:实时操作系统 一、实验题目:Makefile的编写及应用 二、实验地点:大成楼A210 三、实验目的: 1、了解Makefile的基本概念和基本结构; 2、初步掌握编写简单Makefile的方法; 3、了解递归Make的编译过程; 4、初步掌握应用GNU Make编译应用程序的方法。 四、实验内容: 1、使用命令行的方式手动编译程序的方法; 五、实验环境(使用的软硬件): 硬件:计算机 软件:Ubuntu Linux 六、实验结果: (1)使用命令行的方式手动编译程序方法 1、利用文本编辑器创建hello.c 文件

2、手动编译hello 应用程序 在hello.c 的目录的终端下输入: #gcc -c hello.c #gcc hello.o -o hello 通过ls 命令查看当前目录下是否生成源代码hello.c 的object 文件hello.o 和可执行文件hello,运行可执行文件hello。查看一下运行结果。 3、修改hello.c 文件,重新手动编译应用程序。

4、删除hello.o 和hello 文件 #rm -f hello.o #rm -f hello (2) 利用GNU make 自动编译应用程序方法 1、利用文本编辑器创建一个Makefile 文件,并将其保存到与hello.c 相同的目录下。 2、先执行如下命令。 #make #ls #./hello 查看并记录所生成的文件和运行的结果。

3、执行make clean 命令: 4、修改hello.c 文件,重复第2、3 步操作,查看并记录所生成的文件和运行结果,并与手动编译进行比较,写出你的结论。 5、重新编辑Makefile 文件(斜黑体表示修改部分)

如何编写makefile文件

目的: 基本掌握了make 的用法,能在Linux系统上编程。 环境: Linux系统,或者有一台Linux服务器,通过终端连接。一句话:有Linux编译环境。准备: 准备三个文件:file1.c, file2.c, file2.h file1.c: #include #include "file2.h" int main() { printf("print file1$$$$$$$$$$$$$$$$$$$$$$$$\n"); 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**********************\n"); } 基础: 先来个例子: 有这么个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

linux下makefile文件的编写

linux下Makefile文件的编写- 红联Linux门户- 中国领先 的Linux技... linux下Makefile文件的编写victorywylbc发布于 2009-7-30 | 951次阅读字号: 大中小(网友评论7 条) 我要评论开始使用Linux编程时,一个很讨厌的问题就是如何写Makefile文件,由于在Linux下 不像在Windows下那么熟悉,有那么多好的软件(也许是对Linux孤陋寡闻了)。虽然 象Kylix和Anjuta这样的集成编译环境,但是Kylix太大太慢,用它编写console程序 不亚于高射炮打蚊子——大材小用,而Anjuta又太不稳定,况且字体有那么难看。不 说了,还是言归正传,看看Makefile该如何编写。1. 简单的GCC语法:如果你只有一个文件(或者只有几个文件),那么就可以不写Makefile文件(当然有 Makefile更加方便),用gcc直接编译就行了。在这里我们只介绍几个我经常用的几 个参数,第一是“-o”,它后面的参数表示要输出的目标文件,再一个是“-c”, 表示仅编译(Compile),不连接(Make),如果没有

”-c”参数,那么就表示连接 ,如下面的几个命令:gcc –c test.c,表示只编译test.c 文件,成功时输出目标文件test.ogcc –c test.c –o test.o ,与上一条命令完全相同gcc –o test test.o,将test.o连接成可执行的二进制文件testgcc –o test test.c,将test.c编译并连接成可执行的二进制文件testgcc test.c –o test,与上一条命令相同gcc –c test1.c,只编译test1.c,成功时输出目标文件test1.ogcc –c test2.c,只编译test2.c,成功时输出目标文件test2.ogcc –o test test1.o test2.o,将 test1.o和test2.o连接为可执行的二进制文件testgcc –c test test1.c test2.c,将test1.o和test2.o编译并连接为可执行的二进制 文件test注:如果你想编译cpp文件,那么请用g++,否则会有类似如下莫名其妙的错误: cc3r3i2U.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0’ ......还有一个参数是”-l”参数,与之紧紧相连的是表示连接时所要的链接库,比如多线 程,如果你使用了pthread_create函数,那么你就应该在编译语句的最后加上”-lpthread ”,”-l”表示连接,

MAKEFILE的编写

MAKEFILE的编写 第一章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都成为了一种在工程方面的编译方法。 make命令执行时,需要一个Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。 首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。 2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。 3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。 只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make 命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。 以下各章我们将以实际例子详细介绍各类Makefile文件的书写规则。 第二章一个简单的C语言Makefile 红色字体为makefile文件本身,黑色字体为解释。 .SUFFIXES:.ec 用伪目标SUFFIXES来让make知道特定的后缀.ec。后缀规则是一个比较老式的定义隐含规则的方法。后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规

相关文档