Development Environment for Multiple Viewers

From Second Life Wiki
Jump to navigation Jump to search

Development Environment for Multiple Viewers

Highlights:

  • Productivity increase (automation of repetitive tasks)
  • Complete directory structure proposal
  • Directory Dependent History and Environment Switching
  • Support for development of multiple viewers on one host
  • quilt
  • ctags

Directory structure

The ROOT

Choose a directory that will contains everything related to SecondLife, OpenSim etc. In my case this directory contains (currently) 12 GB of data, so pick a place with space ;).

For the sake of copying and pasting commands, lets use an environment variable for this 'root' directory.

export ROOT=/usr/src/secondlife

I use /usr/src/secondlife, but you could of course use something else, like /opt/secondlife, or $HOME/SLroot or whatever.

$ROOT/viewers

The root directory will contain a subdirectory viewers.

mkdir $ROOT/viewers

viewers will contain any data related to viewer development (viewer build system configuration, patches, viewer source trees, viewer subprocesses (ie SLVoice), User Application Directories (AppDir), documentation...) while $ROOT itself will contain everything else (things that are less close to developing the viewers, like special/patched/custom libraries, custom scripts, uploaded assets (textures, sounds, animations), snapshots, third party projects related to SecondLife etc etc).

Purely as a suggestion, you could do

mkdir $ROOT/blender $ROOT/gimp $ROOT/libomv $ROOT/textures $ROOT/wav $ROOT/Snapshots

Viewer project base

Each viewer (version) needs it's own directory, not just for the source tree, but also for meta data (patches, quilt cache, build system configuration, etc). The below deals with a single viewer version, but you can repeat it for multiple viewers. For the sake of easy copy and pasting, lets give our first viewer version an environment variable too. For example,

export VIEWERNAME=snowglobe-1.x-svn

Then, for each such viewer create the following directories:

cd $ROOT/viewers
mkdir $VIEWERNAME
cd $VIEWERNAME
mkdir timestamps
mkdir quilt
mkdir quilt/patches
mkdir quilt/pc

The real source tree (the one containing the indra directory) should be called 'linden' and also goes here. For example,

svn checkout https://svn.secondlife.com/svn/linden/projects/2009/snowglobe/trunk linden

Directory dependent history and environment

Now to automate everything! First install cdeh.

Also set DEFAULTPATH in your .bashrc. For example,

export DEFAULTPATH="$HOME/bin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin"  # Or whatever your current PATH is!
export PATH="$DEFAULTPATH"

Obvious, DEFAULTPATH may not depend on PATH.

If you intended to use cdeh also for library projects (ie, libraries in $ROOT) and you have multiple compilers installed (ie, you use a special compiler version for the viewer) then you also should set DEFAULT_TOPPROJECT in your .bashrc. Set it to $ROOT/viewers, but expand $ROOT (type it out fully) because obviously ROOT is not set at the moment you log in.

Here it might be wise to reboot, so that every login shell has DEFAULTPATH set; or otherwise make sure to source .bashrc to set it until you have time to reboot. The effect of not having it set is getting an empty PATH so that you will have to type full paths to execute anything :p

Next install this file in the root (/) of your operating system, world readable, and rename it to /env.source. Yes, that is the real root, not $ROOT.

Congratulations! You now have directory dependend history and environment switching! Lets start with creating a separate history file for most of the core directories:

cd $ROOT
addhistory
cd viewers
addhistory
cd $VIEWERNAME
addhistory
cd linden
addhistory

As you can see I just love to have a different command history for every directory :)

Next we have to add a few environments. Copy and paste the following code blocks.

cd $ROOT/viewers
cat << EOF > env.compiler
CC="gcc"
CXX="ccache g++"

export CC CXX
EOF
echo "export TOPPROJECT=$ROOT" > env.viewers
cat << EOF >> env.viewers
source /env.source
source $TOPPROJECT/env.compiler

INSTALL_PREFIX="/sl"

LDFLAGS+=" -L$INSTALL_PREFIX/lib -L$INSTALL_PREFIX/usr/lib"

PKG_CONFIG_PATH="$INSTALL_PREFIX/lib/pkgconfig"
pre_path "$INSTALL_PREFIX/bin"
pre_path "$INSTALL_PREFIX/lib" LD_LIBRARY_PATH

export PKG_CONFIG_PATH LD_LIBRARY_PATH

# Use libcwd
#CXXFLAGS+=" $(pkg-config --cflags libcwd_r)"
#LDFLAGS+=" $(pkg-config --libs libcwd_r | sed -e 's/ *$//')"

# Use custom libllqtwebkit
#CXXFLAGS+=" -I/usr/src/secondlife/llqtwebkit/install/include"
#LDFLAGS+=" -L/usr/src/secondlife/llqtwebkit/install/lib"

# Use the patched (CVS) version of gstreamer installed in /sl:
#LDFLAGS+=" -L/sl/lib"
#CFLAGS+="-g3 -I/sl/include/gstreamer-0.10"
#CXXFLAGS+=" -g3 -I/sl/include/gstreamer-0.10"
#export GTS_PLUGIN_PATH="/sl/lib"

REPOBASE="$PROJECTBASE/linden"
INDRA="$REPOBASE/indra"

alias vi='vim -c "set tags=$INDRA/$BUILDDIR/tags" -c "set tabstop=4"'
alias s='/bin/ls $INDRA/ll*/*.{cpp,h} $INDRA/linux_crash_logger/*.{cpp,h} $INDRA/lscript/*/*.{cpp,h} $INDRA/newview/*.{cpp,h} $INDRA/media_plugins/*/*.{cpp,h}'
alias grep='grep -Hn'
alias configure='make configure'

QUILT_PATCHES="$PROJECTBASE/quilt/patches"
QUILT_PATCHES_PREFIX=1
QUILT_DIFF_OPTS="-p"
CCACHE_DIR=/ramdisk/ccache

export QUILT_PATCHES QUILT_PATCHES_PREFIX QUILT_DIFF_OPTS CCACHE_DIR

function make ()
{
  CURDIR=$(pwd)
  cd $INDRA
  case $@ in
  configure)
    rm -f $BUILDDIR/CMakeCache.txt
    ./develop.py $CONFIGURE_OPTS configure $CMAKE_DEFS -DCMAKE_CXX_FLAGS:STRING="$CXXFLAGS" -DCMAKE_EXE_LINKER_FLAGS:STRING="$LDFLAGS"
    cd $BUILDDIR/newview && (\
    ln -sf ../llplugin/slplugin/SLPlugin; \
    mkdir -p llplugin; \
    ln -sf ../../media_plugins/webkit/libmedia_plugin_webkit.so llplugin/libmedia_plugin_webkit.so; \
    ln -sf ../../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so llplugin/libmedia_plugin_gstreamer.so; \
    ln -sf $INDRA/newview/app_settings; \
    ln -sf $INDRA/newview/skins; \
    ln -sf $INDRA/newview/character; \
    ln -sf $INDRA/newview/res-sdl; \
    ln -sf $INDRA/newview/gpu_table.txt; \
    ln -sf $INDRA/newview/featuretable_linux.txt; \
    ln -sf $INDRA/newview/linux_tools/register_secondlifeprotocol.sh; \
    ln -sf $INDRA/newview/linux_tools/launch_url.sh; \
    ln -sf $INDRA/newview/linux_tools/handle_secondlifeprotocol.sh; \
    ln -sf $INDRA/newview/secondlife-i686.supp; \
    ln -sf $INDRA/newview/res/snowglobe_icon.png; \
    ln -sf $REPOBASE/../../gdbinit .gdbinit; \
    ln -sf $TOPPROJECT/SLVoice; \
    cd app_settings; \
    ln -sf $REPOBASE/scripts/messages/message_template.msg; \
    ln -sf $REPOBASE/etc/message.xml; \
    cd ../skins/default/xui/en-us; \
    ln -sf mime_types_linux.xml mime_types.xml; )
    ;;
  "")
    ./develop.py $CONFIGURE_OPTS build
    ;;
  clean|realclean)
    rm -rf $BUILDDIR/*
    #./develop.py $CONFIGURE_OPTS clean
    ;;
  ctags|tags)
    ctags -f $BUILDDIR/tags `s`
    ;;
  *)
    echo "Don't know how to make $@"
    ;;
  esac
  cd $CURDIR
}

function store_timestamps ()
{
  CURDIR=$(pwd);
  cd $REPOBASE;
  for f in `find . -name '*.h' -o -name '*.cpp' -o -name '*.cc' -o -name CMakeLists.txt -o -name '*.cmake'`; do
    mkdir -p `dirname $PROJECTBASE/timestamps/$f`;
    md5sum $f > $PROJECTBASE/timestamps/$f;
    touch -r $f $PROJECTBASE/timestamps/$f;
  done
  cd $CURDIR;
}

function restore_timestamps ()
{
  CURDIR=$(pwd);
  cd $REPOBASE;
  for f in `find . -name '*.h' -o -name '*.cpp' -o -name '*.cc' -o -name CMakeLists.txt -o -name '*.cmake'`; do
    if test "`cat $PROJECTBASE/timestamps/$f`" = "`md5sum $f`"; then
      touch -r $PROJECTBASE/timestamps/$f $f;
    fi
  done
  cd $CURDIR;
}

function quilt ()
{
  case $@ in
  refresh)
    /usr/bin/quilt refresh -p0
    ;;
  *)
    /usr/bin/quilt "$@";
    ;;
  esac
}

function svn ()
{
  case $@ in
  update)
    if /usr/bin/quilt top; then
      echo "Storing timestamps..."
      store_timestamps;
      echo "Merging update..."
      /usr/bin/quilt diff -p0 -z > current.$$.diff && \
          patch -p0 -R < current.$$.diff && \
          TOP=`/usr/bin/quilt top` && \
          /usr/bin/quilt pop -aR && \
          /usr/bin/svn update && \
          /usr/bin/quilt push "$TOP" && \
          patch -p0 < current.$$.diff && \
          rm current.$$.diff;
      echo "Restoring timestamps..."
      restore_timestamps;
    else
      /usr/bin/svn update
    fi
    ;;
  diff)
    if /usr/bin/quilt top 2>/dev/null; then
      /usr/bin/quilt diff -p0 -z;
      echo "Patch relative from 'tag' \"$(basename `/usr/bin/quilt top`)\"."
    else
      /usr/bin/svn diff;
    fi
    ;;
  commit)
    echo "You're not supposed to do a commit in here!"
    ;;
  *)
    /usr/bin/svn "$@";
    ;;
  esac
}
cat << EOF > gdbinit
file ./secondlife-bin
set print static-members off

# Examples:
# Make gdb find the right libraries.
#set env LD_LIBRARY_PATH /usr/src/secondlife/openjpeg-tools/openjpeg-1.3+dfsg:/sl/lib:/sl/usr/lib:/usr/local/lib:/usr/src/secondlife/viewers/snowglobe/snowglobe-1.x-svn/linden/indra/viewer-linux-x86_64-debug/llcommon

# Make it login to a different grid
#set args -loginuri="http://osgrid.org:8002" -loginpage "http://osgrid.org/loginscreen.php" -helperuri "http://osgrid.org/"

# Make gdb find the sources of libraries under test.
#dir /usr/src/secondlife/openjpeg-tools/openjpeg-1.3+dfsg:/usr/src/libc6/eglibc-2.9/nptl:/usr/src/secondlife/viewers/pthread_debug:/usr/src/debian/apr-1.3.5:/usr/src/debian/openal-soft-1.8.466

# Load gstreamer plugins from our prefix
#set env GTS_PLUGIN_PATH /sl/lib

# Do some hackerish threading debugging with preloaded libraries.
#set env LD_PRELOAD /usr/src/secondlife/viewers/pthread_debug/libpthread_debug.so /usr/lib/libapr-1.so.0 /sl/lib/libcwd_r.so/lib/libdl.so.2

# Run gdb on the monitor of a remote PC (ssh-ed into hikaru, where the viewer is installed and running).
#set env DISPLAY hikaru:0.0

# Etc etc. Set all environment variables needed for testing.
#set env __GL_YIELD NOTHING
#set env LIBCWD_NO_STARTUP_MSGS 1