Appendix I. The `ccxx.mk` File

Here we include a complete copy of `rules/object-code/ccxx.mk`.

```# This makefile rules fragment supports compilation of C and C++ code
# into static libraries and dynamically linked executables.  Shared
# libraries are not presently supported but will be in the future.
#
# Please see ccxx-help.txt for details on how to use these rules.

# ---------------

# Notes to implementors

# CCXX_TOOLCHAIN contains the name of a makefile fragment (without the
# .mk; loaded from abuild-specified search path) that defines the
# functions that these rules use to perform actual compiles.  The best
# place to learn about how these work, in addition to carefully
# reading these notes, is to look at the built-in compiler support
# files included with abuild.  gcc.mk is a good UNIX example, and
# msvc.mk is a good Windows example.  The compiler support file
# provide the following:

#   .LIBPATTERNS: gnu make variable which must contain patterns to
#   match library names so that dependencies on -llib will work.

#   OBJ: the suffix of non-library object files

#   LOBJ: the suffix of library object files; may be the same as OBJ

#   PREPROCESS_c: a command used to invoke the C preprocessor

#   PREPROCESS_cxx: a command used to invoke the C++ preprocessor

#   COMPILE_c: a command used to invoke the C compiler

#   COMPILE_cxx: a command used to invoke the C++ compiler

#   LINK_c: a command used to invoke the linker for a C program that
#   uses no C++ libraries

#   LINK_cxx: a command used to invoke the linker for a C++ program

#   DFLAGS: default debugging flags

#   OFLAGS: default optimization flags

#   WFLAGS: default warning flags

#   CCXX_GEN_DEPS: if it is possible to make COMPILE_c and COMPILE_cxx
#   generate correct dependency information as a side effect of
#   compilation, add the appropriate flags to COMPILE_c and
#   COMPILE_cxx and set CCXX_GEN_DEPS to @: to suppress the running of
#   gen_deps.  Otherwise, don't set this variable, in which case it
#   will default to \$(GEN_DEPS).  Abuild requires dependency files
#   that contain an empty rule with each object file depending on all
#   of its dependencies as well as an empty rule for each dependency
#   that depends on nothing.  This way, missing header files will
#   cause the target to rebuild instead of fail.  Our own gen_deps
#   does this, as does gcc's -MP option.

#   IGNORE_TARGETS: optional: a list of targets (object files,
#   libraries, etc.)  that should be ignored when determining whether
#   there are orphan targets.

#   \$(call libname,libbase): a function that returns the full name of
#   a library from its base.  For example, \$(call libname,moo) would
#   typically return libmoo.a on a UNIX system and moo.lib on a
#   Windows system.

#   \$(call shlibname,libbase,major,minor,revision): a function that
#   returns the full name of a shared library from its base, major
#   version, minor version, and revision number.  For example, \$(call
#   shlibname,moo,1,2,3) might return libmoo.so.1.2.3 on a UNIX system
#   and moo1.dll on a Windows system.  The version arguments are
#   optional.  Each one must be ignored if the ones before it are
#   omitted.

#   \$(call binname,binbase): a function that returns the full name of
#   an executable from its base.  For example, \$(call binname,moo)
#   would typically return moo on a UNIX system and moo.exe on a
#   Windows system.

#   \$(call include_flags,include-dirs): a function that returns
#   include flags forthe given include directories.  This result
#   should be suitable to passing as flags to the preprocessor and C
#   or C++ compiler.

#   \$(call make_obj,compiler,pic,flags,src,obj): a function that uses
#   the given compiler to convert src to obj.  The first argument will
#   always be either \$(COMPILE_c) or \$(COMPILE_cxx).  The second
#   argument will be 1 if we need position-independent code for shared
#   libraries (or static libraries that might be linked into shared
#   libraries) and empty otherwise.

#   \$(call make_lib,objects,libbase): a function that creates a
#   library with the given base name.  Note that libbase has not been
#   passed to \$(libname).

\bs,binbase):
#   a function that generates an executable file with the given base
#   name from the given objects linking from libs that are found from
#   the given libdirs.  The first argument will always be either
#   passed to \$(binname).  Compiler support implementors are
#   statements.  This makes it possible for the user to set
#   LINKWRAPPER to some program that wraps the link step.  Examples of
#   programs that do this include Purify and Quantify.  NOTE: Your
#   make_bin function should do something with the
#   WHOLE_lib_\$(libname) variables: either it should link in the whole
#   library or issue an error that it is not supported.  See
#   toolchains/unix_compiler.mk and toolchains/msvc.mk for examples of
#   each case.
#
\libs,shlibbase,major,minor,revision):
#   function that creates a library with the given base name.  This
#   function must take the same arguments as make_bin plus the shared
#   library version information.  Compiler support authors are
#   with make_bin.

# When preparing to use a specific toolchain, please see comments in
# that toolchain's makefile fragment for any requirements that it may
# have.

# ---------------

TARGETS_lib ?=
TARGETS_bin ?=

# Make sure the user has asked for some targets.
ifeq (\$(words \$(TARGETS_lib) \$(TARGETS_bin)), 0)
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk no targets,0)
\$(error No ccxx targets are defined)
endif

# Separate TARGETS_lib into _TARGETS_static_lib and
# _TARGETS_shared_lib
_TARGETS_shared_lib := \$(filter-out %:static,\$(foreach L,\$(TARGETS_lib),\
\\$(L)\$(if \$(filter undefined,\$(origin SHLIB_\$(L))),:static)))
_TARGETS_static_lib := \$(filter-out \$(_TARGETS_shared_lib),\$(TARGETS_lib))

# Define ccxx_shlibname to call shlibname with the right arguments
define ccxx_shlibname
\$(call shlibname,\$(1),\$(word 1,\$(SHLIB_\$(1))),\$(word 2,\$(SHLIB_\$(1))),\$(\
\word 3,\$(SHLIB_\$(1))))
endef

# Define ccxx_all_shlibnames to get all variants of the shared library name
define ccxx_all_shlibnames
\$(sort \$(call shlibname,\$(1),\$(word 1,\$(SHLIB_\$(1))),\$(word 2,\$(SHLIB_\$(\
\1))),\$(word 3,\$(SHLIB_\$(1)))) \
\$(call shlibname,\$(1),\$(word 1,\$(SHLIB_\$(1))),\$(word 2,\$(SHLIB_\$(\
\1))),) \
\$(call shlibname,\$(1),\$(word 1,\$(SHLIB_\$(1))),,) \
\$(call shlibname,\$(1),,,))
endef

# Add each target to the "all" and "clean" rules
_static_lib_TARGETS := \$(foreach T,\$(_TARGETS_static_lib),\$(call libname,\$(T)))
_shared_lib_TARGETS := \$(foreach T,\$(_TARGETS_shared_lib),\$(call ccxx_sh\
\libname,\$(T)))
_lib_TARGETS := \$(_static_lib_TARGETS) \$(_shared_lib_TARGETS)
_bin_TARGETS := \$(foreach T,\$(TARGETS_bin),\$(call binname,\$(T)))

all:: \$(_lib_TARGETS) \$(_bin_TARGETS)

# Add all local libraries to LIBS and all local library directories to
# LIBDIRS.
ifneq (\$(words \$(TARGETS_lib)),0)
LIBS := \$(filter-out \$(LIBS),\$(_TARGETS_static_lib) \$(_TARGETS_shared_li\
\b)) \$(LIBS)
LIBDIRS := \$(filter-out \$(LIBDIRS),.) \$(LIBDIRS)
endif

# Make sure that the user has provided sources for each target.
_UNDEFINED := \$(call undefined_vars,\
\$(foreach T,\$(TARGETS_lib),SRCS_lib_\$(T)) \
\$(foreach T,\$(TARGETS_bin),SRCS_bin_\$(T)))
ifneq (\$(words \$(_UNDEFINED)),0)
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk undefined variables,0)
\$(error The following variables are undefined: \$(_UNDEFINED))
endif

# Basic compilation functions

DFLAGS ?=
OFLAGS ?=
WFLAGS ?=
XCPPFLAGS ?=
XCFLAGS ?=
XCXXFLAGS ?=

ifeq (\$(ABUILD_SUPPORT_1_0),1)
\$(error setting LINK_SHLIBS to an empty value no longer works; overri\
else
\$(call deprecate,1.1,LINK_SHLIBS is deprecated; as of version 1.0.3\$(\
\_comma) abuild always links shared libraries)
endif
endif
endif

# These functions expand to the complete list of debug, optimization
# and warning flags that apply to a specific file.  In this case,
# file-specific values override general values.

# Usage: \$(call file_dflags,src)
define file_dflags
\$(call value_if_defined,DFLAGS_\$(call strip_srcdir,\$(1)),\$(DFLAGS))
endef

# Usage: \$(call file_oflags,src)
define file_oflags
\$(call value_if_defined,OFLAGS_\$(call strip_srcdir,\$(1)),\$(OFLAGS))
endef

# Usage: \$(call file_wflags,src)
define file_wflags
\$(call value_if_defined,WFLAGS_\$(call strip_srcdir,\$(1)),\$(WFLAGS))
endef

# Usage: \$(call file_dowflags,src)
define file_dowflags
\$(call file_dflags,\$(1)) \$(call file_oflags,\$(1)) \$(call file_wflags,\$(1))
endef

# These functions expand to the complete list of "extra" flags that
# apply to a specific file.  They are, from general to specific:
# XCPPFLAGS, then XCPPFLAGS_file (and similar for CFLAGS and
# CXXFLAGS).  We use \$(call value_if_defined ...) to access the
# file-specific variables to avoid the undefined variable warning for
# each undefined variable since not defining these is the usual case.

# Usage: \$(call file_cppflags,src)
define file_cppflags
\$(call include_flags,\$(INCLUDES) \$(SRCDIR) .) \$(call file_dowflags,\$(1))\
\ \$(XCPPFLAGS) \$(call value_if_defined,XCPPFLAGS_\$(call strip_srcdir,\$(1)),)
endef

# Usage: \$(call file_cflags,src)
define file_cflags
\$(call file_cppflags,\$(1)) \$(XCFLAGS) \$(call value_if_defined,XCFLAGS_\$(\
\call strip_srcdir,\$(1)),)
endef

# Usage: \$(call file_cxxflags,src)
define file_cxxflags
\$(call file_cflags,\$(1)) \$(XCXXFLAGS) \$(call value_if_defined,XCXXFLAGS_\
\\$(call strip_srcdir,\$(1)),)
endef

# Usage: \$(call use_pic,src): determines the value of pic to pass to make_obj
define use_pic
\$(and \$(filter \$(call strip_srcdir,\$(<)), \$(_lib_SRCS)), \$(if \$(call val\
\ue_if_defined,NOPIC_\$(call strip_srcdir,\$(<)),),,1))
endef

LANGNAME_c := C
LANGNAME_cxx := C++
CCXX_GEN_DEPS ?= \$(GEN_DEPS)
# Usage: \$(call ccxx_compile,language): language = { c | cxx }
define ccxx_compile
@: \$(call QTC.TC,abuild,ccxx.mk ccxx_compile,0)
@mkdir -p \$(dir \$@)
\$(CCXX_GEN_DEPS) \
"\$(PREPROCESS_\$(1)) \$(call file_cppflags,\$<)" \
"\$<" "\$@" "\$*.\$(DEP)"
-\$(RM) \$@
@\$(PRINT) "Compiling \$< as \$(LANGNAME_\$(1))"
\$(call make_obj,\$(COMPILE_\$(1)),\$(call use_pic,\$<), \
\$(call file_\$(1)flags,\$<),\$<,\$@)
endef

# Usage: \$(call ccxx_preprocess,language): language = { c | cxx }
define ccxx_preprocess
@mkdir -p \$(dir \$@)
@\$(PRINT) "Preprocessing \$< as \$(LANGNAME_\$(1)) to \$@"
-\$(RM) \$@
\$(PREPROCESS_\$(1)) \$(call file_cppflags,\$<) \$< > \$@
endef

# Usage: \$(call ccxx_make_static_lib,library-base)
define ccxx_make_static_lib
@: \$(call QTC.TC,abuild,ccxx.mk ccxx_make_static_lib,0)
-\$(RM) \$(call libname,\$(1))
@\$(PRINT) "Creating \$(1) library"
\$(call make_lib,\$(OBJS_lib_\$(1)),\$(1))
endef

# Usage: \$(call ccxx_make_shared_lib,library-base)
define ccxx_make_shared_lib
@: \$(call QTC.TC,abuild,ccxx.mk ccxx_make_shared_lib,0)
@\$(PRINT) "Creating \$(1) shared library"
er-out \$(_TARGETS_shared_lib),\$(LIBS)),\$(1),\$(word 1,\$(SHLIB_\$(1))),\$(wo\
\rd 2,\$(SHLIB_\$(1))),\$(word 3,\$(SHLIB_\$(1))))
endef

# Usage: \$(call ccxx_make_bin,executable-base)
define ccxx_make_bin
@: \$(call QTC.TC,abuild,ccxx.mk ccxx_make_bin,0)
-\$(RM) \$(call binname,\$(1))
@\$(PRINT) "Creating \$(1) executable"
endef

c_to_o = \$(call ccxx_compile,c)
cxx_to_o = \$(call ccxx_compile,cxx)
lib_c_to_o = \$(c_to_o)
bin_c_to_o = \$(c_to_o)
lib_cxx_to_o = \$(cxx_to_o)
bin_cxx_to_o = \$(cxx_to_o)
c_to_i = \$(call ccxx_preprocess,c)
cxx_to_i = \$(call ccxx_preprocess,cxx)

# For each SRCS_lib_x and SRCS_bin_x, create corresponding OBJS_lib_x
# and OBJS_bin_x by transforming all .c, .cc, and .cpp file names to
# object file names.

\$(foreach T,\$(TARGETS_lib),\
\$(eval OBJS_lib_\$(T) := \
\$(call x_to_y,c,\$(LOBJ),SRCS_lib_\$(T)) \
\$(call x_to_y,cc,\$(LOBJ),SRCS_lib_\$(T)) \
\$(call x_to_y,cpp,\$(LOBJ),SRCS_lib_\$(T))))
\$(foreach T,\$(TARGETS_bin),\
\$(eval OBJS_bin_\$(T) := \
\$(call x_to_y,c,\$(OBJ),SRCS_bin_\$(T)) \
\$(call x_to_y,cc,\$(OBJ),SRCS_bin_\$(T)) \
\$(call x_to_y,cpp,\$(OBJ),SRCS_bin_\$(T))))

# Combine all sources from various bases into types (lib and bin) and
# then separate by suffix.  These variables are used for static pattern
# rules to invoke the correct compilation steps for files based on
# suffix and target type.

_lib_SRCS := \$(sort \$(foreach T,\$(TARGETS_lib),\$(SRCS_lib_\$(T))))
_bin_SRCS := \$(sort \$(foreach T,\$(TARGETS_bin),\$(SRCS_bin_\$(T))))
_all_SRCS := \$(sort \$(_lib_SRCS) \$(_bin_SRCS))
_lib_COBJS := \$(call x_to_y,c,\$(LOBJ),_lib_SRCS)
_lib_CCOBJS := \$(call x_to_y,cc,\$(LOBJ),_lib_SRCS)
_lib_CPPOBJS := \$(call x_to_y,cpp,\$(LOBJ),_lib_SRCS)
_bin_COBJS := \$(call x_to_y,c,\$(OBJ),_bin_SRCS)
_bin_CCOBJS := \$(call x_to_y,cc,\$(OBJ),_bin_SRCS)
_bin_CPPOBJS := \$(call x_to_y,cpp,\$(OBJ),_bin_SRCS)
_Cpproc := \$(call x_to_y,c,i,_lib_SRCS) \$(call x_to_y,c,i,_bin_SRCS)
_CCpproc := \$(call x_to_y,cc,i,_lib_SRCS) \$(call x_to_y,cc,i,_bin_SRCS)
_CPPpproc :=    \$(call x_to_y,cpp,i,_lib_SRCS) \$(call x_to_y,cpp,i,_bin_SRCS)

# Make sure ".." doesn't appear in any source file names.
ifneq (\$(words \$(findstring /../,\$(_all_SRCS)) \$(filter ../%,\$(_all_SRCS))), 0)
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk ERR .. in srcs,0)
\$(error The path component ".." may not appear in any source file names)
endif

# Include dependency files for each source file
_lib_OBJS := \$(_lib_COBJS) \$(_lib_CCOBJS) \$(_lib_CPPOBJS)
_bin_OBJS := \$(_bin_COBJS) \$(_bin_CCOBJS) \$(_bin_CPPOBJS)
_all_DEPS := \$(call x_to_y,\$(LOBJ),\$(DEP),_lib_OBJS) \
\$(call x_to_y,\$(OBJ),\$(DEP),_bin_OBJS)

# Remove any extraneous dep files
_extra_deps := \$(filter-out \$(_all_DEPS),\$(wildcard *.\$(DEP)))
ifneq (\$(words \$(_extra_deps)),0)
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk remove extra deps,0)
DUMMY := \$(shell \$(PRINT) 1>&2 Removing extraneous \$(DEP) files)
DUMMY := \$(shell \$(RM) \$(_extra_deps))
endif

-include \$(_all_DEPS)

# Define static pattern rules that invoke the proper compilation
# function for each object file.

\$(_lib_COBJS): %.\$(LOBJ): %.c
\$(lib_c_to_o)

\$(_lib_CCOBJS): %.\$(LOBJ): %.cc
\$(lib_cxx_to_o)

\$(_lib_CPPOBJS): %.\$(LOBJ): %.cpp
\$(lib_cxx_to_o)

\$(_bin_COBJS): %.\$(OBJ): %.c
\$(bin_c_to_o)

\$(_bin_CCOBJS): %.\$(OBJ): %.cc
\$(bin_cxx_to_o)

\$(_bin_CPPOBJS): %.\$(OBJ): %.cpp
\$(bin_cxx_to_o)

\$(_Cpproc): %.i: %.c FORCE
\$(c_to_i)

\$(_CCpproc): %.i: %.cc FORCE
\$(cxx_to_i)

\$(_CPPpproc): %.i: %.cpp FORCE
\$(cxx_to_i)

# Ensure that we can use -llib dependencies properly.
.LIBPATTERNS ?=
\$(foreach PAT,\$(.LIBPATTERNS),\$(eval vpath \$(PAT) \$(LIBDIRS)))

# For each library and executable target, create a rule that makes the
# target dependent on its objects.  Also make executable targets
# depend on the libraries in LIBS, which includes local libraries,
# and shared libary targets depend on the static libraries in LIBS.
# In addition, we make local executable targets explicitly depend on
# local library targets.  The reason for doing this as well as adding
# the -llib target for local libraries is that make will not try to
# build the -llib target if it doesn't exist.
l_LIBS = \$(foreach L,\$(LIBS),-l\$(L))
l_not_local_shared = \$(foreach L,\$(filter-out \$(_TARGETS_shared_lib),\$(L\
\IBS)),-l\$(L))
\$(foreach T,\$(_TARGETS_static_lib),\
\$(eval \$(call libname,\$(T)): \$(OBJS_lib_\$(T)) ; \
\$(call ccxx_make_static_lib,\$(T))))
\$(foreach T,\$(_TARGETS_shared_lib),\
\$(eval \$(call ccxx_shlibname,\$(T)): \$(OBJS_lib_\$(T)) \$(l_not_local_sh\
\ared) \$(_static_lib_TARGETS); \
\$(call ccxx_make_shared_lib,\$(T))))
\$(foreach T,\$(TARGETS_bin),\
\$(eval \$(call binname,\$(T)): \$(OBJS_bin_\$(T)) \$(l_LIBS) \$(_lib_TARGETS); \
\$(call ccxx_make_bin,\$(T))))

# For each local library target x that does not exist, make -lx depend
# on \$(call libname,x).  This prevents errors about -lx not existing
# when a binary target is built explicitly from clean.  We avoid
# creating this dependency if the library already exists because
# otherwise make will translate this into a circular dependency when
# it replaces -lx with the actual library file in the rule.
\$(foreach T,\$(_TARGETS_static_lib),\
\$(eval -l\$(T): \$(if \$(wildcard \$(call libname,\$(T))),,\$(call libname,\
\\$(T)))))
\$(foreach T,\$(_TARGETS_shared_lib),\
\$(eval -l\$(T): \$(if \$(wildcard \$(call ccxx_shlibname,\$(T))),,\$(call c\
\cxx_shlibname,\$(T)))))

_all_obj := \$(sort \$(_lib_OBJS) \$(_bin_OBJS))
# The list of all libraries includes static versions of the shared
# libraries as well since on some platforms (Windows), creating a
# shared library also creates a static library of the same name.
_all_lib := \$(sort \
\$(foreach T,\$(TARGETS_lib),\$(call libname,\$(T))) \
\$(foreach T,\$(_TARGETS_shared_lib),\$(call ccxx_all_shlibnames,\$(T))))
_all_bin := \$(foreach T,\$(TARGETS_bin),\$(call binname,\$(T)))

# Check for and remove orphan targets
IGNORE_TARGETS ?=
_existing_obj := \$(sort \$(wildcard *.\$(OBJ) *.\$(LOBJ)))
_extra_obj := \$(filter-out \$(_all_obj) \$(IGNORE_TARGETS),\$(_existing_obj))
ifeq (\$(words \$(_extra_obj)),0)
# No extra objects found; check for other extra targets.  Check for
# libraries and shared libraries, and if we can recognize executables
# as such (they have some recognizable suffix), check for them as
# well.
_all_other := \$(_all_lib)
_existing_other := \$(sort \$(wildcard \$(call libname,*) \$(call shlibname\
\,*,,,)))
ifneq (\$(call binname,*),*)
# If executables are recognizable as such
_all_other += \$(_all_bin)
_existing_other += \$(sort \$(wildcard \$(call binname,*)))
endif
_extra_other := \$(filter-out \$(_all_other) \$(IGNORE_TARGETS),\$(_existin\
\g_other))
ifneq (\$(words \$(_extra_other)),0)
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk found extra other,0)
# For all binary and library targets to relink
DUMMY := \$(shell \$(PRINT) 1>&2 Extra targets found: removing libraries\
\ and binaries)
DUMMY := \$(shell \$(RM) \$(_extra_other) \$(_all_lib) \$(_all_bin))
endif
else
# Extra object files found; remove all extra objects as well as any
# library or binary targets which we want to force to be recreated.
_qtx_dummy := \$(call QTC.TC,abuild,ccxx.mk found extra objs,0)
DUMMY := \$(shell \$(PRINT) 1>&2 Extra object files found: removing libra\
\ries and binaries)
DUMMY := \$(shell \$(RM) \$(_extra_obj) \$(_all_lib) \$(_all_bin))
endif

# Create a debugging target that shows values of some critical
# variables.
.PHONY: ccxx_debug
ccxx_debug::
@: \$(call QTC.TC,abuild,ccxx.mk ccxx_debug,0)
@\$(PRINT) INCLUDES = \$(INCLUDES)
@\$(PRINT) LIBDIRS = \$(LIBDIRS)
@\$(PRINT) LIBS = \$(LIBS)

# Include built-in support for certain code generators.  These should
# have been plugins, but they were added before plugins were
# supported.
include \$(abMK)/standard-code-generators.mk
```