RTEMS 应用程序含有多级子目录的Makefile工程文件编写

来源:互联网 发布:递归算法的使用场景 编辑:程序博客网 时间:2024/05/01 08:42
上一篇《RTEMS应用程序的目录管理:Makefile写法》,写得不好。让大家受累了。很多同事童鞋留言,在我QQ里留言。恩,看来我需要把这篇文章重新整理一下。

RTEMS 官方提供的rtems 应用程序的示例,都是平面结构的。即一个目录下,所有的源代码都在同一个目录下。执行make后,如果编译成功,会在源代码目录下创建一个o-optimize,在这个目录下,所有代码生成的文件都在这个目录下。大多数如下目录结构所示:
RTEMS_APP_DIR
 |--main.c
 |--main.h
 |--init.c
 |--other.c
 `--Makefile


实际工程项目可能很复杂,可能平板式的目录结构无法满足复杂项目的需求。源码目录下可能需要再分目录。比如说采用这样的目录结构:

RTEMS_APP_DIR
|-- Makefile
|-- main
|   |-- init.c
|   |-- init.o
|   `-- test
|       |-- test2.c
|       `-- test2.o
`-- test.c


对于这样的一个目录结构,如何编写Makefile,支持这样的目录结构。Makefile的依赖规则在 /opt/rtems-4.9/make/compilers/gcc-target-default.cfg中(第103行到129行)。

${ARCH}/%.o: %.c
    ${COMPILE.c} $(AM_CPPFLAGS) $(AM_CFLAGS) -o $@ $<

${ARCH}/%.o: %.cc
    ${COMPILE.cc} $(AM_CPPFLAGS) $(AM_CXXFLAGS) -o $@ $<

${ARCH}/%.o: %.cpp
    ${COMPILE.cc} $(AM_CPPFLAGS) $(AM_CXXFLAGS) -o $@ $<

${ARCH}/%.o: %.cxx
    ${COMPILE.cc} $(AM_CPPFLAGS) $(AM_CXXFLAGS) -o $@ $<

${ARCH}/%.o: %.C
    ${COMPILE.cc} $(AM_CPPFLAGS) $(AM_CXXFLAGS) -o $@ $<

${ARCH}/%.o: %.S
    ${COMPILE.S} $(AM_CPPFLAGS) -DASM -o $@ $<


%是通配符。当前文件夹是Makefile所在的文件夹,即最顶层的目录文件夹。对于以下目录结构中的 test.c 文件,


RTEMS_APP_DIR
|-- Makefile
|-- main
|   |-- init.c
|   `-- test
|       `-- test2.c
`-- test.c


这个test.c 的规则是:

${ARCH}/test.o: test.c
     ${COMPILE.c} $(AM_CPPFLAGS) $(AM_CFLAGS) -o $@ $<


${ARCH}是什么,就是o-optimize,o-optimize目录是由rtems 的 makefile 库创建的。


但是对于main/init.c这个文件,情况就不一样了。按照规则,它的依赖规则应该是:

${ARCH}/main/init.o: main/init.c
    ${COMPILE.c} $(AM_CPPFLAGS) $(AM_CFLAGS) -o $@ $<


这里就有一个问题了,${ARCH}目录夹下是没有main文件夹的。rtems的makefile库并不会自动创建这个main文件夹。所以,这个规则,会因为${ARCH}下没有main文件夹而验证失败。make会产生一个错误。同理,只要不在顶层目录夹下的源文件都会有这样的问题。


我的目标是将生成的文件还是放在${ARCH}目录下,这样能最大限度的利用rtems makefile库里的一些功能。所以,实际上就是自己编程实现make依赖规则,将带目录的源文件,其源文件的目录全部剥去,${ARCH}下的obj文件直接对应着源文件,而不需要建立任何的子目录。如 main/init.c文件,想办法生成规则:

${ARCH}/init.o: main/init.c
    ${COMPILE.c} $(AM_CPPFLAGS) $(AM_CFLAGS) -o $@ $<

这样,编译就可以顺利通过了。然而这并不是一件轻松的事情。每个工程的文件名和路径都千差万别,不可能自己手工去写,那是要命的。好在,make提供了两个特别牛的函数,一个循环 foreach,一个是 eval。这两个函数还是一样,不懂的童鞋,那就要看看make的手册,好好多读几遍,其实我也看了很多遍,才理解。

这个规则就是:

$(foreach each_obj_files, $(OBJS), $(eval $${ARCH}/$(notdir $(each_obj_files)):$(filter %$(basename $(notdir $(each_obj_files))).c,${SRCS}); ${COMPILE.c} $(AM_CPPFLAGS) $(AM_CFLAGS) -o $$@ $$<))

就是想办法把源文件的路径剥离掉,然后建立${ARCH}目录下目标文件与源文件之间的生成规则。这个没什么太多好说的,由于应用程序中还有可能有c++、汇编文件,还需要不同的源文件生成规则。读者可以依照 .c 文件的规则依次添加。


不管怎么说,还是推荐您多读 GNU make 的手册。毕竟,这是基础。enjoy it!










原创粉丝点击