BSDBuild Logo

Use in a sample application

The BSDBuild module that is used to produce executable files is called build.prog.mk. It is used to build programs from source files in different languages, such as C, C++, Objective C, assembler, Lex and Yacc.

In this tutorial, we will use BSDBuild to compile an executable program from C sources, and install a manual page. We also want to generate a configure script that will look for an OpenGL library and link our executable against it.

Installing BSDBuild

If BSDBuild is not already installed on your system, install it first.

  $ wget http://stable.hypertriton.com/bsdbuild/bsdbuild-2.x.tar.gz
  $ tar -xzf bsdbuild-2.x.tar.gz
  $ (cd bsdbuild-2.x && ./configure && make all install)
Bundling the redistributable components

People building your application do not need to have BSDBuild installed, but you need to bundle the necessary components with your application. mkify reduces this job to executing a single command. To save some space, it will also only install the modules you actually need.

The redistributable components of BSDBuild consist in a number of small make include files (*.mk files) and scripts. These files are normally placed in a directory called ./mk somewhere (usually at the top-level directory) of your source tree. While this may seem like a disadvantage, this actually reduces the amount of gunk that ends up in your tree by orders of magnitude compared to other systems which use generated makefiles.

The mkify program is used to copy the required files into your application directory. It also creates sample Makefile and configure.in files if they do not exist. Since we are going to use the build.prog.mk module, we pass the prog argument to the script.

  $ cd MyApp
  $ mkify prog

You can run mkify again in the future to upgrade your includes to a later BSDBuild version, but updates to the make includes are very rare and you do not need to bother re-running mkify on your projects after having upgraded BSDBuild unless you need some specific functionality that has been added to the new release.

Create the configure script

The mkconfigure script generates a ./configure script from a configure.in file. Our configure scripts offer a similar user interface than GNU-style configure scripts, but the internals are different. Our configure.in allows special directives (see the mkconfigure manual for a complete list), along with Bourne shell code fragments that will be inserted as-is in the configure script.

  # Register some configure options specific to our application.
  REGISTER("--enable-threads", "Thread support [default: no]")
  REGISTER("--enable-gui",     "Graphical user interface [default: yes]")
  
  # Name and version of the application, written to config/progname.h
  # and config/version.h. This is completely optional.
  HDEFINE(PROGNAME, "MyApp")
  HDEFINE(VERSION, "1.0")
 
  # Check for a C compiler. If one exists, ${HAVE_CC} will be set.
  CHECK(cc)
  
  # Check for OpenGL. If it works, then ${HAVE_OPENGL} will be set.
  CHECK(opengl)
  
  # OpenGL is required by our program, so we fail if it is not found.
  if [ "${HAVE_OPENGL}" = "no" ]; then
  	echo "Sorry, this program requires OpenGL."
  	exit 1
  fi
 
  # Alternatively, we can use REQUIRE() which will cause the configure
  # script to exit if the test fails:
  #
  # REQUIRE(opengl)
  
  # The MDEFINE() directive sets a makefile define.
  if [ "${enable_gui}" != "no" ]; then
  	MDEFINE(PROG_TYPE, "gui")
  else
  	MDEFINE(PROG_TYPE, "cli")
  fi
  
  # Define THREADS if --enable-threads was given.
  if [ "${enable_threads}" = "yes" ]; then
  	HDEFINE(THREADS, 1)
  else
  	HDEFINE(THREADS, 0)
  fi

The REGISTER() directives create new options to ./configure. If the user passes the --with-foo option, "${with_foo}" will be set to "yes". If the user passes --without-foo, it will be set to "no".

The next two directives define PROGNAME and VERSION. They are not required but they are useful when it comes to packaging. The HDEFINE() directive generates header files such as ./config/progname.h and ./config/version.h.

The CHECK() directives performs a test. The BSDBuild distribution includes a number of built-in tests for different libraries and programs. The cc test checks for a C compiler, and opengl checks for an OpenGL library. All tests define a number of variables following a standard naming convention, such as HAVE_FOO, FOO_LIBS and FOO_CFLAGS. In this case, our sample application requires OpenGL in order to work, so we fail if the opengl test returned a HAVE_OPENGL value of "no". Instead of manually testing HAVE_OPENGL and failing, we could have also used REQUIRE(opengl).

The CHECK(opengl) test, assuming it was successful, will define the make variables OPENGL_CFLAGS and OPENGL_LIBS, and we will be able to use them directly in our makefiles, like this:

  CFLAGS+= ${OPENGL_CFLAGS}
  LIBS+=   ${OPENGL_LIBS}

The next piece of code sets the make variable $PROG_TYPE using the MDEFINE() directive. This variable will be visible throughout our makefiles. This particular variable ($PROG_TYPE) happens to be recognized by build.prog.mk.

Note that there is a subtle difference between a test like:

  if [ "${enable_threads}" = "yes" ]

and a test like:

  if [ "${enable_threads}" != "no" ]

The first test will evaluate to true if and only if the user has explicitely provided the --enable-threads option. The second test will evaluate to true unless the user has explicitely passed --disable-threads.

To generate the configure script, execute:

  $ cat configure.in | mkconfigure > configure
  $ chmod 755 configure
Create the Makefile

With BSDBuild, makefiles can be edited directly. A simple Makefile might look like:

  TOP=  .
  include ${TOP}/Makefile.config
  
  PROG= MyApp
  SRCS= MySource1.c \
        MySource2.c
  
  CFLAGS+= ${OPENGL_CFLAGS}
  LIBS+=   ${OPENGL_LIBS}
  
  include ${TOP}/mk/build.prog.mk

The definition of TOP is required in all BSDBuild makefiles and determines the top-level source directory. The modules will always look for the BSDBuild scripts in the ${TOP}/mk/ directory.

PROG defines the name of the executable. The actual filename might have different prefixes or suffixes depending on the target platform.

SRCS is simply the list of source files to compile and link into the program. The extensions of the files determine their language and which compiler to use. The full list of supported languages is documented in the build.prog.mk manual.

Since our sample application requires OpenGL, we append the contents of OPENGL_CFLAGS and OPENGL_LIBS to our CFLAGS and LIBS, respectively. These values are defined in Makefile.config, which is generated by the ./configure script (more specifically, the CHECK(opengl) line).

the variables used by build.prog.mk are documented in its manual page.


Csoft.net ElectronTubeStore