1. 程式人生 > >makefile編譯子目錄

makefile編譯子目錄

word file mon 做了 其他 last dal 直接 config

make子目錄常用方法

一般是

SUB_DIR =  lib_src service

.PHONY: subdirs $(SUB_DIR)

subdirs: $(SUB_DIR)

$(SUB_DIR):
    @+make -C $@
    
foo: baz

或者

subdirs:
    for dir in $(SUB_DIR); do       @+make -C $$dir;     done

使用循環的方式比較直觀,但是會有這樣的問題

  • 當submake報錯的時候不會停止,其他submake會繼續執行
  • 不能體驗到make的並行編譯 即-j選項
  • 子目錄之間的依賴不好表示

所以,一般來說會選擇第一種來寫.但是,當用第一種書寫時,怎麽表達make子命令(即:make install)呢?

make子命令書寫


SUB_DIR_TEST = $(SUB_DIR:%=%_test)

test: $(SUB_DIR_TEST)
$(SUB_DIR_TEST): 
    @+make  -C $(@:%_test=%) test

.PHONY: test subdirs $(SUB_DIR_TEST)

核心就是對子目錄名字進行包裹一下,把包裹後的名字當作新的偽目標進行構建

實例

以下是我從工作項目中拷出來的
總共三個級別的目錄

  • 根目錄
  • lib_src service
  • 實際編譯目錄:game gate

所以列舉了3個makefile

項目目錄大致結構

目錄做了一些刪減
bin輸出目錄:deploy/bin

├── deploy
│   └── bin
├── deps
│   └── tinyxml
│       ├── include
│       │   └── tinyxml
│       │       └── tinyxml.h
│       └── lib
│           └── libtinyxml.a
├── lib_src
│   ├── auth
│   │   ├── auth.cpp
│   │   └── auth.h
│   ├── common
│   │   ├── common.cpp
│   │   └── common.h
│   └── lib
└── service
    ├── game
    │   └── game.cpp
    └── gate

項目根目錄下的Makefile

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
SUB_DIR = lib_src service
SUB_DIR_TEST := $(SUB_DIR:%=%_test)
SUB_DIR_CLEAN := $(SUB_DIR:%=%_clean)

all : $(SUB_DIR)
    
lib_src:
    @+make -C $@

service:lib_src 
    @+make -C $@
    
clean:$(SUB_DIR_CLEAN) 
    #$(foreach N, $(SUB_DIR),make clean -C $(N);)

$(SUB_DIR_CLEAN):
    @+make clean -C $(@:%_clean=%)

test:$(SUB_DIR_TEST)
    @echo $(MKFILE_PATH)
    
$(SUB_DIR_TEST):
    @+make test -C $(@:%_test=%)
    
.PHONY: all test clean $(SUB_DIR) $(SUB_DIR_TEST) $(SUB_DIR_CLEAN)

lib_src下的Makefile

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
SUB_DIR = auth common
SUB_DIR_CLEAN := $(SUB_DIR:%=%_clean)
SUB_DIR_TEST := $(SUB_DIR:%=%_test)

all : |mk_dir $(SUB_DIR)
    
$(SUB_DIR): mk_dir
    @+make -C $@
    
mk_dir:
    @mkdir -p bin
    
clean:$(SUB_DIR_CLEAN)
    #$(foreach N, $(SUB_DIR),make clean -C $(N);)
    
$(SUB_DIR_CLEAN):
    @+make clean -C $(@:%_clean=%) 
    
test:$(SUB_DIR_TEST)
    @echo $(MKFILE_PATH)

    
$(SUB_DIR_TEST):
    @+make test -C $(@:%_test=%)
    
.PHONY: all test clean mk_dir $(SUB_DIR) $(SUB_DIR_TEST) $(SUB_DIR_CLEAN)

game下的Makefile

編譯選項這些忽略吧

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
include ../../global.mk
TARGET := $(BIN_DIR)/game_svr$(BIN_TAG)
CUR_INC_FLAGS := -I$(FRAME_INC) -I./ -I$(MYSQL_INC)
CUR_LINK_FLAGS := $(LDFLAGS) -L$(MYSQL_LIB)
CUR_CPPFLAGS := $(CPPFLAGS) $(CUR_INC_FLAGS) 
SUB_DIR := app bll dal db thread config
ALL_OBJS = $(wildcard $(OBJ_DIR)/*.o)

all : |$(OBJ_DIR) $(TARGET)
    
$(TARGET) : $(TARGET_OBJS)  $(SUB_DIR)
    $(CXX) -o $@ $(ALL_OBJS) $(CUR_LINK_FLAGS)
    @echo "#### compile ok "$(TARGET) "####"
    
$(OBJ_DIR)/%.o : %.cpp
    $(CXX) $(CUR_CPPFLAGS) -c $< -o $@
    
$(OBJ_DIR):
    @mkdir  $@

$(SUB_DIR): 
    @echo "#### compile sub dir start ####" $@
    @+make -C $@
    @echo "#### compile sub dir end ####" $@

clean: 

    @rm -f $(wildcard $(OBJ_DIR)/*.o) $(TARGET)
    
test:
    @echo $(MKFILE_PATH)

.PHONY: all test clean 
.PHONY: $(SUB_DIR) 

簡要語法說明

$(SUB_DIR:%=%_test)
表示文件名加後綴,結果為lib_src_test service_test
$(@:%_test=%)
表示去掉後綴,結果為lib_src service
=

在真正執行命令的時候才會對變量求值,所以變量值可能會在中間因為其他引用的其他變量被改變而不是預期的

=:

在賦值的時候直接對變量求值,以後如果不重新賦值是不會變化的

makefile編譯子目錄