[CMake] execute a script before and after configuration

Michael Hertling mhertling at online.de
Wed Jan 25 21:53:25 EST 2012


On 01/21/2012 11:28 AM, Dominik Szczerba wrote:
> On Sat, Jan 21, 2012 at 10:50 AM, Dominik Szczerba <dominik at itis.ethz.ch> wrote:
>>>>> You might use an EXECUTE_PROCESS() command at the beginning of your
>>>>> CMakeLists.txt to unload the modules, and another EXECUTE_PROCESS()
>>>>> at the end to reload them.
>>
>> Will try, thanks for the hint!
> 
> Unfortunately, it does not work. Unloading the module via a call to a
> bash script only unloads it for this script's process - the test run
> is not affected. Instead of calling the script I tried sourcing it
> (like 'source script', so the whole current session is affected) but
> this in turn seems to somehow silently do nothing, it does not even
> seem to be called.
> 
> Still dead end, any more ideas? It would be nice to have a general
> elegant solution for cases where user is not allowed to directly run
> their programs on the current node. Similar scenario will arise for
> executing tests - currently make test fails because the tests are
> built for the scheduler so will not run locally.
> 
> Regards,
> Dominik

If I understand correctly - ATM, I've no access to a Cray machine, so
I can't investigate immediately  - the modules are unloaded/reloaded
for the current process and its children only, but not for the CMake
process where it is actually needed, right? If so, and provided you
can figure out how to unload/reload the modules by C program code,
you might use the hardly deployed LOAD_COMMAND(), look here:

# CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(MODULES C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
ADD_LIBRARY(UnloadModules MODULE EXCLUDE_FROM_ALL UnloadModules.c)
SET_TARGET_PROPERTIES(UnloadModules PROPERTIES
    OUTPUT_NAME cmUnloadModules)
FIND_LIBRARY(UNLOAD_MODULES_LIBRARY cmUnloadModules ${CMAKE_BINARY_DIR})
ADD_LIBRARY(ReloadModules MODULE EXCLUDE_FROM_ALL ReloadModules.c)
SET_TARGET_PROPERTIES(ReloadModules PROPERTIES
    OUTPUT_NAME cmReloadModules)
FIND_LIBRARY(RELOAD_MODULES_LIBRARY cmReloadModules ${CMAKE_BINARY_DIR})
ADD_CUSTOM_TARGET(ModulesLoading)
ADD_DEPENDENCIES(ModulesLoading UnloadModules ReloadModules)
IF(UNLOAD_MODULES_LIBRARY AND RELOAD_MODULES_LIBRARY)
    LOAD_COMMAND(UnloadModules ${CMAKE_BINARY_DIR})
    MESSAGE("UnloadModules: ${CMAKE_LOADED_COMMAND_UnloadModules}")
    UNLOAD_MODULES()
    EXECUTE_PROCESS(
        COMMAND sh -c "echo \"CMake process: \$(pidof cmake)\"")
ENDIF()
# Do usual stuff here.
IF(UNLOAD_MODULES_LIBRARY AND RELOAD_MODULES_LIBRARY)
    LOAD_COMMAND(ReloadModules ${CMAKE_BINARY_DIR})
    MESSAGE("ReloadModules: ${CMAKE_LOADED_COMMAND_ReloadModules}")
    RELOAD_MODULES()
    EXECUTE_PROCESS(
        COMMAND sh -c "echo \"CMake process: \$(pidof cmake)\"")
ENDIF()

/* UnloadModules.c: */
#include <cmCPluginAPI.h>
#include <unistd.h>
#include <stdio.h>

void UnloadModulesInit(cmLoadedCommandInfo *);
static int initialpass(void *, void *, int, char *[]);

void UnloadModulesInit(cmLoadedCommandInfo *info)
{
        info->Name = "UNLOAD_MODULES";
        info->InitialPass = initialpass;
}

static int initialpass(void *i, void *f, int argc, char *argv[])
{
    printf("Unloading modules for process: %d\n",getpid());
    return !0;
}

/* ReloadModules.c: */
#include <cmCPluginAPI.h>
#include <unistd.h>
#include <stdio.h>

void ReloadModulesInit(cmLoadedCommandInfo *);
static int initialpass(void *, void *, int, char *[]);

void ReloadModulesInit(cmLoadedCommandInfo *info)
{
        info->Name = "RELOAD_MODULES";
        info->InitialPass = initialpass;
}

static int initialpass(void *i, void *f, int argc, char *argv[])
{
    printf("Reloading modules for process: %d\n",getpid());
    return !0;
}

The cmCPluginAPI.h header is the one from the CMake code base.

The basic idea is that the new commands are executed in the context of
the CMake process and, thus, can influence the latter, and this is not
true for commands spawned by EXECUTE_PROCESS(). As long as the {Un,Re}
loadModules targets aren't built, everything works as usual, but after
"make ModulesLoading", a reconfiguration invokes the UNLOAD_MODULES()
and RELOAD_MODULES() commands which exemplarily shows the PID of the
CMake process. Therefore, if you manage to unload/reload the modules
via the two initialpass() functions, this might be a practicable way.
Refer to [1] for more information about such LOAD_COMMAND() plugins.

Alternatively, if it's possible to unload/reload the modules for an
arbitrary process, e.g. by "module -p <PID> un/load XXXX", you might
use the above-noted example's means to find out the PID of the CMake
process and use it with EXECUTE_PROCESS().

A final remark: If I use the following executable "CMake" script

#!/bin/sh
if [ "$1" != "-E" ]; then
    echo "Unloading modules"
    cmake -DCMAKE_COMMAND="$0" "$@"
    echo "Reloading modules"
else
    cmake "$@"
fi

for the initial configuration, I can see the "{Un,Re}loading modules"
messages appearing around each further automatic reconfiguration, e.g.
after touching CMakeLists.txt and rebuilding. Thus, Eike's suggestion
of setting the CMAKE_COMMAND variable and using a wrapper script is
possibly not that bad?

Regards,

Michael

[1] http://www.cmake.org/Wiki/CMake/C_Plugins_for_Loadable_Commands


More information about the CMake mailing list