How to Make an Executable Program

The code for the user examples in Geant4 is placed in the subdirectory examples of the main Geant4 source package. This directory is installed to the share/Geant4-G4VERSION/examples (where G4VERSION is the Geant4 version number) subdirectory under the installation prefix. In the following section, a quick overview will be given on how to build a concrete example, “ExampleB1”, which is part of the Geant4 distribution, using CMake.

Using CMake to Build Applications

Geant4 installs a file named Geant4Config.cmake located in

+- CMAKE_INSTALL_PREFIX
   +- lib/
      +- cmake/
         +- Geant4/
            +- Geant4Config.cmake

which is designed for use with the CMake find_package command. Building a Geant4 application using CMake therefore involves writing a CMakeLists.txt script using this and other CMake commands to locate Geant4 and describe the build of your client application. Whilst it requires a bit of effort to write the script, CMake provides a very friendly yet powerful tool, especially if you are working on multiple platforms. It is therefore the method we recommend for building Geant4 applications.

We’ll use Basic Example B1, which you may find in the Geant4 source directory under examples/basic/B1, to demonstrate the use of CMake to build a Geant4 application. You’ll find links to the latest CMake documentation for the commands used throughout, so please follow these for further information. The application sources and scripts are arranged in the following directory structure:

+- B1/
   +- CMakeLists.txt
   +- exampleB1.cc
   +- include/
   |  ... headers.hh ...
   +- src/
      ... sources.cc ...

Here, exampleB1.cc contains main() for the application, with include/ and src/ containing the implementation class headers and sources respectively. This arrangement of source files is not mandatory when building with CMake, apart from the location of the CMakeLists.txt file in the root directory of the application.

The text file CMakeLists.txt is the CMake script containing commands which describe how to build the exampleB1 application

# (1)
cmake_minimum_required(VERSION 3.16...3.27)
project(B1)

# (2)
find_package(Geant4 REQUIRED ui_all vis_all)

# (3)
file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cc)
file(GLOB headers ${PROJECT_SOURCE_DIR}/include/*.hh)

# (4)
add_executable(exampleB1 exampleB1.cc ${sources} ${headers})
target_include_directories(exampleB1 PRIVATE include)
target_link_libraries(exampleB1 PRIVATE ${Geant4_LIBRARIES})

# (5)
set(EXAMPLEB1_SCRIPTS
  exampleB1.in
  exampleB1.out
  init_vis.mac
  run1.mac
  run2.mac
  vis.mac
  )

foreach(_script ${EXAMPLEB1_SCRIPTS})
  configure_file(
    ${PROJECT_SOURCE_DIR}/${_script}
    ${PROJECT_BINARY_DIR}/${_script}
    COPYONLY
    )
endforeach()

For clarity, the above listing has stripped out the main comments (CMake comments begin with a “#”) you’ll find in the actual file to highlight each distinct task:

  1. Basic Configuration

    The cmake_minimum_required command simply ensures we’re using a suitable version of CMake and that it has been setup appropriately. The project command sets the name of the project and enables and configures C and C++ compilers.

  2. Find and Configure Geant4

    The aforementioned find_package command is used to locate and configure Geant4 (we’ll see how to specify the location later when we run CMake), the REQUIRED argument being supplied so that CMake will fail with an error if it cannot find Geant4. The ui_all vis_all “component” arguments to find_package state that we want Geant4 setup to include all available UI and Visualization drivers. An overview of available components is provided Use of Geant4Config.cmake with find_package in CMake with a full listing at the top of the installed Geant4Config.cmake file.

  3. List the Sources to Build the Application

    Uses the globbing functionality of the file command to prepare lists of the B1 source and header files that should be compiled into the final executable.

    Note however that CMake globbing is only used here as a convenience. The expansion of the glob only happens when CMake is run, so if you later add or remove files, the generated build scripts will not know a change has taken place. Kitware strongly recommend listing sources explicitly as CMake automatically makes the build depend on the CMakeLists.txt file. This means that if you explicitly list the sources in CMakeLists.txt, any changes you make will be automatically picked up when you rebuild. This is also useful when you are working on a project with sources under version control and multiple contributors to ensure traceability and consistent builds.

  4. Define and Link the Executable

    The add_executable command defines the build of an application, outputting an executable named by its first argument, with the sources following. Note that we add the headers to the list of sources so that they will appear in IDEs like Xcode.

    After adding the executable, we use the target_include_directories command to tell CMake where to find the headers for the application. We then use the target_link_libraries command to link it with the Geant4 libraries. The Geant4_LIBRARIES variable is set by find_package when Geant4 is located, and is a list of all the libraries needed to link against to use Geant4.

  5. Copy any Runtime Scripts to the Build Directory

    Because we want to support out of source builds so that we won’t mix CMake generated files with our actual sources, we copy any scripts used by the B1 application to the build directory. We use foreach to loop over the list of scripts we constructed, and configure_file to perform the actual copy.

    Here, the CMake variable PROJECT_BINARY_DIR is set by the earlier call to the project command and points to the directory where we run CMake to configure the build.

This sequence of commands is the most basic needed to compile and link an application with Geant4, and is easily extendable to more involved use cases such as platform specific configuration or using other third party packages (via find_package).

With the CMake script in place, using it to build an application is a two step process. First CMake is run to generate buildscripts to describe the build. By default, these will be Makefiles on Unix platforms, and Visual Studio solutions on Windows, but you can generate scripts for other tools like Xcode and Eclipse if you wish. Second, the buildscripts are run by the chosen build tool to compile and link the application.

A key concept with CMake is that we generate the buildscripts and run the build in a separate directory, the so-called build directory, from the directory in which the sources reside, the so-called source directory. This is the exact same technique we used when building Geant4 itself. Whilst this may seem awkward to begin with, it is a very useful technique to employ. It prevents mixing of CMake generated files with those of your application, and allows you to have multiple builds against a single source without having to clean up, reconfigure and rebuild.

We’ll illustrate this configure and build process on Linux/macOS using Makefiles, and on Windows using Visual Studio. The example script and Geant4’s Geant4Config.cmake script are vanilla CMake, so you should be able to use other Generators (such as Xcode and Eclipse) without issue.

Building ExampleB1 with CMake on Unix with Makefiles

We’ll assume, for illustration only, that you’ve copied the exampleB1 sources into a directory under your home area so that we have:

+- /home/you/B1/
   +- CMakeLists.txt
   +- exampleB1.cc
   +- include/
   +- src/
   +- ...

Here, our source directory is /home/you/B1, in other words the directory holding the CMakeLists.txt file.

Let’s also assume that you have already installed Geant4 in your home area under, for illustration only, /home/you/geant4-install.

Our first step is to create a build directory in which build the example. We will create this alongside our B1 source directory as follows:

$ cd $HOME
$ mkdir B1-build

We now change to this build directory and run CMake to generate the Makefiles needed to build the B1 application. We pass CMake two arguments

$ cd $HOME/B1-build
$ cmake -DCMAKE_PREFIX_PATH=/home/you/geant4-install $HOME/B1

Here, the first argument points CMake to the install prefix of Geant4. CMAKE_INSTALL_PREFIX may be extended with additional paths to search for packages, and also set in the environment. See the CMake documentation on CMAKE_PREFIX_PATH and find_package for more details.

For an exact search, you may also use the Geant4_DIR variable, e.g:

$ cd $HOME/B1-build
$ cmake -DGeant4_DIR=/home/you/geant4-install/lib/cmake/Geant4 $HOME/B1

This variable should set to the directory holding the Geant4Config.cmake file for the install of Geant4 you want to use.

The second argument to CMake is the path to the source directory of the application we want to build. Here it’s just the B1 directory as discussed earlier. You should of course adapt the value of that variable to where you copied the B1 source directory.

CMake will now run to configure the build and generate Makefiles and you will see output similar to

$ cmake -DCMAKE_PREFIX_PATH=/home/you/geant4-install $HOME/B1
-- The C compiler identification is GNU 11.5.0
-- The CXX compiler identification is GNU 11.5.0
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/g++
-- Check for working CXX compiler: /usr/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/you/B1-build

The exact output will depend on the UNIX variant, compiler, and CMake version but the last three lines should be identical to within the exact path used.

If you now list the contents of you build directory, you can see the files generated:

$ ls
CMakeCache.txt       exampleB1.in   Makefile      vis.mac
CMakeFiles           exampleB1.out  run1.mac
cmake_install.cmake  init_vis.mac   run2.mac

Note the Makefile and that all the scripts for running the exampleB1 application we’re about to build have been copied across. With the Makefile available, we can now build by simply running make:

$ make -jN

CMake generated Makefiles support parallel builds, so N can be set to the number of cores on your machine (e.g. on a dual core processor, you could set N to 2). When make runs, you should see the output:

$ make
Scanning dependencies of target exampleB1
[ 12%] Building CXX object B1/CMakeFiles/exampleB1.dir/exampleB1.cc.o
[ 25%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/ActionInitialization.cc.o
[ 37%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/DetectorConstruction.cc.o
[ 50%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/EventAction.cc.o
[ 62%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/PrimaryGeneratorAction.cc.o
[ 75%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/RunAction.cc.o
[ 87%] Building CXX object B1/CMakeFiles/exampleB1.dir/src/SteppingAction.cc.o
[100%] Linking CXX executable exampleB1
[100%] Built target exampleB1

CMake Unix Makefiles are quite terse, but you can make them more verbose by adding the VERBOSE argument to make:

$ make VERBOSE=1

If you now list the contents of your build directory you will see the exampleB1 application executable has been created:

$ ls
CMakeCache.txt       exampleB1      init_vis.mac      run2.mac
CMakeFiles           exampleB1.in   Makefile          vis.mac
cmake_install.cmake  exampleB1.out  run1.mac

You can now run the application in place:

$ ./exampleB1
Available UI session types: [ GAG, tcsh, csh ]

*************************************************************
 Geant4 version Name: geant4-11-03 [MT]   (6-December-2024)
  << in Multi-threaded mode >>
                      Copyright : Geant4 Collaboration
                     References : NIM A 506 (2003), 250-303
                                : IEEE-TNS 53 (2006), 270-278
                                : NIM A 835 (2016), 186-225
                            WWW : http://geant4.org/
*************************************************************

<<< Reference Physics List QBBC
Visualization Manager instantiating with verbosity "warnings (3)"...
Visualization Manager initialising...
Registering graphics systems...

Note that the exact output shown will depend on how both Geant4 and your application were configured. Further output and behaviour beyond the Registering graphics systems... line will depend on what UI and Visualization drivers your Geant4 install supports. If you recall the use of the ui_all vis_all in the find_package command, this results in all available UI and Visualization drivers being activated in your application. If you didn’t want any UI or Visualization, you could rerun CMake in your build directory with arguments:

$ cmake -DWITH_GEANT4_UIVIS=OFF .

This would switch the option we set up to false, and result in find_package not activating any UI or Visualization for the application. You can easily adapt this pattern to provide options for your application such as additional components or features.

Once the build is configured, you can edit code for the application in its source directory. You only need to rerun make in the corresponding build directory to pick up and compile the changes. However, note that due to the use of CMake globbing to create the source file list, if you add or remove files, you must remember to rerun CMake to pick up the changes. This is another reason why Kitware recommend listing the sources explicitly.

Building ExampleB1 with CMake on Windows with Visual Studio

As with building Geant4 itself, the simplest system to use for building applications on Windows is a Visual Studio Developer Command Prompt, which can be started from StartVisual Studio 2017Developer Command Prompt for VS2017 (similarly for VS2015)

We’ll assume, for illustration only, that you’ve copied the exampleB1 sources into a directory C:\Users\YourUsername\B1 so that we have:

+- C:\Users\YourUsername\B1
   +- CMakeLists.txt
   +- exampleB1.cc
   +- include\
   +- src\
   +- ...

Here, our source directory is C:\Users\YourUsername\B1, in other words the directory holding the CMakeLists.txt file.

Let’s also assume that you have already installed Geant4 in your home area under, for illustration only, C:\Users\YourUsername\Geant4-install.

Our first step is to create a build directory in which build the example. We will create this alongside our B1 source directory as follows, working from the Visual Studio Developer Command Prompt:

> cd %HOMEPATH%
> mkdir B1-build

We now change to this build directory and run CMake to generate the Visual Studio solution needed to build the B1 application. We pass CMake two arguments

> cd %HOMEPATH%\Geant4\B1-build
> cmake -DCMAKE_PREFIX_PATH="%HOMEPATH%\Geant4-install" "%HOMEPATH%\B1"

Here, the first argument points CMake to the install prefix of Geant4. CMAKE_INSTALL_PREFIX may be extended with additional paths to search for packages, and also set in the environment. See the CMake documentation on CMAKE_PREFIX_PATH and find_package for more details. As with the examples above, you can also use the Geant4_DIR variable. The second argument is the path to the source directory of the application we want to build. Here it’s just the B1 directory as discussed earlier. You should of course adapt it to where you copied the B1 source directory. In both cases the arguments are quoted in case of the paths containing spaces.

CMake will now run to configure the build and generate Visual Studio solutions and you will see output similar to

-- Building for: Visual Studio 22 2022
-- The C compiler identification is MSVC 19.11.25547.0
-- The CXX compiler identification is MSVC 19.11.25547.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/.../cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/.../cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/.../cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/.../cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/YourUsername/B1-build

If you now list the contents of you build directory, you can see the files generated:

> dir /B
ALL_BUILD.vcxproj
ALL_BUILD.vcxproj.filters
B1.sln
B1.vcxproj
B1.vcxproj.filters
CMakeCache.txt
CMakeFiles
cmake_install.cmake
exampleB1.in
exampleB1.out
exampleB1.vcxproj
exampleB1.vcxproj.filters
init_vis.mac
INSTALL.vcxproj
INSTALL.vcxproj.filters
run1.mac
run2.mac
vis.mac
ZERO_CHECK.vcxproj
ZERO_CHECK.vcxproj.filters

Note the B1.sln solution file and that all the scripts for running the exampleB1 application we’re about to build have been copied across. With the solution available, we can now build by running cmake to drive MSBuild:

> cmake --build . --config Release

Solution based builds are quite verbose, but you should not see any errors at the end. In the above, we have built the B1 program in Release mode, meaning that it is optimized and has no debugging symbols. As with building Geant4 itself, this is chosen to provide optimum performance. If you require debugging information for your application, simply change the argument to RelWithDebInfo. Note that in both cases you must match the configuration of your application with that of the Geant4 install, i.e. if you are building the application in Release mode, then ensure it uses a Release build of Geant4. Link and/or runtime errors may result if mixed configurations are used.

After running the build, if we list the contents of the build directory again we see:

> dir /B
ALL_BUILD.vcxproj
ALL_BUILD.vcxproj.filters
B1.sln
B1.vcxproj
B1.vcxproj.filters
CMakeCache.txt
CMakeFiles
cmake_install.cmake
exampleB1.dir
exampleB1.in
exampleB1.out
exampleB1.vcxproj
exampleB1.vcxproj.filters
init_vis.mac
INSTALL.vcxproj
INSTALL.vcxproj.filters
Release
run1.mac
run2.mac
vis.mac
Win32
ZERO_CHECK.vcxproj
ZERO_CHECK.vcxproj.filters

> dir /B Release
exampleB1.exe
...

Here, the Release subdirectory contains the executable, and the main build directory contains all the .mac scripts for running the program. If you build in different modes, the executable for that mode will be in a directory named for that mode, e.g. RelWithDebInfo/exampleB1.exe. You can now run the application in place:

> .\Release\exampleB1.exe

*************************************************************
 Geant4 version Name: geant4-11-03 [MT]   (6-December-2024)
  << in Multi-threaded mode >>
                      Copyright : Geant4 Collaboration
                     References : NIM A 506 (2003), 250-303
                                : IEEE-TNS 53 (2006), 270-278
                                : NIM A 835 (2016), 186-225
                            WWW : http://geant4.org/
*************************************************************

<<< Reference Physics List QBBC
Visualization Manager instantiating with verbosity "warnings (3)"...
Visualization Manager initialising...
Registering graphics systems...

Note that the exact output shown will depend on how both Geant4 and your application were configured. Further output and behaviour beyond the Registering graphics systems... line will depend on what UI and Visualization drivers your Geant4 install supports.

Whilst the Visual Studio Developer Command prompt provides the simplest way to build an application, the generated Visual Studio Solution file (B1.sln in the above example) may also be opened directly in the Visual Studio IDE. This provides a more comprehensive development and debugging environment, and you should consult its documentation if you wish to use this.

One key CMake related item to note goes back to our listing of the headers for the application in the call to add_executable. Whilst CMake will naturally ignore these for configuring compilation of the application, it will add them to the Visual Studio Solution. If you do not list them, they will not be editable in the Solution in the Visual Studio IDE.

Use of Geant4Config.cmake with find_package in CMake

The Geant4Config.cmake file installed by Geant4 is designed to be used with CMake’s find_package command. CMake will search for the file using a standard set of paths used by find_package, or via the Geant4_DIR. When found, it sets several CMake variables and provides a mechanism for checking and activating optional features of Geant4 if your application requires these. The simplest possible usage of find_package and these variables to configure an application or library requiring Geant4 is:

find_package(Geant4 REQUIRED)                       # Find Geant4
add_executable(myg4app myg4app.cc)                  # Compile application
target_link_libraries(myg4app ${Geant4_LIBRARIES})  # Link it to Geant4

The Geant4_LIBRARIES variable holds the list of CMake Imported Targets for the Geant4 libraries. These set and propagate all Usage Requirements of Geant4 to the consuming target(s) (the myg4app executable in the above).

The minimal example just requires that a Geant4 install be found. A version number may be supplied to search for an install greater than or equal to the supplied version, e.g.

find_package(Geant4 11.0 REQUIRED)

makes CMake search for a Geant4 install whose version number is greater than or equal to 10.0. An exact version number may also be specified:

find_package(Geant4 11.1.0 EXACT REQUIRED)

In both cases, CMake will fail with an error if a Geant4 install meeting these version requirements is not found.

Geant4 can be installed with many optional components, and the presence of these can also be required and activated by passing extra “component” arguments. For example, to require that Geant4 is found and that it has support for gdml and Qt:

find_package(Geant4 REQUIRED gdml qt)

which will fail if the found install was not built with these options. If you want to activate components only if they exist, you can use the pattern

find_package(Geant4 REQUIRED)
find_package(Geant4 QUIET OPTIONAL_COMPONENTS qt)

which will require CMake to locate a core install of Geant4, and then check for and activate Qt support if the install provides it, continuing without error otherwise. A key thing to note here is that you can call find_package multiple times to append configuration of components. If you use this pattern and need to check if a component was found, you can use the Geant4_<COMPONENTNAME>_FOUND variables which are set after the call to find_package.

Some components are “passive” in that they just indicate support is available, others are “active” in that they indicate support for and activate use of the component in the application linking to the targets in Geant4_LIBRARIES. A partial list of the most useful components and their behaviour is given below, but for a full list, please see the listing in the installed Geant4Config.cmake file.

  • multithreaded

    Geant4_multithreaded_FOUND is TRUE if the install of Geant4 was built with multithreading support.

    Note that this is a passive option and only indicates availability of multithreading support! Multithreading in your application code requires creation and usage of the appropriate C++ objects and interfaces as described in this guide.

  • gdml

    Geant4_gdml_FOUND is TRUE if the install of Geant4 was built with GDML support.

    Note that this is a passive option, and indicates support for GDML is availble in the found install.

  • ui_all

    Activates all available UI drivers. Does not set any variables, and never causes CMake to fail. It is recommended to use this over specific UI drivers unless your application has strong requirements.

  • vis_all

    Activates all available Visualization drivers. Does not set any variables, and never causes CMake to fail. It is recommended to use this over specific Vis drivers unless your application has strong requirements.

  • ui_tcsh

    Geant4_ui_tcsh_FOUND is TRUE if the install of Geant4 provides the TCsh command line User Interface. Using this component activates and allows use of the TCsh command line interface in the linked application.

  • ui_win32

    Geant4_ui_win32_FOUND is TRUE if the install of Geant4 provides the Win32 command line User Interface. Using this component activates and allows use of the Win32 command line interface in the linked application.

  • motif

    Geant4_motif_FOUND is TRUE if the install of Geant4 provides the Motif(Xm) User Interface and Visualization driver. Using this component activates and allows use of the Motif User Interface and Visualization Driver in the linked application.

  • qt

    Geant4_qt_FOUND is TRUE if the install of Geant4 provides the Qt User Interface and Visualization driver. Using this component activates and allows use of the Qt User Interface and Visualization Driver in the linked application.

  • vis_raytracer_x11

    Geant4_vis_raytracer_x11_FOUND is TRUE if the install of Geant4 provides the X11 interface to the RayTracer Visualization driver. Using this component activates and allows use of the RayTracer X11 Visualization Driver in the linked application.

  • vis_opengl_x11

    Geant4_vis_opengl_x11_FOUND is TRUE if the install of Geant4 provides the X11 interface to the OpenGL Visualization driver. Using this component activates and allows use of the X11 OpenGL Visualization Driver in the linked application.

  • vis_opengl_win32

    Geant4_vis_opengl_win32_FOUND is TRUE if the install of Geant4 provides the Win32 interface to the OpenGL Visualization driver. Using this component activates and allows use of the Win32 OpenGL Visualization Driver in the linked application.

  • vis_openinventor

    Geant4_vis_openinventor_FOUND is TRUE if the install of Geant4 provides the OpenInventor Visualization driver. Using this component activates and allows use of the OpenInventor Visualization Driver in the linked application.

  • vis_toolssg_x11_gles

    Geant4_vis_toolssg_x11_gles_FOUND is TRUE if the install of Geant4 provides the ToolsSG visualization driver with X11 backend. Using this component allows use of the ToolsSG Visualization Driver in the linked application.

  • vis_toolssg_xt_gles

    Geant4_vis_toolssg_xt_gles_FOUND is TRUE if the install of Geant4 provides the ToolsSG visualization driver with Motif backend. Using this component allows use of the ToolsSG Visualization Driver in the linked application.

  • vis_toolssg_qt_gles

    Geant4_vis_toolssg_qt_gles_FOUND is TRUE if the install of Geant4 provides the ToolsSG visualization driver with Qt5 backend. Using this component allows use of the ToolsSG Visualization Driver in the linked application.

  • vis_toolssg_windows_gles

    Geant4_vis_toolssg_windows_gles_FOUND is TRUE if the install of Geant4 provides the ToolsSG visualization driver with Windows backend. Using this component allows use of the ToolsSG Visualization Driver in the linked application.

  • vis_Vtk

    Geant4_vis_Vtk_FOUND is TRUE if the install of Geant4 provides the Vtk visualization driver. Using this component allows use of the Vtk Visualization Driver in the linked application.