Skip to content

Commit

Permalink
reworked environment generation again
Browse files Browse the repository at this point in the history
  • Loading branch information
dirk-thomas committed Aug 25, 2012
1 parent d885e33 commit 2b5f1dc
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 64 deletions.
30 changes: 23 additions & 7 deletions cmake/catkin_generate_environment.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@ function(catkin_generate_environment)
# buildspace
set(SETUP_DIR ${catkin_BUILD_PREFIX})
set(CURRENT_WORKSPACE ${catkin_BUILD_PREFIX}:${CMAKE_SOURCE_DIR})
# copy setup.py
file(COPY ${catkin_EXTRAS_DIR}/templates/setup.py
DESTINATION ${catkin_BUILD_PREFIX})

if(NOT MSVC)
# non-windows
# generate env
configure_file(${catkin_EXTRAS_DIR}/templates/env.sh.in
${catkin_BUILD_PREFIX}/env.sh)
${catkin_BUILD_PREFIX}/env.sh
@ONLY)
# generate setup for various shells
em_expand(${catkin_EXTRAS_DIR}/templates/setup.context.py.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.buildspace.context.py
${catkin_EXTRAS_DIR}/em/setup.sh.em
${catkin_BUILD_PREFIX}/setup.sh)
foreach(shell bash zsh)
configure_file(${catkin_EXTRAS_DIR}/templates/setup.${shell}.in
${catkin_BUILD_PREFIX}/setup.${shell})
${catkin_BUILD_PREFIX}/setup.${shell}
@ONLY)
endforeach()

else()
# windows
# generate env
configure_file(${catkin_EXTRAS_DIR}/templates/env.bat.in
${catkin_BUILD_PREFIX}/env.bat)
${catkin_BUILD_PREFIX}/env.bat
@ONLY)
# generate setup
em_expand(${catkin_EXTRAS_DIR}/templates/setup.context.py.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.buildspace.context.py
Expand All @@ -34,11 +41,17 @@ function(catkin_generate_environment)
# installspace
set(SETUP_DIR ${CMAKE_INSTALL_PREFIX})
set(CURRENT_WORKSPACE ${CMAKE_INSTALL_PREFIX})
# install setup.py
install(PROGRAMS
${catkin_EXTRAS_DIR}/templates/setup.py
DESTINATION ${CMAKE_INSTALL_PREFIX})

if(NOT MSVC)
# non-windows
# generate and install env
configure_file(${catkin_EXTRAS_DIR}/templates/env.sh.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.sh)
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.sh
@ONLY)
install(PROGRAMS
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.sh
DESTINATION ${CMAKE_INSTALL_PREFIX})
Expand All @@ -52,7 +65,8 @@ function(catkin_generate_environment)
DESTINATION ${CMAKE_INSTALL_PREFIX})
foreach(shell bash zsh)
configure_file(${catkin_EXTRAS_DIR}/templates/setup.${shell}.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/setup.${shell})
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/setup.${shell}
@ONLY)
install(FILES
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/setup.${shell}
DESTINATION ${CMAKE_INSTALL_PREFIX})
Expand All @@ -62,7 +76,8 @@ function(catkin_generate_environment)
# windows
# generate and install env
configure_file(${catkin_EXTRAS_DIR}/templates/env.bat.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.bat)
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.bat
@ONLY)
install(PROGRAMS
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/env.bat
DESTINATION ${CMAKE_INSTALL_PREFIX})
Expand All @@ -79,7 +94,8 @@ function(catkin_generate_environment)
# XXX what is .rosinstall needed for?
#if(catkin_SOURCE_DIR)
# configure_file(${catkin_EXTRAS_DIR}/templates/rosinstall.installable.in
# ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/.rosinstall)
# ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/.rosinstall
# @ONLY)
# install(FILES
# ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/installspace/.rosinstall
# DESTINATION ${CMAKE_INSTALL_PREFIX})
Expand Down
159 changes: 102 additions & 57 deletions cmake/em/setup.sh.em
Original file line number Diff line number Diff line change
@@ -1,80 +1,125 @@
#!/bin/sh
# generated from catkin/cmake/em/setup.sh.em
# CURRENT_WORKSPACE="@CURRENT_WORKSPACE"
# CATKIN_WORKSPACES="@CATKIN_WORKSPACES"

# absolute path to the folder containing this script
DIRNAME=@SETUP_DIR
# remember type of shell if not already set
if [ -z "$CATKIN_SHELL" ] ; then
CATKIN_SHELL=sh
CATKIN_SHELL=sh
fi

# source setup.SHELL from parent workspace (if any)
@{
import os
parent_path = None
if 'CATKIN_WORKSPACES' in os.environ and os.environ['CATKIN_WORKSPACES'] != '':
parent_path = os.environ['CATKIN_WORKSPACES'].split(';')[0].split(':')[0]
print('. %s/setup.$CATKIN_SHELL' % parent_path)
}@
# called without arguments: create a clean environment, resetting all already set variables
# - removes all prepended items from environment variables (based on current CATKIN_WORKSPACES)
# - sets CATKIN_WORKSPACES to current + list of parents
# - calls setup from all parent workspaces with "--recursive" argument
# - prepends current to all variables
# - sources current environment hooks
# called with "--recursive": used in recursive call from other setup
# - does not touch CATKIN_WORKSPACES
# - prepends current to all variables
# - sources current environment hooks
# called with "--extend": used to extend one environment with a second one
# - prepends current + list of parent to existing CATKIN_WORKSPACES
# - calls setup from all parent workspaces with "--recursive" argument
# - prepends current to all variables
# - sources current environment hooks

# python function to prepend a value to an environment variable if it not already included (outputs the prefix if it needs to be prepended)
PYTHON_CODE_PREPENDING_TO_ENV=$(cat <<EOF
from __future__ import print_function
import os
import sys
if len(sys.argv) != 4:
print("\nWrong number of arguments passed to Python code\n", file=sys.stderr)
exit(1)
prepended_item, separator, env_name = sys.argv[1:]
items = os.environ[env_name].split(separator) if env_name in os.environ and os.environ[env_name] != '' else []
print(prepended_item + (separator if items else '') if prepended_item not in items else '')
EOF
)
# bin folder of workspace prepended to PATH
PATH_dir=/bin
# lib/pythonX.Y/..-packages folder of workspace prepended to PYTHONPATH
# the path suffix is calculated in catkin/cmake/python.cmake
PYTHONPATH_dir=/@PYTHON_INSTALL_DIR
# include folder of workspace prepended to CPATH
CPATH_dir=/include
# lib folder of workspace prepended to (DY)LD_LIBRARY_PATH
LD_LIBRARY_PATH_dir=/lib
# folder of workspace prepended to CMAKE_PREFIX_PATH
CMAKE_PREFIX_PATH_dir=""
# lib/pkgconfig folder of workspace prepended to PKG_CONFIG_PATH
PKG_CONFIG_PATH_dir=/lib/pkgconfig

# prepend current workspace to CATKIN_WORKSPACES
CATKIN_WORKSPACES_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "@CURRENT_WORKSPACE" ";" "CATKIN_WORKSPACES"`
export CATKIN_WORKSPACES="${CATKIN_WORKSPACES_PREFIX}${CATKIN_WORKSPACES}"
# decide which mode is requested
RECURSIVE_MODE=0
EXTEND_MODE=0
NORMAL_MODE=0
if [ "$_CATKIN_SETUP_RECURSION" = "1" ]; then
RECURSIVE_MODE=1
elif [ $# -eq 1 -a "$1" = "--extend" ]; then
EXTEND_MODE=1
else
NORMAL_MODE=1
fi

# define base dir for further variables (based on current workspace)
BASE_DIR="@(CURRENT_WORKSPACE.split(':')[0])"
# detect if running on Darwin platform
UNAME=`which uname`
UNAME=`$UNAME`
IS_DARWIN=0
if [ "$UNAME" = "Darwin" ]; then
IS_DARWIN=1
fi

# prepend bin folder of workspace to PATH
PATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/bin" ":" "PATH"`
export PATH="${PATH_PREFIX}${PATH}"
# reset environment variables by unrolling modifications based on CATKIN_WORKSPACES (when called without arguments)
if [ $NORMAL_MODE -eq 1 ]; then
export PATH=$($DIRNAME/setup.py --remove --name PATH --value "$PATH_dir")
export PYTHONPATH=$($DIRNAME/setup.py --remove --name PYTHONPATH --value "$PYTHONPATH_dir")
export CPATH=$($DIRNAME/setup.py --remove --name CPATH --value "$CPATH_dir")
if [ $IS_DARWIN -eq 0 ]; then
export LD_LIBRARY_PATH=$($DIRNAME/setup.py --remove --name LD_LIBRARY_PATH --value "$LD_LIBRARY_PATH_dir")
else
export DYLD_LIBRARY_PATHPATH=$($DIRNAME/setup.py --remove --name DYLD_LIBRARY_PATH --value "$LD_LIBRARY_PATH_dir")
fi
export CMAKE_PREFIX_PATH=$($DIRNAME/setup.py --remove --name CMAKE_PREFIX_PATH --value "$CMAKE_PREFIX_PATH_dir")
export PKG_CONFIG_PATH=$($DIRNAME/setup.py --remove --name PKG_CONFIG_PATH --value "$PKG_CONFIG_PATH_dir")
fi

# prepend lib/pythonX.Y/..-packages folder of workspace to PYTHONPATH
# the path suffix is calculated in catkin/cmake/python.cmake
PYTHONPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/@PYTHON_INSTALL_DIR" ":" "PYTHONPATH"`
export PYTHONPATH="${PYTHONPATH_PREFIX}${PYTHONPATH}"
# set CATKIN_WORKSPACES (when called without arguments)
if [ $NORMAL_MODE -eq 1 ]; then
export CATKIN_WORKSPACES=`$DIRNAME/setup.py --set-workspaces --value "@CURRENT_WORKSPACE;@CATKIN_WORKSPACES"`
fi

# prepend include folder of workspace to CPATH
#CPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/include" ":" "CPATH"`
#export CPATH="${CPATH_PREFIX}${CPATH}"
# prepend current and parent workspaces to CATKIN_WORKSPACES (when called with argument --extend)
if [ $EXTEND_MODE -eq 1 ]; then
export CATKIN_WORKSPACES=`$DIRNAME/setup.py --prefix-workspaces --value "@CURRENT_WORKSPACE;@CATKIN_WORKSPACES"`$CATKIN_WORKSPACES
fi

# prepend lib folder of workspace to (DY)LD_LIBRARY_PATH
UNAME=`which uname`
if [ `$UNAME` = Darwin ]; then
DYLD_LIBRARYPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/lib" ":" "DYLD_LIBRARY_PATH"`
export DYLD_LIBRARY_PATH="${DYLD_LIBRARYPATH_PREFIX}${DYLD_LIBRARY_PATH}"
else
LD_LIBRARYPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/lib" ":" "LD_LIBRARY_PATH"`
export LD_LIBRARY_PATH="${LD_LIBRARYPATH_PREFIX}${LD_LIBRARY_PATH}"
# source setup.SHELL from parent workspaces (if any) (when called without --recursive argument)
@[if CATKIN_WORKSPACES]@
if [ $RECURSIVE_MODE -eq 0 ]; then
_CATKIN_SETUP_RECURSION=1
for workspace in @(' '.join(['"%s"' % ws.split(':')[0] for ws in reversed(CATKIN_WORKSPACES.split(';'))]))
do
. $workspace/setup.$CATKIN_SHELL --recursive
done
_CATKIN_SETUP_RECURSION=0
fi
@[end if]@

# prepend folder of workspace (cmake-subfolder for build-space) to CMAKE_PREFIX_PATH
CMAKE_PREFIXPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR" ":" "CMAKE_PREFIX_PATH"`
export CMAKE_PREFIX_PATH="${CMAKE_PREFIXPATH_PREFIX}${CMAKE_PREFIX_PATH}"
# define base dir of workspace (based on CURRENT_WORKSPACE) (after sourcing the parents)
BASE_DIR="@(CURRENT_WORKSPACE.split(':')[0])"

# prepend lib/pkgconfig folder of workspace to PKG_CONFIG_PATH
PKG_CONFIGPATH_PREFIX=`python -c "$PYTHON_CODE_PREPENDING_TO_ENV" "$BASE_DIR/lib/pkgconfig" ":" "PKG_CONFIG_PATH"`
export PKG_CONFIG_PATH="${PKG_CONFIGPATH_PREFIX}${PKG_CONFIG_PATH}"
# prepend folders of workspace to environment variables
export PATH=$($DIRNAME/setup.py --prefix --name PATH --value $BASE_DIR$PATH_dir)$PATH
export PYTHONPATH=$($DIRNAME/setup.py --prefix --name PYTHONPATH --value $BASE_DIR$PYTHONPATH_dir)$PYTHONPATH
export CPATH=$($DIRNAME/setup.py --prefix --name CPATH --value $BASE_DIR$CPATH_dir)$CPATH
if [ $IS_DARWIN -eq 0 ]; then
export LD_LIBRARY_PATH=$($DIRNAME/setup.py --prefix --name LD_LIBRARY_PATH --value $BASE_DIR$LD_LIBRARY_PATH_dir)$LD_LIBRARY_PATH
else
export DYLD_LIBRARY_PATH=$($DIRNAME/setup.py --prefix --name DYLD_LIBRARY_PATH --value $BASE_DIR$LD_LIBRARY_PATH_dir)$DYLD_LIBRARY_PATH
fi
export CMAKE_PREFIX_PATH=$($DIRNAME/setup.py --prefix --name CMAKE_PREFIX_PATH --value $BASE_DIR$CMAKE_PREFIX_PATH_dir)$CMAKE_PREFIX_PATH
export PKG_CONFIG_PATH=$($DIRNAME/setup.py --prefix --name PKG_CONFIG_PATH --value $BASE_DIR$PKG_CONFIG_PATH_dir)$PKG_CONFIG_PATH

# run all environment hooks of workspace
# run all environment hooks of this workspace
FIND=`which find`
for envfile in `$FIND "$BASE_DIR/etc/catkin/profile.d" -maxdepth 1 -name "*.sh" 2>/dev/null`
do
. $envfile
. $envfile
done
if [ "$CATKIN_SHELL" != "sh" ]; then
for envfile in `$FIND "$BASE_DIR/etc/catkin/profile.d" -maxdepth 1 -name "*.$CATKIN_SHELL" 2>/dev/null`
do
. $envfile
done
for envfile in `$FIND "$BASE_DIR/etc/catkin/profile.d" -maxdepth 1 -name "*.$CATKIN_SHELL" 2>/dev/null`
do
. $envfile
done
fi
2 changes: 2 additions & 0 deletions cmake/templates/setup.context.py.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
CATKIN_WORKSPACES="@CATKIN_WORKSPACES@"
CURRENT_WORKSPACE="@CURRENT_WORKSPACE@"
PYTHON_EXECUTABLE="@PYTHON_EXECUTABLE@"
PYTHON_INSTALL_DIR="@PYTHON_INSTALL_DIR@"
SETUP_DIR="@SETUP_DIR@"
85 changes: 85 additions & 0 deletions cmake/templates/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python

from __future__ import print_function
import argparse
import os
import sys


def set_workspaces(value):
'''Return the value for the environment variable CATKIN_WORKSPACES without empty or duplicate items.'''
values = [v for v in value.split(';') if v != '']
unique = []
for v in values:
if v not in unique:
unique.append(v)
return ';'.join(unique)


def prefix_workspaces(value):
'''Return the prefix to prepend VALUE to the environment variable CATKIN_WORKSPACES without empty or duplicate items.'''
name = 'CATKIN_WORKSPACES'
items = os.environ[name].split(';') if name in os.environ and os.environ[name] != '' else []
values = [v for v in value.split(';') if v != '']
for v in reversed(values):
if v not in items:
items.insert(0, v)
return ';'.join(items)


def prefix_env(name, value):
'''Return the prefix to prepend VALUE to the environment variable NAME.'''
if os.environ.get(name, '') == '':
return value
return '%s:' % value


def remove_from_env(name, value):
'''Remove the first item whose value is VALUE from env[NAME] and return the updated value of the environment variable.'''
items = os.environ[name].split(':') if name in os.environ and os.environ[name] != '' else []
env_name = 'CATKIN_WORKSPACES'
workspaces = [ws.split(':')[0] for ws in os.environ[env_name].split(';')] if env_name in os.environ and os.environ[env_name] != '' else []
for workspace in workspaces:
try:
items.remove(workspace + value)
except ValueError:
pass
return ':'.join(items)


def _parse_arguments():
parser = argparse.ArgumentParser(description='Generates code blocks for the setup.SHELL script.')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--set-workspaces', action='store_true', help='Set current and parent workspaces in environment')
group.add_argument('--prefix-workspaces', action='store_true', help='Prefix current and parent workspaces to environment')
group.add_argument('--prefix', action='store_true', help='Prepend a unique value to an environment variable')
group.add_argument('--remove', action='store_true', help='Remove a value from an environment variable')
parser.add_argument('--name', nargs='?', help='The name of the environment variable')
parser.add_argument('--value', help='The value')
args = parser.parse_args()

# verify correct argument combination
if (args.prefix or args.remove) and args.name is None:
raise RuntimeError('Argument "--name" must be passed for "%s"' % ('--prefix' if args.prefix else '--remove'))
if (args.set_workspaces or args.prefix_workspaces) and args.name is not None:
raise RuntimeError('Argument "--name" must not be passed for "%s"' % ('--set-workspaces' if args.set_workspaces else '--prefix-workspaces'))

return args


if __name__ == "__main__":
try:
args = _parse_arguments()
except Exception as e:
print(e, file=sys.stderr)
exit(1)

# dispatch to requested operation
if args.set_workspaces:
print(set_workspaces(args.value))
elif args.prefix_workspaces:
print(prefix_workspaces(args.value))
elif args.prefix:
print(prefix_env(args.name, args.value))
elif args.remove:
print(remove_from_env(args.name, args.value))

0 comments on commit 2b5f1dc

Please sign in to comment.