Use kwinject or kwwrap with CMake

If you use CMake to manage your build process, the most common and recommended approach is to generate the build pipeline and execute the build while running kwinject.

The following example shows how to use kwinject with CMake:

  1. Generate the build pipeline:

    mkdir build
    cd build
    cmake -G 'Unix Makefiles' ../my_proj/
  2. Run the build tool under kwinject:

    kwinject -o my_proj.out make

If something is preventing kwinject from working (for instance, a security software or if you run distributed builds), you can use kwwrap with CMake in the following ways. However, only resort to these methods when the preferred kwinject strategy does not work.

Use kwwrap with CMAKE_<LANG>_COMPILER_LAUNCHER and CMAKE_<LANG>_LINKER_LAUNCHER variables

You can enable kwwrap without modifying the build script(s) by using the CMAKE_<LANG>_COMPILER_LAUNCHER and CMAKE_<LANG>_LINKER_LAUNCHER variables. The following prerequisites apply:

  • You are using CMake version 3.21 or later

  • The build tool is either make or ninja

To use kwwrap with CMAKE_<LANG>_COMPILER_LAUNCHER and CMAKE_<LANG>_LINKER_LAUNCHER:

  1. Create a script to run kwwrap. This example uses bash on Linux.

    #!/bin/bash
    set -e
    "$KWW" -o "$KWO" "$@"
    exit $?

    Both kwwrap and the output file name are passed via environment variables, which isn't strictly necessary but makes it a easier to change things.

  2. Run another script to set the relevant environment variables, then run CMake as usual.

    Note that CMake will change directories when building, so the paths to both the output file and runner.sh must be absolute:

    #!/bin/bash
    set -e
    export KWW=/path/to/kw/bin/kwwrap
    export KWO=/absolute/path/to/tracefile.out
    
    wrapcmd="/absolute/path/to/runner.sh"
    
    export CMAKE_C_COMPILER_LAUNCHER=$wrapcmd
    export CMAKE_CXX_COMPILER_LAUNCHER=$wrapcmd
    export CMAKE_C_LINKER_LAUNCHER=$wrapcmd
    export CMAKE_CXX_LINKER_LAUNCHER=$wrapcmd
    
    cmake -G 'Unix Makefiles' path/to/my/sources/       # Insert your normal build command here
    rm "$KWO"   # cmake itself creates a junk trace file
    
    make

    After running the script, there will be a trace file at $KWO that can be fed to kwinject to generate your build specification file.

Use kwwrap by modifying CMakeLists.txt

Another approach is to modify your CMakeLists.txt file to generate a build trace file to be fed to kwinject. However, how and if this works depends on the vagaries of your CMakeFile.txt and related files.

Since you are modifying global variables, this method can introduce problems in the build process. We suggest defining the variables as late as possible in the build script.

The following example shows how to use kwwrap by modifying CMakeLists.txt; you may need to tweak it to your specific use case.

set(KWWRAP_PATH "<path to Klocwork install directory>/bin/kwwrap")   # Specify kwwrap full path
set(KWWRAP_TRACE_PATH "${PROJECT_BINARY_DIR}/kw.trace")              # Specify path to Klocwork trace file
set(KWWRAP_TARGET "${KWWRAP_PATH} -o ${KWWRAP_TRACE_PATH}")
 
set(CMAKE_C_COMPILE_OBJECT "${KWWRAP_TARGET} ${CMAKE_C_COMPILE_OBJECT}")
set(CMAKE_C_LINK_EXECUTABLE "${KWWRAP_TARGET} ${CMAKE_C_LINK_EXECUTABLE}")
set(CMAKE_C_CREATE_SHARED_LIBRARY "${KWWRAP_TARGET} ${CMAKE_C_CREATE_SHARED_LIBRARY}")
set(CMAKE_C_CREATE_SHARED_MODULE "${KWWRAP_TARGET} ${CMAKE_C_CREATE_SHARED_MODULE}")
set(CMAKE_C_CREATE_STATIC_LIBRARY "${KWWRAP_TARGET} ${CMAKE_C_CREATE_STATIC_LIBRARY}")
 
set(CMAKE_CXX_COMPILE_OBJECT "${KWWRAP_TARGET} ${CMAKE_CXX_COMPILE_OBJECT}")
set(CMAKE_CXX_LINK_EXECUTABLE "${KWWRAP_TARGET} ${CMAKE_CXX_LINK_EXECUTABLE}")
set(CMAKE_CXX_CREATE_SHARED_LIBRARY "${KWWRAP_TARGET} ${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
set(CMAKE_CXX_CREATE_SHARED_MODULE "${KWWRAP_TARGET} ${CMAKE_CXX_CREATE_SHARED_MODULE}")
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "${KWWRAP_TARGET} ${CMAKE_CXX_CREATE_STATIC_LIBRARY}")