How to write a Makefile using different directorie

2019-01-20 18:55发布

I am writing up a Makefile and I would like to separate the build and source directories. My initial thought was just “Oh, I can write my rules prepending the source path to the filename and be done with it.”

The problem is that this solution would be super repetitive and doesn't look very nice. What would be the best approach for writing myself a Makefile that stores targets in a directory distinct from the directory holding my sources.

标签: makefile
1条回答
你好瞎i
2楼-- · 2019-01-20 18:57

The program has a very good support for storing the built targets in a directory distinct form the one holding the sources. A Makefile using this functionality might be a bit harder to write, so I will review the most important techniques in my answer.

Choosing a directory to store built targets

The built-in variable .OBJDIR contains the name of a directory where targets are built. It is determined like this (excerpt from the man page):

 .OBJDIR         A path to the directory where the targets are built.  Its
                 value is determined by trying to chdir(2) to the follow‐
                 ing directories in order and using the first match:

                 1.   ${MAKEOBJDIRPREFIX}${.CURDIR}

                      (Only if ‘MAKEOBJDIRPREFIX’ is set in the environ‐
                      ment or on the command line.)

                 2.   ${MAKEOBJDIR}

                 …

                 6.   ${.CURDIR}

The program make will chdir(2)to .OBJDIR and set PWD to that directory before executing any targets. In the absence of any adequate preparation .OBJDIR is .CURDIR, therefore we need to create the desired directory — or tree structure ­— before running make to build our targets.

Assume, you choose to rely on the first mechanism to set .OBJDIR, you can then organise your build system so that, before running make to build your targets,

  • The environment variable MAKEOBJDIRPREFIX is set to suitable value.
  • A special script (it might be a make target) prepares the necessary directory or directories under ${MAKEOBJDIRPREFIX}.

Makefiles arrangements

We consider a simple Makefile and describe arrangements necessary for the previous setup to work.

program         : a.o b.o c.o
        cc a.o b.o c.o -o program

a.o b.o c.o     : defs.h
a.o             : a.c
       cc -c a.c

b.o             : b.c
       cc -c b.c

c.o             : c.c
       cc -c c.c

manual.html: manual.css
manual.html: a.c b.c c.c defs.h
       manualtool -c manual.css -o manual.html a.c b.c c.c defs.h

Before building a.o the program make will chdir(2) to ${.OBJDIR} and run the compiler cc from that directory. Since the source a.c is located in another directory, the compiler cc will not find it and the compilation will fail. This issue is solved by using the local variables defined by make, the previous Makefile therefore translates to:

program         : a.o b.o c.o
        cc ${.ALLSRC} -o program

a.o b.o c.o     : defs.h
a.o             : a.c
       cc -c ${.ALLSRC:M*.c}

b.o             : b.c
       cc -c ${.ALLSRC:M*.c}

c.o             : c.c
       cc -c ${.ALLSRC:M*.c}

manual.html: manual.css
manual.html: a.c b.c c.c defs.h
       manualtool -c ${.ALLSRC:M*.css} -o manual.html ${.ALLSRC:N*.css}

Note how globbing patterns are used in the last recipe to appropriately select pieces of the sources at the various locations of the command line.

Examples

The build system for — and possibly and — use this functionality to be able to build simultaneously the operating system for various architectures. (It also make cleaning easier!) You could study these Makefiles to gain a better understanding of the techniques involved.

My portable macros bsdowl for also support this functionality of bsdmake, you could look at the file bps.objdir.mk and the examples.

查看更多
登录 后发表回答