看到關(guān)于Makefile的必要性討論,忽然想起自己干過(guò)一些有趣的的事情。
一個(gè)目錄下有一大堆同質(zhì)或不同質(zhì)的程序,要測(cè)試系統(tǒng)處理并發(fā)任務(wù)的效率不得不寫一個(gè)任務(wù)分發(fā)器(work load manager),用C寫對(duì)新手來(lái)說(shuō)還是有點(diǎn)大條的,利用make -j可以模擬一個(gè)簡(jiǎn)單的wlm。代碼大概如下:
binaries := $(foreach ccode, \
$(shell for cfile in `ls *.c`; do echo $cfile; done),\
$(ccode:.c=))
$(binaries): %:%.c
@echo BLD $@
@gcc -o $@ $《 》/dev/null 2》&1
to_run := $(foreach ccode, \
$(shell for cfile in `ls *.c`; do echo $cfile; done),\
to_run_$(ccode:.c=))
run: clean $(to_run)
to_run_%: %
@to_run=$@; \
echo ${to_run##to_run_};
clean:
@echo -n “-------------------------------- CLEAN ”
@echo “--------------------------------”
@echo RMV $(binaries)
@rm -f $(binaries)
.PHONY: run clean
運(yùn)行 make -jN 即可
簡(jiǎn)而言之就是:
1. default 的 target 是 run,run 依賴于 clean 和 to_run
run: clean $(to_run)
2. to_run 是由一段 shell 產(chǎn)生的
to_run := $(foreach ccode, \
$(shell for cfile in `ls *.c`; do echo $cfile; done),\
to_run_$(ccode:.c=))
3. 假設(shè)目錄下有 1.c 2.c 3.c 4.c 。。. 100.c 這100個(gè)c程序, 那段 shell 生成的變量 to_run 等于這樣的一串: to_run_1 to_run2 。。. to_run_100
4. to_run_%: % 那一段 rule 的意思是對(duì)于某個(gè)目標(biāo) to_run_73 依賴于 73,當(dāng) 73 不存在或者 73.c 被更新過(guò), make 就按照上面聲明的 binaries 的規(guī)則去(重新)生成它:
$(binaries): %:%.c
@echo BLD $@
@gcc -o $@ $《 》/dev/null 2》&1
5. 73 生成以后就運(yùn)行它,示例里用的是 echo
@to_run=$@; \
echo ${to_run##to_run_};
實(shí)際上可以是
@to_run=$@; \
。/${to_run##to_run_};
這樣 73 就在適當(dāng)?shù)臅r(shí)候被運(yùn)行了。
假設(shè)輸入 make -j32 run,結(jié)果就是可執(zhí)行文件 1, 2, 3 。。. 32 同時(shí)被運(yùn)行,其中的某個(gè)結(jié)束后 make 會(huì)自動(dòng)啟動(dòng)后面的 33, 34 。。. 直至所有的運(yùn)行結(jié)束,這就模擬了一個(gè)簡(jiǎn)單的本地 work load manager。
這個(gè)make腳本的另外一個(gè)變種可以是:你有一個(gè)程序(假設(shè)叫 EXEC0),在一臺(tái)16核的機(jī)器上你希望并行地運(yùn)行32個(gè)帶不同參數(shù)的 EXEC0 實(shí)例,總共運(yùn)行 1024 個(gè)實(shí)例來(lái)測(cè)試系統(tǒng)或者 EXEC0 的運(yùn)行效率,Makefile大概可以這樣寫:
ifeq ($(MAX),)
MAX=1024
endif
parameter0=0
parameter1=11
parameter2=22
parameter3=33
prerequisites := $(foreach num, \
$(shell i=0; while [ $$i -lt $(MAX) ]; \
do \
echo $$i; \
i=$$((i + 1)); \
done), \
target_$(num))
run:$(prerequisites)
EXEC0: EXEC0.c
gcc -o $@ $《
target_%:EXEC0
@./EXEC0 $(parameter$(shell expr $(subst target_,,$@) % 4))
.PHONY: run
一個(gè)無(wú)聊的EXEC0.c 可以是:
int
main(int argc, char **argv)
{
sleep(atoi(argv[1]));
printf(“%s %d\n”, argv[0], atoi(argv[1]));
return 0;
}
然后make -j32 MAX=1024
/////////////////////////////////////////////////////////////////////////////////////////////////////////
試驗(yàn)記錄:
testcase := $(shell for test in `ls 。。/tests/`; do echo $$test; done)
to_run := $(foreach test, \
$(shell for test in `ls 。。/tests/`; do echo $$test; done), \
to_run_$(test))
run : $(to_run)
to_run_%:
@to_run=$@; \
run_test $${to_run##to_run_};
#$(shell grep -rn “Error” 。/$${to_run##to_run_}/irun.log 》》 error.log)
clean:
@echo -n “-------------------------- CLEAN”
@echo “--------------------------”
@echo RMV $(testcase)
@rm -rf $(testcase)
.PHONY: run clean
評(píng)論