#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.

Writing Library Makefiles in ON
===============================

Introduction
------------

This document guides you through the gnarly process of writing library
Makefiles for the ON consolidation.  It assumes that you're comfortable with
make(1) and are somewhat familiar with the ON Makefile standards outlined in
/shared/ON/general_docs/make_std.txt.

Makefile Overview
-----------------

Your library should consist of a hierarchical collection of Makefiles:

	lib/<library>/Makefile:

	  This is your library's top-level Makefile.  It should contain rules
	  for building any ISA-independent targets, such as installing header
	  files and building message catalogs, but should defer all other
	  targets to ISA-specific Makefiles.

	lib/<library>/Makefile.com

	  This is your library's common Makefile.  It should contain rules
	  and macros which are common to all ISAs. This Makefile should never
	  be built explicitly, but instead should be included (using the make
	  include mechanism) by all of your ISA-specific Makefiles.

	lib/<library>/<isa>/Makefile

	  These are your library's ISA-specific Makefiles, one per ISA
	  (usually sparc and i386, and often sparcv9 and amd64).  These
	  Makefiles should include your common Makefile and then provide any
	  needed ISA-specific rules and definitions, perhaps overriding those
	  provided in your common Makefile.

To simplify their maintenance and construction, $(SRC)/lib has a handful of
provided Makefiles that yours must include; the examples provided throughout
the document will show how to use them.  Please be sure to consult these
Makefiles before introducing your own custom build macros or rules.

	lib/Makefile.lib:

	  This contains the bulk of the macros for building shared objects.

	lib/Makefile.lib.64

	  This contains macros for building 64-bit objects, and should be
	  included in Makefiles for 64-bit native ISAs.

	lib/Makefile.rootfs

	  This contains macro overrides for libraries that install into /lib
	  (rather than /usr/lib).

	lib/Makefile.targ

	  This contains rules for building shared objects.

The remainder of this document discusses how to write each of your Makefiles
in detail, and provides examples from the libinetutil library.

The Library Top-level Makefile
------------------------------

As described above, your top-level library Makefile should contain
rules for building ISA-independent targets, but should defer the
building of all other targets to ISA-specific Makefiles.  The
ISA-independent targets usually consist of:

	install_h

	  Install all library header files into the proto area.
	  Can be omitted if your library has no header files.

	check

	  Check all library header files for hdrchk compliance.
	  Can be omitted if your library has no header files.

	_msg

	  Build and install a message catalog.
	  Can be omitted if your library has no message catalog.

Of course, other targets (such as `cstyle') are fine as well, as long as
they are ISA-independent.

The ROOTHDRS and CHECKHDRS targets are provided in lib/Makefile.lib to make
it easy for you to install and check your library's header files.  To use
these targets, your Makefile must set the HDRS to the list of your library's
header files to install and HDRDIR to the their location in the source tree.
In addition, if your header files need to be installed in a location other
than $(ROOT)/usr/include, your Makefile must also set ROOTHDRDIR to the
appropriate location in the proto area.  Once HDRS, HDRDIR and (optionally)
ROOTHDRDIR have been set, your Makefile need only contain

	  install_h: $(ROOTHDRS)

	  check: $(CHECKHDRS)

to bind the provided targets to the standard `install_h' and `check' rules.

Similar rules are provided (in $(SRC)/Makefile.msg.targ) to make it easy for
you to build and install message catalogs from your library's source files.

To install a catalog into the catalog directory in the proto area, define the
POFILE macro to be the name of your catalog, and specify that the _msg target
depends on $(MSGDOMAINPOFILE).  The examples below should clarify this.

To build a message catalog from arbitrarily many message source files, use
the BUILDPO.msgfiles macro.

	  include ../Makefile.lib

	  POFILE =	  libfoo.po
	  MSGFILES =	  $(OBJECTS:%.o=%.i)

	  # ...

	  $(POFILE): $(MSGFILES)
		$(BUILDPO.msgfiles)

	  _msg: $(MSGDOMAINPOFILE)

	  include $(SRC)/Makefile.msg.targ

Note that this example doesn't use grep to find message files, since that can
mask unreferenced files, and potentially lead to the inclusion of unwanted
messages or omission of intended messages in the catalogs.  As such, MSGFILES
should be derived from a known list of objects or sources.

It is usually preferable to run the source through the C preprocessor prior
to extracting messages.  To do this, use the ".i" suffix, as shown in the
above example.  If you need to skip the C preprocessor, just use the native
(.[ch]) suffix.

The only time you shouldn't use BUILDPO.msgfiles as the preferred means of
extracting messages is when you're extracting them from shell scripts; in
that case, you can use the BUILDPO.pofiles macro as explained below.

To build a message catalog from other message catalogs, or from source files
that include shell scripts, use the BUILDPO.pofiles macro:

	  include ../Makefile.lib

	  SUBDIRS =	  $(MACH)

	  POFILE =	  libfoo.po
	  POFILES =	  $(SUBDIRS:%=%/_%.po)

	  _msg :=	  TARGET = _msg

	  # ...

	  $(POFILE): $(POFILES)
		$(BUILDPO.pofiles)

	  _msg: $(MSGDOMAINPOFILE)

	  include $(SRC)/Makefile.msg.targ

The Makefile above would work in conjunction with the following in its
subdirectories' Makefiles:

	  POFILE =	  _thissubdir.po
	  MSGFILES =	  $(OBJECTS:%.o=%.i)

	  $(POFILE):	  $(MSGFILES)
		  $(BUILDPO.msgfiles)

	  _msg:		  $(POFILE)

	  include $(SRC)/Makefile.msg.targ

Since this POFILE will be combined with those in other subdirectories by the
parent Makefile and that merged file will be installed into the proto area
via MSGDOMAINPOFILE, there is no need to use MSGDOMAINPOFILE in this Makefile
(in fact, using it would lead to duplicate messages in the catalog).

When using any of these targets, keep in mind that other macros, like
XGETFLAGS and TEXT_DOMAIN may also be set in your Makefile to override or
augment the defaults provided in higher-level Makefiles.

As previously mentioned, you should defer all ISA-specific targets to your
ISA-specific Makefiles.  You can do this by:

	1. Setting SUBDIRS to the list of directories to descend into:

		SUBDIRS = $(MACH)

	   Note that if your library is also built 64-bit, then you should
	   also specify

		$(BUILD64)SUBDIRS += $(MACH64)

	   so that SUBDIRS contains $(MACH64) if and only if you're compiling
	   on a 64-bit ISA.

	2. Providing a common "descend into SUBDIRS" rule:

		$(SUBDIRS): FRC
			@cd $@; pwd; $(MAKE) $(TARGET)

		FRC:

	3. Providing a collection of conditional assignments that set TARGET
	   appropriately:

		all	:= TARGET= all
		clean	:= TARGET= clean
		clobber := TARGET= clobber
		install := TARGET= install

	   The order doesn't matter, but alphabetical is preferable.

	4. Having the aforementioned targets depend on SUBDIRS:

		all clean clobber install: $(SUBDIRS)

	   The `all' target must be listed first so that make uses it as the
	   default target; the others might as well be listed alphabetically.

As an example of how all of this goes together, here's libinetutil's
top-level library Makefile (license notice and copyright omitted):

	include ../Makefile.lib

	HDRS =		libinetutil.h
	HDRDIR =	common
	SUBDIRS =	$(MACH)
	$(BUILD64)SUBDIRS += $(MACH64)

	all :=		TARGET = all
	clean :=	TARGET = clean
	clobber :=	TARGET = clobber
	install :=	TARGET = install

	.KEEP_STATE:

	all clean clobber install: $(SUBDIRS)

	install_h:	$(ROOTHDRS)

	check:		$(CHECKHDRS)

	$(SUBDIRS): FRC
		@cd $@; pwd; $(MAKE) $(TARGET)

	FRC:

	include ../Makefile.targ

The Common Makefile
-------------------

In concept, your common Makefile should contain all of the rules and
definitions that are the same on all ISAs.  However, for reasons of
maintainability and cleanliness, you're encouraged to place even
ISA-dependent rules and definitions, as long you express them in an
ISA-independent way (e.g., by using $(MACH), $(TARGETMACH), and their kin).
(TARGETMACH is the same as MACH for 32-bit targets, and the same as MACH64
for 64-bit targets).

The common Makefile can be conceptually split up into four sections:

	1. A copyright and comments section.  Please see the prototype
	   files in usr/src/prototypes for examples of how to format the
	   copyright message properly.  For brevity and clarity, this
	   section has been omitted from the examples shown here.

	2. A list of macros that must be defined prior to the inclusion of
	   Makefile.lib.  This section is conceptually terminated by the
	   inclusion of Makefile.lib, followed, if necessary, by the
	   inclusion of Makefile.rootfs (only if the library is to be
	   installed in /lib rather than the default /usr/lib).

	3. A list of macros that need not be defined prior to the inclusion
	   of Makefile.lib (or which must be defined following the inclusion
	   of Makefile.lib, to override or augment its definitions).  This
	   section is conceptually terminated by the .KEEP_STATE directive.

	4. A list of targets.

The first section is self-explanatory.  The second typically consists of the
following macros:

	LIBRARY

	  Set to the name of the static version of your library, such
	  as `libinetutil.a'.  You should always specify the `.a' suffix,
	  since pattern-matching rules in higher-level Makefiles rely on it,
	  even though static libraries are not normally built in ON, and
	  are never installed in the proto area.  Note that the LIBS macro
	  (described below) controls the types of libraries that are built
	  when building your library.

	  If you are building a loadable module (i.e., a shared object that
	  is only linked at runtime with dlopen(3dl)), specify the name of
	  the loadable module with a `.a' suffix, such as `devfsadm_mod.a'.

	VERS

	  Set to the version of your shared library, such as `.1'.  You
	  actually do not need to set this prior to the inclusion of
	  Makefile.lib, but it is good practice to do so since VERS and
	  LIBRARY are so closely related.

	OBJECTS

	  Set to the list of object files contained in your library, such as
	  `a.o b.o'.  Usually, this will be the same as your library's source
	  files (except with .o extensions), but if your library compiles
	  source files outside of the library directory itself, it will
	  differ.  We'll see an example of this with libinetutil.

The third section typically consists of the following macros:

	LIBS

	  Set to the list of the types of libraries to build when building
	  your library.  For dynamic libraries, you should set this to
	  `$(DYNLIB)' so that a dynamic library is built.

	  If your library needs to be built as a static library (typically
	  to be used in other parts of the build), you should set LIBS to
	  `$(LIBRARY)'.  However, you should do this only when absolutely
	  necessary, and you must *never* ship static libraries to customers.

	ROOTLIBDIR (if your library installs to a nonstandard directory)

	  Set to the directory your 32-bit shared objects will install into
	  with the standard $(ROOTxxx) macros.  Since this defaults to
	  $(ROOT)/usr/lib ($(ROOT)/lib if you included Makefile.rootfs),
	  you usually do not need to set this.

	ROOTLIBDIR64 (if your library installs to a nonstandard directory)

	  Set to the directory your 64-bit shared objects will install into
	  with the standard $(ROOTxxx64) macros.  Since this defaults to
	  $(ROOT)/usr/lib/$(MACH64) ($(ROOT)/lib/$(MACH64) if you included
	  Makefile.rootfs), you usually do not need to set this.

	SRCDIR

	  Set to the directory containing your library's source files, such
	  as `../common'.  Because this Makefile is actually included from
	  your ISA-specific Makefiles, make sure you specify the directory
	  relative to your library's <isa> directory.

	SRCS (if necessary)

	  Set to the list of source files required to build your library.
	  This defaults to $(OBJECTS:%.o=$(SRCDIR)/%.c) in Makefile.lib, so
	  you only need to set this when source files from directories other
	  than SRCDIR are needed.  Keep in mind that SRCS should be set to a
	  list of source file *pathnames*, not just a list of filenames.


	LDLIBS

	  Appended with the list of libraries and library directories needed
	  to build your library; minimally "-lc".  Note that this should
	  *never* be set, since that will inadvertently clear the library
	  search path, causing the linker to look in the wrong place for
	  the libraries.

	MAPFILES (if necessary)

	  Set to the list of mapfiles used to link each ISA-specific version
	  of your library.  This defaults to `$(SRCDIR)/mapfile-vers' in
	  Makefile.lib, so you only need to change this if you have additional
	  mapfiles or your mapfile doesn't follow the standard naming
	  convention.  If you have supplemental ISA-dependent mapfiles that
	  reside in the respective <isa> directories, you can augment
	  MAPFILES like this:

		MAPFILES += mapfile-vers

	CPPFLAGS (if necessary)

	   Appended with any flags that need to be passed to the C
	   preprocessor (typically -D and -I flags).  When compiling MT-safe
	   code, CPPFLAGS *must* include -D_REENTRANT.  When compiling large
	   file aware code, CPPFLAGS *must* include -D_FILE_OFFSET_BITS=64.

	CFLAGS

	   Appended with any flags that need to be passed to the C compiler.
	   Minimally, append `$(CCVERBOSE)'.  Keep in mind that you should
	   add any C preprocessor flags to CPPFLAGS, not CFLAGS.

	CFLAGS64 (if necessary)

	   Appended with any flags that need to be passed to the C compiler
	   when compiling 64-bit code.  Since all 64-bit code is compiled
	   $(CCVERBOSE), you usually do not need to modify CFLAGS64.

	COPTFLAG (if necessary)

	   Set to control the optimization level used by the C compiler when
	   compiling 32-bit code.  You should only set this if absolutely
	   necessary, and it should only contain optimization-related
	   settings (or -g).

	COPTFLAG64 (if necessary)

	   Set to control the optimization level used by the C compiler when
	   compiling 64-bit code.  You should only set this if absolutely
	   necessary, and it should only contain optimization-related
	   settings (or -g).

	COMPATLINKS (if necessary)

	  Set to a list of symbolic links that should also be provided for
	  this library.  Each should also have a target-specific assignment to
	  COMPATLINKTARGET stating what the target of each link should be

          COMPATLINKS= usr/lib/libfoo.so
          $(ROOT)/usr/lib/libfoo.so := COMPATLINKTARGET= libbar.so

	COMPATLINKS64 (if necessary)

          As COMPATLINKS, above, for 64bit objects.

Of course, you may use other macros as necessary.

The fourth section typically consists of the following targets:

	all

	  Build all of the types of the libraries named by LIBS.  Must always
	  be the first real target in common Makefile.  Since the
	  higher-level Makefiles already contain rules to build all of the
	  different types of libraries, you can usually just specify

		all: $(LIBS)

	  though it should be listed as an empty target if LIBS is set by your
	  ISA-specific Makefiles (see above).


Conspicuously absent from this section are the `clean' and `clobber' targets.
These targets are already provided by lib/Makefile.targ and thus should not
be provided by your common Makefile.  Instead, your common Makefile should
list any additional files to remove during a `clean' and `clobber' by
appending to the CLEANFILES and CLOBBERFILES macros.

Once again, here's libinetutil's common Makefile, which shows how many of
these directives go together.  Note that Makefile.rootfs is included to
cause libinetutil.so.1 to be installed in /lib rather than /usr/lib:

	LIBRARY =	libinetutil.a
	VERS =		.1
	OBJECTS =	octet.o inetutil4.o ifspec.o ifaddrlist.o eh.o tq.o

	include ../../Makefile.lib
	include ../../Makefile.rootfs

	LIBS =		$(DYNLIB)

	SRCDIR =	../common
	COMDIR =	$(SRC)/common/net/dhcp
	SRCS =		$(COMDIR)/octet.c $(SRCDIR)/inetutil4.c \
			$(SRCDIR)/ifspec.c $(SRCDIR)/eh.c $(SRCDIR)/tq.c \
			$(SRCDIR)/ifaddrlist.c

	LDLIBS +=	-lsocket -lc

	CFLAGS +=	$(CCVERBOSE)
	CPPFLAGS +=	-I$(SRCDIR)

	.KEEP_STATE:

	all: $(LIBS)

	pics/%.o: $(COMDIR)/%.c
		$(COMPILE.c) -o $@ $<
		$(POST_PROCESS_O)

	include ../../Makefile.targ

The mapfile for libinetutil is named `mapfile-vers' and resides in $(SRCDIR),
so the MAPFILES definition is omitted, defaulting to $(SRCDIR)/mapfile-vers.

Note that for libinetutil, not all of the object files come from SRCDIR.  To
support this, an alternate source file directory named COMDIR is defined, and
the source files listed in SRCS are specified using both COMDIR and SRCDIR.
Additionally, a special build rule is provided to build object files from the
sources in COMDIR; the rule uses COMPILE.c and POST_PROCESS_O so that any
changes to the compilation and object-post-processing phases will be
automatically picked up.

The ISA-Specific Makefiles
--------------------------

As the name implies, your ISA-specific Makefiles should contain macros and
rules that cannot be expressed in an ISA-independent way.  Usually, the only
rule you will need to put here is `install', which has different dependencies
for 32-bit and 64-bit libraries.  For instance, here are the ISA-specific
Makefiles for libinetutil:

	sparc/Makefile:

		include ../Makefile.com

		install: all $(ROOTLIBS) $(ROOTLINKS)

	sparcv9/Makefile:

		include ../Makefile.com
		include ../../Makefile.lib.64

		install: all $(ROOTLIBS64) $(ROOTLINKS64)

	i386/Makefile:

		include ../Makefile.com

		install: all $(ROOTLIBS) $(ROOTLINKS)

	amd64/Makefile:

		include ../Makefile.com
		include ../../Makefile.lib.64

		install: all $(ROOTLIBS64) $(ROOTLINKS64)

If you included Makefile.rootfs to install your library into /lib, you should
also add $(ROOTCOMPATLINKS) and $(ROOTCOMPATLINKS64) to your install: target
to install compatibility symlinks into /usr/lib.

Observe that there is no .KEEP_STATE directive in these Makefiles, since all
of these Makefiles include libinetutil/Makefile.com, and it already has a
.KEEP_STATE directive.  Also, note that the 64-bit Makefiles also include
Makefile.lib.64, which overrides some of the definitions contained in the
higher level Makefiles included by the common Makefile so that 64-bit
compiles work correctly.

CTF Data in Libraries
---------------------

By default, all position-independent objects are built with CTF data using
ctfconvert, which is then merged together using ctfmerge when the shared
object is built.  All C-source objects processed via ctfmerge need to be
processed via ctfconvert or the build will fail.  Objects built from non-C
sources (such as assembly or C++) are silently ignored for CTF processing.

Filter libraries that have no source files will need to explicitly disable
CTF by setting CTFMERGE_LIB to ":"; see libw/Makefile.com for an example.

More Information
----------------

Other issues and questions will undoubtedly arise while you work on your
library's Makefiles.  To help in this regard, a number of libraries of
varying complexity have been updated to follow the guidelines and practices
outlined in this document:

	lib/libdhcputil

	  Example of a simple 32-bit only library.

	lib/libdhcpagent

	  Example of a simple 32/64-bit library that obtains its sources
	  from multiple directories.

	lib/nametoaddr/straddr

	  Example of a simple loadable module.

	lib/libipmp

	  Example of a simple library that builds a message catalog.

	lib/libdhcpsvc

	  Example of a Makefile hierarchy for a library and a collection
	  of related pluggable modules.

	lib/lvm

	  Example of a Makefile hierarchy for a collection of related
	  libraries and pluggable modules.

	  Also an example of a Makefile hierarchy that supports the
	  _dc target for domain and category specific messages.

Of course, if you still have questions, please do not hesitate to send email
to the ON gatekeepers.