一. 我分享的是一个简化版的编译架构,我要实现的目标是:对遵循以下组织结构的文件夹进行编译:
bb_xxx
_inc
_src
entry
………
modules
module1
………
module2
………
………
_src目录下可以允许有递归目录或者文件,最大深度不超过5,Makefile定义规则会去自动搜索所有的c源文件,编译出的所有.o文件会生成在out/obj目录,可执行文件会生成在out/bin目录
通常Makefile可能需要这样写:
rm=/bin/rm -f
CC= gcc
DEFS=
PROGNAME= out/bin/test
INCLUDES= -I./_inc
LIBS=
DEFINES= $(INCLUDES) $(DEFS)-DSYS_UNIX=1
CFLAGS= -g $(DEFINES)
SRCS = src/entry/entry.csrc/modules/ module1/Mytest.c src/modules/module2/test.c
OBJS = out/obj/entry.oout/obj/Mytest.o out/obj/test.o
all: $(PROGNAME)
$(PROGNAME) : $(OBJS)
$(CC) $(CFLAGS) -o $(PROGNAME) $(OBJS) $(LIBS)
out/obj/%.o:src/entry/%.c
$(CC) $(CFLAGS) -c $< -o $@
out/obj/%.o:src/modules/module1/%.c
$(CC) $(CFLAGS) -c $< -o $@
out/obj/%.o:src/modules/module2/%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
$(rm)$(OBJS) $(PROGNAME) core *~
虽然以上Makefile也可以工作,但是扩展性不佳,如果_src目录下将来需要加入更多module或者其他代码,就需要修改Makefile里面的SRCS以及依赖关系,假如_src目录很深,底下的文件众多,这个工作量可能比较繁琐
二、
再看看下面的Makefile:
# Created with mak.pl v0.1 on FriMay 26 19:43:38 2017
rm=/bin/rm -f
CC= gcc
DEFS=
PROGNAME= out/bin/test
INCLUDES= -I./_inc
LIBS=
DEFINES= $(INCLUDES) $(DEFS)-DSYS_UNIX=1
CFLAGS= -g $(DEFINES)
SRCS_DIR = $(shell find _src -maxdepth 5 -type d)
OBJS_DIR = out/obj
SRCS = $(foreach d,$(SRCS_DIR),$(wildcard $(d)/*.c))
OBJS = $(addprefix$(OBJS_DIR)/,$(patsubst%.c,%.o,$(notdir $(SRCS))))
all: $(PROGNAME)
$(PROGNAME) : $(OBJS)
$(CC) $(CFLAGS) -o $(PROGNAME) $(OBJS) $(LIBS)
define make-object
$1:$2
$(CC) $(CFLAGS) -c $$< -o $$@
endef
$(foreach d,$(SRCS_DIR),$(eval $(callmake-object,$(OBJS_DIR)/%.o,$(d)/%.c)))
clean:
$(rm) $(OBJS) $(PROGNAME) core *~
通过定义自己的规则,即使源码目录发生改变,Makefile也不需要做修改,达到增强扩展性的目的.大家有兴趣可以看看BASA编译体系里面的project.mk,它定义的规则更加复杂和庞大
三、
实现Makefile自动生成,以上Makefile可以通过一个perl脚本自动生成,执行run.sh即可(请参考附件),以下是run.sh脚本的内容:
#!/bin/sh
if [ ! -d "out"];then
mkdir -p out/bin
mkdir -p out/obj
fi
PROGNAME=hsm_test
./mak.pl --app=$PROGNAME _src >Makefile
其中--app选项定义生成的可执行文件名,_src指定存放源码的目录(其实源码目录也可以是其他名称而不局限于”_src”)
run.sh
#!/bin/sh if [ ! -d "out" ];then mkdir -p out/bin mkdir -p out/obj fi PROGNAME=hsm_test ./mak.pl --app=$PROGNAME _src > Makefilemak.pl
#!/usr/bin/perl use strict; use Getopt::Long; $|=1; my ($g_app,$g_help)=''; my %g_op=(); ## Unix application template follows my $g_unix_app_template=<<EOF; # -=VERSION=- rm=/bin/rm -f CC= gcc DEFS= PROGNAME= -=PROG=- INCLUDES= -I./_inc LIBS= DEFINES= \$(INCLUDES) \$(DEFS) -DSYS_UNIX=1 CFLAGS= -g \$(DEFINES) SRCS_DIR = \$(shell find -=SRCS=- -maxdepth 5 -type d) OBJS_DIR = out/obj SRCS = \$(foreach d,\$(SRCS_DIR),\$(wildcard \$(d)/*.c)) OBJS = \$(addprefix \$(OBJS_DIR)/,\$(patsubst %.c,%.o,\$(notdir \$(SRCS)))) all: \$(PROGNAME) \$(PROGNAME) : \$(OBJS) \$(CC) \$(CFLAGS) -o \$(PROGNAME) \$(OBJS) \$(LIBS) define make-object \$1:\$2 \$(CC) \$(CFLAGS) -c \$\$< -o \$\$@ endef \$(foreach d,\$(SRCS_DIR),\$(eval \$(call make-object,\$(OBJS_DIR)/%.o,\$(d)/%.c))) clean: \$(rm) \$(OBJS) \$(PROGNAME) core *~ EOF ; my $argc=$#ARGV+1; my %g_options=( "app=s" =>\$g_op{app}, "help" =>\$g_help, ); &do_it(); # show usage and exit sub usage { print<<EOF; gm.pl v0.1 A program to generate simple Makefiles for Linux/Unix $0 [options] Where the options include: --app=name generate Makefile for an application Example: $0 --app=myapp > Makefile EOF ; exit(1); } ##----- # do everything and exit ##----- sub do_it { my $result=GetOptions(%g_options); $g_app=$g_op{app}; if ($g_app) { $argc--; &gen_unix_makefile(); exit(0); } &usage(); } # generate Makefile for Linux/Unix sub gen_unix_makefile { my $date=localtime(time()); my $created="Created with mak.pl v0.1 on $date"; my $i; my $srcs=''; for ($i=0; $i < $argc; $i++) { $srcs .= "$ARGV[$i] "; } $g_unix_app_template =~ s/-=PROG=-/out\/bin\/$g_app/g; $g_unix_app_template =~ s/-=VERSION=-/$created/g; $g_unix_app_template =~ s/-=SRCS=-/$srcs/g; $g_unix_app_template =~ s/-=CC=-/cc/g; print $g_unix_app_template; }