Create/Modify a Project

This how-to guide introduces the basisproject command-line tool which is installed as part of BASIS. This tool is used to create a new project based on BASIS or to modify an existing BASIS project. The creation of a new project based on BASIS is occasionally also referred to as instantiating the Project Template.

For a detailed description and overview of the available command options, please refer to the output of the following command:

basisproject --help

Create a New Project

The fastest way to create a new project is to call basisproject with the name of the new project and a brief project description as arguments:

basisproject create --name MyProject \
        --description "This is a brief description of the project."

Note

Use the –full option to create a project from all template features. Most projects, however, will only need the default set of features.

This will create a subdirectory called MyProject under the current working directory and populate it with the standard project directory structure and BASIS configuration. No CMake commands to resolve dependencies to other software packages will be added. These can be added later either manually or as described below. However, if you know already that your project will depend, for example, on ITK and optionally make use of VTK if available, you can specify these dependencies when creating the project using the --use or --useopt option, respectivley:

basisproject create --name MyProject \
        --description "This is a brief description of the project." \
        --use ITK --useopt VTK

The basisproject tool will in turn modify the BasisProject.cmake file to add the named packages to the corresponding lists of dependencies.

Note

In order for basisproject to be able to find the correct place where to insert the new dependencies, the #<dependency> et al. placeholders have to be present. See the BasisProject.cmake template file.

Modify an Existing Project

basisproject allows a detailed selection of the features included in the project template for a particular BASIS project. Which of these features are needed will often not be known during the creation of the project, but change during the work on the project. Therefore, an existing BASIS project which was created as described above can be modified using basisproject to add or remove certain project features and to conveniently add CMake commands to resolve further dependencies on other software packages. How this is done is described in the following.

General Notes

The two project attributes which cannot be modified using basisproject are the project name and its description. These attributes need to be modified manually by editing the project files. Be aware that changing the project name may require the modification of several project files including source files. Furthermore, the project name is used to identify the project within the lab and possibly even externally. Therefore, it should be fixed as early as possible. In order to change the project description, simply edit the BasisProject.cmake file which you can find in the top directory of the source tree. Specifically, the argument for the DESCRIPTION option of the basis_project() function.

Hence, in order to modify an existing project, the --name and --description options cannot be used. Instead, use the --root option to specify the root directory of the source tree of the project you want to modify or run the command without either of these options with the root directory as current working directory.

Adding Features

By features, we refer here to the set of directories and contained CMake/BASIS configuration files for which template files exist in the BASIS project template. For a list of available project features, please have a look at the help output of basisproject. You can either select a pre-configured project template consisting of a certain set of directories and configuration files and optionally modify these sets by removing features from them and/or adding other features, or you can simply remove and/or add selected features only from/to the current set of directories and configuration files which already exist in the project’s source tree.

For example, if you created a project using the standard project template (i.e., by supplying no particular option or the option --standard during the project creation), but your software requires auxiliary data such as a pre-computed lookup table or a medical image atlas, you can add the data/ directory in which these auxiliary files should be stored in the source tree using the command:

basisproject update --data

As another example, if you want to extend the default script configuration file which is used to configure the build of scripts written in Python, Perl, BASH, or any other scripting language (even if not currently supported by BASIS will it likely still be able to “build” these), use the command:

basisproject update --config-script

Removing Features

For example, in order to remove the conf/Settings.cmake file and the example/ directory tree, run the command:

basisproject update --noconfig-settings --noexample

If any of the project files which were initially added during the project creation differ from the original project file, the removal of such files will fail with an error message. If you are certain that the changes are not important and still want to remove those files from the project, use the --force option. Moreover, if a directory is not empty, it will only be removed if the --force option is given. Note that a directory is also considered empty if it only contains hidden subdirectories which are used by the revision control software to manage the revisions of the files inside this directory, i.e., the .svn/ subdirectory in case of Subversion or the .git/ subdirectory in case of Git. Before using the --force option, you should be certain which directories would be removed and if their content is no longer needed. Thus, run any command first without the --force option, and only if it failed consider to add the --force option.

Adding Dependencies

A dependency is either a program required by your software at runtime or an external software package such as the nifticlib or ITK. basisproject can be used to add the names of packages your project depends on to the lists of dependencies which are given as arguments to the basis_project() command. For each named package in this list, the basis_find_package() command is called to look for a corresponding package installation. In order to understand how CMake searches for external software packages, please read the documentation of CMake’s find_package() command.

The BASIS package provides so-called Find modules (e.g., FindMATLAB.cmake or FindNiftiCLib.cmake) for external software packages which are commonly used at SBIA and not (yet) part of CMake or improve upon the standard modules. If you have problems resolving the dependency on an external software package required by your software due to a missing corresponding Find module, please contact the maintainer of the BASIS project and state your interest in a support by BASIS for this particular software package. Alternatively, you can write such Find module yourself and save it in the PROJECT_CONFIG_DIR of your project.

As an example on how to add another dependency to an existing BASIS project, consider the following scenario. We created a project without any dependency and now notice that we would like to make use of ITK in our implementation. Thus, in order to add CMake code to the build configuration to resolve the dependency on ITK, which also includes the so-called Use file of ITK (named UseITK.cmake) to import its build configuration, run the command:

basisproject update --use ITK

If your project can optionally make use of the features of a certain external software package, but will also built and run without this package being installed, you can use the --useopt option to exploit CMake code which tries to find the software package, but will not cause CMake to fail if the package was not found. In this case, you will need to consider the <Pkg>_FOUND variable in order to decide whether to make use of the software package or not. Note that the package name is case sensitive and that the case must match the one of the first argument of basis_find_package().

For example, let’s assume your software can optionally make use of CUDA. Therefore, as CMake includes already a FindCUDA.cmake module, we can run the following command in order to have CMake look for an installation of the CUDA libraries:

basisproject update --useopt CUDA

If this search was successful, the CMake variable CUDA_FOUND will be TRUE, and FALSE otherwise.

Another example of a dependency on an external package is the compilation of MATLAB source files using the MATLAB Compiler (MCC). In this case, you need to add a dependency on the MATLAB package. Please note that it is important to capitalize the package name and not to use Matlab as this would refer to the FindMatlab.cmake module included with CMake. The FindMATLAB.cmake module which we are using is included with BASIS. It improves the way CMake looks for a MATLAB installation and furthermore looks for executables required by BASIS, such as in particular matlab, mcc, and mex. Use the following command to add a dependency on MATLAB:

basisproject update --use MATLAB

Removing Dependencies

basisproject does not currently support the removal of previously added dependencies. Therefore, please edit the BasisProject.cmake file manually and simply remove all CMake code referring to the particular package you do no longer require or use.

Modularize a Project

Project Modularization is a technique that aims to maximize code reusability, allowing components to be split up as independent modules that can be shared with other projects while only building and packaging the components that are really needed. Modularized projects consist of a Top Level Project and one or more Project Modules.

Create the Top Level Project

First create the top-level project as follows (or simply add a modules/ directory to an existing project):

basisproject create --name MyToolkit --description "A modularized project." --toplevel

Create the Modules

To add modules to your Top Level project, which has a modules/ subdirectory, change to the modules/ subdirectory of the top-level project, and run the command:

cd MyToolkit/modules
basisproject create --name MyModule --description "A module in MyToolkit." --module

More than one module can be in the same folder:

basisproject create --name OtherModule --description "Another module in MyToolkit." --module

You may also add an existing BASIS project module to the /modules folder, but not another Top Level project.

Configure the build

Configure the build system using CMake 2.8.4 or a more recent version:

cd ../..
mkdir build && cd build
ccmake ../MyToolkit
  • Press c to configure the project.
  • Change CMAKE_INSTALL_PREFIX to ~/local.
  • Set option BUILD_ALL_MODULES to ON.
  • Press g to generate the Makefiles and exit ccmake.

Build the Top Level Project and its Modules

CMake has generated Makefiles for GNU Make. The build and installation are then thus triggered with the make command:

make
make install

As a result, CMake copies the built files into the installation tree as specified by the CMAKE_INSTALL_PREFIX variable.

Upgrade a Project

Occasionally, the project template of BASIS may be modified as the development of BASIS progresses, you may want or need to upgrade the files from a previous version to the current version of the template. basisproject provides the ability to upgrade by using a three-way file comparison similar to Subversion to merge changes in the template files with those changes you have made to the corresponding files of your project. If such merge fails because both the template as well as the project file have been changed at the same lines, a merge conflict occurs which has to be resolved manually. However, basisproject will never discard your changes. There will always be a backup of your current project file before the automatic file merge is performed.

To upgrade the project files, run the following command in the root directory of your project’s source tree:

basisproject upgrade

If the project template has not been changed since the last upgrade, no files will be modified by this command.

Resolving Merge Conflicts

When the same lines of the template file as well as the project file have been modified since the creation or last update of the project, you will get a merge conflict. A merge conflict results in a merged project file which contains the changes of both the template and your current project file. Markers such as the following are used to highlight the lines of the merged file which are in conflict with each other.

Marker Description
<<<<<<< Marks the start of conflicting lines. This marker is followed by your changes from the corresponding lines of your project file.
||||||| Marks the start of the corresponding lines from the original template file which was used to create the project or which the project has been updated to last.
======= Marks the start of the corresponding lines from the current template file, i.e., the one the project file should be updated to.
>>>>>>> Marks the end of the conflicting lines.

In order to resolve the conflicts in one file, you have to edit the merged project file manually. For reference, basisproject writes the new template file to a file named like the project file in conflict with this project file, using .template as file name suffix. It further keeps a backup of your current project file before the update. The file name suffix for this backup file is .mine. For example, if conflicts occured when updating the README.txt file, the following files are written to your project’s directory.

File Name Description
README.txt.mine A copy of the project file before the update.
README.txt.template A copy of the current template file which differs from the template file used to create the project or corresponds to the version of the template file of the last update.
README.txt The file containing changes from both the README.txt.template and README.txt.mine file, where conflicts have been highlighted using above markers.

After you edited the project files which contain conflicts, possibly using merge tools installed on your system, you need to remove the .template and .mine files to let basisproject know that the conflicts are resolved. Otherwise, when you run the update command again, it will fail with an error message indicating that there are unresolved merge conflicts. You can delete those files either manually or using the following command in the root directory of your project’s source tree.

basisproject upgrade --cleanup