Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.

It's often useful to be able to run "scons install" to copy the programs and shared libraries to their correct locations. Here's one way to do that:

   1 prefix = "/usr/local"
   2 
   3 someshlib = env.SharedLibrary('foo', "foo.c")
   4 someprogram = env.Program("fooprog", "fooprog.c")
   5 
   6 # the install target
   7 env.Alias("install", env.Install(os.path.join(prefix, "lib"), someshlib))
   8 env.Alias("install", env.Install(os.path.join(prefix, "bin"), someprogram))

Basically we alias 'install' to a couple of Install nodes, returned by the Install() method. That's all.

NB: There is no need to add something like 'Depends(install, someshlib)', since SCons does find this dependency automatically.

If you need some fine-grained install targets, you may use something like this:

   1 Alias('install-lib', Install(os.path.join(prefix, "lib"), ...))
   2 Alias('install-bin', Install(os.path.join(prefix, "bin"), ...))
   3 Alias('install', ['install-bin', 'install-lib'])

Permissions

Question: how to set permissions properly (binaries get 755, headers get 644, etc.) after an install?

   1 import SCons
   2 
   3 # define the custom function
   4 from SCons.Script.SConscript import SConsEnvironment
   5 SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
   6         lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
   7 
   8 def InstallPerm(env, dest, files, perm):
   9     obj = env.Install(dest, files)
  10     for i in obj:
  11         env.AddPostAction(i, env.Chmod(str(i), perm))
  12     return dest
  13 
  14 # put this function "in" scons
  15 SConsEnvironment.InstallPerm = InstallPerm
  16 
  17 # great, we're ready to use it!
  18 env.InstallPerm(bindir, ['fooprog', 'barprog'], 0755)
  19 
  20 # but let's say we're not happy yet, we'd prefer nicer names.
  21 SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
  22 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
  23 
  24 # great, now you can also install by calling a method named 'InstallHeader' or 'InstallProgram'!
  25 env.InstallHeader(incdir, ['foo.h', 'bar.h'])

Don't forget to set the umask, or created directories might get wrong permissions on Unix and Windows:

   1 try:
   2     umask = os.umask(022)
   3     print 'setting umask to 022 (was 0%o)' % umask
   4 except OSError:     # ignore on systems that don't support umask
   5     pass

   1 source="./data/icon.png"
   2 target="/usr/local/share/X/icon.png"
   3 
   4 env.Alias("install", target)
   5 env.Command( target, source,
   6 [
   7 Copy("$TARGET","$SOURCE"),
   8 Chmod("$TARGET", 0664),
   9 ])

where target and source could be set in a directory parsing loop for conveniance :

   1 # where you need to implement 'RecursiveGlob' yourself 
   2 for file in RecursiveGlob("./data", "*"):
   3     # strip 'data/' out to have the filepath relative to data dir
   4     index = file.find("data/") + len("data/")
   5     filename_relative = file[index:]
   6     source = os.path.join("./data", filename_relative)
   7     target = os.path.join(data_dir, filename_relative)
   8             
   9     env.Alias("install", target)
  10     env.Command( target, source,
  11     [
  12     Copy("$TARGET","$SOURCE"),
  13     Chmod("$TARGET", 0664),
  14     ])

For best results, also make sure the umask is set like described above.

Locale files

Installing locale files on UNIX systems can be a little tricky :

This is an example that will handle installing .mo files for a source layout of /po/[language code]/app_name.mo.

   1 # install .mo files
   2 locale_dir = "/usr/local/share/locale"
   3 
   4 mo_files = Glob("./po/*/app_name.mo",strings=True)
   5 for mo in mo_files:
   6     # extract language code
   7     index_lo = mo.find("po/") + len("po/")
   8     index_hi = mo.find("/app_name.mo")
   9     lang_name = mo[index_lo:index_hi]
  10     # copy file
  11     install_location = locale_dir + "/" + lang_name + "/LC_MESSAGES/app_name.mo"
  12     env.Alias("install", env.InstallAs( install_location, mo ) )

It should be simple enough to adapt this code to layouts like /po/[language code].mo or any other.

Uninstall targets

Here's a sample uninstall function :

   1 def create_uninstall_target(env, path, is_glob):
   2     if is_glob:
   3         all_files = Glob(path,strings=True)
   4         for filei in all_files:
   5             env.Command( "uninstall-"+filei, filei,
   6             [
   7             Delete("$SOURCE"),
   8             ])
   9             env.Alias("uninstall", "uninstall-"+filei)   
  10     else:
  11         env.Command( "uninstall-"+path, path,
  12         [
  13         Delete("$SOURCE"),
  14         ])
  15         env.Alias("uninstall", "uninstall-"+path)  

You can use it like this :

   1 if 'uninstall' in COMMAND_LINE_TARGETS:
   2     # create uninstall targets
   3     create_uninstall_target(env, "/usr/local/bin/myapp", False)
   4     create_uninstall_target(env, "/usr/local/share/myapp/", False)
   5     create_uninstall_target(env, "/usr/local/share/locale/*/LC_MESSAGES/myapp.mo", True)

If you want to uninstall all the files installed using Install or InstallAs, there is a more expeditive way:

   1 env.Command("uninstall", None, Delete(FindInstalledFiles()))

InstallTargets (last edited 2010-10-30 19:47:24 by david.garcia)