Using Make.Common

Make.Common is a file meant to be used with GNU make (see also: info pages and man page). To use it, simply include it twice in your regular Makefile, once at the beginning and once at the end. (Using the include directive... see Make.Common itself for examples.)

Restrictions (Read: Keep It Simple Stupid)

You must only have one executable or library generated per director leaf and the executable or library must be named the same as the directory it is in. You can, however, create a directory structure as deep as is needed to keep the right things grouped together. Just remember to create a symlink to Make.Common in the level above when you make a directory tree deeper. (See how /cfht/src/pegasus/cli/ is set up for some good examples too.)

Shell scripts (can be more than one) must all be named *.sh and appear in a subdirectory somewhere in your tree called ./scripts/. When these are installed in the bin directory, the .sh is stripped off so you invoke as their "basename".

Configuration files (par files, bitmap files, etc.) must be kept together in a directory called ./confs/ and will get copied to /cfht/conf/ during a "make install" if needed.

Some wording you'll find below:

  /cfht/src/medusa/project-"head"-directory/
               .../project-"head"-directory/"leaves"

Standard Targets Provided by Make.Common


make world
If you have a project that is divided into other subdirectories and you run "make world" in the head directory, all subdirectories will be built with "make all install". If you run "make world" in one of the leaves, it will change to the head directory and run "make all install" from there. So you can use "make world" from anywhere within a sub-project to build the whole thing.

make all
In a head directory for a subproject, runs "make all" in all the subdirectories. In a leaf, builds either the library or the executable for that subdirectory. Note that "make all" from a subproject head directory may cause some targets to be installed also (i.e., libraries that are required by one of the other targets.)

make preinstall
This exists to make complete releases build properly. It is used mainly to install header files. For example, if library A and library B both need each other's header files in order to compile, this is the way to deal with this chicken-and-egg problem.

make install
In a head directory for a subproject, runs "make install" in all the subdirectories. In a leaf, installs (and builds, if it is out of date) the library or executable in .../lib/ or .../bin/, respectively.

make clean
Removes emacs backup files and all object files in the "/cfht/obs/project/" directory.

make depend
Your Makefile should not be checked in to RCS when you do this. Running "make depend" will append the list of C source file dependencies (generated by "gcc -MM") to your Makefile.

make execlist
Prints a list of all the programs with their runnable names (shell scripts will have the .sh removed) from this directory level down. This is the list of things that gets versioned and installed in .../bin/ when you do "make install".

make titles
Generates emacs parsable output of the results of a search of your code for "===" and "%%%" markers. Files in each subdirectory are expected to be summarized in a file called "Index". (See /cfht/src/pegasus/libCFHT++/Index, for an example.) Copyright headers are automatically inserted into known file types, and DOS newlines (if found) are changed back to unix newlines. The modification time-stamp on the file is not altered.

make tar
Makes a tar file of the current directory tree, excluding RCS subdirectories and emacs backup files.

Ways to turn on other options from the command line:


make TARGET=VXSPARC
Cross compilation! Assuming there's a block already in Make.Common for TARGET=VXSPARC, this will select a different compiler, linker, and obj.CROSSCC/ directory to place the binaries. No modifications needed to your Makefile. Add new cross-configurations to Make.Common.

make obj/program-pure
Assuming you have "$(EXECNAME) $(EXECNAME)-pure: $(OBJS)..." instead of just "$(EXECNAME): $(OBJS)" in your Makefile, this will produce a purified copy of the program which you can then copy or rename if needed.

make EXTRA_CFLAGS="-pg"
If you have already used EXTRA_CFLAGS in the Makefile, this will override. The example above causes the program to be compiled with gprof profiling support. You must do a "make clean" if this is the first time you are compiling for gprof.

make EXTRA_CFLAGS="-DDEBUG -DDEBUGDEBUG"
Use this notation to include any arbitrary defines that you want your code to see, for this invocation of make only. Don't worry about the fact that these extra flags get passed even at link time; gcc will simply ignore them where-ever they do not apply.

make EXTRA_CFLAGS="-g" ?????
Don't do this, and don't try to remove the `-g' from the default options either. GCC can handle doing optimizations while also putting in debugging symbols. The installed versions are always stripped, however, so run the one in the project's ./bin/ directory if you want one with debugging symbols. It is even possible to analyze cores dumped by one of the stripped versions if you rebuild the exact same executable with symbols again (or if you still have the unstripped version in the ./bin/ directory. Here's an example of how gdb could be invoked on one of these cores:
gdb --symbols=/cfht/obs/dumper/dumper --exec=/cfht/bin/dumper --core=.../core

Variables You May Want to Override or Add to


VERSION
Normally this is the date, in the form YYMMDD, but you can override this with something like "1.1" if you prefer.

CONFS
Contains *.def *.par *.bm *.xbm *.rdb *.xrdb, any of which may or may not exists, but they must all be a subdirectory called "conf". During "make install" they are all copied to "dev/conf". If you override, do not include the "conf/" part of the the filenames.

SCRIPTS
Contains *.sh. To limit the list to only specific .sh files within your scripts/ directory, list only the names of those files, but the MUST all still be .sh files. (See restrictions at top of document.)

SUBDIRS
If you define this, only SCRIPTS and CONFS are installed at this level, and then each of the directories named in SUBDIRS are recursed into. Do not list "scripts" and "conf" in this list. They are handled automatically. Also, all built programs must live at the "leaves" of the directory tree, so there cannot be a program at a directory level that defines SUBDIRS.

SRCS
Contains *.c and *.cc by default. OBJS is generated from SRCS .cc and .c with .o. If you override SRCS, OBJS will be adjusted accordingly.

HDRS
Contains *.h and *.hh by default. If you have internal-only header files, then you can either place those in a subdirectory called "internal" and #include them with "internal/foo.h", OR explicitly override HDRS in your Makefile.

EXTRA_CFLAGS
This variable is normally empty. Anything you put in it will be passed as extra options during the compile and link stages. If you have things that don't belong in CCDEFS or CCINCS (below) just stick 'em in here.

CCWARN
The defaults for CCWARN are "-Wall -Wstrict-prototypes", but you might want to override (with "CCWARN=...") or add to (with "CCWARN+=...") in the Makefile. If a project compiles cleanly without any warnings, one way to keep it that way is to add
    CCWARN += $(WERROR)
so that any warnings will prevent compilation (as if they were errors.) [Note: this assumes that there is a file Make.Local in the toplevel src/ directory which defines "WERROR = -Werror". We have this at CFHT in our copy of the source trees.]

CCDEFS
This will contain defines to be passed to the C source code. You can add your own with "CCDEFS+=..." in the Makefile. Be sure to use += because any -Dxxxx from Make.Common itself are important to the build process. At most one of the following will be defined, if a known system type was detected:
-DSUNOS    - SunOS 4.1.x
-DSOLARIS  - SunOS 5.x
-DHPUX     - HP-UX 9 or 10
-DLINUX    - Linux 1.x or 2.x
-DCYGWIN32 - Cygnus win32 on Windows NT
So you can do things like this in the C code:
#include <sys/socket.h>

#ifdef SUNOS
/* Old Suns lack prototypes for these... */
int socket(int domain, int type, int protocol);
int bind(int   sockfd,  struct  sockaddr  *my_addr,  int addrlen);
int listen(int s, int backlog);
#endif

. . .
In addition, the following -D's may come from Make.Common under the following conditions:
-DNO_CFHTLOG  - If /tmp/pipes/syslog.np was not found at compile-time.
-DUSE_EPICS   - If this machine is one on which we want EPICS channel access.
-DHACK_SELECT - If target OS (HP-UX 9) has messed up select() prototype,
                requiring use of SELECT() macro in place of select().
                (In other cases, missing_protos.h defines SELECT to select,
                so always use SELECT() in your code.  Only missing_protos.h
                needs to worry about HACK_SELECT.)
-DHACK_XLIBS  - Another obscure work-around, only for un-patched HP-UX 9
                systems that have buggy X-libraries in /usr/lib.  Only
                "hform" uses this.
-D__USE_FIXED_PROTOTYPES__ - Enables some extra prototypes in the gcc-fixed
                             include files on our SUNOS machines.  Not of
                             interest to user code.
-DEXIT_FAILURE=1 - Only on SUNOS, which forgets this in stdlib.h.
-DEXIT_SUCCESS=0 - Only on SUNOS, which forgets this in stdlib.h.
On our primary development system, HP-UX 10, only -DHPUX usually appears, and possibly -DUSE_EPICS.

CCINCS
Use "CCINCS+=-I..." to append to the list of directories for include files.

CCLIBS
Use "CCLIBS+=-L..." to append to the list of directories to search for libraries.

CCLINK
Set this to a list of "-llibname" options for linking. For example, if your program requires symbols from "libm.a", use
CCLINK += -lm

CCINCSX11, CCLIBSX11, CCLINKX11
These contain extra include paths, library paths, and library names, respectively, to be used with X-applications. Since vendors put these in different places, having these variables defined makes it easy within projects to indicate a program needs X by just saying:
CCINCS += $(CCINCSX11)
CCLIBS += $(CCLIBSX11)
CCLINK += $(CCLINKX11)

CCLINKNET
Any application that uses unix networking stuff (sockets, hostname lookup, etc.) should add the following to their Makefile:
CCLINK += $(CCLINKNET)
Because some platforms (namely new Sun Solaris) need to add "-lsocket" and "-lnsl" in the link stage for the proper network routines. Other platforms may need a "-lresolv" here also for hostname lookup. Simply using CCLINKNET takes care of whatever might be needed here.

Variables That Might Be Useful in the Makefile


HOSTNAME
Contains the name of the host that the project is currently being built on, as returned by the hostname command.

TARGET
This is the equivalent of the "SUNOS", "SOLARIS", "HPUX" symbols defined for C programs, for use within the Makefile. If you wanted certain projects to be built only on a certain architecture, you could use this variable. It contains the name of the operating system, as returned by "uname -s" followed by a dash (-) and the major revision of the OS. For SunOS, this is either a 4 or a 5, and for HP it is either an A (version 9) or a B (version 10). For example, to have certain projects build themselves only on old Suns:
SUBDIRS = libdet cdma chmem deti detio lu trafficoff
ifeq ($(TARGET),SunOS-4)
SUBDIRS += detserver rdmem wrmem
endif

NO_CFHTLOG
If /tmp/pipes/syslog.np exists on the machine, this variable contains nothing. If /tmp/pipes/syslog.np is missing, this will contain "-DNO_CFHTLOG", and it will be passed to your C programs as well. If you want to do something differently depending on whether cfht_log facilities exist, you could do something like this in the Makefile, if you only need libcfht when cfht_log is used:
ifeq ($(NO_CFHTLOG),)
CCLINK += -lcfht
endif
And something like this in the C source code:
#ifdef NO_CFHTLOG
   syslog(syslog_type, message);
#else
   cfht_log(CFHT_MAIN, cfht_log_type, message);
#endif              

Variables That Depend on Local Installation

Make.Common assumes that gcc is available. At CFHT, the following variables are set correctly for our installation, but at another site where gcc is not available (at least as a symbolic link) in /usr/local/bin, or in a case where gcc was not compiled to also use the Gnu linker, you may need to tweak some variables in Make.Common itself. (For all the variables mentioned previously, you override them in the individual project Makefiles, but for site installation stuff, you'll have to modify Make.Common).

DIR_GNU
If gcc is in /usr/local/bin or /usr/bin, there is no need to change this. Otherwise, you should set this to the path where `gcc' can be found.

INSTALL
This must be set to the name of a BSD compatible install program. If you don't have GNU install on your system and you have a compatible install program, you can try putting it here (with full path). Otherwise it is recommended to download "fileutils-X.YY.tar.gz" from ftp.gnu.ai.mit.edu or a mirror and install it. Be sure to configure it with "./configure --program-prefix=g" so it doesn't use names that conflict with the vendor-provided file utilities on your system.

Although I wouldn't recommend it, it is possible to go through Make.Common and search for all $(INSTALL)'s and replace them with regular "cp" or "mkdir" commands (depending on whether it is installing a file or a directory.) GNU fileutils are not difficult to install, so try that first.


CCLINK
The default setting for CCLINK under Solaris may be problematic if you do not have a gcc that uses the GNU linker. Search for "-Wl,-rpath,". This garbage is needed to ensure that shared libraries will be found even if a user has an incorrect LD_LIBRARY_PATH or if the program needs to run without a complete environment (e.g. from a cgi script.) I think the equivalent of "-rpath" for the Sun linker is "-R", but you can comment out the entire CCLINK setting as long as you have the proper search paths in your LD_LIBRARY_PATH and/or the program is statically linked with any libraries that are in non-standard places.

Sidik Isani
Last modified: Wed Sep 29 16:26:04 HST