How to capture CMake command line arguments?

前端 未结 3 1684
礼貌的吻别
礼貌的吻别 2020-12-06 01:46

I want to record the arguments passed to cmake in my generated scripts. E.g., \"my-config.in\" will be processed by cmake, it has definition like this:

<
相关标签:
3条回答
  • 2020-12-06 01:54

    I don't know of any variable which provides this information, but you can generate it yourself (with a few provisos).

    Any -D arguments passed to CMake are added to the cache file CMakeCache.txt in the build directory and are reapplied during subsequent invocations without having to be specified on the command line again.

    So in your example, if you first execute CMake as

    cmake ../.. -DCMAKE_INSTALL_PREFIX:PATH=/usr
    

    then you will find that subsequently running simply

    cmake .
    

    will still have CMAKE_INSTALL_PREFIX set to /usr


    If what you're looking for from CMAKE_ARGS is the full list of variables defined on the command line from every invocation of CMake then the following should do the trick:

    get_cmake_property(CACHE_VARS CACHE_VARIABLES)
    foreach(CACHE_VAR ${CACHE_VARS})
      get_property(CACHE_VAR_HELPSTRING CACHE ${CACHE_VAR} PROPERTY HELPSTRING)
      if(CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line.")
        get_property(CACHE_VAR_TYPE CACHE ${CACHE_VAR} PROPERTY TYPE)
        if(CACHE_VAR_TYPE STREQUAL "UNINITIALIZED")
          set(CACHE_VAR_TYPE)
        else()
          set(CACHE_VAR_TYPE :${CACHE_VAR_TYPE})
        endif()
        set(CMAKE_ARGS "${CMAKE_ARGS} -D${CACHE_VAR}${CACHE_VAR_TYPE}=\"${${CACHE_VAR}}\"")
      endif()
    endforeach()
    message("CMAKE_ARGS: ${CMAKE_ARGS}")
    

    This is a bit fragile as it depends on the fact that each variable which has been set via the command line has the phrase "No help, variable specified on the command line." specified as its HELPSTRING property. If CMake changes this default HELPSTRING, you'd have to update the if statement accordingly.


    If this isn't what you want CMAKE_ARGS to show, but instead only the arguments from the current execution, then I don't think there's a way to do that short of hacking CMake's source code! However, I expect this isn't what you want since all the previous command line arguments are effectively re-applied every time.

    0 讨论(0)
  • 2020-12-06 02:06

    A very Linux specific way of achieving the same objective:

    if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
        file(STRINGS /proc/self/status _cmake_process_status)
    
        # Grab the PID of the parent process
        string(REGEX MATCH "PPid:[ \t]*([0-9]*)" _ ${_cmake_process_status})
    
        # Grab the absolute path of the parent process
        file(READ_SYMLINK /proc/${CMAKE_MATCH_1}/exe _cmake_parent_process_path)
    
        # Compute CMake arguments only if CMake was not invoked by the native build
        # system, to avoid dropping user specified options on re-triggers.
        if(NOT ${_cmake_parent_process_path} STREQUAL ${CMAKE_MAKE_PROGRAM})
            execute_process(COMMAND bash -c "tr '\\0' ' ' < /proc/$PPID/cmdline"
                            OUTPUT_VARIABLE _cmake_args)
    
            string(STRIP "${_cmake_args}" _cmake_args)
    
            set(CMAKE_ARGS "${_cmake_args}"
                CACHE STRING "CMake command line args (set by end user)" FORCE)
        endif()
        message(STATUS "User Specified CMake Arguments: ${CMAKE_ARGS}")
    endif()
    
    0 讨论(0)
  • 2020-12-06 02:07

    One way to store CMake command line arguments, is to have a wrapper script called ~/bin/cmake (***1) , which does 2 things:

    • create ./cmake_call.sh that stores the command line arguments
    • call the real cmake executable with the command line arguments

    ~/bin/cmake # code is shown below

    #!/usr/bin/env bash
    
    #
    # Place this file into this location: ~/bin/cmake
    # (with executable rights)
    #
    # This is a wrapper for cmake!
    # * It calls cmake -- see last line of the script
    # It also:
    # * Creates a file cmake_call.sh in the current directory (build-directory)
    #   which stores the cmake-call with all it's cmake-flags etc.
    #   (It also stores successive calls to cmake, so that you have a trace of all your cmake calls)
    #
    # You can simply reinvoke the last cmake commandline with: ./cmake_call.sh  !!!!!!!!!!
    #
    # cmake_call.sh is not created
    #   when cmake is called without any flags,
    #   or when it is called with flags such as --help, -E, -P, etc. (refer to NON_STORE_ARGUMENTS -- you might need to modify it to suit your needs)
    
    SCRIPT_PATH=$(readlink -f "$BASH_SOURCE")
    SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
    
    #http://stackoverflow.com/a/13864829
    if [ -z ${SUDO_USER+x} ]; then
        # var SUDO_USER is unset
        user=$USER
    else
        user=$SUDO_USER
    fi
    
    
    #http://stackoverflow.com/a/34621068
    path_append ()  { path_remove $1 $2; export $1="${!1}:$2"; }
    path_prepend()  { path_remove $1 $2; export $1="$2:${!1}"; }
    path_remove ()  { export $1="`echo -n ${!1} | awk -v RS=: -v ORS=: '$1 != "'$2'"' | sed 's/:$//'`"; }
    
    path_remove PATH ~/bin # when calling cmake (at the bottom of this script), do not invoke this script again!
    
    
    
    
    # when called with no arguments, don't create cmake_call.sh
    if [[ -z "$@" ]]; then
       cmake "$@"
       exit
    fi
    
    
    # variable NON_STORE_ARGUMENTS stores flags which, if any are present, cause cmake_call.sh to NOT be created
    read -r -d '' NON_STORE_ARGUMENTS <<'EOF'
    -E
    --build
    #-N
    -P
    --graphviz
    --system-information
    --debug-trycompile
    #--debug-output
    --help
    -help
    -usage
    -h
    -H
    --version
    -version
    /V
    --help-full
    --help-manual
    --help-manual-list
    --help-command
    --help-command-list
    --help-commands
    --help-module
    --help-module-list
    --help-modules
    --help-policy
    --help-policy-list
    --help-policies
    --help-property
    --help-property-list
    --help-properties
    --help-variable
    --help-variable-list
    --help-variables
    EOF
    
    NON_STORE_ARGUMENTS=$(echo "$NON_STORE_ARGUMENTS" | head -c -1 `# remove last newline` | sed "s/^/^/g" `#begin every line with ^` | tr '\n' '|')
    
    #echo "$NON_STORE_ARGUMENTS" ## for debug purposes
    
    ## store all the args
    ARGS_STR=
    for arg in "$@"; do
        if cat <<< "$arg" | grep -E -- "$NON_STORE_ARGUMENTS" &> /dev/null; then  # don't use   echo "$arg"  ....
                                                                                  # since echo "-E"    does not do what you want here,
                                                                                  # but   cat <<< "-E" does what you want (print minus E)
            # do not create cmake_call.sh
            cmake "$@"
            exit
        fi
    
        # concatenate to ARGS_STR
        ARGS_STR="${ARGS_STR}$(echo -n " \"$arg\"" | sed "s,\($(pwd)\)\(\([/ \t,:;'\"].*\)\?\)$,\$(pwd)\2,g")"
        #                                             replace $(pwd) followed by
        #                                                                  /             or
        #                                                                   whitespace   or
        #                                                                      ,         or
        #                                                                       :        or
        #                                                                        ;       or
        #                                                                         '      or
        #                                                                           "
        #                                                                    or nothing
        #                                             with \$(pwd)
    done
    
    
    
    
    
    
    
    
    
    if [[ ! -e $(pwd)/cmake_call.sh ]]; then
    echo    "#!/usr/bin/env bash" >  $(pwd)/cmake_call.sh
    
    # escaping:
    # note in the HEREDOC below, \\ means \ in the output!!
    #                            \$ means $ in the output!!
    #                            \` means ` in the output!!
    cat <<EOF                     >>  $(pwd)/cmake_call.sh
    
    
    #http://stackoverflow.com/a/34621068
    path_remove ()  { export \$1="\`echo -n \${!1} | awk -v RS=: -v ORS=: '\$1 != "'\$2'"' | sed 's/:\$//'\`"; }
    
    path_remove PATH ~/bin # when calling cmake (at the bottom of this script), do not invoke ~/bin/cmake but real cmake!
    
    
    EOF
    else
        # remove bottom 2 lines from cmake_call.sh
        sed -i '$ d' $(pwd)/cmake_call.sh
        sed -i '$ d' $(pwd)/cmake_call.sh
    fi
    
    
    echo "ARGS='${ARGS_STR}'" >> $(pwd)/cmake_call.sh
    echo "echo cmake \"\$ARGS\""  >> $(pwd)/cmake_call.sh
    echo "eval cmake \"\$ARGS\""  >> $(pwd)/cmake_call.sh
    #echo "eval which cmake"       >> $(pwd)/cmake_call.sh
    
    chmod +x     $(pwd)/cmake_call.sh
    chown $user: $(pwd)/cmake_call.sh
    
    cmake "$@"
    

    Usage:

    mkdir build
    cd    build
    cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$(pwd)/install ..
    

    This will create cmake_call.sh with the following content:

    #!/usr/bin/env bash
    
    
    #http://stackoverflow.com/a/34621068
    path_remove ()  { export $1="`echo -n ${!1} | awk -v RS=: -v ORS=: '$1 != "'$2'"' | sed 's/:$//'`"; }
    
    path_remove PATH ~/bin # when calling cmake (at the bottom of this script), do not invoke ~/bin/cmake but real cmake!
    
    
    ARGS=' "-DCMAKE_BUILD_TYPE=Debug" "-DCMAKE_INSTALL_PREFIX=$(pwd)/install" ".."'
    echo cmake "$ARGS"
    eval cmake "$ARGS"
    

    The 3rd last line stores the cmake arguments. You can now reinvoke the exact command-line that you used by simply calling:

    ./cmake_call.sh
    

    Footnotes:

    (***1) ~/bin/cmake is usually in the PATH because of ~/.profile. When creating ~/bin/cmake the very 1st time, it might be necessary to log out and back in, so that .profile sees ~/bin.

    0 讨论(0)
提交回复
热议问题