BENV Overview

Introduction

The BENV build environment is a reusable make engine that greatly simplifies the process of setting-up and maintaining make files for projects.  BENV effectively reduces a project’s makefile to two files: the first is a list of source code directories to compile and link. The second file is a list all of the project’s specific compile and link options/switches.  That’s it. Couldn’t be simpler.  Well, not exactly.  The devil is in the details.  The above description is correct once a specific host-compiler-target toolset has been configured. No matter what make system/engine you use, it must first be tailored/customized to your specific Host platform, compiler, linker, target OS and platform.  What is different about BENV, is that this customization process is only done once.  Once configured, a given toolset can be used on an unlimited number of projects.

 

Components

BENV is built on top of GNU make.  It was originally designed to run on Unix platforms and to support embedded, cross platform development.  It has been successfully ported to run under Windows.  The BENV engine is broken down into several subsystem or components.  The structure is such that subsystems/components can be mixed and matched to meet the needs of a given toolset.  Adding new toolsets is a straight forward process, but it does require general knowledge of MAKE, the compiler to be used, and the target platform.  The following is very brief description of the major components of the BENV environment.  A detailed reference guide is in progress, but currently not available. 

 

Component

Description

host

Contains the makefile fragments that define the computing environment in which BENV executes. 

targetOS

Contains the of makefile fragments that describe the target OS for the compiler and linker. 

link

Contains the makefile fragments that are used during the link phase of the build process.

toolchain

Contains the makefile fragments that specify the tools (compiler, assembler, linker, etc.) that are used during the build process.

templates

 

Contains the top-level makefile fragments and shell script(s) for a given toolset.  These files provide the ‘base make’ for new projects.

make

Contains the core makefile and make rules.  It is independent of host/target/OS.

bin

Contains a collection of shell scripts that is used by the make engine.

hostlinks

Contains a collection of “links” to the host tools (compilers, linkers, etc.).  This simplifies the process of identifying the absolute location of the host tools.

latest

Contains a minimum set of shell scripts that are stored at well-known, absolute location.  The directory of this component is required to be in your command search path.  The scripts contained in this component provide the minimum infrastructure needed to allow the other components of the build engine to be stored at an arbitrary root location.

 

Using BENV

BENV is organized with certain assumptions about the directory structure of the make engine, the projects directories, and the source code.  The following is a brief description of the top-level directory structure of the overall build/source code environment.  The directory that contains the following directories is called the BENV root directory.  The BENV root directory can be located anywhere.

 

Directory

Description

build

Contains the majority of the files that make up the BENV build engine.

hostlinks

Contains the “links” to the various host tools (compilers, linkers, etc) that are integrated into BENV. 

iheaders

This directory is used for the “indirect header include” build pattern.  This build pattern allows code to include target/platform/compiler specific header files while at the same time being independent of any of the specifics.

projects

Contains all of the individual project directories.  A project directory contains the top-level source code module (i.e. main()) and it is where the code is compiled (i.e. where you invoke make).  

src

Contains 99% of the entire C/C++ source code base.  All code under this directory is reusable by any/all projects.

com,org,net,edu

Contains the JAVA source code that is intended to be compiled under the BENV framework

xsource

Contains external, legacy, third-party C/C++ source code.  Code in this directory has no absolute requirements placed on it - and is therefore only reusable at a very "coarse" level.

xjava

Contains external/third-party JAVA class files, jar files, beans, etc that can be “linked” to a JAVA project.  No JAVA code is compiled from this directory.  All third-party JAVA code to be compiled must be moved to the appropriate com/, org/, net/, edu/ directories.

NOTE: Directories in italics are required for BENV to operate correctly.

 

NOTE: The following instructions assume that BENV had been previously installed and that the desired toolset already exists in BENV.

 

Configuring the Environment

Each developer must modify his/her login profile with basic information about BENV.

Unix – Bash shell. 

Add the following the lines to your login profile.  NOTE: it assumes that the ‘latest’ component is stored at /tools/latest/benv.

# Build Environment

export BENV_LATEST_ROOT=/tools/latest

export PATH=$PATH:$BENV_LATEST_ROOT/benv

 

For Unix system’s where GNU Make is not the native make, you must set an additional environment variable to inform BENV of the executable name of the GNU Make tool.

# Solaris

export BENV_GMAKE=gmake

 

Windows

Make the following modification to your environment. NOTE: it assumes that the ‘latest’ component is stored at c:\tools\latest\benv.

set BENV_LATEST_ROOT=c:\tools\latest

set PATH=%PATH%;%BENV_LATEST_ROOT%\benv

 

Creating a New Project

  1. Create a new project directory under benvroot/projects.
  2. Run cfgmake in the newly created directory.  This will provide a list of available toolsets.  For example:
                $ cfgmake
          gnu/templates/java/unix/application/basic
          gnu/templates/cross/gnu/ecos/powerpc-eabi/psim
          gnu/templates/cross/gnu/legOS/h8300/user
          gnu/templates/native/gnu/unix/mt
          gnu/templates/native/gnu/unix/std
          gnu/templates/native/gnu/unix/ansi
          $
  3. Run cfgmake with the –c option while specifying the desired toolset.  This will copy the base makefiles and scripts to the current directory.  For example:
                $ cfgmake –c psim
          Initial Project Make files created.
          $
  4. Create two additional text files.  The first is sources.b.  This file contains a list of source code files in the project directory to be compiled and linked for the project.  The second is libdirs.b.  This file contains a list of directories to be compiled and linked for the projects.  Always use the Unix directory separator “/” – even for non-Unix projects.  Specify the directories relative to the “root” of the build environment.  This allows directories under benvroot/src, benvroot/com, as well as benvroot/xsource to be included in your project.

    For C/C++ example:

sources.b

main.cpp

 

libdirs.b

   # This file contains a list of library pathnames

   # relative to the build environment root directory.
   #

   # devtest
   src/jcl/devtests/streamio/stdio

   # streamio
   src/jcl/streamio/stdio/api
   src/jcl/streamio/stdio/win32

   # support
   src/jcl/strings/fixed
   src/jcl/strings/common
   src/jcl/strings/utils
   src/jcl/errors/stderr/ansi

 

For JAVA example:

sources.b

JXCodeMain.java

 

libdirs.b

   # This file contains a list of library pathnames

   # relative to the build environment root directory.
   #

   #

   com/shiftright/jcl/xcode

   com/shiftright/jcl/asx

   com/shiftright/jcl/cmdline

   com/shiftright/jcl/types/numeric

 

   # support

   org/apache/avalon/excalibur/io

 

  1. Make modifications (if any) to overrides.b.  This file is a makefile fragment and contains the following:
                - Additions to the header include path (C/C++).
                - Additions to the class path (Java).
                - Additional compiler and linker options specific to this project.
                - Name of the executable produced.

Building a Project

To build a project, simply set the current working directory to the desired project directory and type mk.  Invoking mk with no options will build the “release” build of the project.  To get a listing of available build options, type mk –h.  The following sections provide additional details to the build process.

mk

mk is a native shell script that is used to build the project.  This additional layer provides the following functionality:

1.      Provides a consistent “build interface” independent of the underlying tool(s) are actually used to build the project.  This is important when projects are built using third-party and/or legacy components that are not easily ported to the BENV build environment.

2.      Allows the build interface to be host platform independent.

 

buildCfg.h (C/C++ specific)

buildCfg.h is a header file that the build engine automatically includes with every file that is compiled.  This header file can be used to provide global macros, definitions, etc.  The intent of this file is to facilitate debugging and as an alternative to specifying “compile” macros (i.e. replace the –Dmacro command line argument).   Warning: Every c/cpp file is dependent on this file!  This kind of a global dependency is usually a bad thing. It is recommended that you avoid using this file.

 

sources.b

sources.b is makefile fragment file that is optionally used with every directory that is compiled.  This file is used to specify which files in the directory are to be compiled.  The file optionally exists in the source directory itself.  If no sources.b file is specified, the build engine defaults to “compiling” all files in the directory.  NOTE: Builds will run faster if you create a sources.b file for each directory.

 

flags.b

flags.b is a makefile fragment file that can be used on a individual directory biases.  This file allows additional compile options, or to override existing options when compiling a directory.  This file optionally exists in the source directory itself.  Typically this file is used for debugging purposes to selectively enable debug and/or tracing options for individual directories.  This file should never be “permanently” used, i.e. never checked into the Revision Control System and never required for “release” builds.

 

ANSI projects

ANSI projects are projects that have no host/target dependencies.  These projects will compile and link using an ANSI compiler and libraries.  Though the source code has no host dependencies – you still must specify a host environment to build the project.  One way to do this would be to replicate the project for each host platform you would like to build it under.  Another way would be to create a single project and at “build time” specify the host platform.  BENV compromises by having a single project directory, but replicating the “make files” for each host platform.  To build an ANSI project, the developer types mkxxxx, where xxxx is the desired host platform (i.e. mkwin32 or mkunix).  An ANSI project is created simply by selecting it when running cfgmake.  For example:

            $ cfgmake
      gnu/templates/java/unix/application/basic
      gnu/templates/cross/gnu/ecos/powerpc-eabi/psim
      gnu/templates/cross/gnu/legOS/h8300/user
      gnu/templates/native/gnu/unix/mt
      gnu/templates/native/gnu/unix/std
      gnu/templates/native/gnu/unix/ansi
            $ cfgmake –c ansi
      Initial Project Make files created.
      $

JAVA projects

JAVA projects are similar to ANSI projects in that they have no host/target run-time dependencies (only dependent on the host’s JVM).  Though pure JAVA source code has no host dependencies – you still must specify a host environment to build the project.  To build a JAVA project, the developer types mkxxxx, where xxxx is the desired host platform (i.e. mkwin32 or mkunix).

 

manifest.mf (JAVA specific)

The file manifest.mf, if it exists, will be used as the manifest file when creating the jar file for the project.  If the file does not exists, BENV will attempt to create a basic manifest file that specifies the ‘Main-Class’.  BENV searches the project directory for a JAVA class that contains the “main()” method.  If one and only one such class is found, a manifest is created using the founded class as ‘Main-Class’.  If no match is found, then an empty manifest is created.

 

Windows

BENV was originally designed to run under Unix.  BENV has been tested on Windows 2000 and ME and should be able to run on Windows 9x, NT, and XP.  It has been ported to Windows by making use of Open Source ports of the standard Unix tools and shell.  The main tools used are Cygwin and ZshCygwin is used for the BASH shell emulation and the win32 port of GNU make.  Zsh is used to provide native win32 implementations of the common Unix tools such as ls, grep, etc.  By using Zsh instead of the complete Cygwin emulation, build time under Windows is greatly reduced.

 

What does all this mean?  For Windows, the “latest” component contains the additional Cygwin/Zsh binaries that provide the Unix emulation.  Also build times under Windows are slightly slower because of the emulation layer.  There are no differences between Windows and Unix with respect to creating and building projects! 

 

JAVA

BENV started as build environment for C/C++ code, it has just recently been extended to build JAVA projects.  The first significant build issue for JAVA projects is how to determine the file dependencies.  Typically, this functionality is provided by the compiler.  The JAVA compiler does not properly provide this functionality.  As a result, a third party JAVA based tool, javadeps, is used to derive the file dependencies.  The next issue is build times.  First, the javadeps tool is a JAVA application which incurs a startup time penalty (as the JVM is initialized) each time it is invoked. Since it is called once per file, this adds up.  Second, the JAVA compiler itself is slow to start-up and it too is called on a per-file basis.  These start-up delays are serialized and add up to longer build times (compared to C/C++ projects).  The slow build times are compounded on Windows boxes as BENV framework is slower to begin with.  

 

In an effort to speed up build times, individual directories are compiled in a batch mode.  If one file in a given directory needs to be rebuilt, the entire directory is rebuilt.  This batch mode has the following characteristics.  First, it has the cut the original build times in half.  Second, the JAVA compiler and javadeps is called at most one time per directory.  This effects the output of the build scripts by only echoing the status of first ‘dirty’ target detected.