summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGary Oberbrunner <garyo@oberbrunner.com>2011-03-02 01:53:21 (GMT)
committerGary Oberbrunner <garyo@oberbrunner.com>2011-03-02 01:53:21 (GMT)
commitb25e8d31d6d60f73780309ff9a00cb1b23a58f73 (patch)
tree3075c0d3885023d45b802e3787d437537ac6f50e
parent8a1ad1c1942246536c33c11adf2eeb4b6ac68638 (diff)
downloadSCons-b25e8d31d6d60f73780309ff9a00cb1b23a58f73.zip
SCons-b25e8d31d6d60f73780309ff9a00cb1b23a58f73.tar.gz
SCons-b25e8d31d6d60f73780309ff9a00cb1b23a58f73.tar.bz2
Support automatically embedding manifests in EXEs and DLLs on Windows.
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/RELEASE.txt4
-rw-r--r--src/engine/SCons/Tool/mslink.py66
-rw-r--r--src/engine/SCons/Tool/mslink.xml37
-rw-r--r--test/MSVC/embed-manifest.py88
5 files changed, 192 insertions, 7 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 2aa48b3..8bb1bb7 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -7,6 +7,10 @@
RELEASE 2.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
+ From Gary Oberbrunner and Sohail Somani:
+ - new construction variable WINDOWS_EMBED_MANIFEST to automatically
+ embed manifests in Windows EXEs and DLLs.
+
From Gary Oberbrunner:
- Adding None to an Action no longer fails (just returns original action)
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 306403d..f8db734 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -31,6 +31,9 @@
NEW FUNCTIONALITY
+ - SCons can now automatically embed manifests in Windows executables
+ and DLLs, by setting WINDOWS_EMBED_MANIFEST in the environment.
+
- SCons now searches for site_scons dirs in several system-wide
and per-user locations, in addition to the SConstruct top dir.
This should enable much easier use of third-party (non-core)
@@ -120,6 +123,7 @@
Rob Managan,
Gary Oberbrunner,
Evgeny Podjachev,
+ Sohail Somani,
Anatoly Techtonik,
Allen Weeks,
Russel Winder,
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index e0eec8c..07af49e 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -116,8 +116,9 @@ def _dllEmitter(target, source, env, paramtp):
"WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"))
version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
- if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0):
- # MSVC 8 automatically generates .manifest files that must be installed
+ if version_num >= 8.0 and \
+ (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)):
+ # MSVC 8 and above automatically generate .manifest files that must be installed
extratargets.append(
env.ReplaceIxes(dll,
'%sPREFIX' % paramtp, '%sSUFFIX' % paramtp,
@@ -164,8 +165,9 @@ def prog_emitter(target, source, env):
raise SCons.Errors.UserError("An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX"))
version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
- if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0):
- # MSVC 8 automatically generates .manifest files that have to be installed
+ if version_num >= 8.0 and \
+ (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)):
+ # MSVC 8 and above automatically generate .manifest files that have to be installed
extratargets.append(
env.ReplaceIxes(exe,
"PROGPREFIX", "PROGSUFFIX",
@@ -188,12 +190,50 @@ def RegServerFunc(target, source, env):
return ret
return 0
+# These are the actual actions run to embed the manifest.
+# They are only called from the Check versions below.
+embedManifestExeAction = SCons.Action.Action('$MTEXECOM')
+embedManifestDllAction = SCons.Action.Action('$MTSHLIBCOM')
+
+def embedManifestDllCheck(target, source, env):
+ """Function run by embedManifestDllCheckAction to check for existence of manifest
+ and other conditions, and embed the manifest by calling embedManifestDllAction if so."""
+ if env.get('WINDOWS_EMBED_MANIFEST', 0):
+ manifestSrc = target[0].abspath + '.manifest'
+ if os.path.exists(manifestSrc):
+ ret = (embedManifestDllAction) ([target[0]],None,env)
+ if ret:
+ raise SCons.Errors.UserError, "Unable to embed manifest into %s" % (target[0])
+ return ret
+ else:
+ print '(embed: no %s.manifest found; not embedding.)'%str(target[0])
+ return 0
+
+def embedManifestExeCheck(target, source, env):
+ """Function run by embedManifestExeCheckAction to check for existence of manifest
+ and other conditions, and embed the manifest by calling embedManifestExeAction if so."""
+ if env.get('WINDOWS_EMBED_MANIFEST', 0):
+ manifestSrc = target[0].abspath + '.manifest'
+ if os.path.exists(manifestSrc):
+ ret = (embedManifestExeAction) ([target[0]],None,env)
+ if ret:
+ raise SCons.Errors.UserError, "Unable to embed manifest into %s" % (target[0])
+ return ret
+ else:
+ print '(embed: no %s.manifest found; not embedding.)'%str(target[0])
+ return 0
+
+embedManifestDllCheckAction = SCons.Action.Action(embedManifestDllCheck, None)
+embedManifestExeCheckAction = SCons.Action.Action(embedManifestExeCheck, None)
+
regServerAction = SCons.Action.Action("$REGSVRCOM", "$REGSVRCOMSTR")
regServerCheck = SCons.Action.Action(RegServerFunc, None)
shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_SHLINK_SOURCES")}')
-compositeShLinkAction = shlibLinkAction + regServerCheck
+compositeShLinkAction = shlibLinkAction + regServerCheck + embedManifestDllCheckAction
ldmodLinkAction = SCons.Action.Action('${TEMPFILE("$LDMODULE $LDMODULEFLAGS $_LDMODULE_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_LDMODULE_SOURCES")}')
-compositeLdmodAction = ldmodLinkAction + regServerCheck
+compositeLdmodAction = ldmodLinkAction + regServerCheck + embedManifestDllCheckAction
+exeLinkAction = SCons.Action.Action('${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows")}')
+compositeLinkAction = exeLinkAction + embedManifestExeCheckAction
def generate(env):
"""Add Builders and construction variables for ar to an Environment."""
@@ -209,7 +249,7 @@ def generate(env):
env['LINK'] = 'link'
env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
env['_PDB'] = pdbGenerator
- env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows")}'
+ env['LINKCOM'] = compositeLinkAction
env.Append(PROGEMITTER = [prog_emitter])
env['LIBDIRPREFIX']='/LIBPATH:'
env['LIBDIRSUFFIX']=''
@@ -238,6 +278,18 @@ def generate(env):
env['REGSVRFLAGS'] = '/s '
env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS ${TARGET.windows}'
+ env['WINDOWS_EMBED_MANIFEST'] = 0
+ env['MT'] = 'mt'
+ #env['MTFLAGS'] = ['-hashupdate']
+ env['MTFLAGS'] = SCons.Util.CLVar('/nologo')
+ # Note: use - here to prevent build failure if no manifest produced.
+ # This seems much simpler than a fancy system using a function action to see
+ # if the manifest actually exists before trying to run mt with it.
+ env['MTEXECOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;1'
+ env['MTSHLIBCOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;2'
+ # Future work garyo 27-Feb-11
+ env['_MANIFEST_SOURCES'] = None # _windowsManifestSources
+
# Set-up ms tools paths
msvc_setup_env_once(env)
diff --git a/src/engine/SCons/Tool/mslink.xml b/src/engine/SCons/Tool/mslink.xml
index a2105db..35e8b64 100644
--- a/src/engine/SCons/Tool/mslink.xml
+++ b/src/engine/SCons/Tool/mslink.xml
@@ -94,6 +94,43 @@ see the entry for that variable for specific examples.
</summary>
</cvar>
+<cvar name="WINDOWS_EMBED_MANIFEST">
+<summary>
+Set this variable to True or 1 to embed the compiler-generated manifest
+(normally <literal>${TARGET}.manifest</literal>)
+into all Windows exes and DLLs built with this environment,
+as a resource during their link step.
+This is done using &cv-link-MT; and &cv-link-MTEXECOM; and &cv-link-MTSHLIBCOM;.
+</summary>
+</cvar>
+
+<cvar name="MT">
+<summary>
+The program used on Windows systems to embed manifests into DLLs and EXEs.
+See also &cv-link-WINDOWS_EMBED_MANIFEST;.
+</summary>
+</cvar>
+
+<cvar name="MTFLAGS">
+<summary>
+Flags passed to the &cv-link-MT; manifest embedding program (Windows only).
+</summary>
+</cvar>
+
+<cvar name="MTEXECOM">
+<summary>
+The Windows command line used to embed manifests into executables.
+See also &cv-link-MTSHLIBCOM;.
+</summary>
+</cvar>
+
+<cvar name="MTSHLIBCOM">
+<summary>
+The Windows command line used to embed manifests into shared libraries (DLLs).
+See also &cv-link-MTEXECOM;.
+</summary>
+</cvar>
+
<cvar name="REGSVR">
<summary>
The program used on Windows systems
diff --git a/test/MSVC/embed-manifest.py b/test/MSVC/embed-manifest.py
new file mode 100644
index 0000000..a5a906e
--- /dev/null
+++ b/test/MSVC/embed-manifest.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that manifest files get embedded correctly in EXEs and DLLs
+"""
+
+import sys
+
+import TestSCons
+
+_exe = TestSCons._exe
+_dll = TestSCons._dll
+_lib = TestSCons._lib
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+ msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform
+ test.skip_test(msg)
+
+test.write('SConstruct', """\
+env=Environment(WINDOWS_EMBED_MANIFEST=True)
+env.Append(CCFLAGS = '/MD')
+exe=env.Program('test.cpp')
+dll=env.SharedLibrary('testdll.cpp')
+env.Command('exe-extracted.manifest', exe,
+ '$MT /nologo -inputresource:${SOURCE};1 -out:${TARGET}')
+env.Command('dll-extracted.manifest', dll,
+ '$MT /nologo -inputresource:${SOURCE};2 -out:${TARGET}')
+env2=Environment(WINDOWS_EMBED_MANIFEST=True) # no /MD here
+env2.Program('test-nomanifest', env2.Object('test-nomanifest', 'test.cpp'))
+""")
+
+test.write('test.cpp', """\
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *argv)
+{
+ printf("test.cpp\\n");
+ exit (0);
+}
+""")
+
+test.write('testdll.cpp', """\
+int i;
+""")
+
+test.run(arguments = '.')
+
+test.must_exist('test%s' % _exe)
+test.must_exist('test%s.manifest' % _exe)
+test.must_contain('exe-extracted.manifest', '</assembly>')
+test.must_exist('testdll%s' % _dll)
+test.must_exist('testdll%s.manifest' % _dll)
+test.must_contain('dll-extracted.manifest', '</assembly>')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: