| # |
| # 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. |
| # |
| # ident "%Z%%M% %I% %E% SMI" |
| # |
| |
| 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 |
| lint := TARGET= lint |
| |
| The order doesn't matter, but alphabetical is preferable. |
| |
| 4. Having the aforementioned targets depend on SUBDIRS: |
| |
| all clean clobber install lint: $(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 |
| lint := TARGET = lint |
| |
| .KEEP_STATE: |
| |
| all clean clobber install lint: $(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) $(LINTLIB)' so that a dynamic library and lint library |
| are built. For loadable modules, you should just list DYNLIB, |
| since there's no point in building a lint library for libraries |
| that are never linked at compile-time. |
| |
| 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. |
| |
| LINTLIB-specific SRCS (required if building a lint library) |
| |
| Set to a special "lint stubs" file to use when constructing your |
| library's lint library. The lint stubs file must be used to |
| guarantee that programs that link against your library will be able |
| to lint clean. To do this, you must conditionally set SRCS to use |
| your stubs file by specifying `LINTLIB := SRCS= $(SRCDIR)/$(LINTSRC)' |
| in your Makefile. Of course, you do not need to set this if your |
| library does not build a lint library. |
| |
| 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. |
| |
| Since lint targets also make use of LDLIBS, LDLIBS *must* only |
| contain -l and -L directives; all other link-related directives |
| should be put in DYNFLAGS (if they apply only to shared object |
| construction) or LDFLAGS (if they apply in general). |
| |
| 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). Since lint macros use |
| CPPFLAGS, CPPFLAGS *must* only contain directives known to the C |
| preprocessor. 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). |
| |
| LINTFLAGS (if necessary) |
| |
| Appended with any flags that need to be passed to lint when |
| linting 32-bit code. You should only modify LINTFLAGS in |
| rare instances where your code cannot (or should not) be fixed. |
| |
| LINTFLAGS64 (if necessary) |
| |
| Appended with any flags that need to be passed to lint when |
| linting 64-bit code. You should only modify LINTFLAGS64 in |
| rare instances where your code cannot (or should not) be fixed. |
| |
| 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). |
| |
| lint |
| |
| Use the `lintcheck' rule provided by lib/Makefile.targ to lint the |
| actual library sources. Historically, this target has also been |
| used to build the lint library (using LINTLIB), but that usage is |
| now discouraged. Thus, this rule should be specified as |
| |
| lint: lintcheck |
| |
| 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) $(LINTLIB) |
| |
| 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 |
| |
| $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) |
| LDLIBS += -lsocket -lc |
| |
| CFLAGS += $(CCVERBOSE) |
| CPPFLAGS += -I$(SRCDIR) |
| |
| .KEEP_STATE: |
| |
| all: $(LIBS) |
| |
| lint: lintcheck |
| |
| 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) $(ROOTLINT) |
| |
| sparcv9/Makefile: |
| |
| include ../Makefile.com |
| include ../../Makefile.lib.64 |
| |
| install: all $(ROOTLIBS64) $(ROOTLINKS64) |
| |
| i386/Makefile: |
| |
| include ../Makefile.com |
| |
| install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) |
| |
| amd64/Makefile: |
| |
| include ../Makefile.com |
| include ../../Makefile.lib.64 |
| |
| install: all $(ROOTLIBS64) $(ROOTLINKS64) |
| |
| 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-bit only library that obtains its sources |
| from multiple directories. |
| |
| lib/ncad_addr |
| |
| 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. |