Subject: Building multiple progs from a single directory
To: None <>
From: Julio M. Merino Vidal <>
List: tech-toolchain
Date: 07/08/2007 17:34:54
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;


[ Please CC me any replies ]
[ CCing Marting because he is my SoC mentor ]

I see that some of our bsd.*.mk files support building different  
targets or installing different sets of files as part of a single  
run.  The clearest example is SCRIPTS, or the ability to install  
include files in different target directories.

As part of my SoC project, I'm now adding a file that  
allows me to easily build test programs.  It seems to me that keeping  
each test program in its own directory will be overkill, given that  
test programs should be fine-grained and thus there will be many of  
them.  For example, I now have an "atf/units" directory with unit- 
tests for different atf modules; each unit-test is a test program,  
and there currently are 6 of them.  Certainly more to come.   
Following the current principle of one program per source directory  
will make our source tree explode in the number of required inodes to  
host it -- an extra Makefile plus a directory for each of these tiny  

My file is built on top of file for  
simplicity (and because I see no reason to do it otherwise).  In  
order to get the above to work, I have adapted our file  
to support building several different programs in the same directory.

What I have done is add a couple of new variables, PROGS and  
PROGS_CXX, that take the list of programs to build.  Then, the SRCS,  
OBJS, PROGNAME and similar variables are specialized to belong to  
each individual program by appending a .<prog> suffix.  Of course  
compatibility is kept with the old Makefiles so that the current tree  
does not need to be modified.  Furthermore, it is possible to build  
each program on its own by saying 'make foo' where foo is the program  
name.  Similarly it is also possible to only install or clean a  
specific one.

I have attached the preliminary patch to achieve this.  It is still  
somewhat ugly (have to adjust line wrappings, reorder things a bit,  
etc.) and it may still be bogus.  I'm now running a full release  
build from scratch to see how everything behaves.

Before I work more on this, I want to ask: are there any strong  
objections to this change?  If not I'll come back later on with a  
cleaner patch :-)


Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
Content-Disposition: attachment;

RCS file: /cvsroot/src/share/mk/,v
retrieving revision 1.220
diff -u -p -r1.220
---	25 Jan 2007 23:04:28 -0000	1.220
+++	8 Jul 2007 15:31:31 -0000
@@ -7,26 +7,49 @@
 .include <>
 .include <>
-.if defined(PROG_CXX)
-.if defined(PAXCTL_FLAGS)
+# Definitions and targets shared among all programs built by a single
+# Makefile.
 ##### Basic targets
 realinstall:	proginstall scriptsinstall
 clean:		cleanprog
-##### PROG specific flags.
-COPTS+=     ${COPTS.${PROG}}
-LDADD+=     ${LDADD.${PROG}}
+	rm -f .gdbinit
+.if defined(DESTDIR) && !empty(DESTDIR)
+	echo "set solib-absolute-prefix ${DESTDIR}" > .gdbinit
+	touch .gdbinit
+.for __gdbinit in ${GDBINIT}
+	echo "source ${__gdbinit}" >> .gdbinit
+cleanextra: .PHONY
+.if defined(CLEANFILES) && !empty(CLEANFILES)
+	rm -f ${CLEANFILES}
+cleanobjs: .PHONY
+cleanprog: .PHONY cleanobjs cleanextra
+	rm -f a.out [Ee]rrs mklog core *.core .gdbinit
+.if defined(SHAREDSTRINGS)
+	${CC} -E ${CPPFLAGS} ${CFLAGS} ${.IMPSRC} | xstr -c -
+	@${CC} ${CPPFLAGS} ${CFLAGS} -c x.c -o ${.TARGET}
+	@rm -f x.c
+ .cpp.o .cxx.o .C.o:
+	${CXX} -E ${CPPFLAGS} ${CXXFLAGS} ${.IMPSRC} | xstr -c -
+	@mv -f x.c
+	@${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o ${.TARGET}
+	@rm -f
 ##### Default values
 CPPFLAGS+=	${DESTDIR:D-nostdinc ${CPPFLAG_ISYSTEM} ${DESTDIR}/usr/include}
@@ -123,48 +146,10 @@ LIB${_lib:tu}=	${DESTDIR}/usr/X11R6/lib/
-##### Build and install rules
-.if defined(SHAREDSTRINGS)
-	${CC} -E ${CPPFLAGS} ${CFLAGS} ${.IMPSRC} | xstr -c -
-	@${CC} ${CPPFLAGS} ${CFLAGS} -c x.c -o ${.TARGET}
-	@rm -f x.c
- .cpp.o .cxx.o .C.o:
-	${CXX} -E ${CPPFLAGS} ${CXXFLAGS} ${.IMPSRC} | xstr -c -
-	@mv -f x.c
-	@${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o ${.TARGET}
-	@rm -f
-.if defined(PROG)							# {
-.if defined(PROG_CXX)
-SRCS?=		${PROG}.cc
-SRCS?=		${PROG}.c
 .if defined(RESCUEDIR)
-_YPSRCS=	${SRCS:M*.[ly]:C/\..$/.c/} ${YHEADER:D${SRCS:M*.y:.y=.h}}
-.if !empty(SRCS:N*.h:N*.sh:N*.fth)
-OBJS+=		${SRCS:N*.h:N*.sh:N*.fth:R:S/$/.o/g}
-LOBJS+=		${LSRCS:.c=.ln} ${SRCS:M*.c:.c=.ln}
-.if defined(OBJS) && !empty(OBJS)					# {
 .if ${SHLINKDIR} != "/usr/libexec"	# XXX: change or remove if moves
 .if ${OBJECT_FMT} == "ELF"
@@ -180,126 +165,209 @@ _PROGLDOPTS+=	-Wl,-rpath-link,${DESTDIR}
+__proginstall: .USE
+__progdebuginstall: .USE
+		${.ALLSRC} ${.TARGET}
+# Backwards compatibility with Makefiles that assume that
+# can only build a single binary.
 .if defined(PROG_CXX)
-.if ${MKDEBUG} != "no" && ${OBJECT_FMT} == "ELF" && !commands(${PROG})
+.if defined(PROG)
+.  if defined(PROGNAME)
+.  endif
+.  if defined(SRCS)
+.  endif
+# Turn the single-program PROG and PROG_CXX variables into their multi-word
+# counterparts, PROGS and PROGS_CXX.
+.if defined(PROG_CXX) && !defined(PROGS_CXX)
-	rm -f .gdbinit
-.if defined(DESTDIR) && !empty(DESTDIR)
-	echo "set solib-absolute-prefix ${DESTDIR}" > .gdbinit
-	touch .gdbinit
+.if defined(PROG) && !defined(PROGS)
-.for __gdbinit in ${GDBINIT}
-	echo "source ${__gdbinit}" >> .gdbinit
+# Per-program definitions and targets.
+# Definitions specific to C programs.
+.for _P in ${PROGS}
+SRCS.${_P}?=	${_P}.c
+_CCLINK.${_P}=	${CC}
+# Definitions specific to C++ programs.
+.for _P in ${PROGS_CXX}
+SRCS.${_P}?=	${_P}.cc
+_CCLINK.${_P}=	${CXX}
+# Language-independent definitions.
+.for _P in ${PROGS} ${PROGS_CXX}					# {
+PROGNAME.${_P}?=	${_P}
-.if !commands(${PROG})
+.if ${MKDEBUG} != "no" && ${OBJECT_FMT} == "ELF" && !commands(${_P})
+_PROGDEBUG.${_P}:=	${PROGNAME.${_P}}.debug
+.if defined(PAXCTL_FLAGS)
+##### PROG specific flags.
+COPTS+=     ${COPTS.${_P}}
+LDADD+=     ${LDADD.${_P}}
+_COPTS.${_P}=		${COPTS}    ${COPTS.${_P}}
+_LDADD.${_P}=		${LDADD}    ${LDADD.${_P}}
+_LDFLAGS.${_P}=		${LDFLAGS}  ${LDFLAGS.${_P}}
+##### Build and install rules
+SRCS+=		${SRCS.${_P}} # For
+_YPSRCS.${_P}=	${SRCS.${_P}:M*.[ly]:C/\..$/.c/} ${YHEADER:D${SRCS.${_P}:M*.y:.y=.h}}
+DPSRCS+=		${_YPSRCS.${_P}}
+.if !empty(SRCS.${_P}:N*.h:N*.sh:N*.fth)
+OBJS.${_P}+=	${SRCS.${_P}:N*.h:N*.sh:N*.fth:R:S/$/.o/g}
+LOBJS.${_P}+=	${LSRCS:.c=.ln} ${SRCS.${_P}:M*.c:.c=.ln}
+.if defined(OBJS.${_P}) && !empty(OBJS.${_P})			# {
+.NOPATH: ${OBJS.${_P}} ${_P} ${_YPSRCS.${_P}}
+${OBJS.${_P}} ${LOBJS.${_P}}: ${DPSRCS}
+${_P}: .gdbinit ${LIBCRT0} ${OBJS.${_P}} ${LIBC} ${LIBCRTBEGIN} ${LIBCRTEND} ${DPADD}
+.if !commands(${_P})
 .if defined(DESTDIR)
-	${_CCLINK} -Wl,-nostdlib \
+	${_CCLINK.${_P}} -Wl,-nostdlib \
+	    ${_LDFLAGS.${_P}} ${_LDSTATIC.${_P}} -o ${.TARGET} ${_PROGLDOPTS} \
 	    -B${_GCC_CRTDIR}/ -B${DESTDIR}/usr/lib/  \
-	    ${OBJS} ${LDADD} \
+	    ${OBJS.${_P}} ${_LDADD.${_P}} \
 	    -L${_GCC_LIBGCCDIR} -L${DESTDIR}/usr/lib
+	${_CCLINK.${_P}} ${_LDFLAGS.${_P}} ${_LDSTATIC.${_P}} -o ${.TARGET} ${_PROGLDOPTS} ${OBJS.${_P}} ${_LDADD.${_P}}
 .endif	# defined(DESTDIR)
-.if defined(PAXCTL_FLAGS.${PROG})
+.if defined(PAXCTL_FLAGS.${_P})
-.endif	# !commands(${PROG})
+.endif	# !commands(${_P})
-${PROG}.ro: ${OBJS} ${DPADD}
+${_P}.ro: ${OBJS.${_P}} ${DPADD}
-	${LD} -r -dc -o ${.TARGET} ${OBJS}
+	${LD} -r -dc -o ${.TARGET} ${OBJS.${_P}}
-.if defined(_PROGDEBUG)
+.if defined(_PROGDEBUG.${_P})
+${_PROGDEBUG}.${_P}: ${_P}
-	${OBJCOPY} --only-keep-debug ${PROG} ${_PROGDEBUG}
-	${OBJCOPY} -R .gnu_debuglink --add-gnu-debuglink=${_PROGDEBUG} ${PROG} \
-	    || rm -f ${_PROGDEBUG}
+	${OBJCOPY} --only-keep-debug ${_P} ${_PROGDEBUG.${_P}}
+	${OBJCOPY} -R .gnu_debuglink --add-gnu-debuglink=${_PROGDEBUG.${_P}} ${_P} \
+	    || rm -f ${_PROGDEBUG.${_P}}
-.endif	# defined(OBJS) && !empty(OBJS)					# }
+.endif	# defined(OBJS.${_P}) && !empty(OBJS.${_P})			# }
-.if !defined(MAN)
-MAN=	${PROG}.1
-.endif	# !defined(MAN)
-.endif	# defined(PROG)							# }
+.if !defined(MAN.${_P})
+MAN.${_P}=	${_P}.1
+.endif	# !defined(MAN.${_P})
+MAN+= ${MAN.${_P}}
-realall: ${PROG} ${_PROGDEBUG} ${SCRIPTS}
+realall: ${_P} ${_PROGDEBUG.${_P}}
-cleanprog: .PHONY cleanobjs cleanextra
-	rm -f a.out [Ee]rrs mklog core *.core .gdbinit ${PROG} ${_PROGDEBUG}
+cleanprog: cleanprog-${_P}
+	rm -f ${_P} ${_PROGDEBUG.${_P}}
-cleanobjs: .PHONY
-.if defined(OBJS) && !empty(OBJS)
-	rm -f ${OBJS} ${LOBJS}
-cleanextra: .PHONY
-.if defined(CLEANFILES) && !empty(CLEANFILES)
-	rm -f ${CLEANFILES}
+.if defined(OBJS.${_P}) && !empty(OBJS.${_P})
+cleanobjs: cleanobjs-${_P}
+	rm -f ${OBJS.${_P}} ${LOBJS.${_P}}
-.if defined(PROG) && !target(proginstall)				# {
+_PROG_INSTALL+=	proginstall-${_P}
-__proginstall: .USE
-__progdebuginstall: .USE
-		${.ALLSRC} ${.TARGET}
+.if !target(proginstall-${_P})					# {
+proginstall-${_P}::	${DESTDIR}${BINDIR}/${PROGNAME.${_P}} \
 .if ${MKUPDATE} == "no"
-${DESTDIR}${BINDIR}/${PROGNAME}! ${PROG} __proginstall
-.if !defined(BUILD) && !make(all) && !make(${PROG})
-.if defined(_PROGDEBUG)
-${DESTDIR}${DEBUGDIR}${BINDIR}/${_PROGDEBUG}! ${_PROGDEBUG} __progdebuginstall
-.if !defined(BUILD) && !make(all) && !make(${PROG})
+${DESTDIR}${BINDIR}/${PROGNAME.${_P}}! ${_P} __proginstall
+.if !defined(BUILD) && !make(all) && !make(${_P})
+.if defined(_PROGDEBUG.${_P})
+${DESTDIR}${DEBUGDIR}${BINDIR}/${_PROGDEBUG.${_P}}! ${_PROGDEBUG.${_P}} __progdebuginstall
+.if !defined(BUILD) && !make(all) && !make(${_P})
-.endif	#  define(_PROGDEBUG)
+.endif	#  define(_PROGDEBUG.${_P})
 .else	# MKUPDATE != no
-${DESTDIR}${BINDIR}/${PROGNAME}: ${PROG} __proginstall
-.if !defined(BUILD) && !make(all) && !make(${PROG})
-.if defined(_PROGDEBUG)
-${DESTDIR}${DEBUGDIR}${BINDIR}/${_PROGDEBUG}: ${_PROGDEBUG} __progdebuginstall
-.if !defined(BUILD) && !make(all) && !make(${PROG})
+${DESTDIR}${BINDIR}/${PROGNAME.${_P}}: ${_P} __proginstall
+.if !defined(BUILD) && !make(all) && !make(${_P})
+.if defined(_PROGDEBUG.${_P})
+${DESTDIR}${DEBUGDIR}${BINDIR}/${_PROGDEBUG.${_P}}: ${_PROGDEBUG.${_P}} __progdebuginstall
+.if !defined(BUILD) && !make(all) && !make(${_P})
-.endif	#  defined(_PROGDEBUG)
+.endif	#  defined(_PROGDEBUG.${_P})
 .endif	# MKUPDATE != no
-.endif	# defined(PROG) && !target(proginstall)				# }
+.endif	# !target(proginstall-${_P})					# }
+lint: lint-${_P}
+lint-${_P}: ${LOBJS.${_P}}
+.if defined(LOBJS.${_P}) && !empty(LOBJS.${_P})
+	${LINT} ${LINTFLAGS} ${_LDFLAGS.${_P}:C/-L[  ]*/-L/Wg:M-L*} ${LOBJS.${_P}} ${_LDADD.${_P}}
+.endfor # _P in ${PROGS} ${PROGS_CXX}					# }
 .if !target(proginstall)
+proginstall:: ${_PROG_INSTALL}
 .PHONY:		proginstall
+realall: ${SCRIPTS}
 .if defined(SCRIPTS) && !target(scriptsinstall)				# {
@@ -337,11 +405,6 @@ scriptsinstall::
 .PHONY:		scriptsinstall
-lint: ${LOBJS}
-.if defined(LOBJS) && !empty(LOBJS)
-	${LINT} ${LINTFLAGS} ${LDFLAGS:C/-L[  ]*/-L/Wg:M-L*} ${LOBJS} ${LDADD}
 ##### Pull in related .mk logic
 .include <>
 .include <>

Content-Transfer-Encoding: 7bit
Content-Type: text/plain;

Julio M. Merino Vidal <>