summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorgab@chromium.org <gab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-17 20:15:11 +0000
committergab@chromium.org <gab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-17 20:15:11 +0000
commit08eccdd88478af40d6550c8f1e51c351bb7123e9 (patch)
treeff8fa815223a411205675d1404c2fffb0a9b790b /chrome
parent92afc45a43336c468720a3143e7f2adfa882fa78 (diff)
downloadchromium_src-08eccdd88478af40d6550c8f1e51c351bb7123e9.zip
chromium_src-08eccdd88478af40d6550c8f1e51c351bb7123e9.tar.gz
chromium_src-08eccdd88478af40d6550c8f1e51c351bb7123e9.tar.bz2
Make setup.exe compatible with the component build.
The problem with the current component build is that chrome.exe and setup.exe only know to look for DLLs like base.dll in the current directory (except chrome.dll for which they're hardcoded to know where to look). On an install those DLLs are in the version directory so chrome.exe and setup.exe fail to run not finding required DLLs... To fix this we generate config files (to point in the version directory) and manifests (to list all the DLL dependencies explicitly) to be installed beside the exes. Each DLL also has a manifest in the version directory to give it an "assemblyIdentity" (i.e. a unique name which is referred to as a dependency by each exe's manifest). These manifests are called "assembly manifest" and do NOT interfere with the private manifest possibly embedded in each DLL (details here http://msdn.microsoft.com/en-us/library/windows/desktop/aa374219(v=vs.85).aspx) <dependency> tags then need to be added to chrome.exe.manifest and setup.exe.manifest for each DLL in the version directory it will use (to be safe we make add an entry for all DLLs as there is no downside to referring an unused DLL). In this step, we augment the manifests generated by the build instead of creating new one to make sure any property passed on by the build is kept and that we are only *adding* new functionality without hindering current behavior. NOTE: This CL doesn't make mini_installer.exe compatible with the component build yet (as mini_installer runs setup.exe right after extracting it and without any other DLLs/manifests beside it). However it is now possible to use setup.exe (which takes the exact same parameters as mini_installer.exe) from the build output directory with a component build :)!!! BUG=127233 TEST=Turn on component build with gyp config "component=shared_libary" and make sure we can install chrome with the generated setup.exe. Make sure we can run the installed Chrome. Make sure we can uninstall the installed Chrome (i.e. that setup.exe in <version_dir>/Installer is able to find its DLLs). Review URL: https://chromiumcodereview.appspot.com/10399041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137722 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/chrome_exe.gypi7
-rw-r--r--chrome/chrome_installer.gypi7
-rw-r--r--chrome/installer/mini_installer.gyp10
-rw-r--r--chrome/installer/setup/install_worker.cc20
-rwxr-xr-xchrome/tools/build/win/create_installer_archive.py127
5 files changed, 169 insertions, 2 deletions
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 1bb2b17..f64af02 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -44,6 +44,13 @@
'INFOPLIST_FILE': 'app/app-Info.plist',
},
'conditions': [
+ ['component == "shared_library"', {
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ }],
['order_profiling!=0 and (chromeos==1 or OS=="linux")', {
'dependencies' : [
'../tools/cygprofile/cygprofile.gyp:cygprofile',
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index fa9e0ba..b178e67 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -324,6 +324,13 @@
},
],
'conditions': [
+ ['component == "shared_library"', {
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ }],
# TODO(mark): <(branding_dir) should be defined by the
# global condition block at the bottom of the file, but
# this doesn't work due to the following issue:
diff --git a/chrome/installer/mini_installer.gyp b/chrome/installer/mini_installer.gyp
index 70a607e..e0980db 100644
--- a/chrome/installer/mini_installer.gyp
+++ b/chrome/installer/mini_installer.gyp
@@ -213,6 +213,15 @@
'enable_metro_flag': '',
},
}],
+ ['component == "shared_library"', {
+ 'variables': {
+ 'component_build_flag': '--component_build=1',
+ },
+ }, {
+ 'variables': {
+ 'component_build_flag': '',
+ },
+ }],
],
'inputs': [
'<(create_installer_archive_py_path)',
@@ -241,6 +250,7 @@
'--resource_file_path', '<(INTERMEDIATE_DIR)/packed_files.rc',
'<(enable_hidpi_flag)',
'<(enable_metro_flag)',
+ '<(component_build_flag)',
# TODO(sgk): may just use environment variables
#'--distribution=$(CHROMIUM_BUILD)',
'--distribution=_google_chrome',
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index 74d9a8f..f7067c5 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -794,6 +794,26 @@ void AddInstallWorkItems(const InstallationState& original_state,
temp_path);
}
+ // For the component build to work with the installer, we need to drop a
+ // config file and a manifest by chrome.exe. These files are only found in
+ // the archive if this is a component build.
+#if defined(COMPONENT_BUILD)
+ static const FilePath::CharType kChromeExeConfig[] =
+ FILE_PATH_LITERAL("chrome.exe.config");
+ static const FilePath::CharType kChromeExeManifest[] =
+ FILE_PATH_LITERAL("chrome.exe.manifest");
+ install_list->AddMoveTreeWorkItem(
+ src_path.Append(kChromeExeConfig).value(),
+ target_path.Append(kChromeExeConfig).value(),
+ temp_path.value(),
+ WorkItem::ALWAYS_MOVE);
+ install_list->AddMoveTreeWorkItem(
+ src_path.Append(kChromeExeManifest).value(),
+ target_path.Append(kChromeExeManifest).value(),
+ temp_path.value(),
+ WorkItem::ALWAYS_MOVE);
+#endif // defined(COMPONENT_BUILD)
+
// In the past, we copied rather than moved for system level installs so that
// the permissions of %ProgramFiles% would be picked up. Now that |temp_path|
// is in %ProgramFiles% for system level installs (and in %LOCALAPPDATA%
diff --git a/chrome/tools/build/win/create_installer_archive.py b/chrome/tools/build/win/create_installer_archive.py
index 78bc63b9..f1a1f6b 100755
--- a/chrome/tools/build/win/create_installer_archive.py
+++ b/chrome/tools/build/win/create_installer_archive.py
@@ -312,6 +312,121 @@ def CreateResourceInputFile(
f.write(resource_file)
+# Reads |manifest_name| from |build_dir| and writes |manifest_name| to
+# |output_dir| with the same content plus |inserted_string| added just before
+# |insert_before|.
+def CopyAndAugmentManifest(build_dir, output_dir, manifest_name,
+ inserted_string, insert_before):
+ manifest_file = open(
+ os.path.join(build_dir, manifest_name), 'r')
+ manifest_lines = manifest_file.readlines()
+ manifest_file.close()
+
+ insert_index = next((i for i, s in enumerate(manifest_lines)
+ if s.find(insert_before) != -1), -1)
+ if insert_index == -1:
+ raise ValueError('could not find {0} in the manifest:\n{1}'.format(
+ insert_before, ''.join(manifest_lines)))
+ manifest_lines.insert(insert_index, inserted_string)
+
+ modified_manifest_file = open(
+ os.path.join(output_dir, manifest_name), 'w')
+ modified_manifest_file.write(''.join(manifest_lines))
+ modified_manifest_file.close()
+
+
+# Copies component build DLLs and generates required config files and manifests
+# in order for chrome.exe and setup.exe to be able to find those DLLs at
+# run-time.
+# This is meant for developer builds only and should never be used to package
+# an official build.
+def DoComponentBuildTasks(staging_dir, build_dir, current_version):
+ # Get the required directories for the upcoming operations.
+ chrome_dir = os.path.join(staging_dir, CHROME_DIR)
+ version_dir = os.path.join(chrome_dir, current_version)
+ installer_dir = os.path.join(version_dir, 'Installer')
+ # |installer_dir| is technically only created post-install, but we need it
+ # now to add setup.exe's config and manifest to the archive.
+ if not os.path.exists(installer_dir):
+ os.mkdir(installer_dir)
+
+ # Copy all the DLLs in |build_dir| to the version directory. Simultaneously
+ # build a list of their names to mark them as dependencies of chrome.exe and
+ # setup.exe later.
+ dlls = glob.glob(os.path.join(build_dir, '*.dll'))
+ dll_names = []
+ for dll in dlls:
+ shutil.copy(dll, version_dir)
+ dll_names.append(os.path.splitext(os.path.basename(dll))[0])
+
+ exe_config = (
+ "<configuration>\n"
+ " <windows>\n"
+ " <assemblyBinding xmlns='urn:schemas-microsoft-com:asm.v1'>\n"
+ " <probing privatePath='{rel_path}'/>\n"
+ " </assemblyBinding>\n"
+ " </windows>\n"
+ "</configuration>")
+
+ # Write chrome.exe.config to point to the version directory.
+ chrome_exe_config_file = open(
+ os.path.join(chrome_dir, 'chrome.exe.config'), 'w')
+ chrome_exe_config_file.write(exe_config.format(rel_path=current_version))
+ chrome_exe_config_file.close()
+
+ # Write setup.exe.config to point to the version directory (which is one
+ # level up from setup.exe post-install).
+ setup_exe_config_file = open(
+ os.path.join(installer_dir, 'setup.exe.config'), 'w')
+ setup_exe_config_file.write(exe_config.format(rel_path='..'))
+ setup_exe_config_file.close()
+
+ # Add a dependency for each DLL in |dlls| to the existing manifests for
+ # chrome.exe and setup.exe. Some of these DLLs are not actually used by
+ # either process, but listing them all as dependencies doesn't hurt as it
+ # only makes them visible to the exes, just like they already are in the
+ # build output directory.
+ exe_manifest_dependencies_list = []
+ for name in dll_names:
+ exe_manifest_dependencies_list.append(
+ " <dependency>\n"
+ " <dependentAssembly>\n"
+ " <assemblyIdentity type='win32' name='chrome.{dll_name}'\n"
+ " version='0.0.0.0' processorArchitecture='x86'\n"
+ " language='*'/>\n"
+ " </dependentAssembly>\n"
+ " </dependency>\n".format(dll_name=name))
+
+ exe_manifest_dependencies = ''.join(exe_manifest_dependencies_list)
+
+ # Write a modified chrome.exe.manifest beside chrome.exe.
+ CopyAndAugmentManifest(build_dir, chrome_dir, 'chrome.exe.manifest',
+ exe_manifest_dependencies, '</assembly>')
+
+ # Write a modified setup.exe.manifest beside setup.exe in
+ # |version_dir|/Installer.
+ CopyAndAugmentManifest(build_dir, installer_dir, 'setup.exe.manifest',
+ exe_manifest_dependencies, '</assembly>')
+
+ # Generate assembly manifests for each DLL in |dlls|. These do not interfere
+ # with the private manifests potentially embedded in each DLL. They simply
+ # allow chrome.exe and setup.exe to see those DLLs although they are in a
+ # separate directory post-install.
+ for name in dll_names:
+ dll_manifest = (
+ "<assembly\n"
+ " xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>\n"
+ " <assemblyIdentity name='chrome.{dll_name}' version='0.0.0.0'\n"
+ " type='win32' processorArchitecture='x86'/>\n"
+ " <file name='{dll_name}.dll'/>\n"
+ "</assembly>".format(dll_name=name))
+
+ dll_manifest_file = open(os.path.join(
+ version_dir, "chrome.{dll_name}.manifest".format(dll_name=name)), 'w')
+ dll_manifest_file.write(dll_manifest)
+ dll_manifest_file.close()
+
+
def main(options):
"""Main method that reads input file, creates archive file and write
resource input file.
@@ -338,6 +453,9 @@ def main(options):
staging_dir, options.build_dir,
options.enable_hidpi, options.enable_metro)
+ if options.component_build == '1':
+ DoComponentBuildTasks(staging_dir, options.build_dir, current_version)
+
version_numbers = current_version.split('.')
current_build_number = version_numbers[2] + '.' + version_numbers[3]
prev_build_number = ''
@@ -393,6 +511,8 @@ def _ParseOptions():
parser.add_option('--enable_metro', default='0',
help='Whether to include resource files from the "METRO" section of the '
'input file.')
+ parser.add_option('--component_build', default='0',
+ help='Whether this archive is packaging a component build.')
options, args = parser.parse_args()
if not options.build_dir:
@@ -401,12 +521,15 @@ def _ParseOptions():
if not options.staging_dir:
parser.error('You must provide a staging dir.')
+ if not options.input_file:
+ parser.error('You must provide an input file')
+
if not options.output_dir:
options.output_dir = options.build_dir
if not options.resource_file_path:
- options.options.resource_file_path = os.path.join(options.build_dir,
- MINI_INSTALLER_INPUT_FILE)
+ options.resource_file_path = os.path.join(options.build_dir,
+ MINI_INSTALLER_INPUT_FILE)
return options