├── Makefile ├── README.md ├── examples ├── cpp │ ├── Makefile │ └── main.cpp ├── custom │ ├── Makefile │ └── main.c ├── flags │ ├── Makefile │ └── main.c ├── hello │ ├── Makefile │ └── main.c ├── library │ ├── Makefile │ └── hello.c └── module │ ├── Makefile │ ├── moduleA │ └── Makefile │ ├── moduleB │ └── Makefile │ └── moduleC │ └── Makefile └── scripts ├── build.mk ├── conf.mk ├── define.mk ├── env.mk ├── fixdep.c ├── include.mk ├── rule.mk └── wrapper.mk /Makefile: -------------------------------------------------------------------------------- 1 | sinclude scripts/env.mk 2 | MODULE += examples/hello 3 | MODULE += examples/library 4 | MODULE += examples/custom 5 | MODULE += examples/flags 6 | MODULE += examples/module 7 | MODULE += examples/cpp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XBuild (v0.2) 2 | XBuild是一个基于Makefile的构建框架,旨在提供轻量级的编译功能。目前支持多线程,增量编译,配置。 3 | ## Usage 4 | - 编译 5 | ```sh 6 | make 7 | make -j8 #多线程编译 8 | make O=Build #将生成文件导出到Build目录 9 | ``` 10 | - 清除目标 11 | ```sh 12 | make clean 13 | ``` 14 | ## Examples 15 | 根目录执行`make`可运行所有`examples` 16 | - Hello XBuild (`examples/hello`) 17 | 18 | ```makefile 19 | sinclude ../../scripts/env.mk 20 | 21 | NAME := hello 22 | SRC += main.c 23 | ``` 24 | 导入`XBuild`,通常只需要在顶层Makefile设置 25 | ```makefile 26 | sinclude ../../scripts/env.mk 27 | ``` 28 | 定义最终目标 29 | ```makefile 30 | NAME := hello 31 | ``` 32 | 添加需要编译的源码 33 | ```makefile 34 | SRC += main.c 35 | ``` 36 | - 静态库/动态库 (`examples/library`) 37 | ```makefile 38 | sinclude ../../scripts/env.mk 39 | 40 | #TARGET_TYPE := shared 41 | TARGET_TYPE := static 42 | NAME := hello 43 | SRC += hello.c 44 | ``` 45 | 指定`TARGET_TYPE`为`static/shared`,目标输出为`静态库/动态库`。 46 | 47 | 默认为`binary`(参考Hello XBuild)。`static`会将`hello`改为`libhello.a`,`shared`会将`hello`改为`libhello.s`o或`libhello.dll`。 48 | - 自定义命令 (`examples/custom`) 49 | 50 | 如果定义了`CUSTOM_TARGET_CMD`,最终目标会保持为原始名字,即便设置了`TARGET_TYPE`。 51 | ```makefile 52 | sinclude ../../scripts/env.mk 53 | 54 | NAME := hello.bin 55 | SRC += main.c 56 | 57 | define CUSTOM_TARGET_CMD 58 | echo [CUSTOM TARGET] $@ 59 | $(CC) $(X_CFLAGS) $(X_CPPFLAGS) $(X_OBJS) -o $@ $(X_LDFLAGS) $(X_LDLIBS) 60 | endef 61 | ``` 62 | - 编译器`flags`使用 (`examples/flags`) 63 | ```makefile 64 | sinclude ../../scripts/env.mk 65 | 66 | X_DEFINES += HELLO=1 #定义HELLO宏,等效代码(#define HELLO 1) 67 | X_CFLAGS += -std=c11 #设置C语言标准为C11 68 | 69 | NAME := hello 70 | SRC += main.c 71 | ``` 72 | 最终命令为: 73 | ```sh 74 | gcc -std=c11 -DHELLO=1 examples/flags/main.c.o -o examples/flags/hello 75 | ``` 76 | 所有`flags`如下: 77 | ```sh 78 | X_ASFLAGS #汇编器命令行参数 79 | X_CFLAGS #C编译器命令行参数 80 | X_LDFLAGS #链接器命令行参数 81 | X_LIBDIRS #库路径(e.g. libs) 82 | X_LIBS #依赖库(e.g. hello) 83 | X_DEFINES #预处理宏定义(e.g. DEBUG=1) 84 | X_INCDIRS #预处理头文件路径(e.g. include) 85 | X_INCS #预处理包含头文件(e.g. include/config.h) 86 | 87 | X_CPPFLAGS <- X_INCDIRS + X_DEFINES + X_INCS 88 | #预处理命令行参数(e.g. -I include -DDEBUG=1 -include include/config.h) 89 | X_LDLIBS <- X_LIBDIRS + X_LIBS 90 | #链接器链接库命令行参数(e.g. -Llibs -lhello) 91 | ``` 92 | `X_CPPFLAGS`,`X_LDLIBS`会自动将数据加工为编译器可以识别的命令行参数,可以避免用户繁琐的字符串处理,这也意味用户不应该主动设置这些变量。 93 | - 模块化 (`examples/module`) 94 | ```makefile 95 | sinclude scripts/env.mk 96 | MODULE += moduleA 97 | MODULE += moduleB 98 | MODULE += moduleC 99 | 100 | moduleA: moduleB 101 | moduleB: moduleC 102 | ``` 103 | 定义了三个模块,`moduleA`依赖`moduleB`,`moduleB`依赖`moduleC`。 104 | 105 | `moduleA` 106 | ```makefile 107 | define CUSTOM_AFTER_BUILD #结束build执行此命令 108 | echo [MOUDLE A] 109 | endef 110 | ``` 111 | 模块化支持意味着每个`Makefile`都是等价的,即便是顶层`Makefile`。 112 | 113 | 114 | ## 联系 115 | QQ:891085309 -------------------------------------------------------------------------------- /examples/cpp/Makefile: -------------------------------------------------------------------------------- 1 | sinclude ../../scripts/env.mk 2 | 3 | NAME := hello.bin 4 | SRC += main.cpp 5 | 6 | X_CXXFLAGS += -std=c++11 7 | X_LIBS += stdc++ -------------------------------------------------------------------------------- /examples/cpp/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout<<"Hello World\n"; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /examples/custom/Makefile: -------------------------------------------------------------------------------- 1 | sinclude ../../scripts/env.mk 2 | 3 | NAME := hello.bin 4 | SRC += main.c 5 | 6 | define CUSTOM_TARGET_CMD 7 | echo [CUSTOM TARGET] $@; 8 | $(CC) $(X_CFLAGS) $(X_CPPFLAGS) $(X_OBJS) -o $@ $(X_LDFLAGS) $(X_LDLIBS) 9 | endef -------------------------------------------------------------------------------- /examples/custom/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("Hello XBuild!"); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /examples/flags/Makefile: -------------------------------------------------------------------------------- 1 | sinclude ../../scripts/env.mk 2 | 3 | X_DEFINES += HELLO=1 4 | X_CFLAGS += -std=c11 5 | 6 | NAME := hello 7 | SRC += main.c -------------------------------------------------------------------------------- /examples/flags/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | #if HELLO 6 | printf("Hello XBuild!"); 7 | #endif 8 | return 0; 9 | } -------------------------------------------------------------------------------- /examples/hello/Makefile: -------------------------------------------------------------------------------- 1 | sinclude ../../scripts/env.mk 2 | 3 | NAME := hello 4 | SRC += main.c -------------------------------------------------------------------------------- /examples/hello/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("Hello XBuild!"); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /examples/library/Makefile: -------------------------------------------------------------------------------- 1 | sinclude ../../scripts/env.mk 2 | 3 | #TARGET_TYPE := shared 4 | TARGET_TYPE := static 5 | NAME := hello 6 | SRC += hello.c -------------------------------------------------------------------------------- /examples/library/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int hello() 4 | { 5 | printf("Hello XBuild!"); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /examples/module/Makefile: -------------------------------------------------------------------------------- 1 | sinclude scripts/env.mk 2 | MODULE += moduleA 3 | MODULE += moduleB 4 | MODULE += moduleC 5 | 6 | moduleA: moduleB 7 | moduleB: moduleC -------------------------------------------------------------------------------- /examples/module/moduleA/Makefile: -------------------------------------------------------------------------------- 1 | define CUSTOM_AFTER_BUILD 2 | echo [MOUDLE A] 3 | endef -------------------------------------------------------------------------------- /examples/module/moduleB/Makefile: -------------------------------------------------------------------------------- 1 | define CUSTOM_AFTER_BUILD 2 | echo [MOUDLE B] 3 | endef -------------------------------------------------------------------------------- /examples/module/moduleC/Makefile: -------------------------------------------------------------------------------- 1 | define CUSTOM_AFTER_BUILD 2 | echo [MOUDLE C] 3 | endef -------------------------------------------------------------------------------- /scripts/build.mk: -------------------------------------------------------------------------------- 1 | PHONY := __build 2 | __build: 3 | 4 | src := $(obj) 5 | 6 | SRC := 7 | INCDIRS := 8 | NAME := 9 | MODULE := 10 | # binary static shared 11 | TARGET_TYPE := binary 12 | 13 | X_SUBDIR := 14 | X_SUB_OBJ := 15 | X_EXTRA := 16 | X_PREPARE := 17 | X_CLEAN := 18 | 19 | include $(XBUILD_DIR)/include.mk 20 | sinclude $(X_CONF_DIR)/auto.conf 21 | 22 | 23 | ifneq ($(wildcard $(srctree)/$(src)/Makefile),) 24 | include $(srctree)/$(src)/Makefile 25 | else 26 | SRC := *.S *.c 27 | endif # ifneq ($(wildcard $(srctree)/$(src)/Makefile),) 28 | 29 | ifeq ($(ISMODULE),0) 30 | X_BUILTIN := $(obj)/built-in.o 31 | endif 32 | 33 | X_MODULE = $(MODULE) 34 | 35 | # X_NAME 36 | ifneq ($(NAME),) 37 | ifneq ($(origin CUSTOM_TARGET_CMD),undefined) 38 | X_NAME = $(obj)/$(NAME) 39 | else ifeq ($(strip $(TARGET_TYPE)),binary) 40 | X_NAME = $(obj)/$(NAME)$(SUFFIX) 41 | else ifeq ($(strip $(TARGET_TYPE)),static) 42 | X_NAME = $(obj)/lib$(NAME).a 43 | else ifeq ($(strip $(TARGET_TYPE)),shared) 44 | X_NAME = $(obj)/lib$(NAME).$(SHARED_SUFFIX) 45 | else ifeq ($(strip $(filter binary static shared,$(TARGET_TYPE))),) 46 | $(error undefined TARGET_TYPE=$(TARGET_TYPE)) 47 | endif 48 | endif 49 | 50 | # FLAGS 51 | X_CPPFLAGS := $(patsubst %, -I %, $(foreach d,$(X_INCDIRS),$(wildcard $(srctree)/$(d)))) $(patsubst %, -D%, $(X_DEFINES)) $(patsubst %, -include %, $(X_INCS)) 52 | X_LDLIBS := $(patsubst %, -L%, $(X_LIBDIRS)) $(patsubst %, -l%, $(X_LIBS)) 53 | 54 | export X_ASFLAGS X_CFLAGS X_CXXFLAGS X_LDFLAGS X_LIBDIRS X_LIBS X_DEFINES X_LDFLAGS X_INCDIRS X_INCS 55 | 56 | X_CUR_OBJ := $(foreach f,$(filter-out %/, $(SRC)),$(wildcard $(srctree)/$(src)/$(f))) 57 | X_CUR_OBJ := $(patsubst $(srctree)/$(src)/%,$(obj)/%.o,$(X_CUR_OBJ)) 58 | X_SUBDIR := $(filter %/,$(foreach f,$(filter %/, $(SRC)),$(wildcard $(srctree)/$(src)/$(f)))) 59 | X_SUBDIR := $(patsubst $(srctree)/%/,%,$(X_SUBDIR)) 60 | X_SUB_OBJ := $(patsubst $(src)/%,$(obj)/%/built-in.o,$(X_SUBDIR)) 61 | 62 | 63 | X_OBJS := $(X_CUR_OBJ) $(X_SUB_OBJ) 64 | # case: $(obj)==. 65 | X_OBJS := $(patsubst $(objtree)/%,%,$(abspath $(X_OBJS))) 66 | X_TARGET := $(X_BUILTIN) $(X_OBJS) $(X_EXTRA) $(X_NAME) 67 | X_DEPS := $(wildcard $(foreach f,$(X_TARGET),$(dir $(f)).$(notdir $(f)).cmd)) 68 | 69 | # Add a semicolon to form an empty command and then recheck the dependency 70 | $(sort $(X_SUB_OBJ)) : $(X_SUBDIR) ; 71 | PHONY += $(X_SUBDIR) $(X_MODULE) 72 | 73 | $(X_OBJS) $(X_EXTRA) $(X_MODULE): $(X_PREPARE) 74 | clean: $(X_SUBDIR) $(X_MODULE) 75 | 76 | $(X_SUBDIR): 77 | @$(MAKE) $(build)=$@ ISMODULE=0 $(MAKECMDGOALS) 78 | $(X_MODULE): 79 | @$(MAKE) $(build)=$(obj)/$@ ISMODULE=1 $(MAKECMDGOALS) 80 | 81 | # Create output directory 82 | _dummy := $(shell $(MKDIR) $(obj) $(dir $(X_TARGET))) 83 | 84 | PHONY += clean 85 | 86 | sinclude $(X_DEPS) 87 | 88 | export X_ASFLAGS X_CFLAGS X_CPPFLAGS 89 | 90 | __build : $(X_TARGET) $(X_MODULE) 91 | $(CUSTOM_AFTER_BUILD) 92 | 93 | $(X_TARGET): $(X_MODULE) 94 | $(X_NAME): $(X_OBJS) 95 | 96 | clean: 97 | ifneq ($(strip $(wildcard $(X_TARGET) $(obj)/.*.cmd $(X_DEPS) $(X_CLEAN))),) 98 | @$(ECHO) '$(ECHO_RM)' $(obj) 99 | @$(RM) $(X_TARGET) $(wildcard $(obj)/.*.cmd) $(X_DEPS) $(X_CLEAN) 100 | endif 101 | 102 | include $(XBUILD_DIR)/rule.mk 103 | 104 | PHONY += FORCE 105 | 106 | FORCE: ; 107 | 108 | .PHONY : $(PHONY) 109 | -------------------------------------------------------------------------------- /scripts/conf.mk: -------------------------------------------------------------------------------- 1 | PHONY += conf 2 | 3 | conf : $(X_CONF_DIR)/auto.conf $(X_CONF_DIR)/autoconf.h 4 | 5 | $(X_CONF_DIR)/autoconf.h : FORCE 6 | $(if $(wildcard $(X_CONF_DIR)),:,@echo [MKDIR] $(X_CONF_DIR) && $(MKDIR) $(X_CONF_DIR)) 7 | $(if $(wildcard $(X_CONF_DIR)/autoconf.h),:,@touch $(X_CONF_DIR)/autoconf.h) 8 | @$(CC) -E -P -dM $(X_INCDIRS) $(srctree)/$(src)/include/xconfigs.h \ 9 | | sed -n -e "/\#define\s\+CONFIG_[[:alnum:]_]*/p" \ 10 | | sed -n -e "s/\s*$$//p" \ 11 | > $(X_CONF_DIR)/autoconf.temp 12 | @$(CD) $(X_CONF_DIR) && grep -vxFf autoconf.temp autoconf.h \ 13 | | sed -n -e "s/\#define\s\+CONFIG_\([[:alnum:]_]*\).*/\L\1\E.h/p" \ 14 | | xargs touch autoconf.h 15 | @$(CD) $(X_CONF_DIR) && grep -vxFf autoconf.h autoconf.temp \ 16 | | sed -n -e "s/\#define\s\+CONFIG_\([[:alnum:]_]*\).*/\L\1\E.h/p" \ 17 | | xargs touch autoconf.h 18 | @$(RM) $(X_CONF_DIR)/autoconf.h 19 | @echo [AUTOCONF] 20 | @$(MV) $(X_CONF_DIR)/autoconf.temp $(X_CONF_DIR)/autoconf.h 21 | 22 | $(X_CONF_DIR)/auto.conf : $(X_CONF_DIR)/autoconf.h 23 | @$(RM) $(X_CONF_DIR)/auto.conf 24 | @$(CD) $(X_CONF_DIR) && cat autoconf.h \ 25 | | sed -n -e "s/\#define\s\+\(CONFIG_[[:alnum:]_]*\)[[:space:]]/\1=/p" \ 26 | >> auto.conf 27 | @$(CD) $(X_CONF_DIR) && cat autoconf.h \ 28 | | sed -n -e "s/\#define\s\+\(CONFIG_[[:alnum:]_]*\)$$/\1=y/p" \ 29 | >> auto.conf 30 | -------------------------------------------------------------------------------- /scripts/define.mk: -------------------------------------------------------------------------------- 1 | MKDIR := mkdir -p 2 | RMDIR := rmdir -p 3 | CP := cp -af 4 | RM := rm -rf 5 | CD := cd 6 | MV := mv 7 | FIND := find 8 | 9 | # System environment variable. 10 | ifeq ($(OS),Windows_NT) 11 | HOSTOS := windows 12 | else 13 | ifeq ($(shell uname),Darwin) 14 | HOSTOS := macos 15 | else 16 | ifeq ($(shell uname),Linux) 17 | HOSTOS := linux 18 | else 19 | HOSTOS := unix-like 20 | endif 21 | endif 22 | endif 23 | 24 | ifeq ($(HOSTOS),windows) 25 | SUFFIX := .exe 26 | SHARED_SUFFIX := dll 27 | else 28 | SUFFIX := 29 | SHARED_SUFFIX := so 30 | endif 31 | 32 | ifeq ($(HOSTOS),linux) 33 | ECHO := /bin/echo -e 34 | else 35 | ECHO := echo 36 | endif 37 | 38 | export RM CP CD MV FIND MKDIR HOSTOS SUFFIX SHARED_SUFFIX ECHO 39 | 40 | ifneq ($(HOSTOS),linux) 41 | ECHO_RM :=RM 42 | ECHO_CC :=CC 43 | ECHO_CXX :=CXX 44 | ECHO_AS :=AS 45 | ECHO_LD :=LD 46 | ECHO_AR :=AR 47 | ECHO_HOSTCC :=HOSTCC 48 | ECHO_OUTPUT :=OUTPUT 49 | else 50 | ECHO_RM :=\e[32mRM\e[0m 51 | ECHO_CC :=\e[32mCC\e[0m 52 | ECHO_CXX :=\e[32mCXX\e[0m 53 | ECHO_AS :=\e[32mAS\e[0m 54 | ECHO_LD :=\e[32mLD\e[0m 55 | ECHO_AR :=\e[35mAR\e[0m 56 | ECHO_HOSTCC :=\e[33mHOSTCC\e[0m 57 | ECHO_OUTPUT :=\e[35mOUTPUT\e[0m 58 | endif 59 | 60 | export ECHO_RM ECHO_CC ECHO_CXX ECHO_AS ECHO_LD ECHO_AR ECHO_OUTPUT ECHO_HOSTCC 61 | 62 | CROSS_COMPILE ?= 63 | 64 | # Make variables (CC, etc...) 65 | AS := $(CROSS_COMPILE)gcc -x assembler-with-cpp 66 | CC := $(CROSS_COMPILE)gcc 67 | CPP := $(CROSS_COMPILE)gcc -E 68 | CXX := $(CROSS_COMPILE)g++ 69 | LD := $(CROSS_COMPILE)ld 70 | AR := $(CROSS_COMPILE)ar 71 | OC := $(CROSS_COMPILE)objcopy 72 | OD := $(CROSS_COMPILE)objdump 73 | NM := $(CROSS_COMPILE)nm 74 | 75 | HOSTCC := gcc 76 | 77 | export AS AR CC LD CPP CXX OC OD NM HOSTCC -------------------------------------------------------------------------------- /scripts/env.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(include_Makefile_env),) 2 | include_Makefile_env:=1 3 | 4 | PHONY = 5 | all: 6 | 7 | # Do not: 8 | # o use make's built-in rules and variables 9 | # (this increases performance and avoids hard-to-debug behaviour); 10 | # o print "Entering directory ..."; 11 | MAKEFLAGS += -rR -s --no-print-directory 12 | 13 | BUILD_SRC := 14 | BUILD_OBJ := 15 | 16 | ifeq ($(BUILD_SRC),) 17 | XBUILD_DIR := $(abspath $(lastword $(MAKEFILE_LIST)/../)) 18 | 19 | include $(XBUILD_DIR)/define.mk 20 | 21 | BUILD_OBJ := . 22 | ifeq ("$(origin O)", "command line") 23 | BUILD_OBJ := $(O) 24 | endif 25 | 26 | ifneq ($(BUILD_OBJ),) 27 | PHONY += all $(MAKECMDGOALS) clean 28 | 29 | BUILD_OBJ := $(abspath $(BUILD_OBJ)) 30 | 31 | ifneq ($(BUILD_OBJ),$(CURDIR)) 32 | ifneq ($(strip $(MAKECMDGOALS)),clean) 33 | __dummy := $(shell $(MKDIR) $(BUILD_OBJ)) 34 | endif 35 | endif 36 | 37 | 38 | ifneq ($(__dummy),) 39 | $(error failed to create $(BUILD_OBJ)) 40 | endif 41 | 42 | $(filter-out all,$(MAKECMDGOALS)) all: sub-mk 43 | 44 | sub-mk: 45 | @$(MAKE) -C $(BUILD_OBJ) XBUILD_DIR=$(XBUILD_DIR) BUILD_SRC=$(CURDIR) -f $(XBUILD_DIR)/wrapper.mk $(MAKECMDGOALS) 46 | 47 | ifneq ($(BUILD_OBJ),$(CURDIR)) 48 | clean: sub-mk 49 | @echo [RM] $(BUILD_OBJ) 50 | @$(RM) $(BUILD_OBJ) 51 | endif 52 | 53 | # Declare the contents of the .PHONY variable as phony. We keep that 54 | # information in a variable so we can use it in if_changed and friends. 55 | .PHONY: $(PHONY) 56 | 57 | endif #ifneq ($(BUILD_OBJ),) 58 | endif #ifeq ($(BUILD_SRC),) 59 | 60 | 61 | endif #ifeq ($(include_Makefile_env),) -------------------------------------------------------------------------------- /scripts/fixdep.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "Optimize" a list of dependencies as spit out by gcc -MD 3 | * for the kernel build 4 | * =========================================================================== 5 | * 6 | * Author Kai Germaschewski 7 | * Copyright 2002 by Kai Germaschewski 8 | * 9 | * This software may be used and distributed according to the terms 10 | * of the GNU General Public License, incorporated herein by reference. 11 | * 12 | * 13 | * Introduction: 14 | * 15 | * gcc produces a very nice and correct list of dependencies which 16 | * tells make when to remake a file. 17 | * 18 | * To use this list as-is however has the drawback that virtually 19 | * every file in the kernel includes autoconf.h. 20 | * 21 | * If the user re-runs make *config, autoconf.h will be 22 | * regenerated. make notices that and will rebuild every file which 23 | * includes autoconf.h, i.e. basically all files. This is extremely 24 | * annoying if the user just changed CONFIG_HIS_DRIVER from n to m. 25 | * 26 | * So we play the same trick that "mkdep" played before. We replace 27 | * the dependency on autoconf.h by a dependency on every config 28 | * option which is mentioned in any of the listed prequisites. 29 | * 30 | * kconfig populates a tree in include/config/ with an empty file 31 | * for each config symbol and when the configuration is updated 32 | * the files representing changed config options are touched 33 | * which then let make pick up the changes and the files that use 34 | * the config symbols are rebuilt. 35 | * 36 | * So if the user changes his CONFIG_HIS_DRIVER option, only the objects 37 | * which depend on "include/linux/config/his/driver.h" will be rebuilt, 38 | * so most likely only his driver ;-) 39 | * 40 | * The idea above dates, by the way, back to Michael E Chastain, AFAIK. 41 | * 42 | * So to get dependencies right, there are two issues: 43 | * o if any of the files the compiler read changed, we need to rebuild 44 | * o if the command line given to the compile the file changed, we 45 | * better rebuild as well. 46 | * 47 | * The former is handled by using the -MD output, the later by saving 48 | * the command line used to compile the old object and comparing it 49 | * to the one we would now use. 50 | * 51 | * Again, also this idea is pretty old and has been discussed on 52 | * kbuild-devel a long time ago. I don't have a sensibly working 53 | * internet connection right now, so I rather don't mention names 54 | * without double checking. 55 | * 56 | * This code here has been based partially based on mkdep.c, which 57 | * says the following about its history: 58 | * 59 | * Copyright abandoned, Michael Chastain, . 60 | * This is a C version of syncdep.pl by Werner Almesberger. 61 | * 62 | * 63 | * It is invoked as 64 | * 65 | * fixdep 66 | * 67 | * and will read the dependency file 68 | * 69 | * The transformed dependency snipped is written to stdout. 70 | * 71 | * It first generates a line 72 | * 73 | * cmd_ = 74 | * 75 | * and then basically copies the ..d file to stdout, in the 76 | * process filtering out the dependency on autoconf.h and adding 77 | * dependencies on include/config/my/option.h for every 78 | * CONFIG_MY_OPTION encountered in any of the prequisites. 79 | * 80 | * It will also filter out all the dependencies on *.ver. We need 81 | * to make sure that the generated version checksum are globally up 82 | * to date before even starting the recursive build, so it's too late 83 | * at this point anyway. 84 | * 85 | * The algorithm to grep for "CONFIG_..." is bit unusual, but should 86 | * be fast ;-) We don't even try to really parse the header files, but 87 | * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will 88 | * be picked up as well. It's not a problem with respect to 89 | * correctness, since that can only give too many dependencies, thus 90 | * we cannot miss a rebuild. Since people tend to not mention totally 91 | * unrelated CONFIG_ options all over the place, it's not an 92 | * efficiency problem either. 93 | * 94 | * (Note: it'd be easy to port over the complete mkdep state machine, 95 | * but I don't think the added complexity is worth it) 96 | */ 97 | /* 98 | * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto 99 | * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not 100 | * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as 101 | * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, 102 | * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that 103 | * those files will have correct dependencies. 104 | */ 105 | 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | 116 | 117 | #ifdef __linux__ 118 | #define OS_LINUX 119 | #elif _WIN32 120 | #define OS_WIN32 121 | #elif __APPLE__ 122 | #include "TargetConditionals.h" 123 | #if TARGET_OS_MAC 124 | #define OS_MAC 125 | #else 126 | #error "Unsupported platforms" 127 | #endif 128 | #else 129 | #error "Unsupported platforms" 130 | #endif 131 | 132 | #ifndef OS_WIN32 133 | #include 134 | #include 135 | #else 136 | #include 137 | #include 138 | #pragma comment(lib,"ws2_32.a") 139 | #endif 140 | 141 | #ifdef OS_WIN32 142 | void *mmap(char *filename, unsigned int filesize, HANDLE *phMap) { 143 | if ((filename == NULL) || (filesize == 0) || (phMap == NULL)) return NULL; 144 | 145 | HANDLE hMap = OpenFileMapping(FILE_MAP_READ, TRUE, filename); 146 | if (hMap == NULL) { 147 | OFSTRUCT buffer; 148 | HFILE hfile = OpenFile(filename, &buffer, OF_READ); 149 | if (hfile == NULL) return NULL; 150 | hMap = CreateFileMapping((HANDLE)hfile, NULL, PAGE_READONLY, 0, filesize, filename); 151 | CloseHandle(hfile); 152 | if (hMap == NULL) return NULL; 153 | } 154 | char *text = (CHAR *)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, filesize); 155 | if (text == NULL) { 156 | CloseHandle(hMap); 157 | return NULL; 158 | } 159 | *phMap = hMap; 160 | return text; 161 | } 162 | 163 | void munmap(char *text, HANDLE hMap) { 164 | if (text && hMap) { 165 | UnmapViewOfFile(text); 166 | CloseHandle(hMap); 167 | } 168 | } 169 | 170 | #endif 171 | 172 | #define INT_CONF ntohl(0x434f4e46) 173 | #define INT_ONFI ntohl(0x4f4e4649) 174 | #define INT_NFIG ntohl(0x4e464947) 175 | #define INT_FIG_ ntohl(0x4649475f) 176 | 177 | #define X_CONF_DIR "include/config/" 178 | 179 | char *target; 180 | char *depfile; 181 | char *cmdline; 182 | 183 | static void usage(void) 184 | { 185 | fprintf(stderr, "Usage: fixdep \n"); 186 | exit(1); 187 | } 188 | 189 | /* 190 | * Print out the commandline prefixed with cmd_ := 191 | */ 192 | static void print_cmdline(void) 193 | { 194 | printf("cmd_%s := %s\n\n", target, cmdline); 195 | } 196 | 197 | struct item { 198 | struct item *next; 199 | unsigned int len; 200 | unsigned int hash; 201 | char name[0]; 202 | }; 203 | 204 | #define HASHSZ 256 205 | static struct item *hashtab[HASHSZ]; 206 | 207 | static unsigned int strhash(const char *str, unsigned int sz) 208 | { 209 | /* fnv32 hash */ 210 | unsigned int i, hash = 2166136261U; 211 | 212 | for (i = 0; i < sz; i++) 213 | hash = (hash ^ str[i]) * 0x01000193; 214 | return hash; 215 | } 216 | 217 | /* 218 | * Lookup a value in the configuration string. 219 | */ 220 | static int is_defined_config(const char *name, int len, unsigned int hash) 221 | { 222 | struct item *aux; 223 | 224 | for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) { 225 | if (aux->hash == hash && aux->len == len && 226 | memcmp(aux->name, name, len) == 0) 227 | return 1; 228 | } 229 | return 0; 230 | } 231 | 232 | /* 233 | * Add a new value to the configuration string. 234 | */ 235 | static void define_config(const char *name, int len, unsigned int hash) 236 | { 237 | struct item *aux = malloc(sizeof(*aux) + len); 238 | 239 | if (!aux) { 240 | perror("fixdep:malloc"); 241 | exit(1); 242 | } 243 | memcpy(aux->name, name, len); 244 | aux->len = len; 245 | aux->hash = hash; 246 | aux->next = hashtab[hash % HASHSZ]; 247 | hashtab[hash % HASHSZ] = aux; 248 | } 249 | 250 | /* 251 | * Clear the set of configuration strings. 252 | */ 253 | static void clear_config(void) 254 | { 255 | struct item *aux, *next; 256 | unsigned int i; 257 | 258 | for (i = 0; i < HASHSZ; i++) { 259 | for (aux = hashtab[i]; aux; aux = next) { 260 | next = aux->next; 261 | free(aux); 262 | } 263 | hashtab[i] = NULL; 264 | } 265 | } 266 | 267 | /* 268 | * Record the use of a CONFIG_* word. 269 | */ 270 | static void use_config(const char *m, int slen) 271 | { 272 | unsigned int hash = strhash(m, slen); 273 | int c, i; 274 | 275 | if (is_defined_config(m, slen, hash)) 276 | return; 277 | 278 | define_config(m, slen, hash); 279 | 280 | printf(" $(wildcard "X_CONF_DIR); 281 | for (i = 0; i < slen; i++) 282 | putchar(tolower(m[i])); 283 | printf(".h) \\\n"); 284 | } 285 | 286 | static void parse_config_file(const char *map, size_t len) 287 | { 288 | const int *end = (const int *) (map + len); 289 | /* start at +1, so that p can never be < map */ 290 | const int *m = (const int *) map + 1; 291 | const char *p, *q; 292 | 293 | for (; m < end; m++) { 294 | if (*m == INT_CONF) { p = (char *) m ; goto conf; } 295 | if (*m == INT_ONFI) { p = (char *) m-1; goto conf; } 296 | if (*m == INT_NFIG) { p = (char *) m-2; goto conf; } 297 | if (*m == INT_FIG_) { p = (char *) m-3; goto conf; } 298 | continue; 299 | conf: 300 | if (p > map + len - 7) 301 | continue; 302 | if (memcmp(p, "CONFIG_", 7)) 303 | continue; 304 | for (q = p + 7; q < map + len; q++) { 305 | if (!(isalnum(*q) || *q == '_')) 306 | goto found; 307 | } 308 | continue; 309 | 310 | found: 311 | if (!memcmp(q - 7, "_MODULE", 7)) 312 | q -= 7; 313 | if( (q-p-7) < 0 ) 314 | continue; 315 | use_config(p+7, q-p-7); 316 | } 317 | } 318 | 319 | /* test is s ends in sub */ 320 | static int strrcmp(char *s, char *sub) 321 | { 322 | int slen = strlen(s); 323 | int sublen = strlen(sub); 324 | 325 | if (sublen > slen) 326 | return 1; 327 | 328 | return memcmp(s + slen - sublen, sub, sublen); 329 | } 330 | 331 | static void do_config_file(const char *filename) 332 | { 333 | struct stat st; 334 | int fd; 335 | void *map; 336 | 337 | fd = open(filename, O_RDONLY); 338 | if (fd < 0) { 339 | fprintf(stderr, "fixdep: error opening config file: "); 340 | perror(filename); 341 | exit(2); 342 | } 343 | fstat(fd, &st); 344 | if (st.st_size == 0) { 345 | close(fd); 346 | return; 347 | } 348 | #ifndef OS_WIN32 349 | map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 350 | if ((long) map == -1) { 351 | perror("fixdep: mmap"); 352 | close(fd); 353 | return; 354 | } 355 | #else 356 | HANDLE fMap; 357 | close(fd); 358 | map = mmap(filename, st.st_size, &fMap); 359 | if ((long) map == NULL) { 360 | perror("fixdep: mmap"); 361 | return; 362 | } 363 | #endif 364 | 365 | parse_config_file(map, st.st_size); 366 | 367 | #ifndef OS_WIN32 368 | munmap(map, st.st_size); 369 | close(fd); 370 | #else 371 | munmap(map, fMap); 372 | #endif 373 | 374 | } 375 | 376 | /* 377 | * Important: The below generated source_foo.o and deps_foo.o variable 378 | * assignments are parsed not only by make, but also by the rather simple 379 | * parser in scripts/mod/sumversion.c. 380 | */ 381 | static void parse_dep_file(void *map, size_t len) 382 | { 383 | char *m = map; 384 | char *end = m + len; 385 | char *p; 386 | char s[PATH_MAX]; 387 | int first; 388 | 389 | p = strchr(m, ':'); 390 | if (!p) { 391 | fprintf(stderr, "fixdep: parse error\n"); 392 | exit(1); 393 | } 394 | memcpy(s, m, p-m); s[p-m] = 0; 395 | m = p+1; 396 | 397 | clear_config(); 398 | 399 | first = 1; 400 | while (m < end) { 401 | while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) 402 | m++; 403 | p = m; 404 | while (p < end && *p != ' ') p++; 405 | if (p == end) { 406 | do p--; while (!isalnum(*p)); 407 | p++; 408 | if(p - m <= 0) 409 | break; 410 | } 411 | memcpy(s, m, p-m); s[p-m] = 0; 412 | 413 | #ifdef OS_WIN32 414 | for (int i = 0;i < p-m; i++) 415 | if (s[i] == '\\') s[i] = '/'; 416 | #endif 417 | 418 | if (strrcmp(s, X_CONF_DIR"autoconf.h")) { 419 | /* 420 | * Do not list the source file as dependency, so that 421 | * kbuild is not confused if a .c file is rewritten 422 | * into .S or vice versa. Storing it in source_* is 423 | * needed for modpost to compute srcversions. 424 | */ 425 | if (first) { 426 | printf("source_%s := %s\n\n", target, s); 427 | printf("deps_%s := \\\n", target); 428 | } else 429 | printf(" %s \\\n", s); 430 | do_config_file(s); 431 | } 432 | first = 0; 433 | m = p + 1; 434 | } 435 | printf("\n%s: $(deps_%s)\n\n", target, target); 436 | printf("$(deps_%s):\n", target); 437 | } 438 | 439 | static void print_deps(void) 440 | { 441 | struct stat st; 442 | int fd; 443 | void *map; 444 | 445 | fd = open(depfile, O_RDONLY); 446 | if (fd < 0) { 447 | fprintf(stderr, "fixdep: error opening depfile: "); 448 | perror(depfile); 449 | exit(2); 450 | } 451 | if (fstat(fd, &st) < 0) { 452 | fprintf(stderr, "fixdep: error fstat'ing depfile: "); 453 | perror(depfile); 454 | exit(2); 455 | } 456 | if (st.st_size == 0) { 457 | fprintf(stderr,"fixdep: %s is empty\n",depfile); 458 | close(fd); 459 | return; 460 | } 461 | 462 | #ifndef OS_WIN32 463 | map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 464 | if ((long) map == -1) { 465 | perror("fixdep: mmap"); 466 | close(fd); 467 | return; 468 | } 469 | #else 470 | HANDLE fMap; 471 | close(fd); 472 | map = mmap(depfile, st.st_size, &fMap); 473 | if ((long) map == NULL) { 474 | perror("fixdep: mmap"); 475 | return; 476 | } 477 | #endif 478 | 479 | parse_dep_file(map, st.st_size); 480 | 481 | #ifndef OS_WIN32 482 | munmap(map, st.st_size); 483 | close(fd); 484 | #else 485 | munmap(map, fMap); 486 | #endif 487 | } 488 | 489 | static void traps(void) 490 | { 491 | static char test[] __attribute__((aligned(sizeof(int)))) = "CONF"; 492 | int *p = (int *)test; 493 | 494 | if (*p != INT_CONF) { 495 | fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n", 496 | *p); 497 | exit(2); 498 | } 499 | } 500 | 501 | int main(int argc, char *argv[]) 502 | { 503 | traps(); 504 | 505 | if (argc != 4) 506 | usage(); 507 | 508 | depfile = argv[1]; 509 | target = argv[2]; 510 | cmdline = argv[3]; 511 | 512 | print_cmdline(); 513 | print_deps(); 514 | 515 | return 0; 516 | } 517 | -------------------------------------------------------------------------------- /scripts/include.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(include_Makefile_include),) 2 | include_Makefile_include:=1 3 | 4 | # Convenient variables 5 | comma := , 6 | squote := ' 7 | empty := 8 | space := $(empty) $(empty) 9 | blank := 10 | 11 | define newline 12 | 13 | $(blank) 14 | endef 15 | 16 | ### 17 | # Escape single quote for use in echo statements 18 | escsq = $(subst $(squote),'\$(squote)',$1) 19 | 20 | echo-cmd = $(if $(quiet_cmd_$(1)),$(ECHO) '$(quiet_cmd_$(1))';) 21 | 22 | # >'< substitution is for echo to work, 23 | # >$< substitution to preserve $ when reloading .cmd file 24 | # note: when using inline perl scripts [perl -e '...$$t=1;...'] 25 | # in $(cmd_xxx) double $$ your perl vars 26 | make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(subst $(newline),,$(cmd_$(1)))))) 27 | 28 | ### 29 | # Shorthand for $(MAKE) -f scripts/build.mk obj= 30 | # Usage: 31 | # $(MAKE) $(build)=dir 32 | build := -f $(XBUILD_DIR)/build.mk obj 33 | 34 | # Check if both arguments has same arguments. Result is empty string if equal. 35 | # User may override this check using make KBUILD_NOCMDDEP=1 36 | arg-check = $(strip $(filter-out $(subst $(newline),,$(cmd_$(1))), $(cmd_$@)) \ 37 | $(filter-out $(cmd_$@),$(subst $(newline),,$(cmd_$(1))))) 38 | 39 | # Find any prerequisites that is newer than target or that does not exist. 40 | # PHONY targets skipped in both cases. 41 | any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) 42 | 43 | dot-target = $(@D)/.$(@F) 44 | depfile = $(dot-target).d 45 | 46 | # Execute command if command has changed or prerequisite(s) are updated. 47 | # 48 | if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ 49 | @set -e; \ 50 | $(echo-cmd) $(cmd_$(1)); \ 51 | echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) 52 | 53 | fixdep := $(objtree)/fixdep 54 | 55 | # Execute the command and also postprocess generated .d dependencies file. 56 | if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ 57 | @set -e; \ 58 | $(echo-cmd) $(cmd_$(1)); \ 59 | $(fixdep) $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \ 60 | rm -f $(depfile); \ 61 | mv -f $(dot-target).tmp $(dot-target).cmd) 62 | 63 | endif #ifeq ($(include_Makefile_include),) -------------------------------------------------------------------------------- /scripts/rule.mk: -------------------------------------------------------------------------------- 1 | include $(XBUILD_DIR)/include.mk 2 | 3 | quiet_cmd_cc_o_c = $(ECHO_CC) $(@:.o=) 4 | cmd_cc_o_c = $(CC) $(X_CFLAGS) -MD -MF $(@D)/.$(@F).d $(X_CPPFLAGS) -c $< -o $@ 5 | 6 | quiet_cmd_as_o_S = $(ECHO_AS) $(@:.o=) 7 | cmd_as_o_S = $(AS) $(X_ASFLAGS) -MD -MF $(@D)/.$(@F).d $(X_CPPFLAGS) -c $< -o $@ 8 | 9 | quiet_cmd_cc_o_cpp = $(ECHO_CXX) $(@:.o=) 10 | cmd_cc_o_cpp = $(CXX) $(X_CXXFLAGS) -MD -MF $(@D)/.$(@F).d $(X_CPPFLAGS) -c $< -o $@ 11 | 12 | # If the list of objects to link is empty, just create an empty built-in.o 13 | quiet_cmd_link_o_target = $(ECHO_LD) $(obj)/built-in.o 14 | cmd_link_o_target = $(if $(strip $(X_OBJS)), \ 15 | $(LD) -r -o $@ $(filter $(X_OBJS), $^), \ 16 | $(RM) $@;$(AR) rcs $@) 17 | 18 | $(obj)/built-in.o : $(X_OBJS) FORCE 19 | $(call if_changed,link_o_target) 20 | 21 | $(obj)/%.S.o : $(src)/%.S FORCE 22 | $(call if_changed_dep,as_o_S) 23 | 24 | $(obj)/%.c.o : $(src)/%.c FORCE 25 | $(call if_changed_dep,cc_o_c) 26 | 27 | $(obj)/%.cpp.o : $(src)/%.cpp FORCE 28 | $(call if_changed_dep,cc_o_cpp) 29 | 30 | # For module target 31 | ifneq ($(NAME),) 32 | ifeq ($(origin CUSTOM_TARGET_CMD),undefined) 33 | quiet_cmd_link_o_binary = $(ECHO_OUTPUT) $(obj)/$(NAME)$(SUFFIX) 34 | cmd_link_o_binary= $(CC) $(X_CFLAGS) $(X_CPPFLAGS) $(X_OBJS) -o $@ $(X_LDFLAGS) $(X_LDLIBS) 35 | 36 | quiet_cmd_ar_o_static = $(ECHO_AR) $(obj)/lib$(NAME).a 37 | cmd_ar_o_static = $(if $(strip $(X_OBJS)), \ 38 | $(AR) rc $@ $(filter $(X_OBJS), $^), \ 39 | $(RM) $@;$(AR) rcs $@) 40 | 41 | quiet_cmd_link_o_shared = $(ECHO_LD) $(obj)/lib$(NAME).$(SHARED_SUFFIX) 42 | cmd_link_o_shared = $(CC) -shared $(X_CFLAGS) $(X_CPPFLAGS) $(X_OBJS) -o $@ $(X_LDFLAGS) $(X_LDLIBS) 43 | 44 | $(obj)/$(NAME)$(SUFFIX) : $(X_OBJS) FORCE 45 | $(call if_changed,link_o_binary) 46 | 47 | $(obj)/lib$(NAME).a : $(X_OBJS) FORCE 48 | $(call if_changed,ar_o_static) 49 | 50 | $(obj)/lib$(NAME).$(SHARED_SUFFIX) : $(X_OBJS) FORCE 51 | $(call if_changed,link_o_shared) 52 | else 53 | quiet_cmd_link_o_custom = 54 | cmd_link_o_custom = $(CUSTOM_TARGET_CMD) 55 | 56 | $(obj)/$(NAME) : $(X_OBJS) FORCE 57 | $(call if_changed,link_o_custom) 58 | endif 59 | endif -------------------------------------------------------------------------------- /scripts/wrapper.mk: -------------------------------------------------------------------------------- 1 | all: 2 | # Don't include env.mk again 3 | include_Makefile_env:=1 4 | export include_Makefile_env 5 | 6 | include $(XBUILD_DIR)/define.mk 7 | include $(XBUILD_DIR)/include.mk 8 | 9 | srctree := $(BUILD_SRC) 10 | objtree := $(CURDIR) 11 | src := . 12 | obj := . 13 | 14 | VPATH := $(srctree) 15 | 16 | export srctree objtree VPATH 17 | 18 | ROOT_DIR := . 19 | CP_FIXDEP := 0 20 | # config 21 | X_CONF_DIR := $(obj)/include/config 22 | X_CONF_FILE := $(srctree)/include/xconfigs.h 23 | 24 | # compiler's flags 25 | X_ASFLAGS := 26 | X_CFLAGS := 27 | X_CXXFLAGS := 28 | X_LDFLAGS := 29 | X_LIBDIRS := 30 | X_LIBS := 31 | X_DEFINES := 32 | X_INCDIRS := 33 | X_INCS := 34 | X_CPPFLAGS := 35 | 36 | ifneq ($(wildcard $(X_CONF_FILE)),) 37 | X_CPPFLAGS += -include $(X_CONF_DIR)/autoconf.h 38 | endif 39 | 40 | export X_ASFLAGS X_CFLAGS X_CXXFLAGS X_LDFLAGS X_LIBDIRS X_LIBS X_DEFINES X_LDFLAGS X_INCDIRS X_INCS 41 | export BUILD_OBJ BUILD_SRC X_CONF_DIR 42 | 43 | PHONY += all clean xbegin xend xclean conf fixdep $(ROOT_DIR) 44 | 45 | ifneq ($(wildcard $(X_CONF_FILE)),) 46 | include $(XBUILD_DIR)/conf.mk 47 | 48 | xbegin: conf 49 | endif 50 | 51 | xbegin: $(objtree)/fixdep$(SUFFIX) 52 | all: xend 53 | xend: $(ROOT_DIR) 54 | 55 | $(objtree)/fixdep$(SUFFIX): $(XBUILD_DIR)/fixdep.c 56 | @$(ECHO) '$(ECHO_HOSTCC)' fixdep.c 57 | ifeq ($(strip $(HOSTOS)),windows) 58 | ifeq ($(strip $(CP_FIXDEP)),0) 59 | @$(HOSTCC) -o $@ $< -lwsock32 60 | else 61 | @$(CP) $(XBUILD_DIR)/fixdep$(SUFFIX) $(objtree)/fixdep$(SUFFIX) 62 | endif 63 | else 64 | @$(HOSTCC) -o $@ $< 65 | endif 66 | 67 | ifneq ($(MAKECMDGOALS),clean) 68 | $(ROOT_DIR): xbegin 69 | endif 70 | 71 | $(ROOT_DIR): 72 | @$(MAKE) $(build)=$@ ISMODULE=1 $(MAKECMDGOALS) 73 | 74 | clean: $(ROOT_DIR) 75 | ifneq ($(wildcard $(objtree)/fixdep$(SUFFIX)),) 76 | @$(ECHO) '$(ECHO_RM)' fixdep 77 | @$(RM) $(objtree)/fixdep$(SUFFIX) 78 | endif 79 | ifneq ($(wildcard $(X_CONF_DIR)),) 80 | @$(ECHO) '$(ECHO_RM)' $(X_CONF_DIR) 81 | @$(RM) $(X_CONF_DIR) 82 | endif 83 | 84 | PHONY += FORCE 85 | 86 | FORCE: 87 | 88 | # Declare the contents of the .PHONY variable as phony. We keep that 89 | # information in a variable so we can use it in if_changed and friends. 90 | .PHONY: $(PHONY) --------------------------------------------------------------------------------