Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-57501

cmakeBuild does not set environment variables in Windows when run in Pipeline

    XMLWordPrintable

Details

    • Bug
    • Status: Closed (View Workflow)
    • Blocker
    • Resolution: Not A Defect
    • cmakebuilder-plugin
    • None
    • Jenkins ver. 2.164.3
      Cmake plugin version 2.6.1
      Jenkins slave running on windows machine as a service.

    Description

      Jenkins pipeline snippet: 

      def cmake_tasks() {
          def tasks=[:]
          def steps = [[withCmake: true]]
          def os = "windows"
          def config = "Debug"
          def generator = "Ninja"
      
      // ==== addidional env vars ====
          def vars="""
      LIB=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\ATLMFC\\LIB\\amd64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17763.0\\ucrt\\x64;C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\lib\\um\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17763.0um\\x64;
      PATH=C:\\Program Files (x86)\\MSBuild\\14.0\\binamd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319;C:\\Windows\\Microsoft.NET\\Framework64;C:\\Program Files (x86)\\Windows Kits\\10\\binx64;C:\\Program Files (x86)\\Windows Kits\\10\\binx86;C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.6.1 Tools\\x64;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\CMake\\bin;c:\\windows\\system32;C:\\
       Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.0bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.0libnvvp;g:\\Bin;
      """
      
      // another variant, also does not affect CMake
      //   vars = bat returnStdout: true, script: """
      //@call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
      //set
      //"""
      
      // third variant, also doesn't work
      //    bat """call c:\Path\to\Visual\Studio\vcvarsall.bat    
      //           set > build.props"""
      //    var = readFile("build.props")
      
           def cmakeArgs = "-DARG=VALUE"
           def cmake_inst = 'InSearchPath'
           steps.add([envVars: vars])
           cmakeArgs = cmakeArgs + " -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_MAKE_PROGRAM=g:\\Bin\\ninja"
           tasks["${os}"] = {
               node("${os}"){
                   stage("${os}/${config}") {
                       withEnv([vars]){
                           if (os == "windows"){
                               bat "set | sort"
                               println vars
                               println steps
                           }
         
                           cmakeBuild(buildDir: "build_${config}",
                                      buildType: config, 
                                      cleanBuild: true,
                                      cmakeArgs: cmakeArgs,
                                      generator: generator,
                                      installation: cmake_inst,
                                      sourceDir: ".", 
                                      steps: steps)
                      }
                  }
               }
            }
       
            return tasks
      }
       
      pipeline {
          agent none
          stages{
              stage('Configurte') {
                  steps{
                      script {
                          parallel cmake_tasks()
                      }
                  }
              }
          }
      }
       
      

       

       

      Snippet of CMakeLists.txt

      cmake_minimum_required(VERSION 3.12)
      message(STATUS "LIB value = $ENV{LIB}")
      message(STATUS "PATH value = $ENV{PATH}")
      

      Result:

      I see LIB and PATH in output of "set | sort " and both println's inside if(os == "windows") block.

      But output of cmake shows only default environment variables. LIB is unset, PATH is default

      LIB value = 
      PATH value = C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\CMake\\bin;c:\\windows\\system32;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.0bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.0\\libnvvp;g:\\Bin;
       
      

       

      Attachments

        Activity

          15knots Martin Weber added a comment -

          withEnv takes an array of multiple key-value pairs, one for each variable. Your script passes an array of a single string containing multiple key-value pairs, if I understand your script correctly. Please try with a minimal example.

          15knots Martin Weber added a comment - withEnv takes an array of multiple key-value pairs, one for each variable. Your script passes an array of a single string containing multiple key-value pairs, if I understand your script correctly. Please try with a minimal example.
          wl2776 Vladimir Eremeev added a comment - - edited

          Yes, indeed. Changing argument of withEnv to 

           

          vars = ["INCLUDE=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE; ..... ",
                  "LIB=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64; ...",
                  "LIBPATH=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;....",
                  "PATH=C:\\Program Files (x86)\\MSBuild\\14.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;...",
                   // etc
          ]

          does the trick.

          Tried adding the same to the "steps" argument of cmakeBuild:

          def steps = [[
              withCmake: true, 
              envVars: ["INCLUDE=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE; ..... ",
           "LIB=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64; ...",
           "LIBPATH=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;....",
           "PATH=C:\\Program Files (x86)\\MSBuild\\14.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;...",
           // etc
          ] ]]
          

          got error:

          "java.lang.ClassCastException: class hudson.plugins.cmake.BuildToolStep.setEnvVars() expects class java.lang.String but received class java.util.ArrayList"
          

           

          I see following issues.

          1. Manual of withEnv is not clear (I understand that this is not related to current issue)

          2. Processing of envVars by cmakeBuild is not consistent with one, done by "withEnv" (Though, I understand that different authors could have different ideas about user interface. But consistency is good).

          3. Description of envVars is misleading. I've come from Python, and sentence "key-value pairs" suggests that this argument should be a dictionary (or a map), not a string. It is not said, how these pairs must be separated, if they are wrapped in a string.

          4. Both documentation pieces, for withEnv and for envVars, miss examples on how to set multiple variables, they only show how to set a single variable, a very rare case, IMHO.

           

           

          wl2776 Vladimir Eremeev added a comment - - edited Yes, indeed. Changing argument of withEnv to    vars = [ "INCLUDE=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE; ..... " , "LIB=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64; ..." , "LIBPATH=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;...." , "PATH=C:\\Program Files (x86)\\MSBuild\\14.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;..." , // etc ] does the trick. Tried adding the same to the "steps" argument of cmakeBuild: def steps = [[ withCmake: true , envVars: [ "INCLUDE=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\INCLUDE; ..... " , "LIB=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64; ..." , "LIBPATH=C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;...." , "PATH=C:\\Program Files (x86)\\MSBuild\\14.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;..." , // etc ] ]] got error: "java.lang.ClassCastException: class hudson.plugins.cmake.BuildToolStep.setEnvVars() expects class java.lang. String but received class java.util.ArrayList"   I see following issues. 1. Manual of withEnv is not clear (I understand that this is not related to current issue) 2. Processing of envVars by cmakeBuild is not consistent with one, done by "withEnv" (Though, I understand that different authors could have different ideas about user interface. But consistency is good). 3. Description of envVars is misleading. I've come from Python, and sentence "key-value pairs" suggests that this argument should be a dictionary (or a map), not a string. It is not said, how these pairs must be separated, if they are wrapped in a string. 4. Both documentation pieces, for withEnv and for envVars, miss examples on how to set multiple variables, they only show how to set a single variable, a very rare case, IMHO.    
          15knots Martin Weber added a comment -
          "java.lang.ClassCastException: class hudson.plugins.cmake.BuildToolStep.setEnvVars() expects class java.lang.String but received class java.util.ArrayList"
          

          You get this, because BuildToolStep.setEnvVars() takes a String, not an array. You may specify more than one envvar, if you separate them by newlines (as stated in the online help). This is the same behavior as in the freestyle project version of the plugin.
          Anyway, you do not need to pass envvars to BuildToolStep to configure cmake. These varaibles are passed to the build tool (make or nija). The main purpose is to run

          make install

          with the DESTDIR variable set to a directory below workspace root in order to ease archiving of artifacts.

          4. Both documentation pieces, for withEnv and for envVars, miss examples on how to set multiple variables, they only show how to set a single variable, a very rare case, IMHO.

          The online help for Build tool | Env. Variables has an example that shows how to set multiple variables.

          15knots Martin Weber added a comment - "java.lang.ClassCastException: class hudson.plugins.cmake.BuildToolStep.setEnvVars() expects class java.lang.String but received class java.util.ArrayList" You get this, because BuildToolStep.setEnvVars() takes a String, not an array. You may specify more than one envvar, if you separate them by newlines (as stated in the online help). This is the same behavior as in the freestyle project version of the plugin. Anyway, you do not need to pass envvars to BuildToolStep to configure cmake . These varaibles are passed to the build tool (make or nija). The main purpose is to run make install with the DESTDIR variable set to a directory below workspace root in order to ease archiving of artifacts. 4. Both documentation pieces, for withEnv and for envVars, miss examples on how to set multiple variables, they only show how to set a single variable, a very rare case, IMHO. The online help for Build tool | Env. Variables has an example that shows how to set multiple variables.
          wl2776 Vladimir Eremeev added a comment - - edited

          Anyway, you do not need to pass envvars to BuildToolStep to configure cmake. These varaibles are passed to the build tool (make or nija).

          Now I see why my attempts failed. It seems, the only way to pass environment variables to cmake is using withEnv.

          The online help for Build tool | Env. Variableshas an example that shows how to set multiple variables.

          Sorry, I cannot figure out where it is, and how I should use it in a pipeline script.

          Here is what I've entered in pipeline snippet generator: 

          And here is the generated code:

          cmakeBuild buildDir: '${build_dir}', buildType: '${config}', cleanBuild: true, generator: 'Ninja', installation: 'InSearchPath', sourceDir: '${env.WORKSPACE}', steps: [[envVars: '''A=B
          C=D''', withCmake: true]]
          

          Code sample in the issue description does exactly this. It generates a string in the form "NAME=VALUE<newline>NAME=VALUE"), and CMake does not see these variables.

           

          I've found two links: https://javadoc.jenkins.io/plugin/cmakebuilder/index.html?hudson/plugins/cmake/BuildToolStep.html and https://javadoc.jenkins.io/plugin/cmakebuilder/hudson/plugins/cmake/BuildToolStep.html

          They don't contain examples either.

          I've also studied sources on GitHub but failed to find how `BuildToolStep` processes `this.vars`, set in `setEnvVars`.

          wl2776 Vladimir Eremeev added a comment - - edited Anyway, you do not need to pass envvars to BuildToolStep to configure  cmake . These varaibles are passed to the  build tool  (make or nija). Now I see why my attempts failed. It seems, the only way to pass environment variables to cmake is using withEnv. The online help for  Build tool | Env. Variables has  an example that shows how to set multiple variables. Sorry, I cannot figure out where it is, and how I should use it in a pipeline script. Here is what I've entered in pipeline snippet generator:  And here is the generated code: cmakeBuild buildDir: '${build_dir}' , buildType: '${config}' , cleanBuild: true , generator: 'Ninja' , installation: 'InSearchPath' , sourceDir: '${env.WORKSPACE}' , steps: [[envVars: '''A=B C=D''', withCmake: true ]] Code sample in the issue description does exactly this. It generates a string in the form "NAME=VALUE<newline>NAME=VALUE"), and CMake does not see these variables.   I've found two links: https://javadoc.jenkins.io/plugin/cmakebuilder/index.html?hudson/plugins/cmake/BuildToolStep.html  and https://javadoc.jenkins.io/plugin/cmakebuilder/hudson/plugins/cmake/BuildToolStep.html They don't contain examples either. I've also studied sources on GitHub but failed to find how `BuildToolStep` processes `this.vars`, set in `setEnvVars`.

          After careful studying of this discussion, as well as a web-page of snippet generator, it became clear for me that envVars, passed to cmakeBuild, has nothing to do with my issue.

          And the issue itself is invalid, since I've incorrectly passed arguments to withEnv.

          Thanks for the help.

          wl2776 Vladimir Eremeev added a comment - After careful studying of this discussion, as well as a web-page of snippet generator, it became clear for me that envVars, passed to cmakeBuild, has nothing to do with my issue. And the issue itself is invalid, since I've incorrectly passed arguments to withEnv. Thanks for the help.

          People

            15knots Martin Weber
            wl2776 Vladimir Eremeev
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: