-
-
Notifications
You must be signed in to change notification settings - Fork 320
InstallTargets
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:
#!python
prefix = "/usr/local"
someshlib = env.SharedLibrary('foo', "foo.c")
someprogram = env.Program("fooprog", "fooprog.c")
# the install target
env.Alias("install", env.Install(os.path.join(prefix, "lib"), someshlib))
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:
#!python
Alias('install-lib', Install(os.path.join(prefix, "lib"), ...))
Alias('install-bin', Install(os.path.join(prefix, "bin"), ...))
Alias('install', ['install-bin', 'install-lib'])
Question: how to set permissions properly (binaries get 755, headers get 644, etc.) after an install?
- One way to do it is to create a method that acts like Install() but has an additional permission argument. Wrappers with predefined permissions are useful for cleaner markup:
#!python
import SCons
# define the custom function
from SCons.Script.SConscript import SConsEnvironment
SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
def InstallPerm(env, dest, files, perm):
obj = env.Install(dest, files)
for i in obj:
env.AddPostAction(i, env.Chmod(str(i), perm))
return dest
# put this function "in" scons
SConsEnvironment.InstallPerm = InstallPerm
# great, we're ready to use it!
env.InstallPerm(bindir, ['fooprog', 'barprog'], 0755)
# but let's say we're not happy yet, we'd prefer nicer names.
SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
# great, now you can also install by calling a method named 'InstallHeader' or 'InstallProgram'!
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:
#!python
try:
umask = os.umask(022)
print 'setting umask to 022 (was 0%o)' % umask
except OSError: # ignore on systems that don't support umask
pass
- Another similar method to install data with correct permissions is to use a Command :
#!python
source="./data/icon.png"
target="/usr/local/share/X/icon.png"
env.Alias("install", target)
env.Command( target, source,
[
Copy("$TARGET","$SOURCE"),
Chmod("$TARGET", 0664),
])
where target and source could be set in a directory parsing loop for conveniance :
#!python
# where you need to implement 'RecursiveGlob' yourself
for file in RecursiveGlob("./data", "*"):
# strip 'data/' out to have the filepath relative to data dir
index = file.find("data/") + len("data/")
filename_relative = file[index:]
source = os.path.join("./data", filename_relative)
target = os.path.join(data_dir, filename_relative)
env.Alias("install", target)
env.Command( target, source,
[
Copy("$TARGET","$SOURCE"),
Chmod("$TARGET", 0664),
])
For best results, also make sure the umask is set like described above.
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.
#!python
# install .mo files
locale_dir = "/usr/local/share/locale"
mo_files = Glob("./po/*/app_name.mo",strings=True)
for mo in mo_files:
# extract language code
index_lo = mo.find("po/") + len("po/")
index_hi = mo.find("/app_name.mo")
lang_name = mo[index_lo:index_hi]
# copy file
install_location = locale_dir + "/" + lang_name + "/LC_MESSAGES/app_name.mo"
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.
Here's a sample uninstall function :
#!python
def create_uninstall_target(env, path, is_glob):
if is_glob:
all_files = Glob(path,strings=True)
for filei in all_files:
env.Command( "uninstall-"+filei, filei,
[
Delete("$SOURCE"),
])
env.Alias("uninstall", "uninstall-"+filei)
else:
env.Command( "uninstall-"+path, path,
[
Delete("$SOURCE"),
])
env.Alias("uninstall", "uninstall-"+path)
You can use it like this :
#!python
if 'uninstall' in COMMAND_LINE_TARGETS:
# create uninstall targets
create_uninstall_target(env, "/usr/local/bin/myapp", False)
create_uninstall_target(env, "/usr/local/share/myapp/", False)
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:
#!python
env.Command("uninstall", None, Delete(FindInstalledFiles()))