Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Setting environment variable

Madhubalan_R_
Beginner
2,816 Views

Hi All I am facing issue in setting environment variable in the linux platform using a fortran code.I have tried with SETENVQQ and export command inside the SYSTEM function and EXECUTE_COMMAND_LINE function.Please help me to solve this issue. Thanks.

0 Kudos
5 Replies
Kevin_D_Intel
Employee
2,816 Views

I assume the interest is in altering an environment variable in the underlying shell under which the Fortran program is running. If so then SYSTEM and EXECUTE_COMMAND_LINE would not be applicable as those affect a separate instance of a shell spawned for the former, and the local context of spawned processes for the latter.

If you can share your source code with us for the SETENVQQ method then we would be able to help get that working for you.

Here is a quick (and not so pretty) example borrowing example code from the Fortran User's Guide from SETENVQQ, GET_ENVIRONMENT_VARIABLE, and .EXECUTE_COMMAND_LINE.

program env_example
implicit none

  call my_setenvqq
  call my_execute_command_line

end program env_example

subroutine my_setenvqq
USE IFPORT
implicit none
character name*20
logical(4) success

  success = SETENVQQ("PATH=c:\mydir\tmp")
  name='PATH'
  call my_getenv(name)

end subroutine  my_setenvqq

subroutine my_execute_command_line
implicit none
integer :: CSTAT, ESTAT
character(100) :: CMSG
character name*20

  call EXECUTE_COMMAND_LINE ("export LIB=/mydir2/tmp;echo ' LIB is: '$LIB", &
                           & EXITSTAT=ESTAT, CMDSTAT=CSTAT, CMDMSG=CMSG)

  if (CSTAT > 0) then
    print *, "Command execution failed with error ", TRIM(CMSG)
  else if (CSTAT < 0) then
    print *, "Command execution not supported"
  else
    print *, "Command completed with status ", ESTAT
  end if

  name='LIB'
  call my_getenv(name)

end subroutine my_execute_command_line

subroutine my_getenv(name)
implicit none
character name*20, val*40
integer len, status

  call get_environment_variable (name, val, len, status, .true.)

  if (status .ge. 2) then
     write (*,*) 'get_environment_variable failed: status = ', status
     stop
  end if

  if (status .eq. 1) then
     write (*,*) 'env var does not exist'
     stop
  end if

  if (status .eq. -1) then
     write (*,*) 'env var length = ', len, ' truncated to 40'
     len = 40
  end if

  if (len .eq. 0) then
     write (*,*) 'env var exists  but has no value'
     stop
  end if

  write (*,*) 'env var value = ', val (1:len)

end subroutine my_getenv
$ ifort -V
Intel(R) Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.0.109 Build 20150815
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

$ ifort u594761.f90  ;  ./a.out
 env var value = c:\mydir\tmp
 LIB is: /mydir2/tmp
 Command completed with status            0
 env var does not exist

 

0 Kudos
rudi-gaelzer
New Contributor I
2,816 Views

If you want to stick to the standard and avoid using extensions that are dependent on the compiler, you could employ C bindings to call a C function that sets the environment variable.

Take a look at the sample codes:

#include <stdlib.h>

void set_ev()
{
   setenv("MY_ENV_VAR", "Hey, what's up!",1);
}

------------------------------------------------------------------------------------------------------

program tes_set_ev
use, intrinsic :: iso_c_binding
implicit none
character(len= 50) :: sys_ev
INTERFACE
   subroutine set_ev() bind(c)
   end subroutine set_ev
END INTERFACE
!
call get_environment_variable('MY_ENV_VAR', sys_ev)
print*, 'Before calling c void: ->|'//trim(sys_ev)//'|<-'
call set_ev()
call get_environment_variable('MY_ENV_VAR', sys_ev)
print*, 'After calling c void: ->|'//trim(sys_ev)//'|<-'
end program tes_set_ev

-------------------------------------------------------------------------------------------------------------------

This is the compilation lines and the output:

$>gcc -c set_ev.c
$>ifort tes_set_ev.f90 set_ev.o -o tes_set_ev
$>./tes_set_ev
 Before calling c void: ->||<-
 After calling c void: ->|Hey, what's up!|<-

 

0 Kudos
JVanB
Valued Contributor II
2,816 Views

Why not

INTERFACE
   function setenv(name,value,overwrite) bind(C,name='setenv')
      use ISO_C_BINDING
      implicit none
      integer(C_INT) setenv
      character(KIND=C_CHAR), intent(in) :: name(*)
      character(KIND=C_CHAR), intent(in) :: value(*)
      integer(C_INT), value :: overwrite
   end function setenv
END INTERFACE

and then invoke setenv() directly?

 

0 Kudos
Bálint_A_
Beginner
2,816 Views

Repeat Offender wrote:

Why not

INTERFACE
   function setenv(name,value,overwrite) bind(C,name='setenv')
      use ISO_C_BINDING
      implicit none
      integer(C_INT) setenv
      character(KIND=C_CHAR), intent(in) :: name(*)
      character(KIND=C_CHAR), intent(in) :: value(*)
      integer(C_INT), value :: overwrite
   end function setenv
END INTERFACE

and then invoke setenv() directly?

I guess, you would have to make sure then, that you pass a proper '\0' terminated string, when calling from Fortran, otherwise C would have problem to detect, where the string ends.

0 Kudos
JVanB
Valued Contributor II
2,816 Views

Yep. Instead of passing "MY_ENV_VAR", one would pass 'MY_ENV_VAR'//C_NULL_CHAR or 'MY_ENV_VAR'//ACHAR(0). Normal stuff encountered when doing C interoperability. This is more commonplace in Windows where users seem to invoke Win32 API functions on more of a routine basis.

 

0 Kudos
Reply